diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..185873ad02a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,33 @@ +name: Bug Report +description: Create a report to help us improve +title: "[BUG] - Issue Title" +labels: bug + +body: + - type: markdown + attributes: + value: "## Describe the bug\nA clear and concise description of what the bug is." + + - type: textarea + attributes: + label: Steps to Reproduce + description: "List the steps to reproduce the bug." + placeholder: "1. Go to '...'\n2. Click on '...'\n3. See error" + + - type: textarea + attributes: + label: Expected Behavior + description: "Describe the behavior you expected to see." + placeholder: "A clear and concise description of what you expected to happen." + + - type: input + attributes: + label: Servicecomb Version + description: "Please provide your Servicecomb version" + placeholder: "3.2.4" + + - type: textarea + attributes: + label: Additional Context + description: "Add any other context about the problem here." + placeholder: "Any additional information that might help us debug the issue." diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..16fd2512ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,18 @@ +blank_issues_enabled: false +contact_links: + - name: "Contact Support" + url: "mailto:dev@servicecomb.apache.org" + about: "If you need help, please contact us." +templates: + - name: "Bug Report" + description: "Report a bug or issue." + filename: "bug_report.yml" + - name: "Feature Request" + description: "Request a new feature or improvement." + filename: "feature_request.yml" + - name: "Documentation Issue" + description: "Report an issue with documentation." + filename: "documentation_issue.yml" + - name: "Question" + description: "Ask a question or seek help." + filename: "question.yml" diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.yml b/.github/ISSUE_TEMPLATE/documentation_issue.yml new file mode 100644 index 00000000000..94ef3490041 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation_issue.yml @@ -0,0 +1,27 @@ +name: Documentation Issue +description: Report an issue with the documentation +title: "[DOCUMENTATION] - Documentation Issue Title" +labels: documentation + +body: + - type: markdown + attributes: + value: "## Describe the documentation issue\nA clear and concise description of the issue with the documentation." + + - type: textarea + attributes: + label: Location in documentation + description: "Please provide the URL or section where the issue appears." + placeholder: "e.g. https://docs.example.com/section" + + - type: textarea + attributes: + label: What should be changed? + description: "Please describe what changes or improvements should be made to the documentation." + placeholder: "Explain how we can improve the content." + + - type: textarea + attributes: + label: Additional Context + description: "Provide any other context or examples here." + placeholder: "Additional comments or suggestions for the documentation." diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..3a44565e0b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,33 @@ +name: Feature Request +description: Suggest an idea or feature for this project +title: "[FEATURE] - Feature Title" +labels: enhancement + +body: + - type: markdown + attributes: + value: "## Describe the feature request\nA clear and concise description of what you want to be added to the project." + + - type: textarea + attributes: + label: Problem this feature would solve + description: "Please describe the problem or challenge you're facing." + placeholder: "Explain why this feature would be helpful." + + - type: textarea + attributes: + label: Describe the solution + description: "How do you envision this feature working?" + placeholder: "Provide a description of how the feature would solve the problem." + + - type: textarea + attributes: + label: Alternatives considered + description: "Have you considered other solutions or alternatives? If yes, describe them." + placeholder: "Provide any alternative solutions you've thought about." + + - type: textarea + attributes: + label: Additional Context + description: "Any other context or information that might help us implement this feature." + placeholder: "Include any links, mockups, or additional details." diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 00000000000..af3f350b518 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,27 @@ +name: General Question +description: Ask a general question related to the project +title: "[QUESTION] - Question Title" +labels: question + +body: + - type: markdown + attributes: + value: "## What is your question?\nDescribe the question or issue you are facing. Be as specific as possible." + + - type: textarea + attributes: + label: Steps to reproduce (if applicable) + description: "If your question is about a specific problem or bug, please include steps to reproduce it." + placeholder: "Provide steps, if applicable." + + - type: textarea + attributes: + label: What have you tried so far? + description: "Please explain what you have already tried to resolve the issue or answer the question." + placeholder: "Describe the steps you've taken." + + - type: textarea + attributes: + label: Additional context + description: "Provide any other context or information related to the question." + placeholder: "Include any relevant links or background information." diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0bcae50e7f5..2d30faefa0b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ Follow this checklist to help us incorporate your contribution quickly and easil - [ ] Each commit in the pull request should have a meaningful subject line and body. - [ ] Format the pull request title like `[SCB-XXX] Fixes bug in ApproximateQuantiles`, where you replace `SCB-XXX` with the appropriate JIRA issue. - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. - - [ ] Run `mvn clean install` to make sure basic checks pass. A more thorough check will be performed on your pull request automatically. + - [ ] Run `mvn clean install -Pit` to make sure basic checks pass. A more thorough check will be performed on your pull request automatically. - [ ] If this contribution is large, please file an Apache [Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf). --- diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..7f7754fc299 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "monthly" + open-pull-requests-limit: 20 diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml new file mode 100644 index 00000000000..3f97b9f1818 --- /dev/null +++ b/.github/workflows/checkstyle.yml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: checkstyle +on: + pull_request: + branches: + - master + +jobs: + checkstyle: + timeout-minutes: 60 + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - name: Set up jdk + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + - name: checkstyle + run: mvn checkstyle:check -B -Pit diff --git a/.github/workflows/linelint.yml b/.github/workflows/linelint.yml new file mode 100644 index 00000000000..8d5112ea3d6 --- /dev/null +++ b/.github/workflows/linelint.yml @@ -0,0 +1,35 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: line lint +on: + pull_request: + branches: + - master + +jobs: + linelint: + timeout-minutes: 60 + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - name: install linelint + run: cargo install linelint-cli + - name: Run linelint check + run: linelint check diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000000..24118c35c99 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,52 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Java CI with Maven + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + timeout-minutes: 60 + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v6 + - name: Set up jdk + uses: actions/setup-java@v5 + with: + java-version: '17.0.8' + distribution: 'temurin' + - name: Set up Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.9 + - uses: actions/cache@v5 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Compilation and Installation + run: mvn clean verify -Dcheckstyle.skip=true -B -Pdocker -Pjacoco -Pit -Pcoverage diff --git a/.github/workflows/rat_check.yml b/.github/workflows/rat_check.yml new file mode 100644 index 00000000000..c2db2508fea --- /dev/null +++ b/.github/workflows/rat_check.yml @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: rat check +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + rat_check: + timeout-minutes: 60 + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + - name: Set up jdk + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + - name: rat check + run: mvn apache-rat:check -B -Pit,release diff --git a/.github/workflows/typo_check.yml b/.github/workflows/typo_check.yml new file mode 100644 index 00000000000..999530a79f7 --- /dev/null +++ b/.github/workflows/typo_check.yml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: typo check +on: + pull_request: + branches: + - master + +jobs: + typo-check: + timeout-minutes: 60 + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + # To run the typo check locally, you can follow these steps: + # 1. Install typos locally using cargo: + # cargo install typos-cli + # 2. Run the typo check with the following command: + # typos + - name: Check typos + uses: crate-ci/typos@v1.38.1 diff --git a/.travis.settings.xml b/.travis.settings.xml deleted file mode 100644 index fb86b2013bd..00000000000 --- a/.travis.settings.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - apache.snapshots.https - ${env.SONATYPE_USERNAME} - ${env.SONATYPE_PASSWORD} - - - apache.releases.https - ${env.SONATYPE_USERNAME} - ${env.SONATYPE_PASSWORD} - - - - - passphrase - - /home/travis/build/apache/incubator-servicecomb-java-chassis - 2DE9D2F9 - ${MYPASSP} - - - - diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0c866927cd1..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -sudo: required -language: java -services: -- docker -cache: - directories: - - "$HOME/.m2" -install: true -jobs: - include: - - stage: Compilation and Installation - script: scripts/travis.sh install - - stage: Deploy on - script: if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then bash scripts/travis.sh deploy; - fi diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 00000000000..e8b6eb33f39 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +[default.extend-words] +"fo" = "fo" +"VERTX" = "VERTX" +"Vertx" = "Vertx" +"vertx" = "vertx" + +[files] +extend-exclude = [ + "**/cobertura.ser" +] +[default] +extend-ignore-words-re = [ + "Verticle", + "verticle", + "VERTICLE", + "Prelease", + "cobertura", + "ser", +] diff --git a/LICENSE b/LICENSE index 48c8a8e595a..7898c758729 100644 --- a/LICENSE +++ b/LICENSE @@ -210,18 +210,12 @@ following licenses. ================================================================ -For foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/MimeTypesUtils.java -transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java +For foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java + transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java ================================================================ This product bundles files from vertx which is licensed under the Apache License v2. For details, see https://github.com/vert-x3/vertx-web -================================================================ -For foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java -================================================================ -This product bundles files from vertx which is licensed under the Apache License v2. -For details, see https://github.com/eclipse-vertx/vert.x - ================================================================ For swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java ================================================================ @@ -229,7 +223,26 @@ This product bundles files from swagger which is licensed under the Apache Licen For details, see https://github.com/swagger-api/swagger-core ================================================================ -For handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java +For foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldSchema.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldTypeUtils.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/HashFieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/ByteArrayInputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/InputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/OutputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/package-info.java + foundations/foundation-protobuf/src/main/java/io/protostuff/ProtobufOutputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaReader.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java +================================================================ +This product bundles files from protostuff which is licensed under the Apache License v2. +For details, see https://github.com/protostuff/protostuff + +================================================================ +For foundations/foundation-protobuf/src/main/resources/google/protobuf/any.proto +For foundations/foundation-protobuf/src/main/resources/google/protobuf/empty.proto ================================================================ -This product bundles files from Hystrix which is licensed under the Apache License v2. -For details, see https://github.com/Netflix/Hystrix +This product bundles files from swagger which is licensed under the BSD-3-Clause. +For details, see https://github.com/protocolbuffers/protobuf diff --git a/NOTICE b/NOTICE index 03549d5b704..e4df59ae99a 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache ServiceComb Java Chassis -Copyright 2017-2018 The Apache Software Foundation +Copyright 2017-2025 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index 24c7ac84088..b2fbc167625 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,97 @@ -# Java Chassis -[![Build Status](https://travis-ci.org/apache/servicecomb-java-chassis.svg?branch=master)](https://travis-ci.org/apache/servicecomb-java-chassis?branch=master) [![Coverage Status](https://coveralls.io/repos/github/apache/servicecomb-java-chassis/badge.svg?branch=master)](https://coveralls.io/github/apache/servicecomb-java-chassis?branch=master) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.servicecomb/java-chassis-core/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Gitter](https://img.shields.io/badge/ServiceComb-Gitter-ff69b4.svg)](https://gitter.im/ServiceCombUsers/Lobby) +# Java Chassis [中文](README_ZH.md) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.servicecomb/java-chassis-core/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -Apache ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features +Apache ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features. -## Quick Start +> If you find this project helpful, please don't forget to `star` it. -Provider service: +# releases + +| Release Train | Latest Version | Compiled JDK Version | Tested JDK Version | Open API | Notes | +|----------------|----------------|----------------------|--------------------|----------|--------------------------| +| Java Chassis 3 | 3.3.0 | OpenJDK 17 | OpenJDK 17 | 3.0.x | Depends on Spring Boot 3 | +| Java Chassis 2 | 2.8.24 | OpenJDK 8 | OpenJDK 8, 11, 17 | 2.0.x | Depends on Spring 5 | +| Java Chassis 1 | 1.3.11 | OpenJDK 8 | OpenJDK 8 | 2.0.x | End of Support | + +Java Chassis core dependencies + +| Java Chassis | Spring Boot | Vert.x | Swagger | Jackson | +|--------------|-------------|--------|---------|---------| +| 3.3.x | 3.4.x | 4.5.x | 2.2.x | 2.18.x | +| 3.2.x | 3.3.x | 4.5.x | 2.2.x | 2.18.x | + +> NOTICE: Since Open API 3.0.x is not compatible with 2.0.x, Java Chassis 2 and Java Chassis 1 can not +> work together with Java Chassis 3. All related consumers, providers and edge service need use Java Chassis 3 when upgrading. + +> NOTICE: Java Chassis 1 reached its end of support now after it's first release from 2018. + +# Quick Start + +* Define API ```java -import org.apache.servicecomb.*; -@RpcSchema(schemaId = "helloworld") -public class HelloWorldProvider implements HelloWorld { - public String sayHello(String name) { - return "Hello " + name; - } +@RequestMapping(path = "/provider") +public interface ProviderService { + @GetMapping("/sayHello") + String sayHello(@RequestParam("name") String name); } ``` -Consumer service: +* Provider service ```java -import org.apache.servicecomb.*; -@Component -public class HelloWorldConsumer { - @RpcReference(microserviceName = "pojo", schemaId = "helloworld") - private static HelloWorld helloWorld; - - public static void main(String[] args) { - helloWorld.sayHello("Tank"); - } +@RestSchema(schemaId = "ProviderController", schemaInterface = ProviderService.class) +public class ProviderController implements ProviderService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } } ``` -## Documentation +* Consumer service +```java +@Configuration +public class ProviderServiceConfiguration { + @Bean + public ProviderService providerService() { + return Invoker.createProxy("provider", "ProviderController", ProviderService.class); + } +} +``` -Project documentation is available on the [ServiceComb website][servicecomb-website]. +Invoke Provider service with RPC +```java +@RestSchema(schemaId = "ConsumerController", schemaInterface = ConsumerService.class) +public class ConsumerController implements ConsumerService { + private ProviderService providerService; + + @Autowired + public void setProviderService(ProviderService providerService) { + this.providerService = providerService; + } + + @Override + public String sayHello(String name) { + return providerService.sayHello(name); + } +} +``` -[servicecomb-website]: http://servicecomb.apache.org/ +Try out this example [here](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/first-sample.html) . -## Building +# Documentation -You don’t need to build from source to use Java Chassis (binaries in apache nexus ), but if you want to try out the latest and greatest, Java Chassis can be easily built with the maven. You also need JDK 1.8. +Project documentation is available on the [ServiceComb Java Chassis Developer Guide][java-chassis-developer-guide]. - mvn clean install +[java-chassis-developer-guide]: https://servicecomb.apache.org/references/java-chassis/zh_CN/ -If you want to build the release kits from the source +# Building - mvn clean install -Prelease,distribution + You don’t need to build from source to use Java Chassis (binaries in apache nexus ), but if you want to try out the latest and greatest, Java Chassis can be easily built with the maven. You also need JDK 17. + + mvn clean install The first build may take a longer than expected as Maven downloads all the dependencies. -## Automated Testing +# Automated Testing To build the docker image and run the integration tests with docker, you can use maven docker profile @@ -58,19 +101,16 @@ The first build may take a longer than expected as Maven downloads all the depen mvn clean install -Pdocker -Pit -Pdocker-machine - -## Get The Latest Release - -[Download Java-Chassis](http://servicecomb.apache.org/release/java-chassis-downloads/) - - -## Contact +# Contact Bugs: [issues](https://issues.apache.org/jira/browse/SCB) mailing list: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [dev](https://lists.apache.org/list.html?dev@servicecomb.apache.org) -## Contributing +# Contributing See [CONTRIBUTING](http://servicecomb.apache.org/developers/contributing) for details on submitting patches and the contribution workflow. + +# License +Licensed under an [Apache 2.0 license](LICENSE). diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 00000000000..bfae9746c2b --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,124 @@ +# Java Chassis | [English](README.md) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.servicecomb/java-chassis-core/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) + +Apache ServiceComb Java Chassis 给开发者提供一个快速构建微服务的JAVA SDK。它包含如下特性: + +* 基于Open API的契约优先(API First)开发模式,满足开发过程可管理、开发规范可验证要求。 +* 多种开发风格,REST(JAX-RS、Spring MVC)和RPC等,高效支持遗留系统迁移和新系统开发场景。 +* 多种通信协议, HTTP over Vert.x、Http Over Servlet、Highway等,满足不同场景对于性能、韧性的需求。 +* 统一一致的服务提供者、服务消费者处理链,易于扩展新功能。 +* 提供服务发现、配置管理、熔断、限流、灰度发布等开箱即用的服务治理能力。 + +可以通过[设计选型参考](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/design.html) 了解更多特性和设计原理。 + +> 如果发现项目能帮助到您,别忘了点击右上角`star`表示鼓励。 + +# 发布版本 + +| 版本火车 | 最新版本 | 编译的JDK版本 | 支持的JDK版本 | Open API | 备注 | +|----------------|--------|------------|-------------------|----------|-----------------| +| Java Chassis 3 | 3.3.0 | OpenJDK 17 | OpenJDK 17 | 3.0.x | 依赖Spring Boot 3 | +| Java Chassis 2 | 2.8.24 | OpenJDK 8 | OpenJDK 8, 11, 17 | 2.0.x | 依赖Spring 5 | +| Java Chassis 1 | 1.3.11 | OpenJDK 8 | OpenJDK 8 | 2.0.x | 停止更新 | + +Java Chassis 的核心依赖 + +| Java Chassis | Spring Boot | Vert.x | Swagger | Jackson | +|--------------|-------------|--------|---------|---------| +| 3.3.x | 3.4.x | 4.5.x | 2.2.x | 2.18.x | +| 3.2.x | 3.3.x | 4.5.x | 2.2.x | 2.18.x | + +> NOTICE: Open API 3.0.x 不兼容 2.0.x, 因此Java Chassis 2、Java Chassis 1不能与Java Chassis 3共存互访. 升级Java Chassis 3, 需要将相关的消费者、提供者和边缘服务同时升级. + +> NOTICE: Java Chassis 1 第一个版本于2018发布,已经停止更新. + +# 快速开始 + +* 定义服务契约 + +```java +@RequestMapping(path = "/provider") +public interface ProviderService { + @GetMapping("/sayHello") + String sayHello(@RequestParam("name") String name); +} +``` + +* 定义提供者 + +```java +@RestSchema(schemaId = "ProviderController", schemaInterface = ProviderService.class) +public class ProviderController implements ProviderService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } +} +``` + +* 定义消费者 + +```java +@Configuration +public class ProviderServiceConfiguration { + @Bean + public ProviderService providerService() { + return Invoker.createProxy("provider", "ProviderController", ProviderService.class); + } +} +``` + +使用RPC方式访问提供者。 + +```java +@RestSchema(schemaId = "ConsumerController", schemaInterface = ConsumerService.class) +public class ConsumerController implements ConsumerService { + private ProviderService providerService; + + @Autowired + public void setProviderService(ProviderService providerService) { + this.providerService = providerService; + } + + @Override + public String sayHello(String name) { + return providerService.sayHello(name); + } +} +``` + +下载并体验上述[示例项目](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/first-sample.html) . + +# 用户文档 + +请访问 [ServiceComb Java Chassis 开发指南][java-chassis-developer-guide]. + +[java-chassis-developer-guide]: https://servicecomb.apache.org/references/java-chassis/zh_CN/ + +# 编译 Java Chassis + +开发者可以通过MAVEN仓库使用Java Chassis。 如果需要构建项目,需要使用JDK 17版本,并预先安装maven。 + + mvn clean install + +# 运行测试用例 + +开发者需要预先安装docker。 + + mvn clean install -Pdocker -Pit + +使用docker machine。 + + mvn clean install -Pdocker -Pit -Pdocker-machine + +# 联系我们 + +报告缺陷: [issues](https://issues.apache.org/jira/browse/SCB) + +邮件列表: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [dev](https://lists.apache.org/list.html?dev@servicecomb.apache.org) + +# 参与代码提交 + +参考 [如何做贡献](http://servicecomb.apache.org/cn/developers/contributing). + +# License +Licensed under an [Apache 2.0 license](LICENSE). diff --git a/archetypes/README.md b/archetypes/README.md deleted file mode 100644 index 84663b55380..00000000000 --- a/archetypes/README.md +++ /dev/null @@ -1,52 +0,0 @@ -## ServiceComb Java Chassis Archetypes -### What's maven archetypes -From http://maven.apache.org/guides/introduction/introduction-to-archetypes.html : - ->In short, Archetype is a Maven project templating toolkit. An archetype is defined as an original pattern or model from which all other things of the same kind are made. The name fits as we are trying to provide a system that provides a consistent means of generating Maven projects. Archetype will help authors create Maven project templates for users, and provides users with the means to generate parameterized versions of those project templates. - -### What we provide -1. business-service-jaxrs - - Archetype for create a common microservice using jaxrs provider. - -2. business-service-springmvc - - Archetype for create a common microservice using springmvc provider. - -3. business-service-pojo - - Archetype for create a common microservice using pojo provider. - -4. business-service-spring-boot-starter - - Archetype for create a common microservice using spring-boot-starter provider. - -### How to build these archetypes -We use **business-service-jaxrs** as an example : - -```bash -cd archetypes -mvn install -``` - -### How to use these archetypes to generate a project -We use **business-service-jaxrs** as an example : -#### Generate via IntelliJ IDEA -New Project(Module) -> Maven -> Check "Create from archetype" -> Add Archetype... -> fill *GroupId* with value "org.apache.servicecomb.archetypes", fill *ArtifactId* with value "business-service-jaxrs-archetype", fill *Version* with current archetype version -> select this archetype that had listed, do next steps. - -#### Generate via Eclipse -New Project(Module) -> Maven -> Next -> Add Archetype... -> fill *GroupId* with value "org.apache.servicecomb.archetypes", fill *ArtifactId* with value "business-service-jaxrs-archetype", fill *Version* with current archetype version -> select this archetype that had listed, do next steps. - -#### Generate via command - -```bash -mvn archetype:generate -DarchetypeGroupId=org.apache.servicecomb.archetypes -DarchetypeArtifactId=business-service-jaxrs-archetype -DarchetypeVersion=${archetype-version} -``` - -In console Interactive mode, input your GroupId, ArtifactId and Version of new project(module), after a while the new project will be generated. - -*Notice: We will publish these archetypes to maven center repository since 1.0.0-m2, if you would like to use an archetype from an unreleased version, must use `archetypeRepository` option in the version 2.4 of archetype-plugin in order to set maven repository to apache snapshot groups: * - -```bash -mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=org.apache.servicecomb.archetypes -DarchetypeArtifactId=business-service-jaxrs-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DarchetypeRepository=https://repository.apache.org/content/groups/snapshots-group -``` \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/README.md b/archetypes/business-service-jaxrs/README.md deleted file mode 100644 index 0f1c6221030..00000000000 --- a/archetypes/business-service-jaxrs/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-jaxrs-archetype*, it use **jaxrs provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-jax-rs/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/pom.xml b/archetypes/business-service-jaxrs/pom.xml deleted file mode 100644 index e0ead9ace9a..00000000000 --- a/archetypes/business-service-jaxrs/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - org.apache.servicecomb - archetypes - 1.2.0-SNAPSHOT - - - org.apache.servicecomb.archetypes - Java Chassis::Archetypes::JAXRS - business-service-jaxrs-archetype - maven-archetype - 4.0.0 - - - 2.3 - - - - - - org.apache.maven.archetype - archetype-packaging - ${maven-archetype-packaging-version} - - - - - - src/main/resources - false - - - src/main/resources-filtered - true - - **/archetype-metadata.xml - - - - - \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml deleted file mode 100644 index e953ae8b716..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - src/main/java - - **/*.java - - - - src/main/resources - - **/* - - - - - - README.md - - - - \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md deleted file mode 100644 index 2f34861a897..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-jaxrs-archetype*, it use **jaxrs provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-jax-rs/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml deleted file mode 100644 index 9a77ae2a7f4..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - ${groupId} - ${artifactId} - ${version} - 4.0.0 - - - UTF-8 - 1.2.0-SNAPSHOT - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - provider-jaxrs - - - org.slf4j - slf4j-log4j12 - - - - - org.apache.servicecomb - provider-springmvc - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - true - lib/ - - ${your-package}.Application - - - . - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - package - - copy-dependencies - - - target/lib - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - - \ No newline at end of file diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java deleted file mode 100644 index 9371b4eed50..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class Application { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java deleted file mode 100644 index 2f4d59a7742..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.springframework.web.client.RestTemplate; - -public class HelloConsumer { - private final RestTemplate restTemplate = RestTemplateBuilder.create(); - - public void invokeHello() { - //service url is : cse://serviceName/operation - restTemplate.getForObject("cse://business-service/hello", String.class); - } -} diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java deleted file mode 100644 index 25bc12f7292..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "hello") -@Path("/") -public class HelloImpl { - - @Path("/hello") - @GET - public String hello() { - return "Hello World!"; - } -} diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml deleted file mode 100644 index cc63634ce54..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml deleted file mode 100644 index cbed0862768..00000000000 --- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml +++ /dev/null @@ -1,43 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -#More details can be found : -# 1.http://servicecomb.apache.org/users/service-definition/ -# 2.http://servicecomb.apache.org/users/service-configurations/ -# 3.http://servicecomb.apache.org/users/communicate-protocol/ - -#Indicates an application name -APPLICATION_ID: business -service_description: -#Indicates a microservice name -#The microservice name should be unique within an application. -#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations. -#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$. - name: business-service -#Indicates a service version - version: 1.0.0 -servicecomb: - service: - #Specifies the service center IP address. - registry: - address: http://127.0.0.1:30100 - #Specifies the rest transport listening IP address. - rest: - address: 0.0.0.0:8080 - #Specifies the highway transport listening IP address. - highway: - address: 0.0.0.0:7070 \ No newline at end of file diff --git a/archetypes/business-service-pojo/README.md b/archetypes/business-service-pojo/README.md deleted file mode 100644 index 333d938b14b..00000000000 --- a/archetypes/business-service-pojo/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-pojo-archetype*, it use **pojo provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-transparent-rpc/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-pojo/pom.xml b/archetypes/business-service-pojo/pom.xml deleted file mode 100644 index e9deb180877..00000000000 --- a/archetypes/business-service-pojo/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - org.apache.servicecomb - archetypes - 1.2.0-SNAPSHOT - - - org.apache.servicecomb.archetypes - Java Chassis::Archetypes::POJO - business-service-pojo-archetype - maven-archetype - 4.0.0 - - - 2.3 - - - - - - org.apache.maven.archetype - archetype-packaging - ${maven-archetype-packaging-version} - - - - - - src/main/resources - false - - - src/main/resources-filtered - true - - **/archetype-metadata.xml - - - - - \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml deleted file mode 100644 index e953ae8b716..00000000000 --- a/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - src/main/java - - **/*.java - - - - src/main/resources - - **/* - - - - - - README.md - - - - \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md b/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md deleted file mode 100644 index 003255e3665..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-pojo-archetype*, it use **pojo provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-transparent-rpc/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml deleted file mode 100644 index b3d16e6d887..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - ${groupId} - ${artifactId} - ${version} - 4.0.0 - - - UTF-8 - 1.2.0-SNAPSHOT - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - true - lib/ - - ${your-package}.Application - - - . - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - package - - copy-dependencies - - - target/lib - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - - \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java deleted file mode 100644 index 20ca721b68e..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class Application { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java deleted file mode 100644 index 1d7d65140e9..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -public interface Hello { - String hello(); -} \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java deleted file mode 100644 index 74ddadbee68..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.springframework.stereotype.Component; - -@Component -public class HelloConsumer { - @RpcReference(microserviceName = "business-service", schemaId = "hello") - private Hello hello; - - public Hello getHello() { - return hello; - } - - public void invokeHello() { - getHello().hello(); - } -} \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java deleted file mode 100644 index 487685a58b6..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.pojo.RpcSchema; - -@RpcSchema(schemaId = "hello") -public class HelloImpl implements Hello { - - public String hello() { - return "Hello World!"; - } -} \ No newline at end of file diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml deleted file mode 100644 index cc63634ce54..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml deleted file mode 100644 index cbed0862768..00000000000 --- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml +++ /dev/null @@ -1,43 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -#More details can be found : -# 1.http://servicecomb.apache.org/users/service-definition/ -# 2.http://servicecomb.apache.org/users/service-configurations/ -# 3.http://servicecomb.apache.org/users/communicate-protocol/ - -#Indicates an application name -APPLICATION_ID: business -service_description: -#Indicates a microservice name -#The microservice name should be unique within an application. -#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations. -#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$. - name: business-service -#Indicates a service version - version: 1.0.0 -servicecomb: - service: - #Specifies the service center IP address. - registry: - address: http://127.0.0.1:30100 - #Specifies the rest transport listening IP address. - rest: - address: 0.0.0.0:8080 - #Specifies the highway transport listening IP address. - highway: - address: 0.0.0.0:7070 \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/README.md b/archetypes/business-service-spring-boot-starter/README.md deleted file mode 100644 index 1017e8708ca..00000000000 --- a/archetypes/business-service-spring-boot-starter/README.md +++ /dev/null @@ -1,36 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-spring-boot-starter-archetype*, it use **spring-boot-starter-provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-spring-boot-starter/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get executable jar in target/bin folder: -- xxxxxx-{version}-exec.jar -```bash -java -jar xxxxxx-{version}-exec.jar -``` -*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.*** - -## Spring Boot and ServiceComb -### Why ServiceComb make integration with Spring Boot -Spring Boot can accelerate develop speed of Spring application, it provides these features: -* Can create independent executable Spring application -* Tomcat embedded, Jetty as Web server, and do not need package(war) -* Provide many starters in order to simplify maven dependency - -Using Spring Boot in microservice development, can greatly simplifying configure and deploy. ServiceComb is a microservice framework with full functionality of service management, focus on rapidly development of microservices, so integration with Spring Boot can obtain greater advantages. - -### How ServiceComb make integration with Spring Boot -Developers often use Spring Boot in the following way: -* Java application : import `spring-boot-starter` then develop general application, does not contain WEB -* Web application : import `spring-boot-starter-web` then develop web application, also include an embedded Tomcat or Jetty server, and use Spring Web MVC framework to develop REST endpoints - -The first way, do not need any refactoring, directly startup ServiceComb via Spring Boot. - -The second way is replace `Spring MVC DispatcherServlet` with `ServiceComb RestServlet`. \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/pom.xml b/archetypes/business-service-spring-boot-starter/pom.xml deleted file mode 100644 index 6da404c6935..00000000000 --- a/archetypes/business-service-spring-boot-starter/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - org.apache.servicecomb - archetypes - 1.2.0-SNAPSHOT - - - org.apache.servicecomb.archetypes - Java Chassis::Archetypes::Spring Boot Starter - business-service-spring-boot-starter-archetype - maven-archetype - 4.0.0 - - - 2.3 - - - - - - org.apache.maven.archetype - archetype-packaging - ${maven-archetype-packaging-version} - - - - - - src/main/resources - false - - - src/main/resources-filtered - true - - **/archetype-metadata.xml - - - - - \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-spring-boot-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml deleted file mode 100644 index e953ae8b716..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - src/main/java - - **/*.java - - - - src/main/resources - - **/* - - - - - - README.md - - - - \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/README.md b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/README.md deleted file mode 100644 index 8a0b8c740b1..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/README.md +++ /dev/null @@ -1,36 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-spring-boot-starter-archetype*, it use **spring-boot-starter-provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-spring-boot-starter/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get executable jar in target/bin folder: -- xxxxxx-{version}-exec.jar -```bash -java -jar xxxxxx-{version}-exec.jar -``` -*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.*** - -## Spring Boot and ServiceComb -### Why ServiceComb make integration with Spring Boot -Spring Boot can accelerate develop speed of Spring application, it provides these features: -* Can create independent executable Spring application -* Tomcat embedded, Jetty as Web server, and do not need package(war) -* Provide many starters in order to simplify maven dependency - -Using Spring Boot in microservice development, can greatly simplifying configure and deploy. ServiceComb is a microservice framework with full functionality of service management, focus on rapidly development of microservices, so integration with Spring Boot can obtain greater advantages. - -### How ServiceComb make integration with Spring Boot -Developers often use Spring Boot in the following way: -* Java application : import `spring-boot-starter` then develop general application, does not contain WEB -* Web application : import `spring-boot-starter-web` then develop web application, also include an embedded Tomcat or Jetty server, and use Spring Web MVC framework to develop REST endpoints - -The first way, do not need any refactoring, directly startup ServiceComb via Spring Boot. - -The second way is replace `Spring MVC DispatcherServlet` with `ServiceComb RestServlet`. \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/pom.xml deleted file mode 100644 index 5a44dd10ba8..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - ${groupId} - ${artifactId} - ${version} - 4.0.0 - - - UTF-8 - 1.2.0-SNAPSHOT - 1.5.12.RELEASE - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - org.springframework.boot - spring-boot-starter - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.hibernate - hibernate-validator - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${springboot.version} - - - - repackage - - - ${project.build.directory}/bin - exec - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - . - - - - - - - \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/Application.java deleted file mode 100644 index c2e135ed535..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/Application.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java deleted file mode 100644 index 6fc027a0d98..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.springframework.web.client.RestTemplate; - -public class HelloConsumer { - private final RestTemplate restTemplate = RestTemplateBuilder.create(); - - public void invokeHello() { - //service url is : cse://serviceName/operation - restTemplate.getForObject("cse://business-service/hello", String.class); - } -} \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java deleted file mode 100644 index 2a2589356ed..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "hello") -@RequestMapping(path = "/") -public class HelloImpl { - - @GetMapping(path = "/hello") - public String hello() { - return "Hello World!"; - } -} \ No newline at end of file diff --git a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml deleted file mode 100644 index cbed0862768..00000000000 --- a/archetypes/business-service-spring-boot-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml +++ /dev/null @@ -1,43 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -#More details can be found : -# 1.http://servicecomb.apache.org/users/service-definition/ -# 2.http://servicecomb.apache.org/users/service-configurations/ -# 3.http://servicecomb.apache.org/users/communicate-protocol/ - -#Indicates an application name -APPLICATION_ID: business -service_description: -#Indicates a microservice name -#The microservice name should be unique within an application. -#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations. -#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$. - name: business-service -#Indicates a service version - version: 1.0.0 -servicecomb: - service: - #Specifies the service center IP address. - registry: - address: http://127.0.0.1:30100 - #Specifies the rest transport listening IP address. - rest: - address: 0.0.0.0:8080 - #Specifies the highway transport listening IP address. - highway: - address: 0.0.0.0:7070 \ No newline at end of file diff --git a/archetypes/business-service-springmvc/README.md b/archetypes/business-service-springmvc/README.md deleted file mode 100644 index bc15691fb17..00000000000 --- a/archetypes/business-service-springmvc/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-springmvc-archetype*, it use **springmvc provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-springmvc/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-springmvc/pom.xml b/archetypes/business-service-springmvc/pom.xml deleted file mode 100644 index 6fc5e23e57d..00000000000 --- a/archetypes/business-service-springmvc/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - org.apache.servicecomb - archetypes - 1.2.0-SNAPSHOT - - - org.apache.servicecomb.archetypes - Java Chassis::Archetypes::Spring MVC - business-service-springmvc-archetype - maven-archetype - 4.0.0 - - - 2.3 - - - - - - org.apache.maven.archetype - archetype-packaging - ${maven-archetype-packaging-version} - - - - - - src/main/resources - false - - - src/main/resources-filtered - true - - **/archetype-metadata.xml - - - - - \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml deleted file mode 100644 index e953ae8b716..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - src/main/java - - **/*.java - - - - src/main/resources - - **/* - - - - - - README.md - - - - \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md deleted file mode 100644 index a09e727dc15..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## Welcome to use ServiceComb Java Chassis -This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-springmvc-archetype*, it use **springmvc provider** to develop service producer. - -### More works can be done further: -1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-springmvc/ -2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/ -3. Modify setting value of "mainClass" in pom.xml for package. - -### Package your service -Under project(module) root folder, run -```bash -mvn package -``` -Then you can get outputs in target folder: -- lib : contains all dependencies jars -- xxxxxx-{version}.jar -```bash -java -jar xxxxxx-{version}.jar -``` -*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.*** \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml deleted file mode 100644 index 45a3738b858..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - ${groupId} - ${artifactId} - ${version} - 4.0.0 - - - UTF-8 - 1.2.0-SNAPSHOT - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - provider-springmvc - - - org.slf4j - slf4j-log4j12 - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - true - lib/ - - ${your-package}.Application - - - . - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - package - - copy-dependencies - - - target/lib - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - - \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java deleted file mode 100644 index 20ca721b68e..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class Application { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java deleted file mode 100644 index 6fc027a0d98..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.springframework.web.client.RestTemplate; - -public class HelloConsumer { - private final RestTemplate restTemplate = RestTemplateBuilder.create(); - - public void invokeHello() { - //service url is : cse://serviceName/operation - restTemplate.getForObject("cse://business-service/hello", String.class); - } -} \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java deleted file mode 100644 index 2a2589356ed..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ${groupId}; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "hello") -@RequestMapping(path = "/") -public class HelloImpl { - - @GetMapping(path = "/hello") - public String hello() { - return "Hello World!"; - } -} \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml deleted file mode 100644 index a32120937e5..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/META-INF/spring/provider.bean.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml deleted file mode 100644 index cbed0862768..00000000000 --- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml +++ /dev/null @@ -1,43 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -#More details can be found : -# 1.http://servicecomb.apache.org/users/service-definition/ -# 2.http://servicecomb.apache.org/users/service-configurations/ -# 3.http://servicecomb.apache.org/users/communicate-protocol/ - -#Indicates an application name -APPLICATION_ID: business -service_description: -#Indicates a microservice name -#The microservice name should be unique within an application. -#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations. -#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$. - name: business-service -#Indicates a service version - version: 1.0.0 -servicecomb: - service: - #Specifies the service center IP address. - registry: - address: http://127.0.0.1:30100 - #Specifies the rest transport listening IP address. - rest: - address: 0.0.0.0:8080 - #Specifies the highway transport listening IP address. - highway: - address: 0.0.0.0:7070 \ No newline at end of file diff --git a/archetypes/pom.xml b/archetypes/pom.xml deleted file mode 100644 index de1f5fbb882..00000000000 --- a/archetypes/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - java-chassis-parent - 1.2.0-SNAPSHOT - ../parent - - - archetypes - Java Chassis::Archetypes - pom - - business-service-jaxrs - business-service-pojo - business-service-springmvc - business-service-spring-boot-starter - - \ No newline at end of file diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 00000000000..08c14d23741 --- /dev/null +++ b/ci/README.md @@ -0,0 +1,25 @@ +# Java Chassis Code Checks + +* Compilation and Installation + + see .github/workflows/maven.yml + +* Checkstyle + + see .github/workflows/checkstyle.yml + +* Rat Check + + see .github/workflows/rat_check.yml + +* Spot Bugs + + see .github/workflows/spotbugs.yml + +* OWASP Dependency Check + + `mvn verify -Powasp-dependency-check` . Very Slow, run manually. + +* Distribution + + `mvn clean deploy -Dcheckstyle.skip -Dspotbugs.skip=true -Dmaven.javadoc.skip=true -DskipTests -Prelease -Pdistribution` . Run manually when preparing a release. diff --git a/ci/checkstyle/checkstyle.xml b/ci/checkstyle/checkstyle.xml new file mode 100644 index 00000000000..3813950a5c8 --- /dev/null +++ b/ci/checkstyle/checkstyle.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ci/checkstyle/suppressions.xml b/ci/checkstyle/suppressions.xml new file mode 100644 index 00000000000..57e56d56c35 --- /dev/null +++ b/ci/checkstyle/suppressions.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/ci/spotbugs/exclude.xml b/ci/spotbugs/exclude.xml new file mode 100644 index 00000000000..b7c53996e85 --- /dev/null +++ b/ci/spotbugs/exclude.xml @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clients/README.md b/clients/README.md new file mode 100644 index 00000000000..53180a4a03b --- /dev/null +++ b/clients/README.md @@ -0,0 +1,13 @@ +# About + +This module implements common http clients for servicecomb-service-center, servicecomb-kie and other +3rd-party services. + +This module is independent on servicecomb-java-chassis, and can be used in many other projects like +Spring Cloud, Dubbo, etc. + +# 关于 + +这个模块给 servicecomb-service-center, servicecomb-kie 以及其他第三方服务实现通用的 Http Client。 + +这个模块独立于 servicecomb-java-chassis, 可以用于 Spring Cloud, Dubbo 等项目。 diff --git a/clients/config-center-client/pom.xml b/clients/config-center-client/pom.xml new file mode 100644 index 00000000000..e7e2fa1fc2b --- /dev/null +++ b/clients/config-center-client/pom.xml @@ -0,0 +1,45 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + config-center-client + ServiceComb::Clients::Config Center Client + + + + + org.apache.servicecomb + http-client-common + + + + org.apache.servicecomb + config-clients-common + + + diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java new file mode 100644 index 00000000000..977c84ef63f --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client; + +import java.util.List; + +import org.apache.servicecomb.http.client.common.AbstractAddressManager; +import org.apache.servicecomb.http.client.common.URLEndPoint; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ConfigCenterAddressManager extends AbstractAddressManager { + + public ConfigCenterAddressManager(String projectName, List addresses, EventBus eventBus, String region, + String availableZone) { + super(projectName, addresses, region, availableZone); + eventBus.register(this); + } + + @Override + protected String normalizeUri(String endpoint) { + String address = new URLEndPoint(endpoint).toString(); + return formatAddress(address); + } + + @Subscribe + public void onRefreshEndpointEvent(RefreshEndpointEvent event) { + refreshEndpoint(event, RefreshEndpointEvent.CONFIG_CENTER_NAME); + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java new file mode 100644 index 00000000000..8ed31a5a61b --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpStatus; +import org.apache.servicecomb.config.common.exception.OperationException; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse; +import org.apache.servicecomb.http.client.common.HttpRequest; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpUtils; +import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent; +import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.eventbus.EventBus; + +public class ConfigCenterClient implements ConfigCenterOperation { + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterClient.class); + + public static final String DEFAULT_APP_SEPARATOR = "@"; + + public static final String DEFAULT_SERVICE_SEPARATOR = "#"; + + public static final String REVISION = "revision"; + + public static final String APPLICATION_CONFIG = "application"; + + public static final String DARK_LAUNCH = "darklaunch@"; + + private static final String ADDRESS_CHECK_PATH = "/v3/default/configuration/health?mode=readiness"; + + private final HttpTransport httpTransport; + + private final ConfigCenterAddressManager addressManager; + + private final Map> dimensionConfigNames = new HashMap<>(); + + private EventBus eventBus; + + public ConfigCenterClient(ConfigCenterAddressManager addressManager, HttpTransport httpTransport) { + this.addressManager = addressManager; + this.httpTransport = httpTransport; + } + + public void setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + addressManager.setEventBus(eventBus); + } + + @Override + public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request, String address) { + String dimensionsInfo = buildDimensionsInfo(request, true); + QueryConfigurationsResponse queryConfigurationsResponse = new QueryConfigurationsResponse(); + + Map configurations = new HashMap<>(); + + String uri = null; + try { + uri = address + "/configuration/items?dimensionsInfo=" + + HttpUtils.encodeURLParam(dimensionsInfo) + "&revision=" + request.getRevision(); + + Map headers = new HashMap<>(); + headers.put("x-environment", request.getEnvironment()); + HttpRequest httpRequest = new HttpRequest(uri, headers, null, + HttpRequest.GET); + + HttpResponse httpResponse = httpTransport.doRequest(httpRequest); + recordAndSendUnAuthorizedEvent(httpResponse, address); + if (httpResponse.getStatusCode() == HttpStatus.SC_OK) { + Map> allConfigMap = HttpUtils.deserialize( + httpResponse.getContent(), + new TypeReference>>() { + }); + + if (allConfigMap.get(REVISION) != null) { + queryConfigurationsResponse.setRevision((String) allConfigMap.get(REVISION).get("version")); + } + + if (allConfigMap.get(APPLICATION_CONFIG) != null) { + configurations.putAll(allConfigMap.get(APPLICATION_CONFIG)); + logConfigurationNames(APPLICATION_CONFIG, allConfigMap.get(APPLICATION_CONFIG)); + } + + if (allConfigMap.get(buildDimensionsInfo(request, false)) != null) { + configurations.putAll(allConfigMap.get(buildDimensionsInfo(request, false))); + logConfigurationNames(buildDimensionsInfo(request, false), + allConfigMap.get(buildDimensionsInfo(request, false))); + } + + if (allConfigMap.get(buildDarkLaunchDimensionsInfo(request)) != null) { + configurations.putAll(allConfigMap.get(buildDarkLaunchDimensionsInfo(request))); + logConfigurationNames(buildDarkLaunchDimensionsInfo(request), + allConfigMap.get(buildDarkLaunchDimensionsInfo(request))); + } + + if (allConfigMap.get(dimensionsInfo) != null) { + configurations.putAll(allConfigMap.get(dimensionsInfo)); + logConfigurationNames(dimensionsInfo, allConfigMap.get(dimensionsInfo)); + } + queryConfigurationsResponse.setConfigurations(configurations); + queryConfigurationsResponse.setChanged(true); + return queryConfigurationsResponse; + } else if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + queryConfigurationsResponse.setChanged(false); + return queryConfigurationsResponse; + } else if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) { + LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", dimensionsInfo); + queryConfigurationsResponse.setChanged(false); + return queryConfigurationsResponse; + } else if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) { + throw new OperationException("Bad request for query configurations."); + } else { + throw new OperationException( + "read response failed. status:" + + httpResponse.getStatusCode() + + "; message:" + + httpResponse.getMessage() + + "; content:" + + httpResponse.getContent()); + } + } catch (IOException e) { + addressManager.recordFailState(address); + LOGGER.error("query configuration from {} failed, message={}", uri, e.getMessage()); + throw new OperationException("", e); + } + } + + private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) { + if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage()); + addressManager.recordFailState(address); + this.eventBus.post(new UnAuthorizedOperationEvent(address)); + } else { + addressManager.recordSuccessState(address); + } + } + + /** + * Only the name of the new configuration item is printed. + * No log is printed when the configuration content is updated. + * + * @param dimension dimension + * @param configs configs + */ + private void logConfigurationNames(String dimension, Map configs) { + if (CollectionUtils.isEmpty(configs)) { + return; + } + List configNames = dimensionConfigNames.get(dimension); + if (configNames == null) { + configNames = new ArrayList<>(); + } + StringBuilder names = new StringBuilder(); + for (String key : configs.keySet()) { + if (configNames.contains(key)) { + continue; + } + names.append(key).append(","); + configNames.add(key); + } + if (names.isEmpty()) { + return; + } + dimensionConfigNames.put(dimension, configNames); + String fileNames = names.substring(0, names.length() - 1); + LOGGER.info("pulling dimension [{}] configurations success, get config names: [{}].", + dimension, fileNames); + } + + @Override + public void checkAddressAvailable(String address) { + ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH); + } + + private String buildDimensionsInfo(QueryConfigurationsRequest request, boolean withVersion) { + String result = + request.getServiceName() + DEFAULT_APP_SEPARATOR + + request.getApplication(); + if (withVersion && !StringUtils.isEmpty(request.getVersion())) { + result = result + DEFAULT_SERVICE_SEPARATOR + request + .getVersion(); + } + return result; + } + + private String buildDarkLaunchDimensionsInfo(QueryConfigurationsRequest request) { + return DARK_LAUNCH + request.getApplication(); + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java new file mode 100644 index 00000000000..448c51a3d79 --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * This event is fired when configuration changed of config center. + */ +public class ConfigCenterConfigurationChangedEvent { + private final Map added; + + private final Map deleted; + + private final Map updated; + + private Set changed; + + private ConfigCenterConfigurationChangedEvent(Map added, Map updated, + Map deleted) { + this.added = added; + this.deleted = deleted; + this.updated = updated; + this.changed = new HashSet<>(); + this.changed.addAll(added.keySet()); + this.changed.addAll(updated.keySet()); + this.changed.addAll(deleted.keySet()); + } + + public static ConfigCenterConfigurationChangedEvent createIncremental(Map latest, + Map last) { + Map itemsCreated = new HashMap<>(); + Map itemsDeleted = new HashMap<>(); + Map itemsModified = new HashMap<>(); + + for (Map.Entry entry : latest.entrySet()) { + String itemKey = entry.getKey(); + if (!last.containsKey(itemKey)) { + itemsCreated.put(itemKey, entry.getValue()); + } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) { + itemsModified.put(itemKey, entry.getValue()); + } + } + for (String itemKey : last.keySet()) { + if (!latest.containsKey(itemKey)) { + itemsDeleted.put(itemKey, null); + } + } + ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent + .createIncremental(itemsCreated, itemsModified, itemsDeleted); + return event; + } + + public static ConfigCenterConfigurationChangedEvent createIncremental(Map added, + Map updated, + Map deleted) { + return new ConfigCenterConfigurationChangedEvent(added, updated, deleted); + } + + public static ConfigCenterConfigurationChangedEvent createIncremental(Map updated) { + return new ConfigCenterConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>()); + } + + public final Map getAdded() { + return added; + } + + + public final Map getUpdated() { + return updated; + } + + + public final Map getDeleted() { + return deleted; + } + + public final Set getChanged() { + return changed; + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java new file mode 100644 index 00000000000..7bfc43b4e05 --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.center.client.model.ConfigCenterConfiguration; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse; +import org.apache.servicecomb.config.common.ConfigConverter; +import org.apache.servicecomb.http.client.task.AbstractTask; +import org.apache.servicecomb.http.client.task.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class ConfigCenterManager extends AbstractTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterManager.class); + + private final ConfigCenterClient configCenterClient; + + private final EventBus eventBus; + + private QueryConfigurationsRequest queryConfigurationsRequest; + + private final ConfigConverter configConverter; + + private final ConfigCenterConfiguration configCenterConfiguration; + + private final ConfigCenterAddressManager configCenterAddressManager; + + public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus, ConfigConverter configConverter, + ConfigCenterConfiguration configCenterConfiguration, ConfigCenterAddressManager configCenterAddressManager) { + super("config-center-configuration-task"); + this.configCenterClient = configCenterClient; + this.eventBus = eventBus; + this.configConverter = configConverter; + this.configCenterConfiguration = configCenterConfiguration; + this.configCenterAddressManager = configCenterAddressManager; + } + + public void setQueryConfigurationsRequest(QueryConfigurationsRequest queryConfigurationsRequest) { + this.queryConfigurationsRequest = queryConfigurationsRequest; + } + + public void startConfigCenterManager() { + this.startTask(new PollConfigurationTask(0)); + schedulerCheckAddressAvailable("cc-addr-check", new CheckConfigCenterAddressTask(), + configCenterConfiguration.getRefreshIntervalInMillis()); + } + + class PollConfigurationTask implements Task { + int failCount; + + public PollConfigurationTask(int failCount) { + this.failCount = failCount; + } + + @Override + public void execute() { + try { + QueryConfigurationsResponse response = configCenterClient.queryConfigurations(queryConfigurationsRequest, + configCenterAddressManager.address()); + if (response.isChanged()) { + queryConfigurationsRequest.setRevision(response.getRevision()); + Map lastData = configConverter.updateData(response.getConfigurations()); + ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent + .createIncremental(configConverter.getCurrentData(), lastData); + if (!event.getChanged().isEmpty()) { + eventBus.post(event); + } + } + startTask( + new BackOffSleepTask(configCenterConfiguration.getRefreshIntervalInMillis(), new PollConfigurationTask(0))); + } catch (Exception e) { + LOGGER.warn("get configurations from ConfigCenter failed, and will try again, cause message: {}. current " + + "fail does not affect the obtained historical configuration.", e.getCause().getMessage()); + startTask(new BackOffSleepTask(failCount + 1, new PollConfigurationTask(failCount + 1))); + } + } + } + + class CheckConfigCenterAddressTask implements Runnable { + @Override + public void run() { + List isolationAddresses = configCenterAddressManager.getIsolationAddresses(); + if (isolationAddresses.isEmpty()) { + return; + } + for (String address : isolationAddresses) { + configCenterClient.checkAddressAvailable(address); + } + } + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java new file mode 100644 index 00000000000..919e9f30cd7 --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client; + +import org.apache.servicecomb.config.common.exception.OperationException; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse; + +public interface ConfigCenterOperation { + /** + * 根据查询条件查询配置项。 + * @param request 查询的维度(project, application, serviceName, version) 和 revision 信息。 + * @param address 查询的配置中心地址。 + * @return 如果存在配置变更,返回全量的配置项, changed = true。 如果没有变更, 返回 null, changed = false, + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request, String address); + + /** + * Check config center isolation address available + * + * @param address isolation address + */ + void checkAddressAvailable(String address); +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java new file mode 100644 index 00000000000..0556d14fced --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client.model; + +public class ConfigCenterConfiguration { + + private long refreshIntervalInMillis = 15000; + + public long getRefreshIntervalInMillis() { + return refreshIntervalInMillis; + } + + public ConfigCenterConfiguration setRefreshIntervalInMillis(long refreshIntervalInMillis) { + this.refreshIntervalInMillis = refreshIntervalInMillis; + return this; + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsRequest.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsRequest.java new file mode 100644 index 00000000000..81c5693fbf7 --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsRequest.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client.model; + +public class QueryConfigurationsRequest { + private String environment; + + private String application; + + private String serviceName; + + private String version; + + private String revision; + + public String getEnvironment() { + return environment; + } + + public QueryConfigurationsRequest setEnvironment(String environment) { + this.environment = environment; + return this; + } + + public String getApplication() { + return application; + } + + public QueryConfigurationsRequest setApplication(String application) { + this.application = application; + return this; + } + + public String getServiceName() { + return serviceName; + } + + public QueryConfigurationsRequest setServiceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public String getVersion() { + return version; + } + + public QueryConfigurationsRequest setVersion(String version) { + this.version = version; + return this; + } + + public String getRevision() { + return revision; + } + + public QueryConfigurationsRequest setRevision(String revision) { + this.revision = revision; + return this; + } +} diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsResponse.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsResponse.java new file mode 100644 index 00000000000..18b8ac65f8d --- /dev/null +++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/QueryConfigurationsResponse.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.center.client.model; + +import java.util.Map; + +public class QueryConfigurationsResponse { + private String revision; + + private boolean changed; + + private Map configurations; + + public String getRevision() { + return revision; + } + + public QueryConfigurationsResponse setRevision(String revision) { + this.revision = revision; + return this; + } + + public boolean isChanged() { + return changed; + } + + public QueryConfigurationsResponse setChanged(boolean changed) { + this.changed = changed; + return this; + } + + public Map getConfigurations() { + return configurations; + } + + public QueryConfigurationsResponse setConfigurations( + Map configurations) { + this.configurations = configurations; + return this; + } +} diff --git a/clients/config-common/pom.xml b/clients/config-common/pom.xml new file mode 100644 index 00000000000..ff10b993583 --- /dev/null +++ b/clients/config-common/pom.xml @@ -0,0 +1,44 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + config-clients-common + ServiceComb::Clients::Config Common + + + + org.apache.servicecomb + http-client-common + + + org.springframework + spring-beans + + + + + diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java new file mode 100644 index 00000000000..0d8973d8aeb --- /dev/null +++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.common; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.util.CollectionUtils; + +public class ConfigConverter { + private Map currentData = Collections.emptyMap(); + + private Map lastRawData; + + private final List fileSources; + + public ConfigConverter(List fileSources) { + this.fileSources = fileSources; + } + + public Map getLastRawData() { + return this.lastRawData; + } + + public Map getCurrentData() { + return this.currentData; + } + + public Map updateData(Map rawData) { + Map lastData = this.currentData; + + this.lastRawData = rawData; + + if (CollectionUtils.isEmpty(fileSources)) { + this.currentData = rawData; + return lastData; + } + + Map fileProperties = new HashMap<>(); + fileSources.forEach(source -> { + if (rawData.get(source) != null) { + fileProperties.put(source, rawData.get(source)); + } + }); + + Map result = new HashMap<>(rawData.size()); + result.putAll(rawData); + fileProperties.forEach((k, v) -> result.putAll(createFileSource(v))); + this.currentData = result; + return lastData; + } + + private Map createFileSource(Object v) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(v.toString().getBytes(StandardCharsets.UTF_8))); + return propertiesToMap(yamlFactory.getObject()); + } + + @SuppressWarnings("unchecked") + private Map propertiesToMap(Properties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + result.put(key, value); + } + return result; + } +} diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java new file mode 100644 index 00000000000..f4e26b50505 --- /dev/null +++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.common.exception; + +public class OperationException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public OperationException(String message) { + super(message); + } + + public OperationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/clients/config-kie-client/pom.xml b/clients/config-kie-client/pom.xml new file mode 100644 index 00000000000..30dac44ba53 --- /dev/null +++ b/clients/config-kie-client/pom.xml @@ -0,0 +1,54 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + config-kie-client + ServiceComb::Clients::Kie Client + + + + org.apache.servicecomb + http-client-common + + + org.apache.servicecomb + config-clients-common + + + org.springframework + spring-beans + + + + com.google.guava + failureaccess + test + + + + + diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java new file mode 100644 index 00000000000..b98a7d3b2a1 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client; + +import com.google.common.eventbus.EventBus; + +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.stream.Collectors; + +import org.apache.http.HttpStatus; + +import org.apache.servicecomb.config.common.exception.OperationException; +import org.apache.servicecomb.config.kie.client.model.ConfigConstants; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse; +import org.apache.servicecomb.config.kie.client.model.KVDoc; +import org.apache.servicecomb.config.kie.client.model.KVResponse; +import org.apache.servicecomb.config.kie.client.model.KieAddressManager; +import org.apache.servicecomb.config.kie.client.model.KieConfiguration; +import org.apache.servicecomb.config.kie.client.model.ValueType; +import org.apache.servicecomb.http.client.common.HttpRequest; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpUtils; +import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent; +import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.util.CollectionUtils; + +public class KieClient implements KieConfigOperation { + + private static final Logger LOGGER = LoggerFactory.getLogger(KieClient.class); + + private static final String ADDRESS_CHECK_PATH = "/v1/health"; + + protected HttpTransport httpTransport; + + protected String revision = "0"; + + private final KieAddressManager addressManager; + + private final KieConfiguration kieConfiguration; + + public static final String DEFAULT_KIE_API_VERSION = "v1"; + + private final Map> dimensionConfigNames = new HashMap<>(); + + private EventBus eventBus; + + public KieClient(KieAddressManager addressManager, HttpTransport httpTransport, KieConfiguration kieConfiguration) { + this.httpTransport = httpTransport; + this.addressManager = addressManager; + this.kieConfiguration = kieConfiguration; + } + + public void setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + addressManager.setEventBus(eventBus); + } + + @Override + public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request, String address) { + String url = buildUrl(request, address); + try { + if (kieConfiguration.isEnableLongPolling()) { + url += "&wait=" + kieConfiguration.getPollingWaitInSeconds() + "s"; + } + + HttpRequest httpRequest = new HttpRequest(url, null, null, HttpRequest.GET); + HttpResponse httpResponse = httpTransport.doRequest(httpRequest); + recordAndSendUnAuthorizedEvent(httpResponse, address); + ConfigurationsResponse configurationsResponse = new ConfigurationsResponse(); + if (httpResponse.getStatusCode() == HttpStatus.SC_OK) { + revision = httpResponse.getHeader("X-Kie-Revision"); + KVResponse allConfigList = HttpUtils.deserialize(httpResponse.getContent(), KVResponse.class); + logConfigurationNames(request.getLabelsQuery(), allConfigList.getData()); + Map configurations = getConfigByLabel(allConfigList); + configurationsResponse.setConfigurations(configurations); + configurationsResponse.setChanged(true); + configurationsResponse.setRevision(revision); + return configurationsResponse; + } + if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) { + throw new OperationException("Bad request for query configurations."); + } + if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + configurationsResponse.setChanged(false); + return configurationsResponse; + } + if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) { + LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", request.getLabelsQuery()); + configurationsResponse.setChanged(false); + return configurationsResponse; + } + throw new OperationException( + "read response failed. status:" + httpResponse.getStatusCode() + "; message:" + + httpResponse.getMessage() + "; content:" + httpResponse.getContent()); + } catch (Exception e) { + addressManager.recordFailState(address); + LOGGER.error("query configuration from {} failed, message={}", url, e.getMessage()); + throw new OperationException("read response failed. ", e); + } + } + + private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) { + if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage()); + addressManager.recordFailState(address); + this.eventBus.post(new UnAuthorizedOperationEvent(address)); + } else { + addressManager.recordSuccessState(address); + } + } + + /** + * Only the name of the new configuration item is printed. + * No log is printed when the configuration content is updated. + * + * @param dimension dimension + * @param data configs-data + */ + private void logConfigurationNames(String dimension, List data) { + if (CollectionUtils.isEmpty(data)) { + return; + } + List configNames = dimensionConfigNames.get(dimension); + if (configNames == null) { + configNames = new ArrayList<>(); + } + StringBuilder names = new StringBuilder(); + for (KVDoc doc : data) { + if (configNames.contains(doc.getKey())) { + continue; + } + names.append(doc.getKey()).append(","); + configNames.add(doc.getKey()); + } + if (names.isEmpty()) { + return; + } + dimensionConfigNames.put(dimension, configNames); + String fileNames = names.substring(0, names.length() - 1); + LOGGER.info("pulling dimension [{}] configurations success, get config names: [{}].", + dimension, fileNames); + } + + @Override + public void checkAddressAvailable(String address) { + ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH); + } + + private String buildUrl(ConfigurationsRequest request, String currentAddress) { + StringBuilder sb = new StringBuilder(); + sb.append(currentAddress); + sb.append("/"); + sb.append(DEFAULT_KIE_API_VERSION); + sb.append("/"); + sb.append(kieConfiguration.getProject()); + sb.append("/kie/kv?"); + sb.append(request.getLabelsQuery()); + sb.append("&revision="); + sb.append(request.getRevision()); + if (request.isWithExact()) { + sb.append("&match=exact"); + } + return sb.toString(); + } + + private Map getConfigByLabel(KVResponse resp) { + Map resultMap = new HashMap<>(); + resp.getData().stream() + .sorted(Comparator.comparing(KVDoc::getUpdateTime, Comparator.nullsFirst(Comparator.naturalOrder()))) + .filter(doc -> doc.getStatus() == null || ConfigConstants.STATUS_ENABLED.equalsIgnoreCase(doc.getStatus())) + .map(this::processValueType) + .collect(Collectors.toList()) + .forEach(resultMap::putAll); + return resultMap; + } + + private Map processValueType(KVDoc kvDoc) { + ValueType valueType; + try { + valueType = ValueType.valueOf(kvDoc.getValueType()); + } catch (IllegalArgumentException e) { + throw new OperationException("value type not support [" + kvDoc.getValue() + "]"); + } + Properties properties = new Properties(); + Map kvMap = new HashMap<>(); + try { + switch (valueType) { + case yml: + case yaml: + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(kvDoc.getValue().getBytes(StandardCharsets.UTF_8))); + return toMap(yamlFactory.getObject()); + case properties: + properties.load(new StringReader(kvDoc.getValue())); + return toMap(properties); + case text: + case string: + default: + kvMap.put(kvDoc.getKey(), kvDoc.getValue()); + return kvMap; + } + } catch (Exception e) { + LOGGER.error("read config failed", e); + } + return Collections.emptyMap(); + } + + @SuppressWarnings("unchecked") + private Map toMap(Properties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + result.put(key, value); + } + return result; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java new file mode 100644 index 00000000000..ed251613530 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import org.apache.servicecomb.config.common.ConfigConverter; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequestFactory; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse; +import org.apache.servicecomb.config.kie.client.model.KieAddressManager; +import org.apache.servicecomb.config.kie.client.model.KieConfiguration; +import org.apache.servicecomb.http.client.task.AbstractTask; +import org.apache.servicecomb.http.client.task.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class KieConfigManager extends AbstractTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(KieConfigManager.class); + + private static final long LONG_POLLING_INTERVAL = 1000; + + private final KieConfigOperation configKieClient; + + private final EventBus eventBus; + + private final ConfigConverter configConverter; + + private final List configurationsRequests; + + private final KieConfiguration kieConfiguration; + + private final KieAddressManager kieAddressManager; + + public KieConfigManager(KieConfigOperation configKieClient, EventBus eventBus, + KieConfiguration kieConfiguration, ConfigConverter configConverter, KieAddressManager kieAddressManager) { + super("config-center-configuration-task"); + this.configurationsRequests = ConfigurationsRequestFactory.buildConfigurationRequests(kieConfiguration); + this.configurationsRequests.sort(ConfigurationsRequest::compareTo); + this.configKieClient = configKieClient; + this.eventBus = eventBus; + this.configConverter = configConverter; + this.kieConfiguration = kieConfiguration; + this.kieAddressManager = kieAddressManager; + } + + public void firstPull() { + Map data = new HashMap<>(); + try { + firstQueryConfigurations(data); + } catch (Exception e) { + if (this.kieConfiguration.isFirstPullRequired()) { + throw e; + } else { + LOGGER.warn("first pull failed!"); + } + } + } + + private void firstQueryConfigurations(Map data) { + for (int i = 0; i < 3;) { + String address = kieAddressManager.address(); + try { + this.configurationsRequests.forEach(r -> { + r.setRevision(ConfigurationsRequest.INITIAL_REVISION); + ConfigurationsResponse response = configKieClient.queryConfigurations(r, address); + if (response.isChanged()) { + r.setRevision(response.getRevision()); + r.setLastRawData(response.getConfigurations()); + data.putAll(response.getConfigurations()); + } + }); + this.configConverter.updateData(data); + break; + } catch (Exception e) { + if (i == 2) { + throw e; + } + LOGGER.warn("firstQueryConfigurations failed, config address {} and ignore {}", address, e.getMessage()); + } + i++; + } + } + + private void onDataChanged() { + Map latestData = new HashMap<>(); + this.configurationsRequests.forEach(r -> latestData.putAll(r.getLastRawData())); + + Map lastData = configConverter.updateData(latestData); + KieConfigurationChangedEvent event = KieConfigurationChangedEvent + .createIncremental(configConverter.getCurrentData(), lastData); + if (!event.getChanged().isEmpty()) { + eventBus.post(event); + } + } + + @Override + protected void initTaskPool(String taskName) { + this.taskPool = Executors.newFixedThreadPool(3, (task) -> + new Thread(task, taskName)); + } + + public void startConfigKieManager() { + this.configurationsRequests.forEach((t) -> + this.startTask(new PollConfigurationTask(0, t))); + schedulerCheckAddressAvailable("kie-addr-check", new CheckKieAddressTask(), + kieConfiguration.getRefreshIntervalInMillis()); + } + + class PollConfigurationTask implements Task { + final int failCount; + + ConfigurationsRequest configurationsRequest; + + public PollConfigurationTask(int failCount, ConfigurationsRequest configurationsRequest) { + this.failCount = failCount; + this.configurationsRequest = configurationsRequest; + } + + @Override + public void execute() { + try { + ConfigurationsResponse response = configKieClient.queryConfigurations(configurationsRequest, + kieAddressManager.address()); + if (response.isChanged()) { + configurationsRequest.setRevision(response.getRevision()); + configurationsRequest.setLastRawData(response.getConfigurations()); + onDataChanged(); + } + if (KieConfigManager.this.kieConfiguration.isEnableLongPolling()) { + startTask( + new BackOffSleepTask(LONG_POLLING_INTERVAL, new PollConfigurationTask(0, this.configurationsRequest))); + } else { + startTask(new BackOffSleepTask(kieConfiguration.getRefreshIntervalInMillis(), + new PollConfigurationTask(0, this.configurationsRequest))); + } + } catch (Exception e) { + LOGGER.warn("get configurations from KieConfigCenter failed, and will try again, cause message: {}. current " + + "fail does not affect the obtained historical configuration.", e.getCause().getMessage()); + startTask( + new BackOffSleepTask(failCount + 1, new PollConfigurationTask(failCount + 1, this.configurationsRequest))); + } + } + } + + class CheckKieAddressTask implements Runnable { + @Override + public void run() { + List isolationAddresses = kieAddressManager.getIsolationAddresses(); + if (isolationAddresses.isEmpty()) { + return; + } + for (String address : isolationAddresses) { + configKieClient.checkAddressAvailable(address); + } + } + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java new file mode 100644 index 00000000000..135ad0c220a --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client; + +import org.apache.servicecomb.config.common.exception.OperationException; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest; +import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse; + +//此处支持配置中心扩展 +public interface KieConfigOperation { + /** + * 根据查询条件查询配置项。 + * @param request 查询的维度(project, application, serviceName, version) 和 revision 信息。 + * @param address 查询的配置中心地址。 + * @return 如果存在配置变更,返回全量的配置项, changed = true。 如果没有变更, 返回 null, changed = false, + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + ConfigurationsResponse queryConfigurations(ConfigurationsRequest request, String address); + + /** + * Check kie isolation address available + * + * @param address isolation address + */ + void checkAddressAvailable(String address); +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java new file mode 100644 index 00000000000..0e22c17e8b9 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * This event is fired when configuration changed of kie. + */ +public class KieConfigurationChangedEvent { + private final Map added; + + private final Map deleted; + + private final Map updated; + + private Set changed; + + private KieConfigurationChangedEvent(Map added, Map updated, + Map deleted) { + this.added = added; + this.deleted = deleted; + this.updated = updated; + this.changed = new HashSet<>(); + this.changed.addAll(added.keySet()); + this.changed.addAll(updated.keySet()); + this.changed.addAll(deleted.keySet()); + } + + public static KieConfigurationChangedEvent createIncremental(Map latest, Map last) { + Map itemsCreated = new HashMap<>(); + Map itemsDeleted = new HashMap<>(); + Map itemsModified = new HashMap<>(); + + for (Map.Entry entry : latest.entrySet()) { + String itemKey = entry.getKey(); + if (!last.containsKey(itemKey)) { + itemsCreated.put(itemKey, entry.getValue()); + } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) { + itemsModified.put(itemKey, entry.getValue()); + } + } + for (String itemKey : last.keySet()) { + if (!latest.containsKey(itemKey)) { + itemsDeleted.put(itemKey, null); + } + } + KieConfigurationChangedEvent event = KieConfigurationChangedEvent + .createIncremental(itemsCreated, itemsModified, itemsDeleted); + return event; + } + + public static KieConfigurationChangedEvent createIncremental(Map added, Map updated, + Map deleted) { + return new KieConfigurationChangedEvent(added, updated, deleted); + } + + public static KieConfigurationChangedEvent createIncremental(Map updated) { + return new KieConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>()); + } + + public final Map getAdded() { + return added; + } + + + public final Map getUpdated() { + return updated; + } + + + public final Map getDeleted() { + return deleted; + } + + public final Set getChanged() { + return changed; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigConstants.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigConstants.java new file mode 100644 index 00000000000..81585ecdff6 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigConstants.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + + +public class ConfigConstants { + + public static final String LABEL_ENV = "environment"; + + public static final String LABEL_APP = "app"; + + public static final String LABEL_SERVICE = "service"; + + public static final String LABEL_VERSION = "version"; + + public static final String STATUS_ENABLED = "enabled"; + + public static final String KEY_PROJECT = "project"; + + // ###### kie config center polling configuration############### // + public static final String KEY_ENABLELONGPOLLING = "enableLongPolling"; + + public static final String KEY_POLLINGWAITSEC = "pollingWaitInSeconds"; + +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java new file mode 100644 index 00000000000..b22f7ecaa23 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigurationsRequest implements Comparable { + public static final String INITIAL_REVISION = "-1"; + + private int order; + + private String revision = INITIAL_REVISION; + + private boolean withExact; + + private String labelsQuery; + + private Map lastRawData = new HashMap<>(); + + public int getOrder() { + return order; + } + + public ConfigurationsRequest setOrder(int order) { + this.order = order; + return this; + } + + public String getRevision() { + return revision; + } + + public ConfigurationsRequest setRevision(String revision) { + this.revision = revision; + return this; + } + + public boolean isWithExact() { + return withExact; + } + + public ConfigurationsRequest setWithExact(boolean withExact) { + this.withExact = withExact; + return this; + } + + public String getLabelsQuery() { + return labelsQuery; + } + + public ConfigurationsRequest setLabelsQuery(String labelsQuery) { + this.labelsQuery = labelsQuery; + return this; + } + + public Map getLastRawData() { + return lastRawData; + } + + public ConfigurationsRequest setLastRawData(Map lastRawData) { + this.lastRawData = lastRawData; + return this; + } + + @Override + public int compareTo(ConfigurationsRequest o) { + // Higher priority, query the last + return o.getOrder() - this.order; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java new file mode 100644 index 00000000000..20c6ba3bacb --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.http.client.common.HttpUtils; + +public class ConfigurationsRequestFactory { + private static final String KEY_APP = "app"; + + private static final String KEY_ENVIRONMENT = "environment"; + + private static final String KEY_SERVICE = "service"; + + private static final String KEY_VERSION = "version"; + + private static final int CUSTOM_ORDER = 100; + + private static final int VERSION_ORDER = 200; + + private static final int SERVICE_ORDER = 300; + + private static final int APP_ORDER = 400; + + public static List buildConfigurationRequests(KieConfiguration configuration) { + List result = new ArrayList<>(); + if (configuration.isEnableAppConfig()) { + result.add(createAppConfigurationsRequest(configuration)); + } + if (configuration.isEnableServiceConfig()) { + result.add(createServiceConfigurationsRequest(configuration)); + } + if (configuration.isEnableVersionConfig()) { + result.add(createVersionConfigurationsRequest(configuration)); + } + if (configuration.isEnableCustomConfig()) { + result.add(createCustomConfigurationsRequest(configuration)); + } + return result; + } + + private static ConfigurationsRequest createAppConfigurationsRequest(KieConfiguration configuration) { + return new ConfigurationsRequest() + .setOrder(APP_ORDER) + .setWithExact(true) + .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()), + buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment()))); + } + + private static ConfigurationsRequest createServiceConfigurationsRequest(KieConfiguration configuration) { + return new ConfigurationsRequest() + .setOrder(SERVICE_ORDER) + .setWithExact(true) + .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()), + buildLabelQueryItem(KEY_SERVICE, configuration.getServiceName()), + buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment()))); + } + + private static ConfigurationsRequest createVersionConfigurationsRequest(KieConfiguration configuration) { + return new ConfigurationsRequest() + .setOrder(VERSION_ORDER) + .setWithExact(true) + .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()), + buildLabelQueryItem(KEY_SERVICE, configuration.getServiceName()), + buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment()), + buildLabelQueryItem(KEY_VERSION, configuration.getVersion()))); + } + + private static ConfigurationsRequest createCustomConfigurationsRequest(KieConfiguration configuration) { + return new ConfigurationsRequest() + .setOrder(CUSTOM_ORDER) + .setWithExact(false) + .setLabelsQuery( + buildLabelQuery(buildLabelQueryItem(configuration.getCustomLabel(), configuration.getCustomLabelValue()))); + } + + private static String buildLabelQuery(String... labels) { + StringBuilder result = new StringBuilder(); + for (String label : labels) { + result.append(label); + result.append("&"); + } + return result.toString(); + } + + private static String buildLabelQueryItem(String key, String value) { + try { + return "label=" + HttpUtils.encodeURLParam(key + ":" + value); + } catch (IOException e) { + throw new IllegalArgumentException("unexpected param", e); + } + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsResponse.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsResponse.java new file mode 100644 index 00000000000..157f2e1f419 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsResponse.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.util.Map; + +public class ConfigurationsResponse { + private String revision; + + private boolean changed; + + private Map configurations; + + public String getRevision() { + return revision; + } + + public ConfigurationsResponse setRevision(String revision) { + this.revision = revision; + return this; + } + + public boolean isChanged() { + return changed; + } + + public ConfigurationsResponse setChanged(boolean changed) { + this.changed = changed; + return this; + } + + public Map getConfigurations() { + return configurations; + } + + public ConfigurationsResponse setConfigurations( + Map configurations) { + this.configurations = configurations; + return this; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java new file mode 100644 index 00000000000..3059a581c61 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import com.fasterxml.jackson.annotation.JsonAlias; + +import java.util.HashMap; +import java.util.Map; + +public class KVDoc { + + private String id; + + private String check; + + private String domain; + + private String key; + + @JsonAlias("label_id") + private String labelId; + + private Map labels = new HashMap<>(); + + private String value; + + @JsonAlias("value_type") + private String valueType; + + private String status; + + @JsonAlias("update_time") + private long updateTime; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getCheck() { + return check; + } + + public String getDomain() { + return domain; + } + + public String getLabelId() { + return labelId; + } + + public Map getLabels() { + return labels; + } + + public String getValue() { + return value; + } + + public void setCheck(String check) { + this.check = check; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public void setLabelId(String labelId) { + this.labelId = labelId; + } + + public void setLabels(Map labels) { + this.labels = labels; + } + + public void setValueType(String valueType) { + this.valueType = valueType; + } + + public void setValue(String value) { + this.value = value; + } + + public String getValueType() { + return valueType; + } + + public long getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(long updateTime) { + this.updateTime = updateTime; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVResponse.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVResponse.java new file mode 100644 index 00000000000..e728acbe660 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVResponse.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.util.List; + +public class KVResponse { + + private List data; + + private LabelDocResponse label; + + private Integer total; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public List getData() { + return data; + } + + public LabelDocResponse getLabel() { + return label; + } + + public void setData(List data) { + this.data = data; + } + + public void setLabel(LabelDocResponse label) { + this.label = label; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java new file mode 100644 index 00000000000..d8c069ee9b1 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.util.List; + +import org.apache.servicecomb.http.client.common.AbstractAddressManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class KieAddressManager extends AbstractAddressManager { + + public KieAddressManager(List addresses, EventBus eventBus, String region, String availableZone) { + super(addresses, region, availableZone); + eventBus.register(this); + } + + @Subscribe + public void onRefreshEndpointEvent(RefreshEndpointEvent event) { + refreshEndpoint(event, RefreshEndpointEvent.KIE_NAME); + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java new file mode 100644 index 00000000000..9c75f2d09c2 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +public class KieConfiguration { + private boolean enableLongPolling; + + private int pollingWaitInSeconds; + + private int refreshIntervalInMillis = 15000; + + private String project; + + private String appName; + + private String serviceName; + + private String environment; + + private String version; + + private boolean enableAppConfig; + + private boolean enableServiceConfig; + + private boolean enableVersionConfig; + + private boolean enableCustomConfig; + + private String customLabelValue; + + private String customLabel; + + private boolean firstPullRequired; + + public String getAppName() { + return appName; + } + + public KieConfiguration setAppName(String appName) { + this.appName = appName; + return this; + } + + public String getServiceName() { + return serviceName; + } + + public KieConfiguration setServiceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public String getEnvironment() { + return environment; + } + + public KieConfiguration setEnvironment(String environment) { + this.environment = environment; + return this; + } + + public String getCustomLabelValue() { + return customLabelValue; + } + + public KieConfiguration setCustomLabelValue(String customLabelValue) { + this.customLabelValue = customLabelValue; + return this; + } + + public boolean isEnableAppConfig() { + return enableAppConfig; + } + + public KieConfiguration setEnableAppConfig(boolean enableAppConfig) { + this.enableAppConfig = enableAppConfig; + return this; + } + + public boolean isEnableServiceConfig() { + return enableServiceConfig; + } + + public KieConfiguration setEnableServiceConfig(boolean enableServiceConfig) { + this.enableServiceConfig = enableServiceConfig; + return this; + } + + public boolean isEnableCustomConfig() { + return enableCustomConfig; + } + + public KieConfiguration setEnableCustomConfig(boolean enableCustomConfig) { + this.enableCustomConfig = enableCustomConfig; + return this; + } + + public String getCustomLabel() { + return customLabel; + } + + public KieConfiguration setCustomLabel(String customLabel) { + this.customLabel = customLabel; + return this; + } + + public boolean isEnableLongPolling() { + return enableLongPolling; + } + + public KieConfiguration setEnableLongPolling(boolean enableLongPolling) { + this.enableLongPolling = enableLongPolling; + return this; + } + + public boolean isEnableVersionConfig() { + return enableVersionConfig; + } + + public KieConfiguration setEnableVersionConfig(boolean enableVersionConfig) { + this.enableVersionConfig = enableVersionConfig; + return this; + } + + public int getPollingWaitInSeconds() { + return pollingWaitInSeconds; + } + + public KieConfiguration setPollingWaitInSeconds(int pollingWaitInSeconds) { + this.pollingWaitInSeconds = pollingWaitInSeconds; + return this; + } + + public String getProject() { + return project; + } + + public KieConfiguration setProject(String project) { + this.project = project; + return this; + } + + public boolean isFirstPullRequired() { + return firstPullRequired; + } + + public KieConfiguration setFirstPullRequired(boolean firstPullRequired) { + this.firstPullRequired = firstPullRequired; + return this; + } + + public int getRefreshIntervalInMillis() { + return refreshIntervalInMillis; + } + + public KieConfiguration setRefreshIntervalInMillis(int refreshIntervallnMillis) { + this.refreshIntervalInMillis = refreshIntervallnMillis; + return this; + } + + public String getVersion() { + return version; + } + + public KieConfiguration setVersion(String version) { + this.version = version; + return this; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java new file mode 100644 index 00000000000..2b9e055de0f --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import com.fasterxml.jackson.annotation.JsonAlias; + +import java.util.HashMap; +import java.util.Map; + +public class LabelDocResponse { + + @JsonAlias("label_id") + private String labelId; + + private Map labels = new HashMap<>(); + + public String getLabelId() { + return labelId; + } + + public Map getLabels() { + return labels; + } + + public void setLabelId(String labelId) { + this.labelId = labelId; + } + + public void setLabels(Map labels) { + this.labels = labels; + } +} diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java new file mode 100644 index 00000000000..23cbce3b367 --- /dev/null +++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +public enum ValueType { + yml, + yaml, + ini, + string, + text, + json, + properties, + xml +} diff --git a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java new file mode 100644 index 00000000000..47c152fa1df --- /dev/null +++ b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +class ConfigurationsRequestTest { + + @Test + void getLastRawData() { + ConfigurationsRequest configurationsRequest = new ConfigurationsRequest(); + Map lastRawData = configurationsRequest.getLastRawData(); + Assertions.assertEquals(lastRawData.size(), 0); + } +} diff --git a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java new file mode 100644 index 00000000000..c8bf1f57a29 --- /dev/null +++ b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.client.model; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class KieAddressManagerTest { + + private static final List addresses = new ArrayList<>(); + + private static KieAddressManager addressManager1; + + @Test + public void kieAddressManagerTest() throws NoSuchFieldException, IllegalAccessException { + addresses.add("http://127.0.0.1:30103"); + addresses.add("https://127.0.0.2:30103"); + addressManager1 = new KieAddressManager(addresses, new EventBus(), "", ""); + Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager1, 0); + + Assertions.assertNotNull(addressManager1); + + List addresses = addressManager1.getAddresses(); + Assertions.assertEquals(2, addresses.size()); + Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0)); + + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + } + + @Test + public void onRefreshEndpointEvent() { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.3:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("http://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + addressManager1 = new KieAddressManager(addresses, new EventBus(), "", ""); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "KIE"); + addressManager1.refreshEndpoint(event, "KIE"); + + List availableZone = addressManager1.getAvailableZone(); + Assertions.assertEquals("http://127.0.0.3:30100", availableZone.get(0)); + + List availableRegion = addressManager1.getAvailableRegion(); + Assertions.assertEquals("http://127.0.0.4:30100", availableRegion.get(0)); + } +} diff --git a/clients/dashboard-client/pom.xml b/clients/dashboard-client/pom.xml new file mode 100644 index 00000000000..fb40407b82a --- /dev/null +++ b/clients/dashboard-client/pom.xml @@ -0,0 +1,50 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + dashboard-client + ServiceComb::Clients::Dashboard Client + + + + org.apache.servicecomb + http-client-common + + + org.springframework + spring-beans + + + + com.google.guava + failureaccess + test + + + + + diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java new file mode 100644 index 00000000000..6897e02acd4 --- /dev/null +++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client; + + +import java.util.List; + +import org.apache.servicecomb.http.client.common.AbstractAddressManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + + +public class DashboardAddressManager extends AbstractAddressManager { + + public DashboardAddressManager(List addresses, EventBus eventBus, String region, String availableZone) { + super(addresses, region, availableZone); + eventBus.register(this); + } + + @Subscribe + public void onRefreshEndpointEvent(RefreshEndpointEvent event) { + refreshEndpoint(event, RefreshEndpointEvent.CSE_MONITORING_NAME); + } +} diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java new file mode 100644 index 00000000000..2fe84429cb7 --- /dev/null +++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.dashboard.client.model.MonitorData; +import org.apache.servicecomb.http.client.common.HttpRequest; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DashboardClient implements DashboardOperation { + private static final Logger LOGGER = LoggerFactory.getLogger(DashboardClient.class); + + protected HttpTransport httpTransport; + + private final DashboardAddressManager addressManager; + + public DashboardClient(DashboardAddressManager addressManager, HttpTransport httpTransport) { + this.httpTransport = httpTransport; + this.addressManager = addressManager; + } + + @Override + public void sendData(String url, MonitorData data) { + String address = addressManager.address(); + try { + HttpRequest httpRequest = new HttpRequest(address + url, null, HttpUtils.serialize(data), HttpRequest.POST); + HttpResponse httpResponse = httpTransport.doRequest(httpRequest); + if (httpResponse.getStatusCode() != HttpStatus.SC_OK) { + LOGGER.error("send data to [{}] failed, status code [{}], message [{}]", url, httpResponse.getStatusCode() + , httpResponse.getContent()); + } + } catch (Exception e) { + LOGGER.error("send data to [{}] failed", url, e); + } + } +} diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java new file mode 100644 index 00000000000..733ebfc4676 --- /dev/null +++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client; + +import org.apache.servicecomb.dashboard.client.model.MonitorData; + +public interface DashboardOperation { + void sendData(String url, MonitorData monitorData); +} diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java new file mode 100644 index 00000000000..1a72c8fe747 --- /dev/null +++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client.model; + +public class InterfaceInfo { + private String name; + + private String desc; + + private double qps; + + private int latency; + + private int l995; + + private int l99; + + private int l90; + + private int l75; + + private int l50; + + private int l25; + + private int l5; + + private double rate; + + private double failureRate; + + private long total; + + private boolean isCircuitBreakerOpen; + + private long failure; + + private long shortCircuited; + + private long semaphoreRejected; + + private long threadPoolRejected; + + private long countTimeout; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public double getQps() { + return qps; + } + + public void setQps(double qps) { + this.qps = qps; + } + + public int getLatency() { + return latency; + } + + public void setLatency(int latency) { + this.latency = latency; + } + + public int getL995() { + return l995; + } + + public void setL995(int l995) { + this.l995 = l995; + } + + public int getL99() { + return l99; + } + + public void setL99(int l99) { + this.l99 = l99; + } + + public int getL90() { + return l90; + } + + public void setL90(int l90) { + this.l90 = l90; + } + + public int getL75() { + return l75; + } + + public void setL75(int l75) { + this.l75 = l75; + } + + public int getL50() { + return l50; + } + + public void setL50(int l50) { + this.l50 = l50; + } + + public int getL25() { + return l25; + } + + public void setL25(int l25) { + this.l25 = l25; + } + + public int getL5() { + return l5; + } + + public void setL5(int l5) { + this.l5 = l5; + } + + public double getRate() { + return rate; + } + + public void setRate(double rate) { + this.rate = rate; + } + + public double getFailureRate() { + return failureRate; + } + + public void setFailureRate(double failureRate) { + this.failureRate = failureRate; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public boolean isCircuitBreakerOpen() { + return isCircuitBreakerOpen; + } + + public void setCircuitBreakerOpen(boolean circuitBreakerOpen) { + isCircuitBreakerOpen = circuitBreakerOpen; + } + + public long getFailure() { + return failure; + } + + public void setFailure(long failure) { + this.failure = failure; + } + + public long getShortCircuited() { + return shortCircuited; + } + + public void setShortCircuited(long shortCircuited) { + this.shortCircuited = shortCircuited; + } + + public long getSemaphoreRejected() { + return semaphoreRejected; + } + + public void setSemaphoreRejected(long semaphoreRejected) { + this.semaphoreRejected = semaphoreRejected; + } + + public long getThreadPoolRejected() { + return threadPoolRejected; + } + + public void setThreadPoolRejected(long threadPoolRejected) { + this.threadPoolRejected = threadPoolRejected; + } + + public long getCountTimeout() { + return countTimeout; + } + + public void setCountTimeout(long countTimeout) { + this.countTimeout = countTimeout; + } +} diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java new file mode 100644 index 00000000000..d02facd5daa --- /dev/null +++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class MonitorData { + public static final double PERCENTAGE_995 = 99.5; + + public static final double PERCENTAGE_99 = 99; + + public static final double PERCENTAGE_90 = 90; + + public static final double PERCENTAGE_75 = 75; + + public static final double PERCENTAGE_50 = 50; + + public static final double PERCENTAGE_25 = 25; + + public static final double PERCENTAGE_5 = 5; + + public static final int SCALE_VAL = 1; + + public static final double DEFAULT_SUCCESS_RATE = 1.0d; + + public static final int CONVERSION = 1000; + + private String appId; + + private String version; + + private String name; + + private String serviceId; + + private String environment; + + private String instance; + + private String instanceId; + + private int thread; + + private double cpu; + + private double loadAverage; + + private long uptime; + + private Map memory; + + private List interfaces = new ArrayList<>(); + + private Map customs; + + public void addInterfaceInfo(InterfaceInfo interfaceInfo) { + interfaces.add(interfaceInfo); + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getInstance() { + return instance; + } + + public void setInstance(String instance) { + this.instance = instance; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public int getThreadCount() { + return thread; + } + + public void setThreadCount(int threadCount) { + this.thread = threadCount; + } + + public double getCpu() { + return cpu; + } + + public void setCpu(double cpu) { + this.cpu = cpu; + } + + public double getLoadAverage() { + return loadAverage; + } + + public void setLoadAverage(double loadAverage) { + this.loadAverage = loadAverage; + } + + public long getUptime() { + return uptime; + } + + public void setUptime(long uptime) { + this.uptime = uptime; + } + + public Map getMemory() { + return memory; + } + + public void setMemory(Map memory) { + this.memory = memory; + } + + public List getInterfaces() { + return interfaces; + } + + public void setInterfaces(List interfaces) { + this.interfaces = interfaces; + } + + public Map getCustoms() { + return customs; + } + + public void setCustoms(Map customs) { + this.customs = customs; + } + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } +} diff --git a/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java new file mode 100644 index 00000000000..fdb7a23922b --- /dev/null +++ b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.dashboard.client; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.google.common.eventbus.EventBus; + +class AddressManagerTest { + + private static final List addresses = new ArrayList<>(); + + private static DashboardAddressManager addressManager1; + + @Test + public void kieAddressManagerTest() throws IllegalAccessException, NoSuchFieldException { + addresses.add("http://127.0.0.1:30103"); + addresses.add("https://127.0.0.2:30103"); + addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", ""); + Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager1, 0); + + Assertions.assertNotNull(addressManager1); + + List addresses = addressManager1.getAddresses(); + Assertions.assertEquals(2, addresses.size()); + Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0)); + + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + } + + @Test + public void onRefreshEndpointEvent() { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.3:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("http://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", ""); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseMonitoring"); + addressManager1.refreshEndpoint(event, "CseMonitoring"); + + List availableZone = addressManager1.getAvailableZone(); + Assertions.assertEquals("http://127.0.0.3:30100", availableZone.get(0)); + + List availableRegion = addressManager1.getAvailableRegion(); + Assertions.assertEquals("http://127.0.0.4:30100", availableRegion.get(0)); + } +} diff --git a/clients/http-client-common/pom.xml b/clients/http-client-common/pom.xml new file mode 100644 index 00000000000..51d982e470c --- /dev/null +++ b/clients/http-client-common/pom.xml @@ -0,0 +1,75 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + http-client-common + ServiceComb::Clients::HTTP Client Common + + + + + org.apache.httpcomponents + httpclient + + + + org.slf4j + slf4j-api + + + + com.fasterxml.jackson.core + jackson-databind + + + + org.apache.commons + commons-lang3 + + + + com.google.guava + guava + + + + org.apache.servicecomb + foundation-ssl + + + + org.apache.servicecomb + foundation-spi + + + + org.java-websocket + Java-WebSocket + + + diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/DefaultRequestAuthHeaderProvider.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/DefaultRequestAuthHeaderProvider.java new file mode 100644 index 00000000000..a701a53695b --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/DefaultRequestAuthHeaderProvider.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.auth; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.auth.SignRequest; + +public class DefaultRequestAuthHeaderProvider implements RequestAuthHeaderProvider { + @Override + public Map loadAuthHeader(SignRequest signRequest) { + return new HashMap<>(0); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/RequestAuthHeaderProvider.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/RequestAuthHeaderProvider.java new file mode 100644 index 00000000000..131bea7aa79 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/auth/RequestAuthHeaderProvider.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.auth; + +import java.util.Map; + +import org.apache.servicecomb.foundation.auth.SignRequest; + +public interface RequestAuthHeaderProvider { + Map loadAuthHeader(SignRequest signRequest); +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java new file mode 100644 index 00000000000..3c5d6214be8 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java @@ -0,0 +1,348 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.http.client.event.EngineConnectChangedEvent; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.EventBus; + +public class AbstractAddressManager { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAddressManager.class); + + public static final String DEFAULT_PROJECT = "default"; + + public static final String V4_PREFIX = "/v4/"; + + private static final String V3_PREFIX = "/v3/"; + + private static final String ZONE = "availableZone"; + + private static final String REGION = "region"; + + private static final int ISOLATION_THRESHOLD = 3; + + private volatile List addresses = new ArrayList<>(); + + // when all addresses are isolation, it will use this for polling. + private final List defaultAddress = new ArrayList<>(); + + private final List defaultIsolationAddress = new ArrayList<>(); + + private int index; + + private String projectName; + + // recording continuous times of failure of an address. + private final Map addressFailureStatus = new ConcurrentHashMap<>(); + + private volatile List availableZone = new ArrayList<>(); + + private final List isolationZoneAddress = new ArrayList<>(); + + private volatile List availableRegion = new ArrayList<>(); + + private final List isolationRegionAddress = new ArrayList<>(); + + private volatile boolean addressAutoRefreshed = false; + + private final Object lock = new Object(); + + private final Random random = new Random(); + + private EventBus eventBus; + + public AbstractAddressManager(List addresses, String ownRegion, String ownAvailableZone) { + this.projectName = DEFAULT_PROJECT; + parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, false); + this.index = !addresses.isEmpty() ? getRandomIndex() : 0; + } + + /** + * address support config with region/availableZone info, to enable engine affinity calls during startup + * address may be like: + * https://192.168.20.13:30110?region=region1&availableZone=az + * https://192.168.20.13:30100?region=region1&availableZone=az + * When address have no datacenter information, roundRobin using address + * + * @param addresses engine addresses + * @param ownRegion microservice region + * @param ownAvailableZone microservice zone + * @param isFormat is need format + */ + private void parseAndInitAddresses(List addresses, String ownRegion, String ownAvailableZone, + boolean isFormat) { + if (CollectionUtils.isEmpty(addresses)) { + return; + } + List tempList = new ArrayList<>(); + addressAutoRefreshed = addresses.stream().anyMatch(addr -> addr.contains(ZONE) || addr.contains(REGION)); + for (String address : addresses) { + // Compatible IpPortManager init address is 127.0.0.1:30100 + if (!address.startsWith("http")) { + tempList.add(address); + continue; + } + URLEndPoint endpoint = new URLEndPoint(address); + tempList.add(endpoint.toString()); + buildAffinityAddress(endpoint, ownRegion, ownAvailableZone); + } + this.addresses.addAll(isFormat ? this.transformAddress(tempList) : tempList); + this.defaultAddress.addAll(isFormat ? this.transformAddress(tempList) : tempList); + } + + private void buildAffinityAddress(URLEndPoint endpoint, String ownRegion, String ownAvailableZone) { + if (addressAutoRefreshed) { + if (regionAndAZMatch(ownRegion, ownAvailableZone, endpoint.getFirst(REGION), endpoint.getFirst(ZONE))) { + availableZone.add(endpoint.toString()); + } else { + availableRegion.add(endpoint.toString()); + } + } + } + + private boolean regionAndAZMatch(String ownRegion, String ownAvailableZone, String engineRegion, + String engineAvailableZone) { + return ownRegion.equalsIgnoreCase(engineRegion) && ownAvailableZone.equals(engineAvailableZone); + } + + public AbstractAddressManager(String projectName, List addresses, String ownRegion, String ownAvailableZone) { + this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : projectName; + parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, true); + this.index = !addresses.isEmpty() ? getRandomIndex() : 0; + } + + private int getRandomIndex() { + return random.nextInt(addresses.size()); + } + + public void refreshEndpoint(RefreshEndpointEvent event, String key) { + if (null == event || !event.getName().equals(key)) { + return; + } + + availableZone = event.getSameZone().stream().map(this::normalizeUri).collect(Collectors.toList()); + availableRegion = event.getSameRegion().stream().map(this::normalizeUri).collect(Collectors.toList()); + addressAutoRefreshed = true; + } + + protected String normalizeUri(String endpoint) { + return new URLEndPoint(endpoint).toString(); + } + + @VisibleForTesting + Map getAddressFailureStatus() { + return addressFailureStatus; + } + + public List getAddresses() { + return addresses; + } + + public List getAvailableZone() { + return availableZone; + } + + public List getAvailableRegion() { + return availableRegion; + } + + public String formatUrl(String url, boolean absoluteUrl, String address) { + return absoluteUrl ? address + url : formatAddress(address) + url; + } + + public boolean sslEnabled() { + return address().startsWith("https://"); + } + + protected List transformAddress(List addresses) { + return addresses.stream().map(this::formatAddress).collect(Collectors.toList()); + } + + protected String formatAddress(String address) { + try { + return getUrlPrefix(address) + HttpUtils.encodeURLParam(this.projectName); + } catch (Exception e) { + throw new IllegalStateException("not possible"); + } + } + + protected String getUrlPrefix(String address) { + return address + V3_PREFIX; + } + + public String address() { + if (!addressAutoRefreshed) { + return getDefaultAddress(); + } else { + return getAvailableZoneAddress(); + } + } + + private String getDefaultAddress() { + if (!addresses.isEmpty()) { + return getCurrentAddress(addresses); + } + LOGGER.warn("all addresses are isolation, please check server status."); + // when all addresses are isolation, it will use all default address for polling. + return getCurrentAddress(defaultAddress); + } + + private String getAvailableZoneAddress() { + List zoneOrRegionAddress = getZoneOrRegionAddress(); + if (!zoneOrRegionAddress.isEmpty()) { + return getCurrentAddress(zoneOrRegionAddress); + } + LOGGER.warn("all auto discovery addresses are isolation, please check server status."); + // when all available address are isolation, it will use config addresses for polling. + return getCurrentAddress(addresses); + } + + private String getCurrentAddress(List addresses) { + synchronized (this) { + this.index++; + if (this.index >= addresses.size()) { + this.index = 0; + } + return addresses.get(index); + } + } + + private List getZoneOrRegionAddress() { + List results = new ArrayList<>(); + if (!availableZone.isEmpty()) { + results.addAll(availableZone); + } else { + results.addAll(availableRegion); + } + return results; + } + + public void recordSuccessState(String address) { + resetFailureStatus(address); + if (addressAutoRefreshed) { + if (isolationZoneAddress.remove(address)) { + LOGGER.warn("restore same region address [{}]", address); + if (eventBus != null && availableZone.isEmpty()) { + eventBus.post(new EngineConnectChangedEvent()); + } + availableZone.add(address); + return; + } + if (isolationRegionAddress.remove(address)) { + LOGGER.warn("restore same zone address [{}]", address); + availableRegion.add(address); + } + return; + } + if (defaultIsolationAddress.remove(address)) { + LOGGER.warn("restore default address [{}]", address); + addresses.add(address); + } + } + + public void resetFailureStatus(String address) { + addressFailureStatus.put(address, 0); + } + + public void recordFailState(String address) { + synchronized (lock) { + if (!addressFailureStatus.containsKey(address)) { + addressFailureStatus.put(address, 1); + return; + } + int number = addressFailureStatus.get(address) + 1; + if (number < ISOLATION_THRESHOLD) { + addressFailureStatus.put(address, number); + } else { + removeAddress(address); + } + } + } + + //Query whether the current address belongs to the same AZ or the same region through AZMap, + // and delete it from the record. At the same time, add records in history and cache + @VisibleForTesting + void removeAddress(String address) { + if (!addressAutoRefreshed) { + if (addresses.remove(address)) { + LOGGER.warn("isolation default address [{}]", address); + defaultIsolationAddress.add(address); + } + return; + } + if (availableZone.remove(address)) { + LOGGER.warn("isolation same zone address [{}]", address); + isolationZoneAddress.add(address); + if (eventBus != null && availableZone.isEmpty() && !availableRegion.isEmpty()) { + eventBus.post(new EngineConnectChangedEvent()); + } + return; + } + if (availableRegion.remove(address)) { + LOGGER.warn("isolation same region address [{}]", address); + isolationRegionAddress.add(address); + } + } + + public void setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + } + + public List getIsolationAddresses() { + List isolationAddresses = new ArrayList<>(defaultIsolationAddress); + isolationAddresses.addAll(isolationZoneAddress); + isolationAddresses.addAll(isolationRegionAddress); + return isolationAddresses; + } + + public String compareAndGetAddress(String host) { + for (String address : defaultAddress) { + if (isAddressHostSame(address, host)) { + return address; + } + } + return ""; + } + + private boolean isAddressHostSame(String address, String host) { + if (StringUtils.isEmpty(host)) { + return false; + } + try { + URI uri = new URI(address); + return host.equals(uri.getHost()); + } catch (Exception e) { + LOGGER.warn("Exception occurred while constructing URI using the address [{}]", address); + } + return false; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpConfiguration.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpConfiguration.java new file mode 100644 index 00000000000..59b6b4c2cc8 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpConfiguration.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; + +public interface HttpConfiguration { + class SSLProperties { + private boolean enabled; + + private SSLOption sslOption; + + private SSLCustom sslCustom; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public SSLOption getSslOption() { + return sslOption; + } + + public void setSslOption(SSLOption sslOption) { + this.sslOption = sslOption; + } + + public SSLCustom getSslCustom() { + return sslCustom; + } + + public void setSslCustom(SSLCustom sslCustom) { + this.sslCustom = sslCustom; + } + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java new file mode 100644 index 00000000000..35e14df06c1 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.entity.StringEntity; + +public class HttpRequest { + + public static final String GET = "GET"; + + public static final String POST = "POST"; + + public static final String DELETE = "DELETE"; + + public static final String PUT = "PUT"; + + private String method; + + private final String url; + + private Map headers; + + private final String content; + + public HttpRequest(String url, Map headers, String content, String method) { + this.url = url; + this.headers = headers; + this.content = content; + this.method = method; + } + + public String getUrl() { + return url; + } + + public Map getHeaders() { + return headers; + } + + public void addHeader(String name, String value) { + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(name, value); + } + + public String getContent() { + return content; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public HttpUriRequest getRealRequest() { + + HttpUriRequest httpUriRequest = null; + + switch (method) { + case GET: { + httpUriRequest = new HttpGet(url); + break; + } + case POST: { + httpUriRequest = new HttpPost(url); + if (content != null) { + ((HttpPost) httpUriRequest).setEntity(new StringEntity(content, "UTF-8")); + } + break; + } + case DELETE: { + httpUriRequest = new HttpDelete(url); + break; + } + case PUT: { + httpUriRequest = new HttpPut(url); + if (content != null) { + ((HttpPut) httpUriRequest).setEntity(new StringEntity(content, "UTF-8")); + } + break; + } + default: { + httpUriRequest = RequestBuilder.create(method).build(); + } + } + + Optional.ofNullable(httpUriRequest).ifPresent(request -> headers.forEach(request::addHeader)); + + return httpUriRequest; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpResponse.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpResponse.java new file mode 100644 index 00000000000..c2a414290d3 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpResponse.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import org.apache.http.Header; + +public class HttpResponse { + + private int statusCode; + + private String message; + + private String content; + + private Header[] headers; + + public HttpResponse() { + + } + + HttpResponse(int statusCode, String message, String content, Header[] headers) { + this.statusCode = statusCode; + this.content = content; + this.message = message; + this.headers = headers; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getHeader(String key) { + if (headers == null) { + return null; + } + for (Header header : headers) { + if (header.getName().equals(key)) { + return header.getValue(); + } + } + return null; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransport.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransport.java new file mode 100644 index 00000000000..731fdbe4e7e --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransport.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.io.IOException; +import java.util.Map; + +/** + * Created by on 2019/10/16. + */ +public interface HttpTransport { + + HttpResponse get(HttpRequest request) throws IOException; + + HttpResponse post(HttpRequest request) throws IOException; + + HttpResponse put(HttpRequest request) throws IOException; + + HttpResponse delete(HttpRequest request) throws IOException; + + HttpResponse doRequest(HttpRequest request) throws IOException; + + void addHeaders(Map headers); +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java new file mode 100644 index 00000000000..b1179321b3f --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.servicecomb.foundation.ssl.SSLManager; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; + +public class HttpTransportFactory { + // All parameters set to 5 seconds now. + public static final int CONNECT_TIMEOUT = 5000; + + public static final int CONNECTION_REQUEST_TIMEOUT = 5000; + + public static final int SOCKET_TIMEOUT = 5000; + + public static final int MAX_TOTAL = 100; + + public static final int DEFAULT_MAX_PER_ROUTE = 10; + + private HttpTransportFactory() { + } + + public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties, + RequestAuthHeaderProvider requestAuthHeaderProvider, HttpClientBuilder httpClientBuilder) { + PoolingHttpClientConnectionManager connectionManager = getPoolingHttpClientConnectionManager(sslProperties); + httpClientBuilder.setConnectionManager(connectionManager).disableCookieManagement(); + return new HttpTransportImpl(httpClientBuilder.build(), requestAuthHeaderProvider); + } + + public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties, + RequestAuthHeaderProvider requestAuthHeaderProvider, RequestConfig config) { + PoolingHttpClientConnectionManager connectionManager = getPoolingHttpClientConnectionManager(sslProperties); + + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(config). + setConnectionManager(connectionManager). + disableCookieManagement(); + + return new HttpTransportImpl(httpClientBuilder.build(), requestAuthHeaderProvider); + } + + private static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(SSLProperties sslProperties) { + //register http/https socket factory + RegistryBuilder builder = RegistryBuilder.create(); + builder.register("http", PlainConnectionSocketFactory.INSTANCE); + if (sslProperties.isEnabled()) { + builder.register("https", + new SSLConnectionSocketFactory( + SSLManager.createSSLContext(sslProperties.getSslOption(), sslProperties.getSslCustom()), + NoopHostnameVerifier.INSTANCE)); + } + Registry connectionSocketFactoryRegistry = builder.build(); + + //connection pool management + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager( + connectionSocketFactoryRegistry); + connectionManager.setMaxTotal(MAX_TOTAL); + connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); + return connectionManager; + } + + public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties, + RequestAuthHeaderProvider requestAuthHeaderProvider) { + return createHttpTransport(sslProperties, requestAuthHeaderProvider, defaultRequestConfig().build()); + } + + public static RequestConfig.Builder defaultRequestConfig() { + return RequestConfig.custom() + .setConnectTimeout(CONNECT_TIMEOUT) + .setConnectionRequestTimeout( + CONNECTION_REQUEST_TIMEOUT) + .setSocketTimeout(SOCKET_TIMEOUT); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java new file mode 100644 index 00000000000..507d8d1c556 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; + +import org.apache.http.client.HttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.servicecomb.foundation.auth.SignRequest; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by on 2019/10/16. + */ +public class HttpTransportImpl implements HttpTransport { + private static final Logger LOGGER = LoggerFactory.getLogger(HttpTransportImpl.class); + + private static final String HEADER_CONTENT_TYPE = "Content-Type"; + + private static final String HEADER_USER_AGENT = "User-Agent"; + + private HttpClient httpClient; + + private Map globalHeaders; + + private final RequestAuthHeaderProvider requestAuthHeaderProvider; + + public HttpTransportImpl(HttpClient httpClient, RequestAuthHeaderProvider requestAuthHeaderProvider) { + this.httpClient = httpClient; + this.requestAuthHeaderProvider = requestAuthHeaderProvider; + } + + public HttpClient getHttpClient() { + return httpClient; + } + + // for testing. + void setHttpClient(HttpClient httpClient) { + this.httpClient = httpClient; + } + + @Override + public HttpResponse get(HttpRequest request) throws IOException { + request.setMethod(HttpRequest.GET); + return doRequest(request); + } + + @Override + public HttpResponse post(HttpRequest request) throws IOException { + request.setMethod(HttpRequest.POST); + return doRequest(request); + } + + @Override + public HttpResponse put(HttpRequest request) throws IOException { + request.setMethod(HttpRequest.PUT); + return doRequest(request); + } + + @Override + public HttpResponse delete(HttpRequest request) throws IOException { + request.setMethod(HttpRequest.DELETE); + return doRequest(request); + } + + public HttpResponse doRequest(HttpRequest httpRequest) throws IOException { + //add header + httpRequest.addHeader(HEADER_CONTENT_TYPE, "application/json"); + httpRequest.addHeader(HEADER_USER_AGENT, "microservice-client/1.0.0"); + + if (globalHeaders != null) { + globalHeaders.forEach(httpRequest::addHeader); + } + + httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest(httpRequest.getUrl()))); + + //get Http response + org.apache.http.HttpResponse response = httpClient.execute(httpRequest.getRealRequest()); + + return new HttpResponse(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), + response.getEntity() == null ? null : + EntityUtils.toString(response.getEntity(), "UTF-8"), + response.getAllHeaders()); + } + + private static SignRequest createSignRequest(String url) { + try { + URI uri = URI.create(url); + SignRequest signRequest = new SignRequest(); + signRequest.setEndpoint(uri); + return signRequest; + } catch (Exception e) { + LOGGER.error("create signRequest failed!", e); + return null; + } + } + + @Override + public void addHeaders(Map headers) { + this.globalHeaders = headers; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java new file mode 100644 index 00000000000..5f259cc3053 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.io.IOException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Hex; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public final class HttpUtils { + private static final String ALGORITHM_HMACSHA256 = "HmacSHA256"; + + private static final ObjectMapper MAPPER = new MessageObjectMapper(); + + public static T deserialize(String content, Class clazz) throws IOException { + return MAPPER.readValue(content, clazz); + } + + public static T deserialize(String content, TypeReference clazz) throws IOException { + return MAPPER.readValue(content, clazz); + } + + public static String serialize(Object value) throws IOException { + return MAPPER.writeValueAsString(value); + } + + public static JsonNode readTree(String content) throws IOException { + return MAPPER.readTree(content); + } + + public static String encodeURLParam(String value) throws IOException { + if (value == null) { + return ""; + } + return URLEncoder.encode(value, StandardCharsets.UTF_8); + } + + public static String decodeURLParam(String value) throws IOException { + if (value == null) { + return null; + } + return URLDecoder.decode(value, StandardCharsets.UTF_8); + } + + public static String sha256Encode(String key, String data) throws Exception { + Mac mac = Mac.getInstance(ALGORITHM_HMACSHA256); + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), + ALGORITHM_HMACSHA256); + mac.init(secretKey); + return Hex.encodeHexString(mac.doFinal(data.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java new file mode 100644 index 00000000000..4eb85472643 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import com.fasterxml.jackson.core.JsonParser.Feature; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +public class MessageObjectMapper extends ObjectMapper { + private static final long serialVersionUID = 189026839992490564L; + + public MessageObjectMapper() { + getFactory().disable(Feature.AUTO_CLOSE_SOURCE); + // Enable features that can tolerance errors and not enable those make more constraints for compatible reasons. + // Developers can use validation api to do more checks. + disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + // no view annotations shouldn't be included in JSON + this._deserializationConfig = this._deserializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION); + this._serializationConfig = this._serializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION); + disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java new file mode 100644 index 00000000000..db5f18afee7 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import javax.net.ssl.SSLSocketFactory; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +public class SSLSocketFactoryExt extends SSLSocketFactory { + private final SSLSocketFactory sslSocketFactory; + + private final String host; + + private final int port; + + public SSLSocketFactoryExt(SSLSocketFactory factory, String host, int port) { + this.sslSocketFactory = factory; + this.host = host; + this.port = port; + } + + @Override + public String[] getDefaultCipherSuites() { + return this.sslSocketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return this.sslSocketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + return this.sslSocketFactory.createSocket(host, port); + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + return this.sslSocketFactory.createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return this.sslSocketFactory.createSocket(host, port); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, + UnknownHostException { + return this.sslSocketFactory.createSocket(host, port, localHost, localPort); + } + + @Override + public Socket createSocket(InetAddress localHost, int port) throws IOException { + return this.sslSocketFactory.createSocket(localHost, port); + } + + @Override + public Socket createSocket(InetAddress localHost, int localPort, InetAddress localHost1, int localPort1) + throws IOException { + return this.sslSocketFactory.createSocket(localHost, localPort, localHost1, localPort1); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java new file mode 100644 index 00000000000..e3e53bad06a --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +public class URLEndPoint { + private static final String SSL_ENABLED_KEY = "sslEnabled"; + + private static final String HTTP_KEY = "http://"; + + private static final String HTTPS_KEY = "https://"; + + private final boolean sslEnabled; + + private final Map> queries; + + private final String hostOrIp; + + private final int port; + + public URLEndPoint(String endpoint) { + URI uri = URI.create(endpoint); + hostOrIp = uri.getHost(); + if (uri.getPort() < 0) { + throw new IllegalArgumentException("port not specified."); + } + port = uri.getPort(); + queries = splitQuery(uri); + if (endpoint.contains(HTTPS_KEY)) { + sslEnabled = true; + } else { + sslEnabled = Boolean.parseBoolean(getFirst(SSL_ENABLED_KEY)); + } + } + + public static Map> splitQuery(URI uri) { + final Map> queryPairs = new LinkedHashMap<>(); + List pairs = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8); + for (NameValuePair pair : pairs) { + List list = queryPairs.computeIfAbsent(pair.getName(), name -> new ArrayList<>()); + list.add(pair.getValue()); + } + return queryPairs; + } + + public String getFirst(String key) { + List values = queries.get(key); + if (values == null) { + return null; + } + return values.get(0); + } + + @Override + public String toString() { + if (sslEnabled) { + return HTTPS_KEY + hostOrIp + ":" + port; + } + return HTTP_KEY + hostOrIp + ":" + port; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketListener.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketListener.java new file mode 100644 index 00000000000..de79c2f7ddd --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketListener.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import org.java_websocket.handshake.ServerHandshake; + +public interface WebSocketListener { + void onMessage(String s); + + void onError(Exception e); + + void onClose(int code, String reason, boolean remote); + + void onOpen(ServerHandshake serverHandshake); +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java new file mode 100644 index 00000000000..ab630c609be --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; + +import javax.net.ssl.SSLSocketFactory; + +import org.apache.servicecomb.foundation.ssl.SSLManager; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.drafts.Draft_6455; +import org.java_websocket.handshake.ServerHandshake; + +public class WebSocketTransport extends WebSocketClient { + public static final int CONNECT_TIMEOUT = 5000; + + private final WebSocketListener webSocketListener; + + public WebSocketTransport(String serverUri, HttpConfiguration.SSLProperties sslProperties, + Map headers, WebSocketListener webSocketListener) + throws URISyntaxException { + super(new URI(serverUri), new Draft_6455(), headers, CONNECT_TIMEOUT); + + if (sslProperties.isEnabled()) { + SSLSocketFactory sslSocketFactory = SSLManager + .createSSLSocketFactory(sslProperties.getSslOption(), sslProperties.getSslCustom()); + URI uri = new URI(serverUri); + setSocketFactory(new SSLSocketFactoryExt(sslSocketFactory, uri.getHost(), uri.getPort())); + } + + this.webSocketListener = webSocketListener; + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + this.webSocketListener.onOpen(serverHandshake); + } + + @Override + public void onMessage(String s) { + this.webSocketListener.onMessage(s); + } + + @Override + public void onClose(int code, String reason, boolean remote) { + this.webSocketListener.onClose(code, reason, remote); + } + + @Override + public void onError(Exception e) { + this.webSocketListener.onError(e); + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java new file mode 100644 index 00000000000..b2029f5c38c --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.event; + +public class EngineConnectChangedEvent { +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java new file mode 100644 index 00000000000..69896f750ec --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.event; + +public abstract class OperationEvents { + public static class UnAuthorizedOperationEvent extends OperationEvents { + private final String address; + + public UnAuthorizedOperationEvent(String address) { + this.address = address; + } + + public String getAddress() { + return address; + } + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java new file mode 100644 index 00000000000..4e4f1be648e --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.event; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RefreshEndpointEvent { + + public static final String SERVICE_CENTER_NAME = "SERVICECENTER"; + + public static final String KIE_NAME = "KIE"; + + public static final String CONFIG_CENTER_NAME = "CseConfigCenter"; + + public static final String CSE_MONITORING_NAME = "CseMonitoring"; + + private static final String SAME_ZONE = "sameZone"; + + private static final String SAME_REGION = "sameRegion"; + + private Map> zoneAndRegion = new HashMap<>(); + + private String name; + + public RefreshEndpointEvent(Map> zoneAndRegion, String name) { + this.zoneAndRegion = zoneAndRegion; + this.name = name; + } + + public List getSameZone() { + if (zoneAndRegion.get(SAME_ZONE).isEmpty()) { + return new ArrayList<>(); + } + return zoneAndRegion.get(SAME_ZONE); + } + + public List getSameRegion() { + if (zoneAndRegion.get(SAME_REGION).isEmpty()) { + return new ArrayList<>(); + } + return zoneAndRegion.get(SAME_REGION); + } + + public Map> getZoneAndRegion() { + return zoneAndRegion; + } + + public void setZoneAndRegion(Map> zoneAndRegion) { + this.zoneAndRegion = zoneAndRegion; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java new file mode 100644 index 00000000000..cc10ae8e142 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.task; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AbstractTask { + public class BackOffSleepTask implements Task { + private static final long BASE = 3000; + + private static final long MAX = 10 * 60 * 1000; + + long waitTime; + + Task nextTask; + + public BackOffSleepTask(int failedCount, Task nextTask) { + this.waitTime = failedCount * failedCount * BASE; + this.nextTask = nextTask; + } + + public BackOffSleepTask(long waitTime, Task nextTask) { + this.waitTime = waitTime; + this.nextTask = nextTask; + } + + @Override + public void execute() { + long time = Math.min(MAX, waitTime); + try { + Thread.sleep(time); + } catch (InterruptedException e) { + LOGGER.error("unexpected interrupt during sleep", e); + } + startTask(nextTask); + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTask.class); + + protected ExecutorService taskPool; + + private volatile boolean running = true; + + public static AtomicInteger taskCounter = new AtomicInteger(0); + + private ScheduledExecutorService addrCheckExecutor; + + protected AbstractTask(String taskName) { + initTaskPool(taskName); + Runtime.getRuntime().addShutdownHook(new Thread(AbstractTask.this::stop, taskName + "-shutdown-hook")); + } + + protected void initTaskPool(String taskName) { + this.taskPool = Executors.newSingleThreadExecutor((task) -> + new Thread(task, taskName + "-" + taskCounter.getAndIncrement())); + } + + protected void schedulerCheckAddressAvailable(String taskName, Runnable task, long delayTime) { + if (addrCheckExecutor == null) { + addrCheckExecutor = Executors.newScheduledThreadPool(1, (t) -> new Thread(t, taskName)); + } + addrCheckExecutor.scheduleWithFixedDelay(task, delayTime, delayTime, TimeUnit.MILLISECONDS); + } + + protected void startTask(Task task) { + if (!running) { + return; + } + + try { + this.taskPool.execute(() -> { + try { + task.execute(); + } catch (Throwable e) { + LOGGER.error("unexpected error execute task {}", task.getClass().getName(), e); + } + }); + } catch (RejectedExecutionException e) { + LOGGER.error("execute task rejected {}", task.getClass().getName(), e); + } + } + + public void stop() { + try { + running = false; + this.taskPool.shutdown(); + this.taskPool.awaitTermination(10, TimeUnit.SECONDS); + if (addrCheckExecutor != null) { + this.addrCheckExecutor.shutdown(); + this.addrCheckExecutor.awaitTermination(10, TimeUnit.SECONDS); + } + } catch (InterruptedException e) { + LOGGER.warn("tasks not shutdown in time {}", e.getMessage()); + } + } +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/Task.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/Task.java new file mode 100644 index 00000000000..bd009717175 --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/Task.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.task; + +public interface Task { + void execute(); +} diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java new file mode 100644 index 00000000000..9139e65f96a --- /dev/null +++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.utils; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.http.client.common.AbstractAddressManager; +import org.apache.servicecomb.http.client.common.HttpRequest; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; + +public class ServiceCombServiceAvailableUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCombServiceAvailableUtils.class); + + public static void checkAddressAvailable(AbstractAddressManager addressManager, String address, + HttpTransport httpTransport, String path) { + String formatUrl = addressManager.formatUrl(path, true, address); + HttpRequest httpRequest = new HttpRequest(formatUrl, null, null, HttpRequest.GET); + try { + HttpResponse response = httpTransport.doRequest(httpRequest); + if (response.getStatusCode() == HttpStatus.SC_OK) { + addressManager.recordSuccessState(address); + return; + } + + // old server does not provide the check api, using TCP checks whether the server is ready. + if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND && telnetCheckAddress(address)) { + LOGGER.warn("[{}] path does not provide, tcp check address ready!", path); + addressManager.recordSuccessState(address); + } + } catch (IOException e) { + LOGGER.error("check isolation address [{}] available error!", address); + } + } + + private static boolean telnetCheckAddress(String address) { + URI ipPort = parseIpPortFromURI(address); + if (ipPort == null) { + return false; + } + try (Socket s = new Socket()) { + s.connect(new InetSocketAddress(ipPort.getHost(), ipPort.getPort()), 3000); + return true; + } catch (IOException e) { + LOGGER.warn("ping endpoint {} failed, It will be quarantined again.", address); + } + return false; + } + + private static URI parseIpPortFromURI(String address) { + try { + return new URI(address); + } catch (URISyntaxException e) { + LOGGER.error("build uri error with address [{}].", address); + return null; + } + } +} diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java new file mode 100644 index 00000000000..b14d6827cb8 --- /dev/null +++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java @@ -0,0 +1,328 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AbstractAddressManagerTest { + + private static final List addresses = new ArrayList<>(); + + private static AbstractAddressManager addressManager1; + + private static AbstractAddressManager addressManager2; + + private static AbstractAddressManager addressManager3; + + @BeforeEach + public void setUp() throws NoSuchFieldException, IllegalAccessException { + addresses.add("http://127.0.0.1:30103"); + addresses.add("https://127.0.0.2:30103"); + addressManager1 = new AbstractAddressManager(addresses, "", ""); + addressManager2 = new AbstractAddressManager("project", addresses, "", ""); + addressManager3 = new AbstractAddressManager(null, addresses, "", ""); + Field addressManagerField = addressManager1.getClass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager1, 0); + addressManagerField = addressManager2.getClass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager2, 0); + addressManagerField = addressManager3.getClass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager3, 0); + } + + @AfterEach + public void tearDown() { + addresses.clear(); + addressManager1 = null; + addressManager2 = null; + addressManager3 = null; + } + + @Test + public void abstractAddressManagerTest() { + Assertions.assertNotNull(addressManager1); + Assertions.assertNotNull(addressManager2); + Assertions.assertNotNull(addressManager3); + + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + } + + @Test + public void recordStateTest() throws ExecutionException { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.3:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("http://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST"); + AbstractAddressManager addressManager = new AbstractAddressManager(addresses, "", "") {}; + + addressManager.refreshEndpoint(event, "TEST"); + + String address = "http://127.0.0.3:30100"; + addressManager.recordFailState(address); + + Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address()); + + addressManager.recordFailState(address); + Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address()); + + // test fail 2 times ,it will not be isolated + addressManager.resetFailureStatus(address); + Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address()); + + // test recodeStatus times + Map recodeStatus = addressManager.getAddressFailureStatus(); + Assertions.assertEquals(0, (int) recodeStatus.get("http://127.0.0.3:30100")); + + // test fail 3 times ,it will be isolated + addressManager.recordFailState(address); + addressManager.recordFailState(address); + addressManager.recordFailState(address); + Assertions.assertEquals("http://127.0.0.4:30100", addressManager.address()); + + // test restore isolation + addressManager.recordSuccessState("http://127.0.0.3:30100"); + Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address()); + Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address()); + } + + + @Test + public void testMultipleThread() throws Exception { + + AbstractAddressManager addressManager = new AbstractAddressManager(addresses, "", ""); + String address = "http://127.0.0.3:30100"; + + CountDownLatch latch = new CountDownLatch(2); + for (int i = 0; i < 2; i++) { + new Thread(() -> { + addressManager.recordFailState(address); + latch.countDown(); + }).start(); + } + latch.await(30, TimeUnit.SECONDS); + + Map recodeStatus = addressManager.getAddressFailureStatus(); + Assertions.assertEquals(2, (int) recodeStatus.get("http://127.0.0.3:30100")); + } + + @Test + public void addressForOnlyDefaultTest() { + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + + Assertions.assertEquals("https://127.0.0.2:30103/v3/project", addressManager2.address()); + Assertions.assertEquals("http://127.0.0.1:30103/v3/project", addressManager2.address()); + + Assertions.assertEquals("https://127.0.0.2:30103/v3/default", addressManager3.address()); + Assertions.assertEquals("http://127.0.0.1:30103/v3/default", addressManager3.address()); + } + + @Test + public void addressForOnlyAzTest() { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.1:30100"); + addressAZ.add("https://127.0.0.2:30100"); + addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true"); + addressAZ.add("rest://127.0.0.2:30100?sslEnabled=false"); + + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", new ArrayList<>()); + RefreshEndpointEvent event1 = new RefreshEndpointEvent(zoneAndRegion, "TEST"); + addressManager1.refreshEndpoint(event1, "TEST"); + + Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.1:30100", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.2:30100", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address()); + } + + @Test + public void addressForOnlyRegionTest() { + List addressRG = new ArrayList<>(); + addressRG.add("rest://127.0.0.5:30100?sslEnabled=true"); + addressRG.add("rest://127.0.0.6:30100"); + addressRG.add("http://127.0.0.7:30100"); + addressRG.add("https://127.0.0.8:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", new ArrayList<>()); + zoneAndRegion.put("sameRegion", addressRG); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST"); + addressManager1.refreshEndpoint(event, "TEST"); + + Assertions.assertEquals("http://127.0.0.6:30100", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.7:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.8:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.5:30100", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.6:30100", addressManager1.address()); + } + + @Test + public void addressForAzAndRegionTest() { + List addressAZ = new ArrayList<>(); + addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true"); + addressAZ.add("https://127.0.0.2:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("rest://127.0.0.3:30100?sslEnabled=true"); + addressRG.add("https://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST"); + addressManager1.refreshEndpoint(event, "TEST"); + + Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.1:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address()); + + addressManager1.removeAddress("https://127.0.0.2:30100"); + addressManager1.removeAddress("https://127.0.0.1:30100"); + Assertions.assertEquals("https://127.0.0.3:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.4:30100", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.3:30100", addressManager1.address()); + + addressManager1.removeAddress("https://127.0.0.4:30100"); + addressManager1.removeAddress("https://127.0.0.3:30100"); + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + } + + @Test + public void sslEnabledTest() { + Assertions.assertTrue(addressManager1.sslEnabled()); + Assertions.assertFalse(addressManager1.sslEnabled()); + Assertions.assertTrue(addressManager1.sslEnabled()); + + Assertions.assertTrue(addressManager2.sslEnabled()); + Assertions.assertFalse(addressManager2.sslEnabled()); + Assertions.assertTrue(addressManager2.sslEnabled()); + } + + @Test + public void transformAddressTest() { + List address = new ArrayList<>(); + address.add("rest://127.0.0.1:30100?sslEnabled=true"); + address.add("rest://127.0.0.2:30100"); + address.add("http://127.0.0.3:30100"); + address.add("https://127.0.0.4:30100"); + + List formAddress = addressManager2.transformAddress(address); + + Assertions.assertEquals("rest://127.0.0.1:30100?sslEnabled=true/v3/project", formAddress.get(0)); + Assertions.assertEquals("rest://127.0.0.2:30100/v3/project", formAddress.get(1)); + Assertions.assertEquals("http://127.0.0.3:30100/v3/project", formAddress.get(2)); + Assertions.assertEquals("https://127.0.0.4:30100/v3/project", formAddress.get(3)); + + formAddress = addressManager3.transformAddress(address); + Assertions.assertEquals("rest://127.0.0.1:30100?sslEnabled=true/v3/default", formAddress.get(0)); + Assertions.assertEquals("rest://127.0.0.2:30100/v3/default", formAddress.get(1)); + Assertions.assertEquals("http://127.0.0.3:30100/v3/default", formAddress.get(2)); + Assertions.assertEquals("https://127.0.0.4:30100/v3/default", formAddress.get(3)); + } + + @Test + public void getUrlPrefixTest() { + Assertions.assertEquals("http://127.0.0.3:30100/v3/", addressManager2.getUrlPrefix("http://127.0.0.3:30100")); + Assertions.assertEquals("http://127.0.0.3:30100/v3/", addressManager3.getUrlPrefix("http://127.0.0.3:30100")); + } + + @Test + public void refreshEndpointTest() { + List addressAZ = new ArrayList<>(); + addressAZ.add("rest://127.0.0.1:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", new ArrayList<>()); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST"); + + addressManager1.refreshEndpoint(event, "KIE"); + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address()); + + addressManager2.refreshEndpoint(event, "TEST"); + Assertions.assertEquals("http://127.0.0.1:30100", addressManager2.address()); + Assertions.assertEquals("http://127.0.0.1:30100", addressManager2.address()); + } + + @Test + public void normalizeIPV4Test() { + String uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=true"); + Assertions.assertEquals("https://127.0.0.1:30100", uri); + + uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=false"); + Assertions.assertEquals("http://127.0.0.1:30100", uri); + + uri = addressManager1.normalizeUri("rest://127.0.0.1:30100"); + Assertions.assertEquals("http://127.0.0.1:30100", uri); + } + + @Test + public void normalizeIPV6Test() { + String uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100?sslEnabled=true"); + Assertions.assertEquals("https://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri); + + uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100"); + Assertions.assertEquals("http://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri); + } + + @Test + public void compareAndGetAddressTest() { + List testAddr = new ArrayList<>(); + testAddr.add("https://192.168.20.160:30100"); + testAddr.add("https://127.0.0.1:30100"); + testAddr.add("https://127.0.0.3:30100"); + AbstractAddressManager manager = new AbstractAddressManager(testAddr, "", ""); + Assertions.assertTrue(manager.compareAndGetAddress("192.168.20.16").isEmpty()); + Assertions.assertEquals("https://192.168.20.160:30100", manager.compareAndGetAddress("192.168.20.160")); + } + + @Test + public void AddressAffinityTest() { + List testAddr = new ArrayList<>(); + testAddr.add("https://192.168.20.160:30100?region=region1&availableZone=zone1"); + testAddr.add("https://127.0.0.1:30100"); + AbstractAddressManager manager = new AbstractAddressManager(testAddr, "region1", "zone1"); + Assertions.assertEquals("https://192.168.20.160:30100", manager.address()); + + AbstractAddressManager manager2 = new AbstractAddressManager("default", testAddr, "region1", "zone1"); + Assertions.assertEquals("https://192.168.20.160:30100", manager2.address()); + } +} diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java new file mode 100644 index 00000000000..2530b80145a --- /dev/null +++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.http.client.common; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpVersion; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpClient; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class HttpTransportImplTest { + + @Test + public void TestHttpTransport() throws IOException { + HttpClient httpClient = mock(HttpClient.class); + RequestAuthHeaderProvider requestAuthHeaderProvider = mock(RequestAuthHeaderProvider.class); + org.apache.http.HttpResponse httpResponse = mock(org.apache.http.HttpResponse.class); + StatusLine statusLine = mock(StatusLine.class); + when(statusLine.getStatusCode()).thenReturn(200); + when(statusLine.getProtocolVersion()).thenReturn(HttpVersion.HTTP_1_1); + when(statusLine.getReasonPhrase()).thenReturn("OK"); + + when(httpResponse.getStatusLine()).thenReturn(statusLine); + when(httpResponse.getEntity()).thenReturn(new StringEntity("Test", ContentType.APPLICATION_JSON)); + + when(httpClient.execute(Mockito.any())).thenReturn(httpResponse); + + HttpTransportImpl httpTransport = new HttpTransportImpl(httpClient, requestAuthHeaderProvider); + Map extraHeaders = new HashMap<>(); + extraHeaders.put("test", "testContext"); + httpTransport.addHeaders(extraHeaders); + + HttpRequest httpRequest = new HttpRequest("111", null, null, HttpRequest.GET); + HttpResponse actualResponse = httpTransport.get(httpRequest); + + Assertions.assertNotNull(actualResponse); + Assertions.assertEquals(200, actualResponse.getStatusCode()); + Assertions.assertEquals("OK", actualResponse.getMessage()); + Assertions.assertEquals("Test", actualResponse.getContent()); + } +} diff --git a/clients/http-client-common/src/test/resources/tls/client.p12 b/clients/http-client-common/src/test/resources/tls/client.p12 new file mode 100644 index 00000000000..acd63412397 Binary files /dev/null and b/clients/http-client-common/src/test/resources/tls/client.p12 differ diff --git a/clients/http-client-common/src/test/resources/tls/server.jks b/clients/http-client-common/src/test/resources/tls/server.jks new file mode 100644 index 00000000000..f3429ed696e Binary files /dev/null and b/clients/http-client-common/src/test/resources/tls/server.jks differ diff --git a/clients/pom.xml b/clients/pom.xml new file mode 100644 index 00000000000..49f481934cc --- /dev/null +++ b/clients/pom.xml @@ -0,0 +1,43 @@ + + + + + + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + 4.0.0 + + clients + ServiceComb::Client + pom + + http-client-common + service-center-client + config-common + config-kie-client + config-center-client + dashboard-client + + + diff --git a/clients/service-center-client/README.md b/clients/service-center-client/README.md new file mode 100644 index 00000000000..a6b4c6d4936 --- /dev/null +++ b/clients/service-center-client/README.md @@ -0,0 +1,97 @@ +## ServiceComb-Service-Center Client for Java + + Sample Java client for ServiceComb-Service-Center HTTP API. + If you want more information about the ServiceComb-Service-Center HTTP API, go [here](https://github.com/apache/servicecomb-service-center/blob/master/docs/openapi/v4.yaml). + +### Build & Install + + local Build from source : + ``` + maven clean install + ``` + + add dependency to maven + ``` + + org.apache.servicecomb + service-center-client + + ``` + + +### Basic Usage + +#### Case 1: Health check +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +//get service-center instance +MicroserviceInstancesResponse instances = client.getServiceCenterInstances(); +``` + +#### Case 2: Register microservice +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +// state Microservice object, and you have to set a serviceName +Microservice microservice = new Microservice(); +microservice.setServiceName("Test"); +microservice.setServiceId("111111"); + +//register microservice +String response = client.registerMicroservice(microservice); +``` + +#### Case 3: Get microservice list +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +//get services lists +MicroservicesResponse services = client.getMicroserviceList(); +``` + +#### Case 4: Register service instance +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +//state MicroserviceInstance object, you have to set existed serviceId +MicroserviceInstance instance = new MicroserviceInstance(); +instance.setServiceId("222222"); + +//register service instanceId, return instanceId +String instanceId = client.registerMicroserviceInstance(instance, "222222"); +``` + +#### Case 5: Get service instances list +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +// get instances list with servcieId being "222222" +MicroserviceInstancesResponse instances = client.getMicroserviceInstanceList("222222"); +``` + +#### Case 6: Heartbeats +```Java +ServiceCenterClient client = new ServiceCenterClient(); + +//all services and all instances send heartbeats +MicroservicesResponse services = client.getMicroserviceList(); +for(Microservice microservice : services.getServices()) +{ + for (MicroserviceInstance instance: client.getMicroserviceInstanceList(microservice.getServiceId()).getInstances()) + { + client.sendHeartBeats(new HeartbeatsRequest(microservice.getServiceId(),instance.getInstanceId())); + } +} +``` + +#### Other API +You can see client API code and tests, go [here](https://github.com/apache/servicecomb-java-chassis/blob/master/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java) + + +### More development + +- Support All Service-center HTTP API + +### Contact +Bugs/Feature : [issues](https://github.com/apache/servicecomb-java-chassis/issues) diff --git a/clients/service-center-client/pom.xml b/clients/service-center-client/pom.xml new file mode 100755 index 00000000000..ccc3900e9db --- /dev/null +++ b/clients/service-center-client/pom.xml @@ -0,0 +1,46 @@ + + + + + + clients + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + service-center-client + ServiceComb::Clients::Service Center Client + + + + + org.apache.servicecomb + http-client-common + + + + com.google.guava + failureaccess + test + + + diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/CacheableServiceCenterOperation.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/CacheableServiceCenterOperation.java new file mode 100644 index 00000000000..68741333b24 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/CacheableServiceCenterOperation.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +public interface CacheableServiceCenterOperation { + +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java new file mode 100644 index 00000000000..e45720f5ebb --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.List; + +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; + +public abstract class DiscoveryEvents { + public static class InstanceChangedEvent extends DiscoveryEvents { + private final String appName; + + private final String serviceName; + + private final List instances; + + public InstanceChangedEvent(String appName, String serviceName, List instances) { + this.appName = appName; + this.serviceName = serviceName; + this.instances = instances; + } + + public String getAppName() { + return appName; + } + + public String getServiceName() { + return serviceName; + } + + public List getInstances() { + return instances; + } + } + + /** + * internal events to ask for a immediate instance pull + */ + public static class PullInstanceEvent extends DiscoveryEvents { + + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java new file mode 100644 index 00000000000..d411913dfed --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; + +public abstract class RegistrationEvents { + protected final boolean success; + + protected final Microservice microservice; + + protected RegistrationEvents(boolean success, Microservice microservice) { + this.success = success; + this.microservice = microservice; + } + + public boolean isSuccess() { + return this.success; + } + + public Microservice getMicroservice() { + return microservice; + } + + public static class MicroserviceRegistrationEvent extends RegistrationEvents { + public MicroserviceRegistrationEvent(boolean success, Microservice microservice) { + super(success, microservice); + } + } + + public static class SchemaRegistrationEvent extends RegistrationEvents { + public SchemaRegistrationEvent(boolean success, Microservice microservice) { + super(success, microservice); + } + } + + public static class MicroserviceInstanceRegistrationEvent extends RegistrationEvents { + protected final MicroserviceInstance microserviceInstance; + + public MicroserviceInstanceRegistrationEvent(boolean success, Microservice microservice, + MicroserviceInstance microserviceInstance) { + super(success, microservice); + this.microserviceInstance = microserviceInstance; + } + } + + public static class HeartBeatEvent extends RegistrationEvents { + protected final MicroserviceInstance microserviceInstance; + + public HeartBeatEvent(boolean success, Microservice microservice, + MicroserviceInstance microserviceInstance) { + super(success, microservice); + this.microserviceInstance = microserviceInstance; + } + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java new file mode 100644 index 00000000000..b19db919e81 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.List; + +import org.apache.servicecomb.http.client.common.AbstractAddressManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ServiceCenterAddressManager extends AbstractAddressManager { + public ServiceCenterAddressManager(String projectName, List addresses, EventBus eventBus, String region, + String availableZone) { + super(projectName, addresses, region, availableZone); + eventBus.register(this); + } + + @Override + protected List transformAddress(List addresses) { + return addresses; + } + + @Override + protected String getUrlPrefix(String address) { + return address + V4_PREFIX; + } + + @Subscribe + public void onRefreshEndpointEvent(RefreshEndpointEvent event) { + refreshEndpoint(event, RefreshEndpointEvent.SERVICE_CENTER_NAME); + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java new file mode 100755 index 00000000000..97aeaa9931a --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java @@ -0,0 +1,569 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpStatus; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.utils.URIBuilder; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.apache.servicecomb.http.client.common.HttpUtils; +import org.apache.servicecomb.service.center.client.exception.OperationException; +import org.apache.servicecomb.service.center.client.model.CreateMicroserviceInstanceRequest; +import org.apache.servicecomb.service.center.client.model.CreateMicroserviceRequest; +import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest; +import org.apache.servicecomb.service.center.client.model.ErrorMessage; +import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.Framework; +import org.apache.servicecomb.service.center.client.model.GetSchemaListResponse; +import org.apache.servicecomb.service.center.client.model.GetSchemaResponse; +import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceResponse; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.MicroserviceResponse; +import org.apache.servicecomb.service.center.client.model.MicroservicesResponse; +import org.apache.servicecomb.service.center.client.model.ModifySchemasRequest; +import org.apache.servicecomb.service.center.client.model.RbacTokenRequest; +import org.apache.servicecomb.service.center.client.model.RbacTokenResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.apache.servicecomb.service.center.client.model.UpdatePropertiesRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; + +public class ServiceCenterClient implements ServiceCenterOperation { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterClient.class); + + private static final String CLIENT_CONNECT_TIMEOUT = "servicecomb.registry.sc.client.timeout.connect"; + + private static final String CLIENT_REQUEST_TIMEOUT = "servicecomb.registry.sc.client.timeout.request"; + + private static final String CLIENT_SOCKET_TIMEOUT = "servicecomb.registry.sc.client.timeout.socket"; + + private final ServiceCenterRawClient httpClient; + + private final ServiceCenterAddressManager addressManager; + + public ServiceCenterClient(ServiceCenterRawClient httpClient, ServiceCenterAddressManager addressManager) { + this.httpClient = httpClient; + this.addressManager = addressManager; + } + + public ServiceCenterClient setEventBus(EventBus eventBus) { + addressManager.setEventBus(eventBus); + this.httpClient.setEventBus(eventBus); + return this; + } + + public ServiceCenterClient(ServiceCenterAddressManager addressManager, + SSLProperties sslProperties, + RequestAuthHeaderProvider requestAuthHeaderProvider, + String tenantName, + Map extraGlobalHeaders, + Environment environment) { + HttpTransport httpTransport = HttpTransportFactory.createHttpTransport(sslProperties, requestAuthHeaderProvider, + buildRequestConfig(environment)); + httpTransport.addHeaders(extraGlobalHeaders); + + this.httpClient = new ServiceCenterRawClient.Builder() + .setTenantName(tenantName) + .setAddressManager(addressManager) + .setHttpTransport(httpTransport).build(); + this.addressManager = addressManager; + } + + private RequestConfig buildRequestConfig(Environment environment) { + RequestConfig.Builder builder = HttpTransportFactory.defaultRequestConfig(); + if (environment == null) { + return builder.build(); + } + builder.setConnectTimeout(environment.getProperty(CLIENT_CONNECT_TIMEOUT, int.class, 5000)); + builder.setConnectionRequestTimeout(environment.getProperty(CLIENT_REQUEST_TIMEOUT, int.class, 5000)); + builder.setSocketTimeout(environment.getProperty(CLIENT_SOCKET_TIMEOUT, int.class, 5000)); + return builder.build(); + } + + @Override + public MicroserviceInstancesResponse getServiceCenterInstances() { + try { + HttpResponse response = httpClient.getHttpRequest("/registry/health", null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class); + } + throw new OperationException( + "get service-center instances fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service-center instances fails", e); + } + } + + @Override + public RegisteredMicroserviceResponse registerMicroservice(Microservice microservice) { + try { + CreateMicroserviceRequest request = new CreateMicroserviceRequest(); + request.setService(microservice); + HttpResponse response = httpClient + .postHttpRequest("/registry/microservices", null, HttpUtils.serialize(request)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class); + } + throw new OperationException( + "register service fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "register service fails", e); + } + } + + @Override + public MicroservicesResponse getMicroserviceList() { + try { + HttpResponse response = httpClient.getHttpRequest("/registry/microservices", null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), MicroservicesResponse.class); + } + throw new OperationException( + "get service List fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service List fails", e); + } + } + + @Override + public RegisteredMicroserviceResponse queryServiceId(Microservice microservice) { + try { + URIBuilder uriBuilder = new URIBuilder("/registry/existence"); + uriBuilder.setParameter("type", "microservice"); + uriBuilder.setParameter("appId", microservice.getAppId()); + uriBuilder.setParameter("serviceName", microservice.getServiceName()); + uriBuilder.setParameter("version", microservice.getVersion()); + uriBuilder.setParameter("env", microservice.getEnvironment()); + + HttpResponse response = httpClient.getHttpRequest(uriBuilder.build().toString(), null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class); + } + LOGGER.info("Query serviceId fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + return null; + } catch (IOException e) { + throw new OperationException( + "query serviceId fails", e); + } catch (URISyntaxException e) { + throw new OperationException( + "build url failed.", e); + } + } + + @Override + public Microservice getMicroserviceByServiceId(String serviceId) { + try { + HttpResponse response = httpClient.getHttpRequest("/registry/microservices/" + serviceId, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + MicroserviceResponse microserviceResponse = HttpUtils + .deserialize(response.getContent(), MicroserviceResponse.class); + return microserviceResponse.getService(); + } + throw new OperationException( + "get service message fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service message fails", e); + } + } + + @Override + public RegisteredMicroserviceInstanceResponse registerMicroserviceInstance(MicroserviceInstance instance) { + try { + CreateMicroserviceInstanceRequest request = new CreateMicroserviceInstanceRequest(); + request.setInstance(instance); + HttpResponse response = httpClient + .postHttpRequest("/registry/microservices/" + instance.getServiceId() + "/instances", null, + HttpUtils.serialize(request)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceInstanceResponse.class); + } + throw new OperationException( + "register service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "register service instance fails", e); + } + } + + @Override + public FindMicroserviceInstancesResponse findMicroserviceInstance(String consumerId, String appId, String serviceName, + String versionRule, + String revision) { + try { + Map headers = new HashMap<>(); + headers.put("X-ConsumerId", consumerId); + HttpResponse response = httpClient + .getHttpRequest("/registry/instances?appId=" + URLEncoder.encode(appId, "UTF-8") + + "&serviceName=" + HttpUtils.encodeURLParam(serviceName) + + "&version=" + HttpUtils.encodeURLParam(versionRule) + + "&rev=" + HttpUtils.encodeURLParam(revision) + , headers, null); + FindMicroserviceInstancesResponse result = new FindMicroserviceInstancesResponse(); + if (response.getStatusCode() == HttpStatus.SC_OK) { + result.setModified(true); + result.setRevision(response.getHeader("X-Resource-Revision")); + result.setMicroserviceInstancesResponse( + HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class)); + return result; + } + if (response.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + result.setModified(false); + return result; + } + if (response.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) { + LOGGER.warn("rate limited, keep the local service {}#{} instance cache unchanged.", appId, serviceName); + result.setModified(false); + return result; + } + throw new OperationException( + "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service instances list fails", e); + } + } + + @Override + public MicroserviceInstancesResponse getMicroserviceInstanceList(String serviceId) { + try { + HttpResponse response = httpClient + .getHttpRequest("/registry/microservices/" + serviceId + "/instances", null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class); + } + throw new OperationException( + "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service instances list fails", e); + } + } + + @Override + public MicroserviceInstance getMicroserviceInstance(String serviceId, String instanceId) { + try { + HttpResponse response = httpClient + .getHttpRequest("/registry/microservices/" + serviceId + "/instances/" + instanceId, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + MicroserviceInstanceResponse instanceResponse = HttpUtils + .deserialize(response.getContent(), MicroserviceInstanceResponse.class); + return instanceResponse.getInstance(); + } + throw new OperationException( + "get service instance message fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service instance message fails", e); + } + } + + @Override + public void deleteMicroserviceInstance(String serviceId, String instanceId) { + try { + HttpResponse response = httpClient + .deleteHttpRequest("/registry/microservices/" + serviceId + "/instances/" + instanceId, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + LOGGER.info("Delete service instance successfully."); + return; + } + throw new OperationException( + "delete service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "delete service instance fails", e); + } + } + + @Override + public boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId, + MicroserviceInstanceStatus status) { + try { + HttpResponse response = httpClient.putHttpRequest( + "/registry/microservices/" + serviceId + "/instances/" + instanceId + "/status?value=" + status, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "update service instance status fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "update service instance status fails", e); + } + } + + @Override + public void sendHeartBeats(HeartbeatsRequest heartbeatsRequest) { + try { + HttpResponse response = httpClient + .putHttpRequest("/registry/heartbeats", null, HttpUtils.serialize(heartbeatsRequest)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return; + } + throw new OperationException( + "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "heartbeats fails ", e); + } + } + + @Override + public boolean sendHeartBeat(String serviceId, String instanceId) { + try { + HttpResponse response = httpClient + .putHttpRequest("/registry/microservices/" + serviceId + "/instances/" + instanceId + "/heartbeat", + null, null); + + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "heartbeats fails ", e); + } + } + + @Override + public List getServiceSchemasList(String serviceId, boolean withContent) { + String url = "/registry/microservices/" + serviceId + "/schemas"; + if (withContent) { + url = url + "?withSchema=1"; + } + + try { + HttpResponse response = httpClient + .getHttpRequest(url, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + GetSchemaListResponse getSchemaResponse = HttpUtils + .deserialize(response.getContent(), GetSchemaListResponse.class); + return getSchemaResponse.getSchemas(); + } + throw new OperationException( + "get service schemas list fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service schemas list fails", e); + } + } + + /** + * Get one schema context of service + * + * @param serviceId + * @param schemaId + * @return + * @throws OperationException + */ + public String getServiceSchemaContext(String serviceId, String schemaId) { + try { + HttpResponse response = httpClient + .getHttpRequest("/registry/microservices/" + serviceId + "/schemas/" + schemaId, null, null); + if (response.getStatusCode() == HttpStatus.SC_OK) { + GetSchemaResponse getSchemaResponse = HttpUtils.deserialize(response.getContent(), GetSchemaResponse.class); + return getSchemaResponse.getSchema(); + } + throw new OperationException( + "get service schema context fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "get service schemas context fails", e); + } + } + + @Override + public boolean registerSchema(String serviceId, String schemaId, CreateSchemaRequest schema) { + try { + HttpResponse response = httpClient + .putHttpRequest("/registry/microservices/" + serviceId + "/schemas/" + schemaId, null, + HttpUtils.serialize(schema)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "update service schema fails", e); + } + } + + @Override + public boolean updateServiceSchemaContext(String serviceId, SchemaInfo schemaInfo) { + try { + CreateSchemaRequest request = new CreateSchemaRequest(); + request.setSchema(schemaInfo.getSchema()); + request.setSummary(schemaInfo.getSummary()); + HttpResponse response = httpClient + .putHttpRequest("/registry/microservices/" + serviceId + "/schemas/" + schemaInfo.getSchemaId(), null, + HttpUtils.serialize(request)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "update service schema fails", e); + } + } + + @Override + public boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRequest modifySchemasRequest) { + try { + HttpResponse response = httpClient + .postHttpRequest("/registry/microservices/" + serviceId + "/schemas", null, + HttpUtils.serialize(modifySchemasRequest)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "update service schema fails", e); + } + } + + @Override + public RbacTokenResponse queryToken(RbacTokenRequest request, String host) { + try { + String queryAddress = addressManager.compareAndGetAddress(host); + HttpResponse response = httpClient + .postHttpRequestAbsoluteUrl("/v4/token", null, HttpUtils.serialize(request), queryAddress); + if (response.getStatusCode() == HttpStatus.SC_OK) { + RbacTokenResponse result = HttpUtils.deserialize(response.getContent(), RbacTokenResponse.class); + result.setStatusCode(HttpStatus.SC_OK); + return result; + } + if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND) { + RbacTokenResponse result = new RbacTokenResponse(); + result.setStatusCode(response.getStatusCode()); + return result; + } + if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED || + response.getStatusCode() == HttpStatus.SC_FORBIDDEN) { + RbacTokenResponse result = new RbacTokenResponse(); + result.setStatusCode(response.getStatusCode()); + ErrorMessage errorMessage = HttpUtils.deserialize(response.getContent(), ErrorMessage.class); + result.setErrorCode(errorMessage.getErrorCode()); + return result; + } + throw new OperationException( + "query token failed, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "query token failed", e); + } + } + + @Override + public boolean updateMicroserviceProperties(String serviceId, Map serviceProperties, + Framework framework) { + try { + UpdatePropertiesRequest request = new UpdatePropertiesRequest(); + request.setProperties(serviceProperties); + request.setFramework(framework); + HttpResponse response = httpClient.putHttpRequest( + "/registry/microservices/" + serviceId + "/properties", null, HttpUtils.serialize(request)); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return true; + } + throw new OperationException( + "update service properties fails, statusCode = " + response.getStatusCode() + "; message = " + response + .getMessage() + + "; content = " + response.getContent()); + } catch (IOException e) { + throw new OperationException( + "update service properties fails", e); + } + } + + @Override + public void checkIsolationAddressAvailable() { + List isolationAddresses = addressManager.getIsolationAddresses(); + if (isolationAddresses.isEmpty()) { + return; + } + for (String address : isolationAddresses) { + httpClient.checkAddressAvailable(address); + } + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java new file mode 100644 index 00000000000..a1ab524c187 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.http.client.task.AbstractTask; +import org.apache.servicecomb.http.client.task.Task; +import org.apache.servicecomb.service.center.client.DiscoveryEvents.InstanceChangedEvent; +import org.apache.servicecomb.service.center.client.DiscoveryEvents.PullInstanceEvent; +import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ServiceCenterDiscovery extends AbstractTask { + + public static final int MAX_INTERVAL = 600000; + + public static final int MIN_INTERVAL = 1000; + + private static final String ALL_VERSION = "0+"; + + private static volatile boolean pullInstanceTaskOnceInProgress = false; + + public static class SubscriptionKey { + final String appId; + + final String serviceName; + + public SubscriptionKey(String appId, String serviceName) { + this.appId = appId; + this.serviceName = serviceName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubscriptionKey that = (SubscriptionKey) o; + return appId.equals(that.appId) && + serviceName.equals(that.serviceName); + } + + @Override + public int hashCode() { + return Objects.hash(appId, serviceName); + } + } + + public static class SubscriptionValue { + String revision; + + List instancesCache; + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterDiscovery.class); + + private final ServiceCenterClient serviceCenterClient; + + private final EventBus eventBus; + + private String myselfServiceId; + + private final Map instancesCache = new ConcurrentHashMap<>(); + + private final Map microserviceCache = new ConcurrentHashMap<>(); + + private long pollInterval = 15000; + + private boolean started = false; + + private final Object lock = new Object(); + + private final Random random = new Random(); + + public ServiceCenterDiscovery(ServiceCenterClient serviceCenterClient, EventBus eventBus) { + super("service-center-discovery-task"); + this.serviceCenterClient = serviceCenterClient; + this.eventBus = eventBus; + this.eventBus.register(this); + } + + public ServiceCenterDiscovery setPollInterval(long interval) { + if (interval > MAX_INTERVAL || interval < MIN_INTERVAL) { + return this; + } + this.pollInterval = interval; + return this; + } + + public void updateMyselfServiceId(String myselfServiceId) { + this.myselfServiceId = myselfServiceId; + } + + public void startDiscovery() { + if (!started) { + started = true; + startTask(new PullInstanceTask()); + } + } + + public void registerIfNotPresent(SubscriptionKey subscriptionKey) { + if (this.instancesCache.get(subscriptionKey) == null) { + synchronized (lock) { + if (this.instancesCache.get(subscriptionKey) == null) { + SubscriptionValue value = new SubscriptionValue(); + pullInstance(subscriptionKey, value, false); + this.instancesCache.put(subscriptionKey, value); + } + } + } + } + + public List getInstanceCache(SubscriptionKey key) { + return this.instancesCache.get(key).instancesCache; + } + + @Subscribe + public void onPullInstanceEvent(PullInstanceEvent event) { + // to avoid too many pulls queued. + if (pullInstanceTaskOnceInProgress) { + return; + } + pullInstanceTaskOnceInProgress = true; + startTask(new PullInstanceOnceTask()); + } + + private void pullInstance(SubscriptionKey k, SubscriptionValue v, boolean sendChangedEvent) { + if (myselfServiceId == null) { + // registration not ready + return; + } + + try { + FindMicroserviceInstancesResponse instancesResponse = serviceCenterClient + .findMicroserviceInstance(myselfServiceId, k.appId, k.serviceName, ALL_VERSION, v.revision); + if (instancesResponse.isModified()) { + List instances = instancesResponse.getMicroserviceInstancesResponse().getInstances() + == null ? Collections.emptyList() : instancesResponse.getMicroserviceInstancesResponse().getInstances(); + setMicroserviceInfo(instances); + LOGGER.info("Instance changed event. " + + "Current: revision={}, instances={}. " + + "Origin: revision={}, instances={}. " + + "appId={}, serviceName={}.", + instancesResponse.getRevision(), + instanceToString(instances), + v.revision, + instanceToString(v.instancesCache), + k.appId, + k.serviceName + ); + v.instancesCache = instances; + v.revision = instancesResponse.getRevision(); + if (sendChangedEvent) { + eventBus.post(new InstanceChangedEvent(k.appId, k.serviceName, + v.instancesCache)); + } + } + } catch (Exception e) { + LOGGER.warn("find service {}#{} instance failed, remaining local instances cache [{}], cause message: {}", + k.appId, k.serviceName, instanceToString(v.instancesCache), e.getMessage()); + } + } + + private void setMicroserviceInfo(List instances) { + instances.forEach(instance -> { + Microservice microservice = microserviceCache + .computeIfAbsent(instance.getServiceId(), id -> { + try { + return serviceCenterClient.getMicroserviceByServiceId(id); + } catch (Exception e) { + LOGGER.error("Find microservice by id={} failed", id, e); + throw e; + } + }); + instance.setMicroservice(microservice); + }); + } + + class PullInstanceTask implements Task { + @Override + public void execute() { + pullAllInstance(); + + startTask(new BackOffSleepTask(buildPollIntervalWithSalt(), new PullInstanceTask())); + } + } + + private long buildPollIntervalWithSalt() { + int positive = random.nextInt(5); + int sign = random.nextBoolean() ? 1 : -1; + long currentPollInterval = pollInterval + sign * positive * 1000; + return currentPollInterval > 0 ? currentPollInterval : pollInterval; + } + + class PullInstanceOnceTask implements Task { + @Override + public void execute() { + try { + pullAllInstance(); + } finally { + pullInstanceTaskOnceInProgress = false; + } + } + } + + private synchronized void pullAllInstance() { + List emptyInstancesCache = new ArrayList<>(); + instancesCache.forEach((k, v) -> { + pullInstance(k, v, true); + if (v.instancesCache.isEmpty()) { + emptyInstancesCache.add(k); + } + }); + emptyInstancesCache.forEach(instancesCache::remove); + emptyInstancesCache.clear(); + } + + private static String instanceToString(List instances) { + if (instances == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + for (MicroserviceInstance instance : instances) { + for (String endpoint : instance.getEndpoints()) { + sb.append(endpoint.length() > 64 ? endpoint.substring(0, 64) : endpoint); + sb.append("|"); + } + sb.append(instance.getStatus()); + sb.append("|"); + } + return sb.toString(); + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java new file mode 100644 index 00000000000..fd39a4ce963 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.service.center.client.exception.OperationException; +import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest; +import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.Framework; +import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.MicroservicesResponse; +import org.apache.servicecomb.service.center.client.model.ModifySchemasRequest; +import org.apache.servicecomb.service.center.client.model.RbacTokenRequest; +import org.apache.servicecomb.service.center.client.model.RbacTokenResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; + +public interface ServiceCenterOperation { + /** + * Query service center instances. + * + * In configuration file, only one address of service center instances can be configured, and + * other instances can be discovered by calling this method. + * + * @return MicroserviceInstancesResponse + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + MicroserviceInstancesResponse getServiceCenterInstances(); + + /** + * Register microservcie. + * + * @return RegisterMicroserviceResponse + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + RegisteredMicroserviceResponse registerMicroservice(Microservice microservice); + + /** + * find all registered microservice of service-center. + * + * @return MicroserviceResponse + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + MicroservicesResponse getMicroserviceList(); + + /** + * Get microservice information by service id. + * + * @return Microservice + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + Microservice getMicroserviceByServiceId(String serviceId); + + /** + * query Microservice ID by appId, serviceName, version and environment. + * + * @return Microservice ID, null if microservice does not exists. + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + RegisteredMicroserviceResponse queryServiceId(Microservice microservice); + + /** + * Register microservice instances to service-center + * + * Notice: microserviceInstance' service id must be set before calling this method. + * + * @return instanceId + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + RegisteredMicroserviceInstanceResponse registerMicroserviceInstance(MicroserviceInstance microserviceInstance); + + /** + * Find microservice instances of service-center + * + * @return MicroserviceInstancesResponse + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + MicroserviceInstancesResponse getMicroserviceInstanceList(String serviceId); + + /** + * Get microservice instance by id + * + * @return MicroserviceInstance + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + MicroserviceInstance getMicroserviceInstance(String serviceId, String instanceId); + + /** + * Find MicroserviceInstance by properties. + * + * @return FindMicroserviceInstancesResponse + * @throws OperationException If some problems happened to contact service center or non http 200 returned.n + */ + FindMicroserviceInstancesResponse findMicroserviceInstance(String consumerId, String appId, String serviceName, + String versionRule, + String revision); + + /** + * Delete a microservice instance + * + * @throws OperationException + */ + void deleteMicroserviceInstance(String serviceId, String instanceId); + + /** + * Update status of microservice Instance + * + * @return if update is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId, + MicroserviceInstanceStatus status); + + /** + * register schema. + * @return if register is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean registerSchema(String serviceId, String schemaId, CreateSchemaRequest schema); + + /** + * update schema context of service + * + * @return if update is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean updateServiceSchemaContext(String serviceId, SchemaInfo schemaInfo); + + /** + * batch update schema context of service + * + * @return if update is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRequest modifySchemasRequest); + + /** + * Batch send heartbeats to service-center + * + * @param heartbeatsRequest + * @throws OperationException + */ + void sendHeartBeats(HeartbeatsRequest heartbeatsRequest); + + /** + * send heart beat of this instance. + * @return if heartbeat is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean sendHeartBeat(String serviceId, String instanceId); + + /** + * Get schemas list of service + * + * @throws OperationException + */ + List getServiceSchemasList(String serviceId, boolean withContent); + + /** + * query token using user confidential + * + * @return if heartbeat is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + RbacTokenResponse queryToken(RbacTokenRequest request, String host); + + /** + * Update properties of microservice + * + * @return if update is successful + * @throws OperationException If some problems happened to contact service center or non http 200 returned. + */ + boolean updateMicroserviceProperties(String microserviceId, Map serviceProperties, + Framework framework); + + /** + * Check serviceCenter isolation address available + */ + void checkIsolationAddressAvailable(); +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java new file mode 100755 index 00000000000..e233f15fb52 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpStatus; +import org.apache.servicecomb.http.client.common.HttpRequest; +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent; +import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class ServiceCenterRawClient { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterRawClient.class); + + private static final String HEADER_TENANT_NAME = "x-domain-name"; + + private static final String ADDRESS_CHECK_PATH = "/v4/default/registry/health/readiness"; + + private final String tenantName; + + private final HttpTransport httpTransport; + + private final ServiceCenterAddressManager addressManager; + + private EventBus eventBus; + + private ServiceCenterRawClient(String tenantName, HttpTransport httpTransport, + ServiceCenterAddressManager addressManager) { + this.httpTransport = httpTransport; + this.tenantName = tenantName; + this.addressManager = addressManager; + } + + public void setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + } + + public HttpResponse getHttpRequest(String url, Map headers, String content) throws IOException { + return doHttpRequest(url, false, headers, content, HttpRequest.GET, ""); + } + + public HttpResponse postHttpRequestAbsoluteUrl(String url, Map headers, String content, + String address) throws IOException { + return doHttpRequest(url, true, headers, content, HttpRequest.POST, address); + } + + public HttpResponse postHttpRequest(String url, Map headers, String content) throws IOException { + return doHttpRequest(url, false, headers, content, HttpRequest.POST, ""); + } + + public HttpResponse putHttpRequest(String url, Map headers, String content) throws IOException { + return doHttpRequest(url, false, headers, content, HttpRequest.PUT, ""); + } + + public HttpResponse deleteHttpRequest(String url, Map headers, String content) throws IOException { + return doHttpRequest(url, false, headers, content, HttpRequest.DELETE, ""); + } + + private HttpResponse doHttpRequest(String url, boolean absoluteUrl, Map headers, String content, + String method, String queryAddress) throws IOException { + String address = StringUtils.isEmpty(queryAddress) ? addressManager.address() : queryAddress; + String formatUrl = addressManager.formatUrl(url, absoluteUrl, address); + HttpRequest httpRequest = buildHttpRequest(formatUrl, headers, content, method); + HttpResponse httpResponse; + try { + httpResponse = httpTransport.doRequest(httpRequest); + recordAndSendUnAuthorizedEvent(httpResponse, address); + return httpResponse; + } catch (IOException e) { + addressManager.recordFailState(address); + String retryAddress = addressManager.address(); + formatUrl = addressManager.formatUrl(url, absoluteUrl, retryAddress); + LOGGER.warn("send request to {} failed and retry to {} once. ", address, retryAddress, e); + httpRequest = new HttpRequest(formatUrl, headers, content, method); + try { + httpResponse = httpTransport.doRequest(httpRequest); + recordAndSendUnAuthorizedEvent(httpResponse, retryAddress); + return httpResponse; + } catch (IOException ioException) { + addressManager.recordFailState(retryAddress); + LOGGER.warn("retry to {} failed again. ", retryAddress, e); + throw ioException; + } + } + } + + private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) { + if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + LOGGER.warn("request unauthorized from server [{}], message [{}]", address, response.getMessage()); + addressManager.recordFailState(address); + this.eventBus.post(new UnAuthorizedOperationEvent(address)); + } else { + addressManager.recordSuccessState(address); + } + } + + public void checkAddressAvailable(String address) { + ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH); + } + + private HttpRequest buildHttpRequest(String url, Map headers, String content, String method) { + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(HEADER_TENANT_NAME, tenantName); + return new HttpRequest(url, headers, content, method); + } + + public static class Builder { + private String tenantName; + + private HttpTransport httpTransport; + + private ServiceCenterAddressManager addressManager; + + public Builder() { + } + + public Builder setTenantName(String tenantName) { + this.tenantName = tenantName; + return this; + } + + public Builder setHttpTransport(HttpTransport httpTransport) { + this.httpTransport = httpTransport; + return this; + } + + public Builder setAddressManager(ServiceCenterAddressManager addressManager) { + this.addressManager = addressManager; + return this; + } + + public ServiceCenterRawClient build() { + return new ServiceCenterRawClient(tenantName, httpTransport, addressManager); + } + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java new file mode 100644 index 00000000000..93988ea8948 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java @@ -0,0 +1,318 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.http.client.task.AbstractTask; +import org.apache.servicecomb.http.client.task.Task; +import org.apache.servicecomb.service.center.client.RegistrationEvents.HeartBeatEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.MicroserviceInstanceRegistrationEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.MicroserviceRegistrationEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.SchemaRegistrationEvent; +import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.apache.servicecomb.service.center.client.model.ServiceCenterConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class ServiceCenterRegistration extends AbstractTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterRegistration.class); + + public static final int MAX_INTERVAL = 600000; + + public static final int MIN_INTERVAL = 1000; + + private final ServiceCenterClient serviceCenterClient; + + private final EventBus eventBus; + + private Microservice microservice; + + private MicroserviceInstance microserviceInstance; + + private List schemaInfos = new ArrayList<>(); + + private final ServiceCenterConfiguration serviceCenterConfiguration; + + private long heartBeatInterval = 15000; + + private long heartBeatRequestTimeout = 5000; + + public ServiceCenterRegistration(ServiceCenterClient serviceCenterClient, ServiceCenterConfiguration + serviceCenterConfiguration, EventBus eventBus) { + super("service-center-registration-task"); + this.serviceCenterClient = serviceCenterClient; + this.serviceCenterConfiguration = serviceCenterConfiguration; + this.eventBus = eventBus; + } + + public ServiceCenterRegistration setMicroserviceInstance(MicroserviceInstance microserviceInstance) { + this.microserviceInstance = microserviceInstance; + return this; + } + + public ServiceCenterRegistration setMicroservice(Microservice microservice) { + this.microservice = microservice; + return this; + } + + public ServiceCenterRegistration setHeartBeatInterval(long interval) { + if (interval > MAX_INTERVAL || interval < MIN_INTERVAL) { + return this; + } + this.heartBeatInterval = interval; + return this; + } + + public ServiceCenterRegistration setHeartBeatRequestTimeout(long timeout) { + if (timeout > MAX_INTERVAL || timeout < MIN_INTERVAL) { + return this; + } + this.heartBeatRequestTimeout = timeout; + return this; + } + + public ServiceCenterRegistration setSchemaInfos(List schemaInfos) { + this.schemaInfos = schemaInfos; + return this; + } + + public ServiceCenterRegistration addSchemaInfo(SchemaInfo schemaInfo) { + this.schemaInfos.add(schemaInfo); + return this; + } + + public List getSchemaInfos() { + return this.schemaInfos; + } + + public void startRegistration() { + startTask(new RegisterMicroserviceTask(0)); + schedulerCheckAddressAvailable("sc-addr-check", new CheckAddressTask(), heartBeatInterval); + } + + class RegisterMicroserviceTask implements Task { + int failedCount; + + RegisterMicroserviceTask(int failedCount) { + this.failedCount = failedCount; + } + + @Override + public void execute() { + try { + RegisteredMicroserviceResponse serviceResponse = serviceCenterClient.queryServiceId(microservice); + if (serviceResponse == null) { + RegisteredMicroserviceResponse response = serviceCenterClient.registerMicroservice(microservice); + if (StringUtils.isEmpty(response.getServiceId())) { + LOGGER.error("register microservice failed, and will try again."); + eventBus.post(new MicroserviceRegistrationEvent(false, microservice)); + startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceTask(failedCount + 1))); + return; + } + microservice.setServiceId(response.getServiceId()); + microserviceInstance.setServiceId(response.getServiceId()); + microserviceInstance.setMicroservice(microservice); + eventBus.post(new MicroserviceRegistrationEvent(true, microservice)); + startTask(new RegisterSchemaTask(0)); + } else { + Microservice newMicroservice = serviceCenterClient.getMicroserviceByServiceId(serviceResponse.getServiceId()); + + Map propertiesTemp = microservice.getProperties(); + microservice.setProperties(newMicroservice.getProperties()); + microservice.getProperties().putAll(propertiesTemp); + if (serviceCenterClient.updateMicroserviceProperties(serviceResponse.getServiceId(), + microservice.getProperties(), microservice.getFramework())) { + LOGGER.info( + "microservice is already registered. Update microservice properties successfully. properties=[{}], " + + "frameworkVersion [{}]", microservice.getProperties(), microservice.getFramework().getVersion()); + } else { + LOGGER.error("microservice is already registered. Update microservice properties failed. properties=[{}], " + + "frameworkVersion [{}]", microservice.getProperties(), microservice.getFramework().getVersion()); + } + + microservice.setServiceId(serviceResponse.getServiceId()); + microserviceInstance.setServiceId(serviceResponse.getServiceId()); + microserviceInstance.setMicroservice(microservice); + if (isSwaggerDifferent(newMicroservice)) { + if (serviceCenterConfiguration.isCanOverwriteSwagger()) { + LOGGER.warn("Service has already registered, but schema ids not equal, try to register it again"); + eventBus.post(new MicroserviceRegistrationEvent(true, microservice)); + startTask(new RegisterSchemaTask(0)); + return; + } + if (serviceCenterConfiguration.isIgnoreSwaggerDifferent()) { + LOGGER.warn("Service has already registered, but schema ids not equal. Ignore and continue to register"); + } else { + throw new IllegalStateException( + "Service has already registered, but schema ids not equal, stop register. " + + "Change the microservice version or delete the old microservice info and try again."); + } + } + eventBus.post(new MicroserviceRegistrationEvent(true, microservice)); + startTask(new RegisterMicroserviceInstanceTask(0)); + } + } catch (IllegalStateException e) { + throw e; + } catch (Exception e) { + LOGGER.error("register microservice failed, and will try again.", e); + eventBus.post(new MicroserviceRegistrationEvent(false, microservice)); + startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceTask(failedCount + 1))); + } + } + } + + private boolean isSwaggerDifferent(Microservice newMicroservice) { + return !isListEquals(newMicroservice.getSchemas(), microservice.getSchemas()); + } + + private boolean isListEquals(List one, List two) { + return one.size() == two.size() && one.containsAll(two) && two.containsAll(one); + } + + class RegisterSchemaTask implements Task { + int failedCount; + + RegisterSchemaTask(int failedCount) { + this.failedCount = failedCount; + } + + @Override + public void execute() { + try { + if (schemaInfos == null || schemaInfos.isEmpty()) { + LOGGER.warn("no schemas defined for this microservice."); + eventBus.post(new SchemaRegistrationEvent(true, microservice)); + startTask(new RegisterMicroserviceInstanceTask(0)); + return; + } + + for (SchemaInfo schemaInfo : schemaInfos) { + CreateSchemaRequest request = new CreateSchemaRequest(); + request.setSchema(schemaInfo.getSchema()); + request.setSummary(schemaInfo.getSummary()); + if (!serviceCenterClient.registerSchema(microservice.getServiceId(), schemaInfo.getSchemaId(), request)) { + LOGGER.error("register schema content failed, and will try again."); + eventBus.post(new SchemaRegistrationEvent(false, microservice)); + // back off by multiply + startTask(new BackOffSleepTask(failedCount + 1, new RegisterSchemaTask((failedCount + 1) * 2))); + return; + } + } + + eventBus.post(new SchemaRegistrationEvent(true, microservice)); + startTask(new RegisterMicroserviceInstanceTask(0)); + } catch (Exception e) { + LOGGER.error("register schema content failed, and will try again.", e); + eventBus.post(new SchemaRegistrationEvent(false, microservice)); + // back off by multiply + startTask(new BackOffSleepTask(failedCount + 1, new RegisterSchemaTask((failedCount + 1) * 2))); + } + } + } + + class RegisterMicroserviceInstanceTask implements Task { + int failedCount; + + RegisterMicroserviceInstanceTask(int failedCount) { + this.failedCount = failedCount; + } + + @Override + public void execute() { + try { + RegisteredMicroserviceInstanceResponse instance = serviceCenterClient + .registerMicroserviceInstance(microserviceInstance); + if (instance == null) { + LOGGER.error("register microservice instance failed, and will try again."); + eventBus.post(new MicroserviceInstanceRegistrationEvent(false, microservice, microserviceInstance)); + startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceInstanceTask(failedCount + 1))); + } else { + microserviceInstance.setInstanceId(instance.getInstanceId()); + LOGGER.info("register microservice successfully, service id={}, instance id={}", microservice.getServiceId(), + microserviceInstance.getInstanceId()); + eventBus.post(new MicroserviceInstanceRegistrationEvent(true, microservice, microserviceInstance)); + startTask(new SendHeartBeatTask(0)); + } + } catch (Exception e) { + LOGGER.error("register microservice instance failed, and will try again.", e); + eventBus.post(new MicroserviceInstanceRegistrationEvent(false, microservice, microserviceInstance)); + startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceInstanceTask(failedCount + 1))); + } + } + } + + class SendHeartBeatTask implements Task { + private static final int FAILED_RETRY = 3; + + int failedCount; + + SendHeartBeatTask(int failedCount) { + this.failedCount = failedCount; + } + + @Override + public void execute() { + try { + if (failedCount >= FAILED_RETRY) { + eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance)); + startTask(new RegisterMicroserviceTask(0)); + return; + } + + if (!serviceCenterClient.sendHeartBeat(microservice.getServiceId(), microserviceInstance.getInstanceId())) { + LOGGER.warn("send heart failed, and will try again."); + eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance)); + startTask(new BackOffSleepTask(failedCount + 1, new SendHeartBeatTask(failedCount + 1))); + } else { + // wait 10 * 3000 ms and send heart beat again. + eventBus.post(new HeartBeatEvent(true, microservice, microserviceInstance)); + startTask( + new BackOffSleepTask(Math.max(heartBeatInterval, heartBeatRequestTimeout), new SendHeartBeatTask(0))); + } + } catch (Exception e) { + // If heartbeat failures three times, log error stack help troubleshooting. Others just log message as warn. + if (failedCount == 2) { + LOGGER.error("send heart failed, and will try again.", e); + } else { + LOGGER.warn("send heart failed, and will try again. message [{}]", e.getMessage()); + } + eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance)); + startTask(new BackOffSleepTask(failedCount + 1, new SendHeartBeatTask(failedCount + 1))); + } + } + } + + class CheckAddressTask implements Runnable { + @Override + public void run() { + serviceCenterClient.checkIsolationAddressAvailable(); + } + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java new file mode 100644 index 00000000000..9f24a74a55a --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.foundation.auth.SignRequest; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.apache.servicecomb.http.client.common.WebSocketListener; +import org.apache.servicecomb.http.client.common.WebSocketTransport; +import org.apache.servicecomb.service.center.client.DiscoveryEvents.PullInstanceEvent; +import org.java_websocket.handshake.ServerHandshake; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class ServiceCenterWatch implements WebSocketListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterWatch.class); + + private static final String HTTP = "http://"; + + private static final String HTTPS = "https://"; + + private static final String WS = "ws://"; + + private static final String WSS = "wss://"; + + private static final String WATCH = "/v4/%s/registry/microservices/%s/watcher"; + + private static final long SLEEP_BASE = 3000; + + private static final long SLEEP_MAX = 10 * 60 * 10000; + + private final ServiceCenterAddressManager addressManager; + + private final SSLProperties sslProperties; + + private final RequestAuthHeaderProvider requestAuthHeaderProvider; + + private final String tenantName; + + private final Map extraGlobalHeaders; + + private WebSocketTransport webSocketTransport; + + private String project; + + private String serviceId; + + private AtomicInteger continuousError = new AtomicInteger(0); + + private final AtomicBoolean reconnecting = new AtomicBoolean(false); + + private final EventBus eventBus; + + private String currentServerUri; + + private final ExecutorService connector = Executors.newFixedThreadPool(1, (r) -> new + Thread(r, "web-socket-connector")); + + public ServiceCenterWatch(ServiceCenterAddressManager addressManager, + SSLProperties sslProperties, + RequestAuthHeaderProvider requestAuthHeaderProvider, + String tenantName, + Map extraGlobalHeaders, + EventBus eventBus) { + this.addressManager = addressManager; + this.sslProperties = sslProperties; + this.requestAuthHeaderProvider = requestAuthHeaderProvider; + this.tenantName = tenantName; + this.extraGlobalHeaders = extraGlobalHeaders; + this.eventBus = eventBus; + } + + public void startWatch(String project, String serviceId) { + this.project = project; + this.serviceId = serviceId; + + startWatch(); + } + + private void startWatch() { + connector.submit(() -> { + backOff(); + String address = addressManager.address(); + try { + Map headers = new HashMap<>(); + headers.put("x-domain-name", this.tenantName); + headers.putAll(this.extraGlobalHeaders); + headers.putAll(this.requestAuthHeaderProvider.loadAuthHeader(createSignRequest(address))); + currentServerUri = convertAddress(address); + LOGGER.info("start watch to address {}", currentServerUri); + webSocketTransport = new WebSocketTransport(currentServerUri, sslProperties, + headers, this); + webSocketTransport.connectBlocking(); + addressManager.recordSuccessState(address); + } catch (Exception e) { + addressManager.recordFailState(address); + LOGGER.error("start watch failed. ", e); + } + }); + } + + private SignRequest createSignRequest(String url) { + try { + URI uri = URI.create(url); + SignRequest signRequest = new SignRequest(); + signRequest.setEndpoint(uri); + return signRequest; + } catch (Exception e) { + return null; + } + } + + private String convertAddress(String address) { + String url = String.format(WATCH, project, serviceId); + if (address.startsWith(HTTP)) { + return WS + address.substring(HTTP.length()) + url; + } + + if (address.startsWith(HTTPS)) { + return WSS + address.substring(HTTPS.length()) + url; + } + return address + url; + } + + public void stop() { + if (webSocketTransport != null) { + webSocketTransport.close(); + } + } + + private void reconnect() { + if (reconnecting.getAndSet(true)) { + return; + } + continuousError.incrementAndGet(); + if (webSocketTransport != null) { + webSocketTransport.close(); + } + startWatch(); + } + + private void backOff() { + if (this.continuousError.get() <= 0) { + return; + } + try { + Thread.sleep(Math.min(SLEEP_MAX, this.continuousError.get() * this.continuousError.get() * SLEEP_BASE)); + } catch (InterruptedException e) { + // do not care + } + } + + @Override + public void onMessage(String s) { + LOGGER.info("web socket receive message [{}], start query instance", s); + this.eventBus.post(new PullInstanceEvent()); + } + + @Override + public void onError(Exception e) { + LOGGER.warn("web socket receive error [{}], will restart.", e.getMessage()); + reconnect(); + } + + @Override + public void onClose(int code, String reason, boolean remote) { + LOGGER.warn("web socket closed, code={}, reason={}.", code, reason); + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + LOGGER.info("web socket connected to server {}, status={}, message={}", currentServerUri, + serverHandshake.getHttpStatus(), + serverHandshake.getHttpStatusMessage()); + continuousError.set(0); + reconnecting.set(false); + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/exception/OperationException.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/exception/OperationException.java new file mode 100644 index 00000000000..95cb1a7849a --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/exception/OperationException.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.exception; + +public class OperationException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public OperationException() { + } + + public OperationException(String message) { + super(message); + } + + public OperationException(String message, Throwable cause) { + super(message, cause); + } + + public OperationException(Throwable cause) { + super(cause); + } + + public OperationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/BasePath.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/BasePath.java old mode 100644 new mode 100755 similarity index 85% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/BasePath.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/BasePath.java index 986d51bc1c1..892f3f393f0 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/BasePath.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/BasePath.java @@ -1,48 +1,42 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * Created by on 2017/3/29. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class BasePath { - private String path; - - private Map property; - - public Map getProperty() { - return property; - } - - public void setProperty(Map property) { - this.property = property; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.Map; + +public class BasePath { + private String path; + + private Map property; + + public Map getProperty() { + return property; + } + + public void setProperty(Map property) { + this.property = property; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceInstanceRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceInstanceRequest.java new file mode 100644 index 00000000000..a0e853fed1b --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceInstanceRequest.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class CreateMicroserviceInstanceRequest { + private MicroserviceInstance instance; + + public MicroserviceInstance getInstance() { + return instance; + } + + public void setInstance(MicroserviceInstance instance) { + this.instance = instance; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceRequest.java new file mode 100644 index 00000000000..a234638f19e --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateMicroserviceRequest.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class CreateMicroserviceRequest { + private Microservice service; + + public Microservice getService() { + return service; + } + + public void setService(Microservice service) { + this.service = service; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateSchemaRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateSchemaRequest.java similarity index 95% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateSchemaRequest.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateSchemaRequest.java index 8de28832af5..39108645df1 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateSchemaRequest.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/CreateSchemaRequest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.api.request; +package org.apache.servicecomb.service.center.client.model; public class CreateSchemaRequest { private String schema; diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/DataCenterInfo.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/DataCenterInfo.java new file mode 100755 index 00000000000..d89f6f5cda5 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/DataCenterInfo.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class DataCenterInfo { + + private String name; + + private String region; + + private String availableZone; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAvailableZone() { + return availableZone; + } + + public void setAvailableZone(String availableZone) { + this.availableZone = availableZone; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ErrorMessage.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ErrorMessage.java new file mode 100644 index 00000000000..5e0735cef5d --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ErrorMessage.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class ErrorMessage { + private String errorCode; + + private String errorMessage; + + private String detail; + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/FindMicroserviceInstancesResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/FindMicroserviceInstancesResponse.java new file mode 100644 index 00000000000..3b9dd474d82 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/FindMicroserviceInstancesResponse.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class FindMicroserviceInstancesResponse { + private boolean modified; + + private String revision; + + private MicroserviceInstancesResponse microserviceInstancesResponse; + + public boolean isModified() { + return modified; + } + + public void setModified(boolean modified) { + this.modified = modified; + } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public MicroserviceInstancesResponse getMicroserviceInstancesResponse() { + return microserviceInstancesResponse; + } + + public void setMicroserviceInstancesResponse( + MicroserviceInstancesResponse microserviceInstancesResponse) { + this.microserviceInstancesResponse = microserviceInstancesResponse; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Framework.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Framework.java old mode 100644 new mode 100755 similarity index 91% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Framework.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Framework.java index a15f4cd5192..797b33d6cf7 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Framework.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Framework.java @@ -1,43 +1,40 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -/** - * Created by on 2017/12/20. - */ -public class Framework { - private String name; - - private String version; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class Framework { + private String name; + + private String version; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaListResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaListResponse.java new file mode 100644 index 00000000000..1a0af177715 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaListResponse.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.List; + +public class GetSchemaListResponse { + private List schemas; + + public List getSchemas() { + return schemas; + } + + public void setSchemas(List schemas) { + this.schemas = schemas; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaResponse.java new file mode 100644 index 00000000000..c91bcfa8c79 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/GetSchemaResponse.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class GetSchemaResponse { + private String schema; + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheck.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheck.java new file mode 100755 index 00000000000..78cf8c5fce4 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheck.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class HealthCheck { + + private HealthCheckMode mode; + + private int port; + + private int interval; + + private int times; + + public HealthCheckMode getMode() { + return mode; + } + + public void setMode(HealthCheckMode mode) { + this.mode = mode; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getInterval() { + return interval; + } + + public void setInterval(int interval) { + this.interval = interval; + } + + public int getTimes() { + return times; + } + + public void setTimes(int times) { + this.times = times; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheckMode.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheckMode.java new file mode 100755 index 00000000000..eb77afc6420 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HealthCheckMode.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public enum HealthCheckMode { + unknown, + push, + pull +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java new file mode 100755 index 00000000000..9f4ea115cfe --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.ArrayList; +import java.util.List; + +public class HeartbeatsRequest { + private List Instances; + + public HeartbeatsRequest(String serviceId, String instanceId) { + List instances = new ArrayList<>(); + instances.add(new InstancesRequest(serviceId, instanceId)); + this.Instances = instances; + } + + public List getInstances() { + return Instances; + } + + public void setInstances(List instances) { + this.Instances = instances; + } + + public void addInstances(InstancesRequest instancesRequest) { + if (this.Instances != null) { + this.Instances.add(instancesRequest); + } else { + this.Instances = new ArrayList<>(); + this.Instances.add(instancesRequest); + } + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/InstancesRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/InstancesRequest.java new file mode 100755 index 00000000000..2eb65de5327 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/InstancesRequest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class InstancesRequest { + private String serviceId; + + private String instanceId; + + public InstancesRequest(String serviceId, String instanceId) { + this.serviceId = serviceId; + this.instanceId = instanceId; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java new file mode 100755 index 00000000000..a034e57569f --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonRootName("service") +public class Microservice { + + private String serviceId; + + private Framework framework; + + private String registerBy; + + private String environment; + + private String appId; + + private String serviceName; + + /** + * for governance + * when invoke cross app, if not use alias name, then {microservice}:{schema}:{operation} will conflict + */ + private String alias; + + private String version; + + private String description; + + private String level; + + private List schemas = new ArrayList<>(); + + private List paths = new ArrayList<>(); + + private MicroserviceStatus status = MicroserviceStatus.UP; + + private Map properties = new HashMap<>(); + + private List instances; + + private String timestamp; + + private String modTimestamp; + + public Microservice() { + + } + + public Microservice(String serviceName) { + this.serviceName = serviceName; + } + + public List getInstances() { + return instances; + } + + public void setInstances(List instances) { + this.instances = instances; + } + + public Framework getFramework() { + return framework; + } + + public void setFramework(Framework framework) { + this.framework = framework; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getRegisterBy() { + return registerBy; + } + + public void setRegisterBy(String registerBy) { + this.registerBy = registerBy; + } + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public List getSchemas() { + return schemas; + } + + public void setSchemas(List schemas) { + this.schemas = schemas; + } + + public MicroserviceStatus getStatus() { + return status; + } + + public void setStatus(MicroserviceStatus status) { + this.status = status; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getModTimestamp() { + return modTimestamp; + } + + public void setModTimestamp(String modTimestamp) { + this.modTimestamp = modTimestamp; + } + + public List getPaths() { + return paths; + } + + public void setPaths(List paths) { + this.paths = paths; + } + + public void addSchema(String schema) { + this.schemas.add(schema); + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java new file mode 100755 index 00000000000..7f03c314043 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonRootName("instance") +public class MicroserviceInstance { + // even disconnected from service center + // instanceId will not be changed + // when register to service center again, use the old instanceId. + private String instanceId; + + private String serviceId; + + private String version; + + private List endpoints = new ArrayList<>(); + + private String hostName; + + private MicroserviceInstanceStatus status; + + private Map properties = new HashMap<>(); // reserved key list: region|az|stage|group + + private HealthCheck healthCheck; + + private DataCenterInfo dataCenterInfo; + + private String timestamp; + + private String modTimestamp; + + @JsonIgnore + private Microservice microservice; + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List getEndpoints() { + return endpoints; + } + + public void setEndpoints(List endpoints) { + this.endpoints = endpoints; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public MicroserviceInstanceStatus getStatus() { + return status; + } + + public void setStatus(MicroserviceInstanceStatus status) { + this.status = status; + } + + public HealthCheck getHealthCheck() { + return healthCheck; + } + + public void setHealthCheck(HealthCheck healthCheck) { + this.healthCheck = healthCheck; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getModTimestamp() { + return modTimestamp; + } + + public void setModTimestamp(String modTimestamp) { + this.modTimestamp = modTimestamp; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo; + } + + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { + this.dataCenterInfo = dataCenterInfo; + } + + public void setMicroservice(Microservice microservice) { + this.microservice = microservice; + } + + @JsonIgnore + public Microservice getMicroservice() { + return this.microservice; + } + + @JsonIgnore + public String getServiceName() { + return this.microservice.getServiceName(); + } + + @JsonIgnore + public String getApplicationName() { + return this.microservice.getAppId(); + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } + + public void addProperty(String key, String value) { + this.properties.put(key, value); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceResponse.java similarity index 88% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceResponse.java index 3f2b612ca09..387ad90297d 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceResponse.java @@ -15,12 +15,9 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +package org.apache.servicecomb.service.center.client.model; public class MicroserviceInstanceResponse { - private MicroserviceInstance instance; public MicroserviceInstance getInstance() { diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceStatus.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceStatus.java new file mode 100755 index 00000000000..1449e088976 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstanceStatus.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public enum MicroserviceInstanceStatus { + STARTING, + TESTING, + UP, + OUTOFSERVICE, + DOWN, + UNKNOWN +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstancesResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstancesResponse.java new file mode 100755 index 00000000000..cb1eb76317d --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstancesResponse.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.List; + +public class MicroserviceInstancesResponse { + + private List instances; + + public List getInstances() { + return instances; + } + + public void setInstances(List instances) { + this.instances = instances; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceResponse.java new file mode 100644 index 00000000000..00c95a1a3f2 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceResponse.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class MicroserviceResponse { + private Microservice service; + + public Microservice getService() { + return service; + } + + public void setService(Microservice service) { + this.service = service; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceStatus.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceStatus.java old mode 100644 new mode 100755 similarity index 89% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceStatus.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceStatus.java index 094dbbb910e..ab3b8b5f3ac --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceStatus.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceStatus.java @@ -1,27 +1,24 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -/** - * Created by on 2016/12/5. - */ -public enum MicroserviceStatus { - UNKNOWN, - UP, - DOWN -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public enum MicroserviceStatus { + UNKNOWN, + UP, + DOWN +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroservicesResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroservicesResponse.java new file mode 100755 index 00000000000..f85ad19fab8 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroservicesResponse.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.List; + +public class MicroservicesResponse { + + private List services; + + public List getServices() { + return services; + } + + public void setServices(List services) { + this.services = services; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ModifySchemasRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ModifySchemasRequest.java new file mode 100644 index 00000000000..1bd3531d897 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ModifySchemasRequest.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +import java.util.List; + +public class ModifySchemasRequest { + private List schemas; + + public List getSchemas() { + return schemas; + } + + public void setSchemas(List schemas) { + this.schemas = schemas; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenRequest.java new file mode 100644 index 00000000000..cd926364f41 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenRequest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class RbacTokenRequest { + private String name; + + private String password; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("RbacTokenRequest{"); + sb.append("name='").append(name).append('\''); + sb.append(", password='").append(password).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenResponse.java new file mode 100644 index 00000000000..1b699d3ae30 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RbacTokenResponse.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class RbacTokenResponse { + private int statusCode; + + private String token; + + private String errorCode; + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceInstanceResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceInstanceResponse.java new file mode 100644 index 00000000000..88dbe50cecb --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceInstanceResponse.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class RegisteredMicroserviceInstanceResponse { + private String instanceId; + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceResponse.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceResponse.java new file mode 100644 index 00000000000..d4a6d5c5a5d --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/RegisteredMicroserviceResponse.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class RegisteredMicroserviceResponse { + private String serviceId; + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java new file mode 100755 index 00000000000..40180433d0b --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class SchemaInfo { + private String schema; + + private String schemaId; + + private String summary; + + public SchemaInfo() { + + } + + public SchemaInfo(String schemaId, String schema, String summary) { + this.schemaId = schemaId; + this.schema = schema; + this.summary = summary; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public String getSchemaId() { + return schemaId; + } + + public void setSchemaId(String schemaId) { + this.schemaId = schemaId; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } +} diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java new file mode 100644 index 00000000000..bc7618aa0f5 --- /dev/null +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client.model; + +public class ServiceCenterConfiguration { + + /** + * for registration service + * when swagger is different between local with remote serviceCenter. if ignoreSwaggerDifferent is true. + * it will ignore the different and continue the program. otherwise, the program will be stop. + */ + private boolean ignoreSwaggerDifferent; + + private boolean canOverwriteSwagger = true; + + public boolean isIgnoreSwaggerDifferent() { + return ignoreSwaggerDifferent; + } + + public boolean isCanOverwriteSwagger(){ + return canOverwriteSwagger; + } + + public ServiceCenterConfiguration setIgnoreSwaggerDifferent(boolean ignoreSwaggerDifferent) { + this.ignoreSwaggerDifferent = ignoreSwaggerDifferent; + return this; + } + + public ServiceCenterConfiguration setCanOverwriteSwagger(boolean canOverwriteSwagger) { + this.canOverwriteSwagger = canOverwriteSwagger; + return this; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java similarity index 81% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java index 5e08a22a9b4..d7d4b093930 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java +++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java @@ -15,16 +15,15 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.api.request; +package org.apache.servicecomb.service.center.client.model; import java.util.Map; -/** - * 更新微服务和实例properties的request - */ public class UpdatePropertiesRequest { private Map properties; + private Framework framework; + public Map getProperties() { return properties; } @@ -32,4 +31,12 @@ public Map getProperties() { public void setProperties(Map properties) { this.properties = properties; } + + public Framework getFramework() { + return framework; + } + + public void setFramework(Framework framework) { + this.framework = framework; + } } diff --git a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java new file mode 100644 index 00000000000..a2888cfad1b --- /dev/null +++ b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; + +import com.google.common.eventbus.EventBus; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class ServiceCenterAddressManagerTest { + + private static final List addresses = new ArrayList<>(); + + private static ServiceCenterAddressManager addressManager1; + + private static ServiceCenterAddressManager addressManager2; + + + @Test + public void getUrlPrefix() { + addresses.add("http://127.0.0.1:30103"); + addressManager1 = new ServiceCenterAddressManager("project", addresses, new EventBus(), "", ""); + + Assertions.assertNotNull(addressManager1); + + List addresses = addressManager1.getAddresses(); + Assertions.assertEquals(1, addresses.size()); + Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0)); + Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103/v4/", addressManager1.getUrlPrefix("http://127.0.0.1:30103")); + } + + @Test + public void formatUrlTest() { + addresses.add("http://127.0.0.1:30103"); + addressManager1 = new ServiceCenterAddressManager("project", addresses, new EventBus(), "", ""); + Assertions.assertNotNull(addressManager1); + + String address = addressManager1.address(); + Assertions.assertEquals("http://127.0.0.1:30103", address); + String url = addressManager1.formatUrl("/test/", false, address); + Assertions.assertEquals("http://127.0.0.1:30103/v4/project/test/", url); + + url = addressManager1.formatUrl("/test/", true, address); + Assertions.assertEquals("http://127.0.0.1:30103/test/", url); + } + + @Test + public void onRefreshEndpointEvent() { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.3:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("http://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + addressManager1 = new ServiceCenterAddressManager("project", addresses, new EventBus(), "", ""); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "SERVICECENTER"); + addressManager1.refreshEndpoint(event, "SERVICECENTER"); + + List availableZone = addressManager1.getAvailableZone(); + Assertions.assertEquals("http://127.0.0.3:30100", availableZone.get(0)); + + List availableRegion = addressManager1.getAvailableRegion(); + Assertions.assertEquals("http://127.0.0.4:30100", availableRegion.get(0)); + } +} diff --git a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java new file mode 100755 index 00000000000..c486b2bd6ce --- /dev/null +++ b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterClientTest.java @@ -0,0 +1,524 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.service.center.client.model.Framework; +import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest; +import org.apache.servicecomb.service.center.client.model.InstancesRequest; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.MicroservicesResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse; +import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.mockito.ArgumentMatchers; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.google.common.eventbus.EventBus; + +/** + * Created by on 2019/10/17. + */ +public class ServiceCenterClientTest { + private final ServiceCenterAddressManager addressManager; + + public ServiceCenterClientTest() { + this.addressManager = new ServiceCenterAddressManager("default", Arrays.asList("http://127.0.0.1:30100"), + new EventBus(), "", ""); + } + + @Test + public void TestGetServiceCenterInstances() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"instances\": [\n" + + " {\n" + + " \"instanceId\": \"111111\",\n" + + " \"serviceId\": \"222222\",\n" + + " \"version\": \"1.0\",\n" + + " \"hostName\": \"Test\",\n" + + " \"endpoints\": [\n" + + " \"string\"\n" + + " ],\n" + + " \"status\": \"UP\",\n" + + " \"properties\": {\n" + + " \"additionalProp1\": \"string\",\n" + + " \"additionalProp2\": \"string\",\n" + + " \"additionalProp3\": \"string\"\n" + + " },\n" + + " \"healthCheck\": {\n" + + " \"mode\": \"push\",\n" + + " \"port\": \"0\",\n" + + " \"interval\": \"0\",\n" + + " \"times\": \"0\"\n" + + " },\n" + + " \"dataCenterInfo\": {\n" + + " \"name\": \"string\",\n" + + " \"region\": \"string\",\n" + + " \"availableZone\": \"string\"\n" + + " },\n" + + " \"timestamp\": \"333333\",\n" + + " \"modTimestamp\": \"4444444\"\n" + + " }\n" + + " ]\n" + + "}"; + + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest("/registry/health", null, null)).thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + MicroserviceInstancesResponse serviceCenterInstances = serviceCenterClient.getServiceCenterInstances(); + + Assertions.assertNotNull(serviceCenterInstances); + Assertions.assertEquals(1, serviceCenterInstances.getInstances().size()); + Assertions.assertEquals("111111", serviceCenterInstances.getInstances().get(0).getInstanceId()); + Assertions.assertEquals("222222", serviceCenterInstances.getInstances().get(0).getServiceId()); + } + + @Test + public void TestRegistryService() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + httpResponse.setContent("{\"serviceId\": \"111111\"}"); + + Microservice microservice = new Microservice(); + microservice.setServiceName("Test"); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true); + + Mockito.when(serviceCenterRawClient + .postHttpRequest(ArgumentMatchers.eq("/registry/microservices"), ArgumentMatchers.eq(null), + Mockito.anyString())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + RegisteredMicroserviceResponse actualResponse = serviceCenterClient.registerMicroservice(microservice); + + Assertions.assertNotNull(actualResponse); + Assertions.assertEquals("111111", actualResponse.getServiceId()); + } + + @Test + public void TestGetServiceMessage() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"service\": {\n" + + " \"serviceId\": \"111111\",\n" + + " \"environment\": \"string\",\n" + + " \"appId\": \"string\",\n" + + " \"serviceName\": \"string\",\n" + + " \"version\": \"string\",\n" + + " \"description\": \"string\",\n" + + " \"level\": \"string\",\n" + + " \"registerBy\": \"string\",\n" + + " \"schemas\": [\n" + + " \"string\"\n" + + " ],\n" + + " \"status\": \"UP\",\n" + + " \"timestamp\": \"string\",\n" + + " \"modTimestamp\": \"string\",\n" + + " \"framework\": {\n" + + " \"name\": \"string\",\n" + + " \"version\": \"string\"\n" + + " },\n" + + " \"paths\": [\n" + + " {\n" + + " \"Path\": \"string\",\n" + + " \"Property\": {\n" + + " \"additionalProp1\": \"string\",\n" + + " \"additionalProp2\": \"string\",\n" + + " \"additionalProp3\": \"string\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"properties\": {\n" + + " \"additionalProp1\": \"string\",\n" + + " \"additionalProp2\": \"string\",\n" + + " \"additionalProp3\": \"string\"\n" + + " }\n" + + " }\n" + + "}"; + + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest("/registry/microservices/111111", null, null)) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + Microservice microservices = serviceCenterClient.getMicroserviceByServiceId("111111"); + + Assertions.assertNotNull(microservices); + Assertions.assertEquals("111111", microservices.getServiceId()); + } + + @Test + public void TestGetServiceList() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + MicroservicesResponse microservicesResponse = new MicroservicesResponse(); + List microserviceList = new ArrayList<>(); + microserviceList.add(new Microservice("Test1")); + microserviceList.add(new Microservice("Test2")); + microserviceList.add(new Microservice("Test3")); + microservicesResponse.setServices(microserviceList); + ObjectMapper mapper = new ObjectMapper(); + httpResponse.setContent(mapper.writeValueAsString(microservicesResponse)); + + Mockito.when(serviceCenterRawClient.getHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + MicroservicesResponse actualMicroservicesResponse = serviceCenterClient.getMicroserviceList(); + + Assertions.assertNotNull(actualMicroservicesResponse); + Assertions.assertEquals(3, actualMicroservicesResponse.getServices().size()); + Assertions.assertEquals("Test1", actualMicroservicesResponse.getServices().get(0).getServiceName()); + } + + @Test + public void TestQueryServiceId() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + httpResponse.setContent("{\"serviceId\": \"111111\"}"); + + Mockito.when(serviceCenterRawClient.getHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + Microservice microservice = new Microservice("Test111"); + RegisteredMicroserviceResponse actualServiceId = serviceCenterClient.queryServiceId(microservice); + + Assertions.assertNotNull(actualServiceId); + Assertions.assertEquals("111111", actualServiceId.getServiceId()); + } + + @Test + public void TestRegisterServiceInstance() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + httpResponse.setContent("{\"instanceId\": \"111111\"}"); + + MicroserviceInstance instance = new MicroserviceInstance(); + instance.setInstanceId("111111"); + instance.setServiceId("222222"); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true); + + Mockito.when(serviceCenterRawClient.postHttpRequest(ArgumentMatchers.eq("/registry/microservices/222222/instances"), + ArgumentMatchers.eq(null), + Mockito.anyString())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + RegisteredMicroserviceInstanceResponse actualResponse = serviceCenterClient.registerMicroserviceInstance(instance); + + Assertions.assertNotNull(actualResponse); + Assertions.assertEquals("111111", actualResponse.getInstanceId()); + } + + @Test + public void TestDeleteServiceInstance() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + Mockito.when(serviceCenterRawClient.deleteHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + serviceCenterClient.deleteMicroserviceInstance("111", "222"); + } + + @Test + public void TestGetServiceInstanceList() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"instances\": [\n" + + " {\n" + + " \"instanceId\": \"111111\",\n" + + " \"serviceId\": \"222222\",\n" + + " \"version\": \"1.0\",\n" + + " \"hostName\": \"Test\",\n" + + " \"endpoints\": [\n" + + " \"string\"\n" + + " ],\n" + + " \"status\": \"UP\",\n" + + " \"timestamp\": \"333333\",\n" + + " \"modTimestamp\": \"4444444\"\n" + + " }\n" + + " ]\n" + + "}"; + + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest("/registry/microservices/222222/instances", null, null)) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + MicroserviceInstancesResponse serviceCenterInstances = serviceCenterClient + .getMicroserviceInstanceList("222222"); + + Assertions.assertNotNull(serviceCenterInstances); + Assertions.assertEquals(1, serviceCenterInstances.getInstances().size()); + Assertions.assertEquals("111111", serviceCenterInstances.getInstances().get(0).getInstanceId()); + Assertions.assertEquals("222222", serviceCenterInstances.getInstances().get(0).getServiceId()); + } + + @Test + public void TestGetServiceInstanceMessage() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"instance\": {\n" + + " \"instanceId\": \"111\",\n" + + " \"serviceId\": \"222\",\n" + + " \"version\": \"1.0\",\n" + + " \"hostName\": \"Test\",\n" + + " \"endpoints\": [\n" + + " \"string\"\n" + + " ],\n" + + " \"status\": \"UP\",\n" + + " \"properties\": {\n" + + " \"additionalProp1\": \"string\",\n" + + " \"additionalProp2\": \"string\",\n" + + " \"additionalProp3\": \"string\"\n" + + " },\n" + + " \"healthCheck\": {\n" + + " \"mode\": \"push\",\n" + + " \"port\": \"0\",\n" + + " \"interval\": \"0\",\n" + + " \"times\": \"0\"\n" + + " },\n" + + " \"dataCenterInfo\": {\n" + + " \"name\": \"string\",\n" + + " \"region\": \"string\",\n" + + " \"availableZone\": \"string\"\n" + + " },\n" + + " \"timestamp\": \"333333\",\n" + + " \"modTimestamp\": \"4444444\"\n" + + " }\n" + + "}"; + + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + MicroserviceInstance responseInstance = serviceCenterClient + .getMicroserviceInstance("111", "222"); + + Assertions.assertNotNull(responseInstance); + Assertions.assertEquals("111", responseInstance.getInstanceId()); + Assertions.assertEquals("Test", responseInstance.getHostName()); + } + + @Test + public void TestSendHeartBeats() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + HeartbeatsRequest heartbeatsRequest = new HeartbeatsRequest("001", "1001"); + heartbeatsRequest.addInstances(new InstancesRequest("002", "1002")); + ObjectMapper mapper = new ObjectMapper(); + + Mockito + .when(serviceCenterRawClient.putHttpRequest("/registry/microservices/111/instances/222/heartbeat", null, null)) + .thenReturn(httpResponse); + Mockito.when(serviceCenterRawClient + .putHttpRequest(ArgumentMatchers.eq("/registry/heartbeats"), ArgumentMatchers.eq(null), + Mockito.anyString())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + serviceCenterClient.sendHeartBeats(heartbeatsRequest); + } + + @Test + public void TestUpdateServicesInstanceStatus() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + Mockito.when(serviceCenterRawClient.putHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + Boolean result = serviceCenterClient + .updateMicroserviceInstanceStatus("111", "222", MicroserviceInstanceStatus.UP); + + Assertions.assertNotNull(result); + Assertions.assertEquals(true, result); + } + + @Test + public void TestGetServiceSchemas() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"schemas\": [\n" + + " {\n" + + " \"schemaId\": \"111111\",\n" + + " \"schema\": \"test\",\n" + + " \"summary\": \"test\"\n" + + " }\n" + + " ]\n" + + "}"; + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + List schemaResponse = serviceCenterClient + .getServiceSchemasList("111", false); + + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(mapper.writeValueAsString(schemaResponse)); + + Assertions.assertNotNull(jsonNode); + Assertions.assertEquals("111111", jsonNode.get(0).get("schemaId").textValue()); + Assertions.assertEquals("test", jsonNode.get(0).get("schema").textValue()); + } + + @Test + public void TestGetServiceSchemasContext() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + String responseString = "{\n" + + " \"schema\": \"test context\"\n" + + "}"; + httpResponse.setContent(responseString); + + Mockito.when(serviceCenterRawClient.getHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + String schemaContext = serviceCenterClient + .getServiceSchemaContext("111", "222"); + + Assertions.assertNotNull(schemaContext); + Assertions.assertEquals("test context", schemaContext); + } + + @Test + public void TestUpdateServiceSchema() throws IOException { + + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + Mockito.when(serviceCenterRawClient.putHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + boolean result = serviceCenterClient + .updateServiceSchemaContext("111", new SchemaInfo()); + + Assertions.assertTrue(result); + } + + @Test + public void testUpdateMicroserviceProperties() throws IOException { + ServiceCenterRawClient serviceCenterRawClient = Mockito.mock(ServiceCenterRawClient.class); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setMessage("ok"); + + Mockito.when(serviceCenterRawClient.putHttpRequest(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(httpResponse); + + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(serviceCenterRawClient, addressManager); + boolean result = serviceCenterClient + .updateMicroserviceProperties("111", new HashMap(), new Framework()); + + Assertions.assertTrue(result); + } +} diff --git a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java new file mode 100755 index 00000000000..48f3bd914c6 --- /dev/null +++ b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClientTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.service.center.client; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.http.client.common.HttpResponse; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import com.google.common.eventbus.EventBus; + +/** + * Created by on 2019/10/16. + */ +public class ServiceCenterRawClientTest { + + private static final String PROJECT_NAME = "default"; + + private static final String TENANT_NAME = "default"; + + @Test + public void TestDefaultParameter() throws IOException { + + HttpTransport httpTransport = Mockito.mock(HttpTransport.class); + ServiceCenterAddressManager addressManager = new ServiceCenterAddressManager(PROJECT_NAME, + Arrays.asList("http://127.0.0.1:30100"), new EventBus(), "", ""); + ServiceCenterRawClient client = new ServiceCenterRawClient.Builder() + .setHttpTransport(httpTransport) + .setAddressManager(addressManager) + .setTenantName(TENANT_NAME) + .build(); + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setStatusCode(200); + httpResponse.setContent("ok"); + + Mockito.when(httpTransport.doRequest(Mockito.any())).thenReturn(httpResponse); + + HttpResponse actualGetResponse = client.getHttpRequest(null, null, null); + HttpResponse actualPostResponse = client.postHttpRequest(null, null, null); + HttpResponse actualPutResponse = client.putHttpRequest(null, null, null); + HttpResponse actualDeleteResponse = client.putHttpRequest(null, null, null); + + Assertions.assertNotNull(actualGetResponse); + Assertions.assertEquals("ok", actualGetResponse.getContent()); + Assertions.assertNotNull(actualPostResponse); + Assertions.assertEquals("ok", actualPostResponse.getContent()); + Assertions.assertNotNull(actualPutResponse); + Assertions.assertEquals("ok", actualPutResponse.getContent()); + Assertions.assertNotNull(actualDeleteResponse); + Assertions.assertEquals("ok", actualDeleteResponse.getContent()); + } +} diff --git a/clients/service-center-client/src/test/resources/tls/client.p12 b/clients/service-center-client/src/test/resources/tls/client.p12 new file mode 100644 index 00000000000..acd63412397 Binary files /dev/null and b/clients/service-center-client/src/test/resources/tls/client.p12 differ diff --git a/clients/service-center-client/src/test/resources/tls/server.jks b/clients/service-center-client/src/test/resources/tls/server.jks new file mode 100644 index 00000000000..f3429ed696e Binary files /dev/null and b/clients/service-center-client/src/test/resources/tls/server.jks differ diff --git a/common/common-access-log/pom.xml b/common/common-access-log/pom.xml new file mode 100644 index 00000000000..e572e6bfd94 --- /dev/null +++ b/common/common-access-log/pom.xml @@ -0,0 +1,54 @@ + + + + + common + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + common-access-log + Java Chassis::Common::CommonAccessLog + + + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + common-rest + + + org.apache.servicecomb + transport-rest-client + + + io.vertx + vertx-codegen + test + + + diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootListener.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootListener.java new file mode 100644 index 00000000000..54becedcbf0 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.foundation.common.event.EventManager; + +public class AccessLogBootListener implements BootListener { + + private final AccessLogBootstrap accessLogBootstrap = new AccessLogBootstrap(); + + @Override + public void onAfterRegistry(BootEvent event) { + accessLogBootstrap.start(EventManager.getEventBus()); + } + + @Override + public void onBeforeClose(BootEvent event) { + accessLogBootstrap.shutdown(); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootstrap.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootstrap.java new file mode 100644 index 00000000000..56cc12ef0e0 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogBootstrap.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; + +import com.google.common.eventbus.EventBus; + +public class AccessLogBootstrap { + private static final AccessLogConfig config = AccessLogConfig.INSTANCE; + + public void start(EventBus eventBus) { + SPIServiceUtils.getSortedService(AccessLogInitializer.class) + .forEach(initializer -> initializer.init(eventBus, config)); + } + + public void shutdown() { + SPIServiceUtils.getSortedService(AccessLogInitializer.class) + .forEach(AccessLogInitializer::destroy); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfig.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfig.java new file mode 100644 index 00000000000..e2f204b3cad --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfig.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; + +public class AccessLogConfig { + + public static final String SERVER_BASE = "servicecomb.accesslog."; + + public static final String CLIENT_BASE = "servicecomb.accesslog.request."; + + public static final String SERVER_LOG_ENABLED = SERVER_BASE + "enabled"; + + public static final String SERVER_LOG_PATTERN = SERVER_BASE + "pattern"; + + public static final String CLIENT_LOG_ENABLED = CLIENT_BASE + "enabled"; + + public static final String CLIENT_LOG_PATTERN = CLIENT_BASE + "pattern"; + + public static final String DEFAULT_SERVER_PATTERN = "%h - - %t %r %s %B %D"; + + public static final String DEFAULT_CLIENT_PATTERN = "%h %SCB-transport - - %t %r %s %D"; + + public static final AccessLogConfig INSTANCE = new AccessLogConfig(); + + private boolean serverLogEnabled; + + private boolean clientLogEnabled; + + private String serverLogPattern; + + private String clientLogPattern; + + private AccessLogConfig() { + init(); + } + + private void init() { + clientLogEnabled = LegacyPropertyFactory.getBooleanProperty(CLIENT_LOG_ENABLED, false); + serverLogEnabled = LegacyPropertyFactory.getBooleanProperty(SERVER_LOG_ENABLED, false); + clientLogPattern = LegacyPropertyFactory.getStringProperty(CLIENT_LOG_PATTERN, DEFAULT_CLIENT_PATTERN); + serverLogPattern = LegacyPropertyFactory.getStringProperty(SERVER_LOG_PATTERN, DEFAULT_SERVER_PATTERN); + } + + public boolean isServerLogEnabled() { + return serverLogEnabled; + } + + public boolean isClientLogEnabled() { + return clientLogEnabled; + } + + public String getServerLogPattern() { + return serverLogPattern; + } + + public String getClientLogPattern() { + return clientLogPattern; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfiguration.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfiguration.java new file mode 100644 index 00000000000..abbb90adc19 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.accessLog; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AccessLogConfiguration { + @Bean + public AccessLogBootListener scbAccessLogBootListener() { + return new AccessLogBootListener(); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogInitializer.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogInitializer.java new file mode 100644 index 00000000000..564f0435203 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/AccessLogInitializer.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.accessLog; + +import com.google.common.eventbus.EventBus; + +public interface AccessLogInitializer { + default int getOrder() { + return 0; + } + + void init(EventBus eventBus, AccessLogConfig accessLogConfig); + + default void destroy() {} +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/client/ClientDefaultInitializer.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/client/ClientDefaultInitializer.java new file mode 100644 index 00000000000..43e5ad9b191 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/client/ClientDefaultInitializer.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.client; + +import org.apache.servicecomb.common.accessLog.AccessLogConfig; +import org.apache.servicecomb.common.accessLog.AccessLogInitializer; +import org.apache.servicecomb.common.accessLog.core.AccessLogGenerator; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.swagger.invocation.InvocationType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.AllowConcurrentEvents; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ClientDefaultInitializer implements AccessLogInitializer { + private static final Logger LOGGER = LoggerFactory.getLogger("scb-access"); + + private AccessLogGenerator accessLogGenerator; + + @Override + public void init(EventBus eventBus, AccessLogConfig accessLogConfig) { + if (!accessLogConfig.isClientLogEnabled()) { + return; + } + accessLogGenerator = new AccessLogGenerator(accessLogConfig.getClientLogPattern()); + eventBus.register(this); + } + + @Subscribe + @AllowConcurrentEvents + public void onRequestOut(InvocationFinishEvent finishEvent) { + if (InvocationType.CONSUMER.equals(finishEvent.getInvocation().getInvocationType())) { + LOGGER.info(accessLogGenerator.generateClientLog(finishEvent)); + } + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/AccessLogGenerator.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/AccessLogGenerator.java new file mode 100644 index 00000000000..d67247d9257 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/AccessLogGenerator.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core; + +import java.util.List; + +import com.google.common.annotations.VisibleForTesting; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.parser.AccessLogPatternParser; +import org.apache.servicecomb.common.accessLog.core.parser.impl.VertxRestAccessLogPatternParser; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import com.google.common.collect.Iterables; + +import io.vertx.ext.web.RoutingContext; + +/* + * Accept {@link AccessLogParam} and generate access log. + *
+ * Each AccessLogParam for a line of access log. + */ +public class AccessLogGenerator { + /* + * traversal this array to generate access log segment. + */ + private final AccessLogItem[] accessLogItems; + + private final AccessLogPatternParser logPatternParser = new VertxRestAccessLogPatternParser(); + + @SuppressWarnings("unchecked") + public AccessLogGenerator(String rawPattern) { + List> accessLogItemList = logPatternParser.parsePattern(rawPattern); + accessLogItems = Iterables.toArray(accessLogItemList, AccessLogItem.class); + } + + public String generateServerLog(ServerAccessLogEvent accessLogEvent) { + StringBuilder log = new StringBuilder(128); + for (AccessLogItem accessLogItem : getAccessLogItems()) { + accessLogItem.appendServerFormattedItem(accessLogEvent, log); + } + return log.toString(); + } + + public String generateClientLog(InvocationFinishEvent finishEvent) { + StringBuilder log = new StringBuilder(128); + for (AccessLogItem accessLogItem : getAccessLogItems()) { + accessLogItem.appendClientFormattedItem(finishEvent, log); + } + return log.toString(); + } + + @VisibleForTesting + AccessLogItem[] getAccessLogItems() { + return accessLogItems; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/AccessLogItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/AccessLogItem.java new file mode 100644 index 00000000000..02fffb25a5c --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/AccessLogItem.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element; + +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +/* + * Access log item represents the items supported in access log and request log printing. + * It generate the segment of log according to {@link AccessLogParam} + */ +public interface AccessLogItem { + default void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + } + + default void appendClientFormattedItem(InvocationFinishEvent clientLogEvent, StringBuilder builder) { + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java new file mode 100644 index 00000000000..9c759ca2cb5 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ConfigurableDatetimeAccessItem.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +/** + * Configurable dateTime element. + */ +public class ConfigurableDatetimeAccessItem implements AccessLogItem { + + public static final String DEFAULT_DATETIME_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz"; + + public static final Locale DEFAULT_LOCALE = Locale.US; + + private final ThreadLocal datetimeFormatHolder = new ThreadLocal<>(); + + private String pattern; + + private TimeZone timezone; + + private Locale locale; + + /** + * all configuration is set to default value. + */ + public ConfigurableDatetimeAccessItem() { + this(DEFAULT_DATETIME_PATTERN); + } + + /** + * the configurations not specified will get a default value. + * @param config the format of configuration is "PATTERN|TIMEZONE|LOCALE" or "PATTERN". It depends on whether the config contains the separator "|" + */ + public ConfigurableDatetimeAccessItem(String config) { + String[] configArr; + if (config.contains("|")) { + configArr = splitConfig(config); + } else { + // if there is no separator "|", regard configuration as pattern. + configArr = new String[3]; + configArr[0] = config; + } + if (3 != configArr.length) { + throw new IllegalArgumentException( + "wrong format of configuration, \"PATTERN|TIMEZONE|LOCALE\" is expected, but actually is \"" + config + "\""); + } + + setConfigurations(configArr); + } + + private String[] splitConfig(String config) { + return config.split("\\|{1}?", -1); + } + + private void setConfigurations(String[] configArr) { + this.pattern = StringUtils.isEmpty(configArr[0]) ? DEFAULT_DATETIME_PATTERN : configArr[0]; + this.timezone = StringUtils.isEmpty(configArr[1]) ? TimeZone.getDefault() : TimeZone.getTimeZone(configArr[1]); + this.locale = StringUtils.isEmpty(configArr[2]) ? DEFAULT_LOCALE : Locale.forLanguageTag(configArr[2]); + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + doAppendFormattedItem(accessLogEvent.getMilliStartTime(), builder); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + long milliDuration = finishEvent.getInvocation().getInvocationStageTrace().calcTotal() / 1000_000; + doAppendFormattedItem( + finishEvent.getInvocation().getInvocationStageTrace().getStartInMillis() + milliDuration, builder); + } + + private void doAppendFormattedItem(long milliStartTime, StringBuilder builder) { + SimpleDateFormat dateFormat = getDatetimeFormat(); + builder.append(dateFormat.format(new Date(milliStartTime))); + } + + private SimpleDateFormat getDatetimeFormat() { + SimpleDateFormat dateFormat = datetimeFormatHolder.get(); + if (null == dateFormat) { + dateFormat = new SimpleDateFormat(pattern, locale); + dateFormat.setTimeZone(timezone); + + datetimeFormatHolder.set(dateFormat); + } + + return dateFormat; + } + + public String getPattern() { + return pattern; + } + + public TimeZone getTimezone() { + return timezone; + } + + public Locale getLocale() { + return locale; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieAccessItem.java new file mode 100644 index 00000000000..e15179acc69 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieAccessItem.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; + +import io.vertx.core.http.Cookie; +import io.vertx.ext.web.RoutingContext; + +public class CookieAccessItem implements AccessLogItem { + + public static final String RESULT_NOT_FOUND = "-"; + + private final String varName; + + public CookieAccessItem(String varName) { + this.varName = varName; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + Set cookies = accessLogEvent.getRoutingContext().request().cookies(); + if (null == cookies) { + builder.append(RESULT_NOT_FOUND); + return; + } + for (Cookie cookie : cookies) { + if (varName.equals(cookie.getName())) { + builder.append(cookie.getValue()); + return; + } + } + builder.append(RESULT_NOT_FOUND); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + RestClientRequestParameters restRequestImpl = (RestClientRequestParameters) finishEvent.getInvocation().getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getCookieMap()) { + builder.append(RESULT_NOT_FOUND); + return; + } + for (Entry entry : restRequestImpl.getCookieMap().entrySet()) { + if (entry.getKey().equals(varName)) { + builder.append(entry.getValue()); + return; + } + } + builder.append(RESULT_NOT_FOUND); + } + + public String getVarName() { + return varName; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondAccessItem.java new file mode 100644 index 00000000000..49ecda73d94 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondAccessItem.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +public class DurationMillisecondAccessItem implements AccessLogItem { + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append(accessLogEvent.getMilliEndTime() - accessLogEvent.getMilliStartTime()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + builder.append(finishEvent.getInvocation().getInvocationStageTrace().calcTotal() / 1000_000); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondAccessItem.java new file mode 100644 index 00000000000..68d2ba0d411 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondAccessItem.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +public class DurationSecondAccessItem implements AccessLogItem { + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append((accessLogEvent.getMilliEndTime() - accessLogEvent.getMilliStartTime()) / 1000); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + builder.append(finishEvent.getInvocation().getInvocationStageTrace().calcTotal() / 1000_000_000); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestAccessItem.java new file mode 100644 index 00000000000..16f00eeb050 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestAccessItem.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +public class FirstLineOfRequestAccessItem implements AccessLogItem { + private static final HttpMethodAccessItem METHOD_ELEMENT = new HttpMethodAccessItem(); + + private static final UrlPathAccessItem URI_PATH_ONLY_ELEMENT = new UrlPathAccessItem(); + + private static final RequestProtocolAccessItem VERSION_OR_PROTOCOL_ELEMENT = new RequestProtocolAccessItem(); + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append("\""); + METHOD_ELEMENT.appendServerFormattedItem(accessLogEvent, builder); + builder.append(" "); + URI_PATH_ONLY_ELEMENT.appendServerFormattedItem(accessLogEvent, builder); + builder.append(" "); + VERSION_OR_PROTOCOL_ELEMENT.appendServerFormattedItem(accessLogEvent, builder); + builder.append("\""); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + builder.append("\""); + METHOD_ELEMENT.appendClientFormattedItem(finishEvent, builder); + builder.append(" "); + URI_PATH_ONLY_ELEMENT.appendClientFormattedItem(finishEvent, builder); + builder.append(" "); + VERSION_OR_PROTOCOL_ELEMENT.appendClientFormattedItem(finishEvent, builder); + builder.append("\""); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodAccessItem.java new file mode 100644 index 00000000000..8c8b61583e3 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodAccessItem.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +/** + * HTTP method + */ +public class HttpMethodAccessItem implements AccessLogItem { + + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || null == request.method()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.method().toString()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + OperationMeta operationMeta = finishEvent.getInvocation().getOperationMeta(); + if (operationMeta != null && !StringUtils.isEmpty(operationMeta.getHttpMethod())) { + builder.append(operationMeta.getHttpMethod()); + return; + } + RestClientRequest restRequestImpl = (RestClientRequest) finishEvent.getInvocation().getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || null == restRequestImpl.getHttpClientRequest().getMethod()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().getMethod().toString()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusAccessItem.java new file mode 100644 index 00000000000..61be5a790a6 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusAccessItem.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.swagger.invocation.Response; + +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +public class HttpStatusAccessItem implements AccessLogItem { + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerResponse response = accessLogEvent.getRoutingContext().response(); + if (null == response) { + builder.append(EMPTY_RESULT); + return; + } + if (response.closed() && !response.ended()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(response.getStatusCode()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Response response = finishEvent.getResponse(); + if (null == response) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(response.getStatusCode()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextAccessItem.java new file mode 100644 index 00000000000..d3a206aa803 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextAccessItem.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + + +import io.vertx.ext.web.RoutingContext; + +public class InvocationContextAccessItem implements AccessLogItem { + + public static final String NOT_FOUND = "-"; + + final String varName; + + public InvocationContextAccessItem(String varName) { + this.varName = varName; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + String invocationContextValue = getValueFromInvocationContext(accessLogEvent); + if (StringUtils.isEmpty(invocationContextValue)) { + builder.append(NOT_FOUND); + return; + } + builder.append(invocationContextValue); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Invocation invocation = finishEvent.getInvocation(); + if (null == invocation || invocation.getContext() == null + || StringUtils.isEmpty(finishEvent.getInvocation().getContext().get(varName))) { + builder.append(NOT_FOUND); + return; + } + builder.append(finishEvent.getInvocation().getContext().get(varName)); + } + + + protected String getValueFromInvocationContext(ServerAccessLogEvent accessLogEvent) { + Map data = accessLogEvent.getRoutingContext().data(); + if (null == data || null == data.get(RestConst.REST_INVOCATION_CONTEXT)) { + return null; + } + return ((Invocation) data.get(RestConst.REST_INVOCATION_CONTEXT)).getContext(varName); + } + + public String getVarName() { + return varName; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostAccessItem.java new file mode 100644 index 00000000000..cfa2068b297 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostAccessItem.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class LocalHostAccessItem implements AccessLogItem { + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append(accessLogEvent.getLocalAddress()); + } + + /** + * client do not need localhost + */ + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + RestClientRequest restRequestImpl = (RestClientRequest) finishEvent.getInvocation().getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || null == restRequestImpl.getHttpClientRequest().connection() + || null == restRequestImpl.getHttpClientRequest().connection().localAddress() + || StringUtils.isEmpty(restRequestImpl.getHttpClientRequest().connection().localAddress().host())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().connection().localAddress().host()); + } + + public static String getLocalAddress(RoutingContext context) { + HttpServerRequest request = context.request(); + if (null == request || null == request.localAddress() || StringUtils.isEmpty(request.localAddress().host())) { + return EMPTY_RESULT; + } + return request.localAddress().host(); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortAccessItem.java new file mode 100644 index 00000000000..def97c325be --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortAccessItem.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class LocalPortAccessItem implements AccessLogItem { + + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || null == request.localAddress()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.localAddress().port()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + RestClientRequestParameters restRequestImpl = (RestClientRequestParameters) finishEvent.getInvocation() + .getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || null == restRequestImpl.getHttpClientRequest().connection() + || null == restRequestImpl.getHttpClientRequest().connection().localAddress()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().connection().localAddress().port()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextAccessItem.java new file mode 100644 index 00000000000..0f7e130a6b9 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextAccessItem.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +/** + * Print content as it is. + */ +public class PlainTextAccessItem implements AccessLogItem { + private final String content; + + public PlainTextAccessItem(String content) { + this.content = content; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append(content); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + builder.append(content); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringAccessItem.java new file mode 100644 index 00000000000..e2493bd3c09 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringAccessItem.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class QueryStringAccessItem implements AccessLogItem { + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || StringUtils.isEmpty(request.query())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.query()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + RestClientRequestParameters restRequestImpl = (RestClientRequestParameters) finishEvent.getInvocation() + .getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || StringUtils.isEmpty(restRequestImpl.getHttpClientRequest().query())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().query()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostAccessItem.java new file mode 100644 index 00000000000..f3b6da6dbd1 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostAccessItem.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class RemoteHostAccessItem implements AccessLogItem { + + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || null == request.remoteAddress() + || StringUtils.isEmpty(request.remoteAddress().host())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.remoteAddress().host()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent clientLogEvent, StringBuilder builder) { + Endpoint endpoint = clientLogEvent.getInvocation().getEndpoint(); + if (null == endpoint || null == endpoint.getAddress() + || StringUtils.isEmpty(((URIEndpointObject) endpoint.getAddress()).getHostOrIp())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(((URIEndpointObject) endpoint.getAddress()).getHostOrIp()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderAccessItem.java new file mode 100644 index 00000000000..54099d3b4b1 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderAccessItem.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; + +import io.vertx.core.MultiMap; +import io.vertx.ext.web.RoutingContext; + +public class RequestHeaderAccessItem implements AccessLogItem { + public static final String RESULT_NOT_FOUND = "-"; + + private final String varName; + + public RequestHeaderAccessItem(String varName) { + this.varName = varName; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + MultiMap headers = accessLogEvent.getRoutingContext().request().headers(); + if (null == headers || StringUtils.isEmpty(headers.get(varName))) { + builder.append(RESULT_NOT_FOUND); + return; + } + builder.append(headers.get(varName)); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent clientLogEvent, StringBuilder builder) { + RestClientRequestParameters restRequestImpl = (RestClientRequestParameters) clientLogEvent.getInvocation() + .getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || null == restRequestImpl.getHttpClientRequest().headers() + || StringUtils.isEmpty(restRequestImpl.getHttpClientRequest().headers().get(varName))) { + builder.append(RESULT_NOT_FOUND); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().headers().get(varName)); + } + + public String getVarName() { + return varName; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolAccessItem.java new file mode 100644 index 00000000000..0556ffa806b --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolAccessItem.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.RoutingContext; + +public class RequestProtocolAccessItem implements AccessLogItem { + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || null == request.version()) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(getStringVersion(request.version())); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Invocation invocation = finishEvent.getInvocation(); + if (invocation == null || null == invocation.getEndpoint() || null == invocation.getEndpoint().getAddress() + || !(invocation.getEndpoint().getAddress() instanceof URIEndpointObject) + || !((URIEndpointObject) invocation.getEndpoint().getAddress()).isHttp2Enabled()) { + builder.append("HTTP/1.1"); + return; + } + builder.append("HTTP/2.0"); + } + + private String getStringVersion(HttpVersion version) { + switch (version) { + case HTTP_2: + return "HTTP/2.0"; + case HTTP_1_0: + return "HTTP/1.0"; + case HTTP_1_1: + return "HTTP/1.1"; + default: + return EMPTY_RESULT; + } + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderAccessItem.java new file mode 100644 index 00000000000..e87962f98eb --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderAccessItem.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.swagger.invocation.Response; + +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +public class ResponseHeaderAccessItem implements AccessLogItem { + + public static final String RESULT_NOT_FOUND = "-"; + + private final String varName; + + public ResponseHeaderAccessItem(String varName) { + this.varName = varName; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerResponse response = accessLogEvent.getRoutingContext().response(); + if (null == response || null == response.headers() || StringUtils.isEmpty(response.headers().get(varName))) { + builder.append(RESULT_NOT_FOUND); + return; + } + builder.append(response.headers().get(varName)); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Response response = finishEvent.getResponse(); + String value = response != null ? response.getHeader(varName) : null; + if (null == value) { + builder.append(RESULT_NOT_FOUND); + return; + } + builder.append(value); + } + + public String getVarName() { + return varName; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeAccessItem.java new file mode 100644 index 00000000000..bbf094b6940 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeAccessItem.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +public class ResponseSizeAccessItem implements AccessLogItem { + // print zeroBytes when bytes is zero + private final String zeroBytes; + + public ResponseSizeAccessItem(String zeroBytesPlaceholder) { + zeroBytes = zeroBytesPlaceholder; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerResponse response = accessLogEvent.getRoutingContext().response(); + if (null == response || 0 == response.bytesWritten()) { + builder.append(zeroBytes); + return; + } + builder.append(response.bytesWritten()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + // client do not know how to calculate is right, maybe Object#toString().length + builder.append(zeroBytes); + } + + public String getZeroBytes() { + return zeroBytes; + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdAccessItem.java new file mode 100644 index 00000000000..e9dfe16d018 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdAccessItem.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +public class TraceIdAccessItem extends InvocationContextAccessItem { + + public static final String TRACE_ID = CoreConst.TRACE_ID_NAME; + + public TraceIdAccessItem() { + super(TRACE_ID); + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + String traceId = getValueFromInvocationContext(accessLogEvent); + if (StringUtils.isEmpty(traceId)) { + traceId = accessLogEvent.getRoutingContext().request().getHeader(TRACE_ID); + } + builder.append(StringUtils.isEmpty(traceId) ? InvocationContextAccessItem.NOT_FOUND : traceId); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Invocation invocation = finishEvent.getInvocation(); + if (invocation == null || invocation.getContext() == null + || StringUtils.isEmpty(invocation.getContext().get(TRACE_ID))) { + builder.append(InvocationContextAccessItem.NOT_FOUND); + return; + } + builder.append(invocation.getContext().get(TRACE_ID)); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportAccessItem.java new file mode 100644 index 00000000000..4a3f8da98a1 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportAccessItem.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +public class TransportAccessItem implements AccessLogItem { + private static final String EMPTY_STR = "-"; + + /** + * access log only support rest + */ + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append("rest"); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + String transportName = finishEvent.getInvocation().getConfigTransportName(); + if (!StringUtils.isEmpty(transportName)) { + builder.append(transportName); + return; + } + Endpoint endpoint = finishEvent.getInvocation().getEndpoint(); + if (endpoint == null || StringUtils.isEmpty(endpoint.getEndpoint())) { + builder.append(EMPTY_STR); + return; + } + builder.append(endpoint.getEndpoint().split(":")[0]); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathAccessItem.java new file mode 100644 index 00000000000..5435a22cfb1 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathAccessItem.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class UrlPathAccessItem implements AccessLogItem { + + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || StringUtils.isEmpty(request.path())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.path()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + OperationMeta operationMeta = finishEvent.getInvocation().getOperationMeta(); + SchemaMeta schemaMeta = finishEvent.getInvocation().getSchemaMeta(); + if (operationMeta != null && schemaMeta != null && schemaMeta.getSwagger() != null) { + builder.append(operationMeta.getOperationPath()); + return; + } + RestClientRequestParameters restRequestImpl = (RestClientRequestParameters) finishEvent.getInvocation() + .getHandlerContext() + .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); + if (null == restRequestImpl || null == restRequestImpl.getHttpClientRequest() + || StringUtils.isEmpty(restRequestImpl.getHttpClientRequest().path())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(restRequestImpl.getHttpClientRequest().path()); + } +} diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryAccessItem.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryAccessItem.java new file mode 100644 index 00000000000..369b458e618 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryAccessItem.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.apache.servicecomb.common.rest.RestConst.REST_CLIENT_REQUEST_PATH; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class UrlPathWithQueryAccessItem implements AccessLogItem { + + public static final String EMPTY_RESULT = "-"; + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + HttpServerRequest request = accessLogEvent.getRoutingContext().request(); + if (null == request || StringUtils.isEmpty(request.uri())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(request.uri()); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent finishEvent, StringBuilder builder) { + Invocation invocation = finishEvent.getInvocation(); + if (null == invocation || null == invocation.getLocalContext(REST_CLIENT_REQUEST_PATH) + || StringUtils.isEmpty(invocation.getLocalContext(REST_CLIENT_REQUEST_PATH).toString())) { + builder.append(EMPTY_RESULT); + return; + } + builder.append(invocation.getLocalContext(REST_CLIENT_REQUEST_PATH).toString()); + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemCreator.java similarity index 82% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemCreator.java index ebd522b4953..9703d588c3c 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemCreator.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemCreator.java @@ -15,9 +15,10 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser; +package org.apache.servicecomb.common.accessLog.core.parser; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.CookieAccessItem; /** * The {@linkplain AccessLogItemCreator}s are able to instantiate a group of {@linkplain AccessLogItem}. @@ -26,7 +27,7 @@ public interface AccessLogItemCreator { /** * Create an instance of {@linkplain AccessLogItem} which is specified by the config. * @param config - * e.g. For {@linkplain org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem CookieItem}, + * e.g. For {@linkplain CookieAccessItem CookieItem}, * the pattern may be "%{varName}C", and it's config is "varName". Some {@linkplain AccessLogItem} with no configurable * pattern (like "%m") will receive {@code null} as config. */ diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemMeta.java similarity index 84% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemMeta.java index b47e5d1fc85..870bd1e9f7c 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogItemMeta.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogItemMeta.java @@ -15,13 +15,9 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser; +package org.apache.servicecomb.common.accessLog.core.parser; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -/** - * The meta data of {@linkplain AccessLogItem}. - */ public class AccessLogItemMeta { protected String prefix; @@ -66,8 +62,7 @@ public AccessLogItemCreator getAccessLogItemCreator() { return accessLogItemCreator; } - public AccessLogItemMeta setAccessLogItemCreator( - AccessLogItemCreator accessLogItemCreator) { + public AccessLogItemMeta setAccessLogItemCreator(AccessLogItemCreator accessLogItemCreator) { this.accessLogItemCreator = accessLogItemCreator; return this; } diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogPatternParser.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogPatternParser.java new file mode 100644 index 00000000000..0dde4099d0c --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/AccessLogPatternParser.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.parser; + +import java.util.List; + +import org.apache.servicecomb.common.accessLog.core.AccessLogGenerator; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; + + +/** + * This parser will parse the rawPattern of access log and generate a list of {@link AccessLogItem}, + * which will be used in {@link AccessLogGenerator} to generate + * access log content. + * @param the type of {@linkplain AccessLogItem + * AccessLogParam.contextData}, which usually depends on the transport way. + */ +public interface AccessLogPatternParser { + List> parsePattern(String rawPattern); +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/CompositeVertxRestAccessLogItemMeta.java similarity index 94% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/CompositeVertxRestAccessLogItemMeta.java index e5a5b82cc7d..6e4c477aa26 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/CompositeVertxRestAccessLogItemMeta.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/CompositeVertxRestAccessLogItemMeta.java @@ -15,14 +15,14 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser; +package org.apache.servicecomb.common.accessLog.core.parser; import java.util.List; /** * Hold a group of {@link VertxRestAccessLogItemMeta} so that user can define * only one VertxRestAccessLogItemMeta in spi loading file and load a group of meta. - * + * * Once the access log loading mechanism finds that a meta is CompositeVertxRestAccessLogItemMeta, * the meta hold by it will be used in access log while this meta itself will be ignored. */ diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/VertxRestAccessLogItemMeta.java similarity index 95% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/VertxRestAccessLogItemMeta.java index 7f7916ff597..b69b90a9abc 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/VertxRestAccessLogItemMeta.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/VertxRestAccessLogItemMeta.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser; +package org.apache.servicecomb.common.accessLog.core.parser; import io.vertx.ext.web.RoutingContext; diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java new file mode 100644 index 00000000000..a900c370d51 --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.parser.impl; + +import java.util.ArrayList; +import java.util.List; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.CookieAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ConfigurableDatetimeAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.DurationMillisecondAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.DurationSecondAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.FirstLineOfRequestAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.HttpMethodAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.HttpStatusAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.InvocationContextAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.LocalHostAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.LocalPortAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.QueryStringAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RemoteHostAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RequestHeaderAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RequestProtocolAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ResponseHeaderAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ResponseSizeAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.TraceIdAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.TransportAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.UrlPathAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.UrlPathWithQueryAccessItem; +import org.apache.servicecomb.common.accessLog.core.parser.CompositeVertxRestAccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta; + +import io.vertx.ext.web.RoutingContext; + +public class DefaultCompositeVertxRestAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta { + private static final List SUPPORTED_META = new ArrayList<>(); + + static { + final AccessLogItem httpMethodItem = new HttpMethodAccessItem(); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%m", config -> httpMethodItem)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-method", config -> httpMethodItem)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%s", config -> new HttpStatusAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("sc-status", config -> new HttpStatusAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%T", config -> new DurationSecondAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%D", config -> new DurationMillisecondAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%h", config -> new RemoteHostAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%v", config -> new LocalHostAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%p", config -> new LocalPortAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%B", config -> new ResponseSizeAccessItem("0"))); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%b", config -> new ResponseSizeAccessItem("-"))); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%r", config -> new FirstLineOfRequestAccessItem())); + final AccessLogItem urlPathItem = new UrlPathAccessItem(); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%U", config -> urlPathItem)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-stem", config -> urlPathItem)); + final AccessLogItem queryStringItem = new QueryStringAccessItem(); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%q", config -> queryStringItem)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-query", config -> queryStringItem)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri", config -> new UrlPathWithQueryAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%H", config -> new RequestProtocolAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%t", config -> new ConfigurableDatetimeAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%SCB-traceId", config -> new TraceIdAccessItem())); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%SCB-transport", config -> new TransportAccessItem())); + + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}t", ConfigurableDatetimeAccessItem::new)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}i", RequestHeaderAccessItem::new)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}o", ResponseHeaderAccessItem::new)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}C", CookieAccessItem::new)); + SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}SCB-ctx", InvocationContextAccessItem::new)); + } + + @Override + public List getAccessLogItemMetas() { + return SUPPORTED_META; + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParser.java similarity index 86% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParser.java index 5151f5c2be0..7a8568b97f7 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParser.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParser.java @@ -15,23 +15,25 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl; +package org.apache.servicecomb.common.accessLog.core.parser.impl; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.PlainTextAccessItem; +import org.apache.servicecomb.common.accessLog.core.parser.AccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.parser.AccessLogPatternParser; +import org.apache.servicecomb.common.accessLog.core.parser.CompositeVertxRestAccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogItemMeta; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogPatternParser; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; + import io.vertx.ext.web.RoutingContext; /** @@ -60,10 +62,10 @@ public class VertxRestAccessLogPatternParser implements AccessLogPatternParser metaList = new ArrayList<>(); + private final List metaList = new ArrayList<>(); public VertxRestAccessLogPatternParser() { - List loadedMeta = loadVertxRestAccessLogItemMeta(); + List loadedMeta = loadVertxRestLogItemMeta(); if (null == loadedMeta || loadedMeta.isEmpty()) { LOGGER.error("cannot load AccessLogItemMeta!"); throw new IllegalStateException("cannot load AccessLogItemMeta!"); @@ -78,7 +80,13 @@ public VertxRestAccessLogPatternParser() { sortAccessLogItemMeta(this.metaList); } - private List loadVertxRestAccessLogItemMeta() { + @VisibleForTesting + List getMetaList() { + return metaList; + } + + @VisibleForTesting + List loadVertxRestLogItemMeta() { return SPIServiceUtils.getOrLoadSortedService(VertxRestAccessLogItemMeta.class); } @@ -105,13 +113,13 @@ public static int comparePlaceholderString(String s1, String s2) { /** * Sort all of the {@link AccessLogItemMeta}, the meta that is in front of the others has higher priority. - * + * * Sort rule(priority decreased): *
    - *
  1. compare the {@link AccessLogItemMeta#order}
  2. - *
  3. compare the {@link AccessLogItemMeta#suffix} in lexicographic order, if one's suffix is start with + *
  4. compare the {@link AccessLogItemMeta#getOrder()}
  5. + *
  6. compare the {@link AccessLogItemMeta#getSuffix()} in lexicographic order, if one's suffix is start with * the other one's suffix, this one(who's suffix is longer) has higher priority
  7. - *
  8. compare the {@link AccessLogItemMeta#prefix}, compare rule is the same as suffix.
  9. + *
  10. compare the {@link AccessLogItemMeta#getPrefix()}, compare rule is the same as suffix.
  11. *
* * e.g. given a list of {@link AccessLogItemMeta} like below: @@ -166,7 +174,6 @@ private List matchAccessLogItem(String rawPattern) { AccessLogItemLocation candidate = null; for (VertxRestAccessLogItemMeta meta : metaList) { if (null != candidate && null == meta.getSuffix()) { - // TODO: // if user define item("%{","}ab") and item("%{_","}abc") and the pattern is "%{_var}ab}abc" // currently the result is item("%{","_var","}ab"), plaintext("}abc") // is this acceptable? @@ -211,10 +218,10 @@ private List matchAccessLogItem(String rawPattern) { /** * After processing of {@link #matchAccessLogItem(String)}, all of the placeholders of {@link AccessLogItem} have been * picked out. So the rest part of rawPattern should be treated as plain text. Those parts will be located in this - * method and wrapped as {@link PlainTextItem}. + * method and wrapped as {@link PlainTextAccessItem}. * @param rawPattern raw pattern string of access log * @param locationList locations picked out by {@link #matchAccessLogItem(String)} - * @return all of the locations including {@link PlainTextItem}. + * @return all of the locations including {@link PlainTextAccessItem}. */ private List fillInPlainTextLocation(String rawPattern, List locationList) { @@ -260,15 +267,14 @@ private List> convertToItemList(String rawPattern, VertxRestAccessLogItemMeta accessLogItemMeta = accessLogItemLocation.accessLogItemMeta; if (null == accessLogItemMeta) { // a PlainTextItem location - itemList.add(new PlainTextItem(rawPattern.substring( + itemList.add(new PlainTextAccessItem(rawPattern.substring( accessLogItemLocation.prefixIndex, accessLogItemLocation.tail ))); continue; } - itemList.add( - accessLogItemMeta.getAccessLogItemCreator().createItem( - getConfigString(rawPattern, accessLogItemLocation)) + itemList.add(accessLogItemMeta.getAccessLogItemCreator().createItem( + getConfigString(rawPattern, accessLogItemLocation)) ); } @@ -290,22 +296,22 @@ private static class AccessLogItemLocation { /** * prefixIndex = rawPattern.indexOf(prefix) */ - int prefixIndex; + final int prefixIndex; /** * suffixIndex = rawPattern.indexOf(suffix) */ - int suffixIndex; + final int suffixIndex; /** * tail = suffixIndex + suffix.length() */ - int tail; + final int tail; VertxRestAccessLogItemMeta accessLogItemMeta; /** - * for {@link PlainTextItem} only + * for {@link PlainTextAccessItem} only */ AccessLogItemLocation(int prefixIndex, int suffixIndex) { this.prefixIndex = prefixIndex; diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/placeholder/AccessLogItemTypeEnum.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/placeholder/AccessLogItemTypeEnum.java similarity index 95% rename from transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/placeholder/AccessLogItemTypeEnum.java rename to common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/placeholder/AccessLogItemTypeEnum.java index 010a080196c..5352e37faa9 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/placeholder/AccessLogItemTypeEnum.java +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/core/placeholder/AccessLogItemTypeEnum.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.placeholder; +package org.apache.servicecomb.common.accessLog.core.placeholder; /** * record what kinds of access log item we support diff --git a/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/server/ServerDefaultInitializer.java b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/server/ServerDefaultInitializer.java new file mode 100644 index 00000000000..7baf69dd8aa --- /dev/null +++ b/common/common-access-log/src/main/java/org/apache/servicecomb/common/accessLog/server/ServerDefaultInitializer.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.server; + +import org.apache.servicecomb.common.accessLog.AccessLogConfig; +import org.apache.servicecomb.common.accessLog.AccessLogInitializer; +import org.apache.servicecomb.common.accessLog.core.AccessLogGenerator; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.AllowConcurrentEvents; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ServerDefaultInitializer implements AccessLogInitializer { + + private static final Logger LOGGER = LoggerFactory.getLogger("scb-access"); + + private AccessLogGenerator accessLogGenerator; + + @Override + public void init(EventBus eventBus, AccessLogConfig accessLogConfig) { + if (!accessLogConfig.isServerLogEnabled()) { + return; + } + accessLogGenerator = new AccessLogGenerator(accessLogConfig.getServerLogPattern()); + eventBus.register(this); + } + + @Subscribe + @AllowConcurrentEvents + public void onRequestReceived(ServerAccessLogEvent accessLogEvent) { + LOGGER.info(accessLogGenerator.generateServerLog(accessLogEvent)); + } +} diff --git a/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.AccessLogInitializer b/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.AccessLogInitializer new file mode 100644 index 00000000000..159849dab99 --- /dev/null +++ b/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.AccessLogInitializer @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.common.accessLog.client.ClientDefaultInitializer +org.apache.servicecomb.common.accessLog.server.ServerDefaultInitializer diff --git a/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta b/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta new file mode 100644 index 00000000000..f793ca0f575 --- /dev/null +++ b/common/common-access-log/src/main/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.common.accessLog.core.parser.impl.DefaultCompositeVertxRestAccessLogItemMeta diff --git a/common/common-access-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/common-access-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..e6814e63814 --- /dev/null +++ b/common/common-access-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.common.accessLog.AccessLogConfiguration diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java new file mode 100644 index 00000000000..e8c7cf38500 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/AccessLogGeneratorTest.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core; + +import static org.mockito.Mockito.when; + +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ConfigurableDatetimeAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.HttpMethodAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.PlainTextAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RemoteHostAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.UserDefinedAccessLogItem; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class AccessLogGeneratorTest { + + private static final AccessLogGenerator LOG_GENERATOR = new AccessLogGenerator("%m - %t"); + + private static final AccessLogGenerator USER_DEFINED_LOG_GENERATOR = new AccessLogGenerator( + "%h - - %{test-config}user-defined"); + + @Test + public void testConstructor() { + AccessLogItem[] elements = LOG_GENERATOR.getAccessLogItems(); + Assertions.assertEquals(3, elements.length); + Assertions.assertEquals(HttpMethodAccessItem.class, elements[0].getClass()); + Assertions.assertEquals(PlainTextAccessItem.class, elements[1].getClass()); + Assertions.assertEquals(ConfigurableDatetimeAccessItem.class, elements[2].getClass()); + } + + @Test + public void testServerLog() { + RoutingContext context = Mockito.mock(RoutingContext.class); + HttpServerRequest request = Mockito.mock(HttpServerRequest.class); + long startMillisecond = 1416863450581L; + ServerAccessLogEvent serverAccessLogEvent = new ServerAccessLogEvent(); + serverAccessLogEvent.setMilliStartTime(startMillisecond).setRoutingContext(context); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ConfigurableDatetimeAccessItem.DEFAULT_DATETIME_PATTERN, + ConfigurableDatetimeAccessItem.DEFAULT_LOCALE); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + when(context.request()).thenReturn(request); + when(request.method()).thenReturn(HttpMethod.DELETE); + + String log = LOG_GENERATOR.generateServerLog(serverAccessLogEvent); + Assertions.assertEquals("DELETE" + " - " + simpleDateFormat.format(startMillisecond), log); + } + + @Test + public void testClientLog() { + Invocation invocation = Mockito.mock(Invocation.class); + InvocationStageTrace stageTrace = Mockito.mock(InvocationStageTrace.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + long startMillisecond = 1416863450581L; + when(stageTrace.getStartInMillis()).thenReturn(startMillisecond); + when(stageTrace.calcTotal()).thenReturn(0L); + when(invocation.getOperationMeta()).thenReturn(operationMeta); + when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); + + InvocationFinishEvent finishEvent = new InvocationFinishEvent(invocation, null); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ConfigurableDatetimeAccessItem.DEFAULT_DATETIME_PATTERN, + ConfigurableDatetimeAccessItem.DEFAULT_LOCALE); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + when(operationMeta.getHttpMethod()).thenReturn(HttpMethod.DELETE.toString()); + String log = LOG_GENERATOR.generateClientLog(finishEvent); + Assertions.assertEquals("DELETE" + " - " + simpleDateFormat.format(startMillisecond), log); + } + + @Test + public void testUserDefinedLogGenerator() { + AccessLogItem[] elements = USER_DEFINED_LOG_GENERATOR.getAccessLogItems(); + Assertions.assertEquals(3, elements.length); + Assertions.assertEquals(RemoteHostAccessItem.class, elements[0].getClass()); + Assertions.assertEquals(PlainTextAccessItem.class, elements[1].getClass()); + Assertions.assertEquals(UserDefinedAccessLogItem.class, elements[2].getClass()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieItemTest.java new file mode 100644 index 00000000000..f1d37e9681f --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/CookieItemTest.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.Cookie; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.impl.CookieImpl; +import io.vertx.ext.web.RoutingContext; + +public class CookieItemTest { + + public static final String COOKIE_NAME = "cookieName"; + + public static final String COOKIE_VALUE = "cookieVALUE"; + + private static final CookieAccessItem ELEMENT = new CookieAccessItem(COOKIE_NAME); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext mockContext; + + private HttpServerRequest httpServerRequest; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + @BeforeEach + public void initStrBuilder() { + mockContext = Mockito.mock(RoutingContext.class); + httpServerRequest = Mockito.mock(HttpServerRequest.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + + accessLogEvent = new ServerAccessLogEvent(); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + HashSet cookieSet = new HashSet<>(); + CookieImpl cookie = new CookieImpl(COOKIE_NAME, COOKIE_VALUE); + + cookieSet.add(cookie); + Mockito.when(mockContext.request()).thenReturn(httpServerRequest); + Mockito.when(httpServerRequest.cookies()).thenReturn(cookieSet); + accessLogEvent.setRoutingContext(mockContext); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(COOKIE_VALUE, strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + + Map cookieMap = new HashMap<>(); + cookieMap.put(COOKIE_NAME, COOKIE_VALUE); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(restClientRequest.getCookieMap()).thenReturn(cookieMap); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(COOKIE_VALUE, strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnCookieCountIsZero() { + HashSet cookieSet = new HashSet<>(); + Mockito.when(mockContext.request()).thenReturn(httpServerRequest); + Mockito.when(httpServerRequest.cookies()).thenReturn(cookieSet); + accessLogEvent.setRoutingContext(mockContext); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnCookieCountIsZero() { + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + Map cookieMap = new HashMap<>(); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(restClientRequest.getCookieMap()).thenReturn(cookieMap); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + + @Test + public void serverFormattedElementOnCookieSetIsNull() { + Mockito.when(mockContext.request()).thenReturn(httpServerRequest); + Mockito.when(httpServerRequest.cookies()).thenReturn(null); + accessLogEvent.setRoutingContext(mockContext); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnCookieSetIsNull() { + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(restClientRequest.getCookieMap()).thenReturn(null); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + + @Test + public void serverFormattedElementOnNotFound() { + HashSet cookieSet = new HashSet<>(); + CookieImpl cookie = new CookieImpl("anotherCookieName", COOKIE_VALUE); + cookieSet.add(cookie); + Mockito.when(mockContext.request()).thenReturn(httpServerRequest); + Mockito.when(httpServerRequest.cookies()).thenReturn(cookieSet); + accessLogEvent.setRoutingContext(mockContext); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnNotFound() { + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + + Map cookieMap = new HashMap<>(); + cookieMap.put("anotherCookieValue", COOKIE_VALUE); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(restClientRequest.getCookieMap()).thenReturn(cookieMap); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java new file mode 100644 index 00000000000..8f55eb0006c --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DatetimeConfigurableItemTest.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class DatetimeConfigurableItemTest { + + private static final long START_MILLISECOND = 1416863450581L; + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private Invocation invocation; + + private InvocationStageTrace invocationStageTrace; + + @BeforeEach + public void initStrBuilder() { + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + when(invocationStageTrace.getStartInMillis()).thenReturn(START_MILLISECOND); + when(invocationStageTrace.calcTotal()).thenReturn(0L); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setMilliStartTime(START_MILLISECOND); + strBuilder = new StringBuilder(); + } + + + @Test + public void getFormattedElementOnNoTimezone() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "yyyy/MM/dd zzz||zh-CN"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd zzz", Locale.forLanguageTag("zh-CN")); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnNoTimezone() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "yyyy/MM/dd zzz||zh-CN"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd zzz", Locale.forLanguageTag("zh-CN")); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnNoLocale() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "EEE, dd MMM yyyy HH:mm:ss zzz|GMT+08|"); + + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("Tue, 25 Nov 2014 05:10:50 GMT+08:00", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnNoLocale() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "EEE, dd MMM yyyy HH:mm:ss zzz|GMT+08|"); + + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("Tue, 25 Nov 2014 05:10:50 GMT+08:00", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnNoConfig() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "||"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ConfigurableDatetimeAccessItem.DEFAULT_DATETIME_PATTERN, + Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnNoConfig() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem( + "||"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ConfigurableDatetimeAccessItem.DEFAULT_DATETIME_PATTERN, + Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void serverConstructorWithNoArg() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz", element.getPattern()); + Assertions.assertEquals(Locale.US, element.getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), element.getTimezone()); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void clientConstructorWithNoArg() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz", element.getPattern()); + Assertions.assertEquals(Locale.US, element.getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), element.getTimezone()); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void serverConstructorWithNoSeparator() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem("yyyy/MM/dd HH:mm:ss zzz"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zzz", Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("yyyy/MM/dd HH:mm:ss zzz", element.getPattern()); + Assertions.assertEquals(Locale.US, element.getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), element.getTimezone()); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } + + @Test + public void clientConstructorWithNoSeparator() { + ConfigurableDatetimeAccessItem element = new ConfigurableDatetimeAccessItem("yyyy/MM/dd HH:mm:ss zzz"); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zzz", Locale.US); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("yyyy/MM/dd HH:mm:ss zzz", element.getPattern()); + Assertions.assertEquals(Locale.US, element.getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), element.getTimezone()); + Assertions.assertEquals(simpleDateFormat.format(START_MILLISECOND), strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondItemTest.java new file mode 100644 index 00000000000..1fdd3b4e0d0 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationMillisecondItemTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class DurationMillisecondItemTest { + + public static final DurationMillisecondAccessItem ELEMENT = new DurationMillisecondAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private Invocation invocation; + + private InvocationStageTrace invocationStageTrace; + + @BeforeEach + public void initStrBuilder() { + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + when(invocationStageTrace.calcTotal()).thenReturn(1000_000L); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setMilliStartTime(1L); + accessLogEvent.setMilliEndTime(2L); + strBuilder = new StringBuilder(); + } + + @Test + public void testAppendFormattedElement() { + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + + strBuilder = new StringBuilder(); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondItemTest.java new file mode 100644 index 00000000000..9cbe7f28da5 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/DurationSecondItemTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class DurationSecondItemTest { + + public static final DurationSecondAccessItem ELEMENT = new DurationSecondAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private Invocation invocation; + + private InvocationStageTrace invocationStageTrace; + + @BeforeEach + public void initStrBuilder() { + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + when(invocationStageTrace.calcTotal()).thenReturn(1L); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setMilliStartTime(1L); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElementOn999ms() { + accessLogEvent.setMilliEndTime(1000L); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("0", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOn999ms() { + when(invocationStageTrace.calcTotal()).thenReturn(0L); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("0", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOn1000ms() { + accessLogEvent.setMilliEndTime(1001L); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOn1000ms() { + when(invocationStageTrace.calcTotal()).thenReturn(1000_000_000L); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOn1001ms() { + accessLogEvent.setMilliEndTime(1002L); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOn1001ms() { + when(invocationStageTrace.calcTotal()).thenReturn(1000_000_000L); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("1", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestItemTest.java new file mode 100644 index 00000000000..54e1fccef33 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/FirstLineOfRequestItemTest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.RoutingContext; + +public class FirstLineOfRequestItemTest { + + public static final FirstLineOfRequestAccessItem ELEMENT = new FirstLineOfRequestAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext mockContext; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpClientRequest clientRequest; + + private Endpoint endpoint; + + private URIEndpointObject urlEndpoint; + + @BeforeEach + public void initStrBuilder() { + mockContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + endpoint = Mockito.mock(Endpoint.class); + urlEndpoint = Mockito.mock(URIEndpointObject.class); + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(urlEndpoint); + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(mockContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + HttpServerRequest request = Mockito.mock(HttpServerRequest.class); + String uri = "/test/uri"; + + when(mockContext.request()).thenReturn(request); + when(request.method()).thenReturn(HttpMethod.DELETE); + when(request.path()).thenReturn(uri); + when(request.version()).thenReturn(HttpVersion.HTTP_1_1); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("\"DELETE " + uri + " HTTP/1.1\"", strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + String uri = "/test/uri"; + when(clientRequest.getMethod()).thenReturn(HttpMethod.DELETE); + when(clientRequest.path()).thenReturn(uri); + when(urlEndpoint.isHttp2Enabled()).thenReturn(true); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("\"DELETE " + uri + " HTTP/2.0\"", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodItemTest.java new file mode 100644 index 00000000000..1dbeba59e9a --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpMethodItemTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class HttpMethodItemTest { + private static final HttpMethodAccessItem ITEM = new HttpMethodAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpClientRequest clientRequest; + + private Endpoint endpoint; + + private URIEndpointObject urlEndpoint; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + endpoint = Mockito.mock(Endpoint.class); + urlEndpoint = Mockito.mock(URIEndpointObject.class); + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(urlEndpoint); + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + HttpServerRequest request = Mockito.mock(HttpServerRequest.class); + Mockito.when(routingContext.request()).thenReturn(request); + Mockito.when(request.method()).thenReturn(HttpMethod.DELETE); + accessLogEvent.setRoutingContext(routingContext); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("DELETE", strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.getMethod()).thenReturn(HttpMethod.DELETE); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("DELETE", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + accessLogEvent.setRoutingContext(routingContext); + Mockito.when(routingContext.request()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + + @Test + public void serverFormattedElementOnMethodIsNull() { + HttpServerRequest request = Mockito.mock(HttpServerRequest.class); + accessLogEvent.setRoutingContext(routingContext); + + Mockito.when(routingContext.request()).thenReturn(request); + Mockito.when(request.method()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnMethodIsNull() { + when(clientRequest.getMethod()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusItemTest.java new file mode 100644 index 00000000000..749a38416d8 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/HttpStatusItemTest.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +public class HttpStatusItemTest { + + private static final HttpStatusAccessItem STATUS_ELEMENT = new HttpStatusAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Response response; + + private HttpServerResponse serverResponse; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + response = Mockito.mock(Response.class); + serverResponse = Mockito.mock(HttpServerResponse.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + int statusCode = 200; + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.getStatusCode()).thenReturn(statusCode); + + STATUS_ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("200", strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + int statusCode = 200; + when(finishEvent.getResponse()).thenReturn(response); + when(response.getStatusCode()).thenReturn(statusCode); + + STATUS_ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("200", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnResponseIsNull() { + Mockito.when(routingContext.response()).thenReturn(null); + STATUS_ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + + Mockito.when(routingContext.response()).thenReturn(serverResponse); + Mockito.when(serverResponse.closed()).thenReturn(true); + Mockito.when(serverResponse.ended()).thenReturn(false); + + strBuilder = new StringBuilder(); + STATUS_ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnResponseIsNull() { + when(finishEvent.getResponse()).thenReturn(null); + STATUS_ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextItemTest.java new file mode 100644 index 00000000000..644ac99de8f --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/InvocationContextItemTest.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.ext.web.RoutingContext; + +public class InvocationContextItemTest { + + public static final String INVOCATION_CONTEXT_KEY = "testKey"; + + public static final String INVOCATION_CONTEXT_VALUE = "testValue"; + + private static final InvocationContextAccessItem ITEM = new InvocationContextAccessItem(INVOCATION_CONTEXT_KEY); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverGetFormattedItem() { + Map routingContextData = new HashMap<>(); + when(routingContext.data()).thenReturn(routingContextData); + routingContextData.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + when(invocation.getContext(INVOCATION_CONTEXT_KEY)).thenReturn(INVOCATION_CONTEXT_VALUE); + + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(INVOCATION_CONTEXT_VALUE)); + } + + @Test + public void clientGetFormattedItem() { + Map context = new HashMap<>(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(context); + context.put(INVOCATION_CONTEXT_KEY, INVOCATION_CONTEXT_VALUE); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(INVOCATION_CONTEXT_VALUE)); + } + + @Test + public void serverGetFormattedItemOnInvocationContextValueNotFound() { + Map routingContextData = new HashMap<>(); + Invocation invocation = Mockito.mock(Invocation.class); + when(routingContext.data()).thenReturn(routingContextData); + routingContextData.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + when(invocation.getContext(INVOCATION_CONTEXT_KEY)).thenReturn(null); + + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void clientGetFormattedItemOnInvocationContextValueNotFound() { + Map context = new HashMap<>(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(context); + context.put(INVOCATION_CONTEXT_KEY, null); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void serverGetFormattedItemOnInvocationNotFound() { + Map routingContextData = new HashMap<>(); + when(routingContext.data()).thenReturn(routingContextData); + + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void clientGetFormattedItemOnInvocationContextNotFound() { + Map context = new HashMap<>(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(context); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void testGetFormattedItemOnRoutingContextDataNotFound() { + when(routingContext.data()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void clientGetFormattedItemOnRoutingContextDataNotFound() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } + + @Test + public void clientGetFormattedItemOnInvocationNotFound() { + when(finishEvent.getInvocation()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), Matchers.is(InvocationContextAccessItem.NOT_FOUND)); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostItemTest.java new file mode 100644 index 00000000000..d1669f0316c --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalHostItemTest.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpConnection; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.SocketAddress; +import io.vertx.ext.web.RoutingContext; + +public class LocalHostItemTest { + public static final LocalHostAccessItem ELEMENT = new LocalHostAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private HttpServerRequest serverRequest; + + private SocketAddress socketAddress; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpClientRequest clientRequest; + + private HttpConnection connection; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + socketAddress = Mockito.mock(SocketAddress.class); + invocation = Mockito.mock(Invocation.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + connection = Mockito.mock(HttpConnection.class); + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void clientFormattedItem() { + String localAddress = "192.168.0.1"; + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(localAddress); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(localAddress, strBuilder.toString()); + } + + @Test + public void serverFormattedItem() { + String localAddress = "192.168.0.1"; + accessLogEvent.setLocalAddress(localAddress); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(localAddress, strBuilder.toString()); + } + + @Test + public void getLocalAddress() { + String localHost = "testHost"; + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(socketAddress); + Mockito.when(socketAddress.host()).thenReturn(localHost); + + String result = LocalHostAccessItem.getLocalAddress(routingContext); + Assertions.assertEquals(localHost, result); + } + + @Test + public void serverLocalAddressOnRequestIsNull() { + Mockito.when(routingContext.request()).thenReturn(null); + String result = LocalHostAccessItem.getLocalAddress(routingContext); + Assertions.assertEquals("-", result); + } + + @Test + public void clientLocalAddressOnRequestIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverLocalAddressOnLocalAddressIsNull() { + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(null); + String result = LocalHostAccessItem.getLocalAddress(routingContext); + Assertions.assertEquals("-", result); + } + + @Test + public void clientLocalAddressOnLocalAddressIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverLocalAddressOnHostIsNull() { + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(socketAddress); + Mockito.when(socketAddress.host()).thenReturn(null); + + String result = LocalHostAccessItem.getLocalAddress(routingContext); + Assertions.assertEquals("-", result); + } + + @Test + public void clientLocalAddressOnHostIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverLocalAddressIsEmpty() { + String localHost = ""; + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(socketAddress); + Mockito.when(socketAddress.host()).thenReturn(localHost); + + String result = LocalHostAccessItem.getLocalAddress(routingContext); + Assertions.assertEquals("-", result); + } + + @Test + public void clientLocalAddressIsEmpty() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(""); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortItemTest.java new file mode 100644 index 00000000000..f77c51fbe74 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/LocalPortItemTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpConnection; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.SocketAddress; +import io.vertx.ext.web.RoutingContext; + +public class LocalPortItemTest { + public static final LocalPortAccessItem ELEMENT = new LocalPortAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private HttpServerRequest serverRequest; + + private SocketAddress socketAddress; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpClientRequest clientRequest; + + private HttpConnection connection; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + socketAddress = Mockito.mock(SocketAddress.class); + invocation = Mockito.mock(Invocation.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + connection = Mockito.mock(HttpConnection.class); + Map handlerMap = new HashMap<>(); + handlerMap.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerMap); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(socketAddress); + Mockito.when(socketAddress.port()).thenReturn(8080); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("8080", strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(socketAddress); + when(socketAddress.port()).thenReturn(8080); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("8080", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + Mockito.when(routingContext.request()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnLocalAddressIsNull() { + Mockito.when(routingContext.request()).thenReturn(serverRequest); + Mockito.when(serverRequest.localAddress()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnLocalAddressIsNull() { + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.connection()).thenReturn(connection); + when(connection.localAddress()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextItemTest.java new file mode 100644 index 00000000000..b49b7562669 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/PlainTextItemTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class PlainTextItemTest { + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private StringBuilder strBuilder; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + PlainTextAccessItem element = new PlainTextAccessItem("contentTest"); + element.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("contentTest", strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + PlainTextAccessItem element = new PlainTextAccessItem("contentTest"); + element.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("contentTest", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringItemTest.java new file mode 100644 index 00000000000..ef472623d43 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/QueryStringItemTest.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class QueryStringItemTest { + private static final QueryStringAccessItem ITEM = new QueryStringAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpServerRequest serverRequest; + + private HttpClientRequest clientRequest; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + String query = "?status=up"; + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.query()).thenReturn(query); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(query, strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + String query = "?status=up"; + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.query()).thenReturn(query); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(query, strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + when(routingContext.request()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(null); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnQueryIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.query()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnQueryIsNull() { + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.query()).thenReturn(null); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnQueryIsEmpty() { + String query = ""; + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.query()).thenReturn(query); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnQueryIsEmpty() { + String query = ""; + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.query()).thenReturn(query); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostItemTest.java new file mode 100644 index 00000000000..096e40f805a --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RemoteHostItemTest.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.SocketAddress; +import io.vertx.ext.web.RoutingContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class RemoteHostItemTest { + public static final RemoteHostAccessItem ELEMENT = new RemoteHostAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private HttpServerRequest serverRequest; + + private Endpoint endpoint; + + private URIEndpointObject uriEndpointObject; + + private SocketAddress socketAddress; + + @BeforeEach + public void initStrBuilder() { + routingContext = mock(RoutingContext.class); + finishEvent = mock(InvocationFinishEvent.class); + invocation = mock(Invocation.class); + serverRequest = mock(HttpServerRequest.class); + endpoint = mock(Endpoint.class); + uriEndpointObject = mock(URIEndpointObject.class); + socketAddress = mock(SocketAddress.class); + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + String remoteHost = "remoteHost"; + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.remoteAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(remoteHost); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(remoteHost, strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + String remoteHost = "remoteHost"; + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(uriEndpointObject); + when(uriEndpointObject.getHostOrIp()).thenReturn(remoteHost); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(remoteHost, strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + when(routingContext.request()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRemoteAddressIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.remoteAddress()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRemoteAddressIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnHostIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.remoteAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnHostIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(uriEndpointObject); + when(uriEndpointObject.getHostOrIp()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnHostIsEmpty() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.remoteAddress()).thenReturn(socketAddress); + when(socketAddress.host()).thenReturn(""); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnHostIsEmpty() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(uriEndpointObject); + when(uriEndpointObject.getHostOrIp()).thenReturn(""); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderItemTest.java new file mode 100644 index 00000000000..f2ae7004251 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestHeaderItemTest.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.ext.web.RoutingContext; + +public class RequestHeaderItemTest { + private static final String VAR_NAME = "varName"; + + private static final RequestHeaderAccessItem ELEMENT = new RequestHeaderAccessItem(VAR_NAME); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private RestClientRequestParameters restClientRequest; + + private HttpServerRequest serverRequest; + + private HttpClientRequest clientRequest; + + private MultiMap headers; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + headers = Mockito.mock(MultiMap.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + HeadersMultiMap headers = HeadersMultiMap.httpHeaders(); + String testValue = "testValue"; + headers.add(VAR_NAME, testValue); + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.headers()).thenReturn(headers); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(testValue, strBuilder.toString()); + Assertions.assertEquals(ELEMENT.getVarName(), VAR_NAME); + } + + @Test + public void clientFormattedElement() { + Map handlerContext = new HashMap<>(); + String testValue = "testValue"; + + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.headers()).thenReturn(headers); + when(headers.get(VAR_NAME)).thenReturn(testValue); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(testValue, strBuilder.toString()); + } + + @Test + public void serverFormattedElementIfHeaderIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.headers()).thenReturn(null); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementIfHeaderIsNull() { + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.headers()).thenReturn(null); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementIfNotFound() { + HeadersMultiMap headers = HeadersMultiMap.httpHeaders(); + String testValue = "testValue"; + headers.add("anotherKey", testValue); + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.headers()).thenReturn(headers); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolItemTest.java new file mode 100644 index 00000000000..020df94aeb2 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/RequestProtocolItemTest.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.RoutingContext; + +public class RequestProtocolItemTest { + private static final RequestProtocolAccessItem ITEM = new RequestProtocolAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private HttpServerRequest serverRequest; + + private Endpoint endpoint; + + private URIEndpointObject urlEndpoint; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + urlEndpoint = Mockito.mock(URIEndpointObject.class); + endpoint = Mockito.mock(Endpoint.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.version()).thenReturn(HttpVersion.HTTP_1_1); + + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("HTTP/1.1", strBuilder.toString()); + + strBuilder = new StringBuilder(); + when(serverRequest.version()).thenReturn(HttpVersion.HTTP_1_0); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("HTTP/1.0", strBuilder.toString()); + + strBuilder = new StringBuilder(); + when(serverRequest.version()).thenReturn(HttpVersion.HTTP_2); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("HTTP/2.0", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(urlEndpoint); + when(urlEndpoint.isHttp2Enabled()).thenReturn(true); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("HTTP/2.0", strBuilder.toString()); + + strBuilder = new StringBuilder(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(urlEndpoint); + when(urlEndpoint.isHttp2Enabled()).thenReturn(false); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("HTTP/1.1", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnVersionIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.version()).thenReturn(null); + + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnVersionIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getAddress()).thenReturn(null); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("HTTP/1.1", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderItemTest.java new file mode 100644 index 00000000000..a8708172945 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseHeaderItemTest.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.ext.web.RoutingContext; + +public class ResponseHeaderItemTest { + + private static final String VAR_NAME = "varName"; + + private static final ResponseHeaderAccessItem ELEMENT = new ResponseHeaderAccessItem(VAR_NAME); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private HttpServerResponse serverResponse; + + private Response response; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + serverResponse = Mockito.mock(HttpServerResponse.class); + response = Mockito.mock(Response.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + HeadersMultiMap headers = HeadersMultiMap.httpHeaders(); + String headerValue = "headerValue"; + headers.add(VAR_NAME, headerValue); + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.headers()).thenReturn(headers); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(headerValue, strBuilder.toString()); + Assertions.assertEquals(ELEMENT.getVarName(), VAR_NAME); + } + + @Test + public void clientFormattedElement() { + String headerValue = "headerValue"; + + response = Response.ok(null) + .setHeader(VAR_NAME, headerValue); + when(finishEvent.getResponse()).thenReturn(response); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(headerValue, strBuilder.toString()); + Assertions.assertEquals(ELEMENT.getVarName(), VAR_NAME); + } + + @Test + public void serverFormattedElementOnHeadersIsNull() { + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.headers()).thenReturn(null); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnHeadersIsNull() { + when(finishEvent.getResponse()).thenReturn(response); + when(response.getHeaders()).thenReturn(null); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnResponseIsNull() { + when(routingContext.response()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnResponseIsNull() { + when(finishEvent.getResponse()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnNotFound() { + HeadersMultiMap headers = HeadersMultiMap.httpHeaders(); + String headerValue = "headerValue"; + headers.add("anotherHeader", headerValue); + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.headers()).thenReturn(headers); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnNotFound() { + String headerValue = "headerValue"; + MultiMap headers = MultiMap.caseInsensitiveMultiMap(); + headers.set("anotherHeader", headerValue); + when(finishEvent.getResponse()).thenReturn(response); + when(response.getHeaders()).thenReturn(headers); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeItemTest.java new file mode 100644 index 00000000000..e5f6e6ae17f --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/ResponseSizeItemTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +public class ResponseSizeItemTest { + private static final ResponseSizeAccessItem ELEMENT = new ResponseSizeAccessItem("0"); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private HttpServerResponse serverResponse; + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + serverResponse = Mockito.mock(HttpServerResponse.class); + + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + long bytesWritten = 16L; + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.bytesWritten()).thenReturn(bytesWritten); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(String.valueOf(bytesWritten), strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("0", strBuilder.toString()); + } + + @Test + public void getFormattedElementOnResponseIsNull() { + when(routingContext.response()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("0", strBuilder.toString()); + } + + @Test + public void getFormattedElementOnBytesWrittenIsZero() { + long bytesWritten = 0L; + when(routingContext.response()).thenReturn(serverResponse); + when(serverResponse.bytesWritten()).thenReturn(bytesWritten); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("0", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdItemTest.java new file mode 100644 index 00000000000..b21dc7dfbaf --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TraceIdItemTest.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class TraceIdItemTest { + private static final TraceIdAccessItem ELEMENT = new TraceIdAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private HttpServerRequest serverRequest; + + private Invocation invocation; + + private final Map clientContext = new HashMap<>(); + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + clientContext.clear(); + } + + @Test + public void serverGetFormattedElementFromInvocationContext() { + Map data = new HashMap<>(); + String traceIdTest = "traceIdTest"; + when(invocation.getContext(CoreConst.TRACE_ID_NAME)).thenReturn(traceIdTest); + when(routingContext.data()).thenReturn(data); + data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is(traceIdTest)); + } + + @Test + public void clientGetFormattedElementFromInvocationContext() { + String traceIdTest = "traceIdTest"; + clientContext.put(CoreConst.TRACE_ID_NAME, traceIdTest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(clientContext); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is(traceIdTest)); + } + + @Test + public void serverGetFormattedElementFromRequestHeader() { + Map data = new HashMap<>(); + String traceIdTest = "traceIdTest"; + when(invocation.getContext(CoreConst.TRACE_ID_NAME)).thenReturn(null); + when(routingContext.data()).thenReturn(data); + data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + + when(serverRequest.getHeader(CoreConst.TRACE_ID_NAME)).thenReturn(traceIdTest); + when(routingContext.request()).thenReturn(serverRequest); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is(traceIdTest)); + } + + @Test + public void serverGetFormattedElementOnTraceIdNotFound() { + Map data = new HashMap<>(); + when(invocation.getContext(CoreConst.TRACE_ID_NAME)).thenReturn(""); + when(routingContext.data()).thenReturn(data); + data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + + when(serverRequest.getHeader(CoreConst.TRACE_ID_NAME)).thenReturn(null); + when(routingContext.request()).thenReturn(serverRequest); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + + strBuilder = new StringBuilder(); + when(invocation.getContext(CoreConst.TRACE_ID_NAME)).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + } + + @Test + public void clientGetFormattedElementOnTraceIdNotFound() { + clientContext.put(CoreConst.TRACE_ID_NAME, null); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(clientContext); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + } + + @Test + public void serverGetFormattedElementOnInvocationContextIsNull() { + when(routingContext.data()).thenReturn(null); + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.getHeader(CoreConst.TRACE_ID_NAME)).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + } + + @Test + public void clientGetFormattedElementOnInvocationContextIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getContext()).thenReturn(null); + + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + } + + @Test + public void serverGetFormattedElementOnDataIsNull() { + when(serverRequest.getHeader(CoreConst.TRACE_ID_NAME)).thenReturn(null); + when(routingContext.request()).thenReturn(serverRequest); + when(routingContext.data()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + MatcherAssert.assertThat(strBuilder.toString(), is("-")); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportItemTest.java new file mode 100644 index 00000000000..02a111b94c0 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/TransportItemTest.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TransportItemTest { + private static final TransportAccessItem ITEM = new TransportAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private Invocation invocation; + + private Endpoint endpoint; + + @BeforeEach + public void initStrBuilder() { + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + endpoint = Mockito.mock(Endpoint.class); + accessLogEvent = new ServerAccessLogEvent(); + strBuilder = new StringBuilder(); + } + + @Test + public void clientFormattedElement() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getConfigTransportName()).thenReturn("rest"); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("rest", strBuilder.toString()); + + strBuilder = new StringBuilder(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getEndpoint()).thenReturn("rest:xxx:30100"); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("rest", strBuilder.toString()); + } + + @Test + public void serverFormattedElement() { + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("rest", strBuilder.toString()); + } + + @Test + public void clientConfigTransportNameIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getConfigTransportName()).thenReturn(null); + + strBuilder = new StringBuilder(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getEndpoint()).thenReturn("rest:xxx:30100"); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("rest", strBuilder.toString()); + } + + @Test + public void clientConfigTransportNameIsEmpty() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getConfigTransportName()).thenReturn(""); + strBuilder = new StringBuilder(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(endpoint); + when(endpoint.getEndpoint()).thenReturn("rest:xxx:30100"); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("rest", strBuilder.toString()); + } + + @Test + public void clientALLIsEmpty() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getConfigTransportName()).thenReturn(null); + strBuilder = new StringBuilder(); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getEndpoint()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathItemTest.java new file mode 100644 index 00000000000..d1601609a28 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathItemTest.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.apache.servicecomb.transport.rest.client.RestClientRequestParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.swagger.v3.oas.models.OpenAPI; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class UrlPathItemTest { + private static final UrlPathAccessItem ITEM = new UrlPathAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private HttpServerRequest serverRequest; + + private OperationMeta operationMeta; + + private SchemaMeta schemaMeta; + + private OpenAPI swagger; + + private RestClientRequestParameters restClientRequest; + + private HttpClientRequest clientRequest; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + operationMeta = Mockito.mock(OperationMeta.class); + schemaMeta = Mockito.mock(SchemaMeta.class); + swagger = Mockito.mock(OpenAPI.class); + restClientRequest = Mockito.mock(RestClientRequestParameters.class); + clientRequest = Mockito.mock(HttpClientRequest.class); + + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void clientFormattedElement() { + String uri = "/test"; + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getOperationMeta()).thenReturn(operationMeta); + when(invocation.getSchemaMeta()).thenReturn(schemaMeta); + when(schemaMeta.getSwagger()).thenReturn(swagger); + when(operationMeta.getOperationPath()).thenReturn("/test"); + + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(uri, strBuilder.toString()); + + strBuilder = new StringBuilder(); + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(invocation.getOperationMeta()).thenReturn(null); + when(invocation.getSchemaMeta()).thenReturn(null); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.path()).thenReturn(uri); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(uri, strBuilder.toString()); + } + + @Test + public void serverFormattedElement() { + String uri = "/test"; + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.path()).thenReturn(uri); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(uri, strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + when(routingContext.request()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnMethodIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.path()).thenReturn(null); + ITEM.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnMethodIsNull() { + Map handlerContext = new HashMap<>(); + handlerContext.put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getHandlerContext()).thenReturn(handlerContext); + when(restClientRequest.getHttpClientRequest()).thenReturn(clientRequest); + when(clientRequest.path()).thenReturn(null); + ITEM.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryItemTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryItemTest.java new file mode 100644 index 00000000000..f0bebc1f3d7 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UrlPathWithQueryItemTest.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import static org.mockito.Mockito.when; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; + +public class UrlPathWithQueryItemTest { + + public static final UrlPathWithQueryAccessItem ELEMENT = new UrlPathWithQueryAccessItem(); + + private StringBuilder strBuilder; + + private InvocationFinishEvent finishEvent; + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + private Invocation invocation; + + private HttpServerRequest serverRequest; + + @BeforeEach + public void initStrBuilder() { + accessLogEvent = new ServerAccessLogEvent(); + routingContext = Mockito.mock(RoutingContext.class); + finishEvent = Mockito.mock(InvocationFinishEvent.class); + invocation = Mockito.mock(Invocation.class); + serverRequest = Mockito.mock(HttpServerRequest.class); + + accessLogEvent.setRoutingContext(routingContext); + strBuilder = new StringBuilder(); + } + + @Test + public void serverFormattedElement() { + String uri = "uriTest"; + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.uri()).thenReturn(uri); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals(uri, strBuilder.toString()); + } + + @Test + public void clientFormattedElement() { + String uri = "uriTest"; + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH)).thenReturn(uri); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals(uri, strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnRequestIsNull() { + when(routingContext.request()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnRequestIsNull() { + when(finishEvent.getInvocation()).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnUriIsNull() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.uri()).thenReturn(null); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnUriIsNull() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH)).thenReturn(null); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void serverFormattedElementOnUriIsEmpty() { + when(routingContext.request()).thenReturn(serverRequest); + when(serverRequest.uri()).thenReturn(""); + ELEMENT.appendServerFormattedItem(accessLogEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } + + @Test + public void clientFormattedElementOnUriIsEmpty() { + when(finishEvent.getInvocation()).thenReturn(invocation); + when(invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH)).thenReturn(""); + ELEMENT.appendClientFormattedItem(finishEvent, strBuilder); + Assertions.assertEquals("-", strBuilder.toString()); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItem.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItem.java new file mode 100644 index 00000000000..0cee6247efe --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItem.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +/** + * For access log extension test + */ +public class UserDefinedAccessLogItem implements AccessLogItem { + private final String config; + + public UserDefinedAccessLogItem(String config) { + this.config = config; + } + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append("user-defined-") + .append(config); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent clientLogEvent, StringBuilder builder) { + builder.append("user-defined-") + .append(config); + } +} diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItemLowPriority.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItemLowPriority.java new file mode 100644 index 00000000000..a4ed8fd6460 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/element/impl/UserDefinedAccessLogItemLowPriority.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.element.impl; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; + +import io.vertx.ext.web.RoutingContext; + +/** + * For access log extension test, will be overridden by {@link RemoteHostAccessItem}("%h"), + * and takes no effect. + */ +public class UserDefinedAccessLogItemLowPriority implements AccessLogItem { + + @Override + public void appendServerFormattedItem(ServerAccessLogEvent accessLogEvent, StringBuilder builder) { + builder.append("OverriddenItem"); + } + + @Override + public void appendClientFormattedItem(InvocationFinishEvent clientLogEvent, StringBuilder builder) { + builder.append("OverriddenItem"); + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestCompositeExtendedAccessLogItemMeta.java similarity index 77% rename from transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java rename to common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestCompositeExtendedAccessLogItemMeta.java index c226babbfa8..5a39657bd9f 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestCompositeExtendedAccessLogItemMeta.java +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestCompositeExtendedAccessLogItemMeta.java @@ -15,14 +15,15 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl; +package org.apache.servicecomb.common.accessLog.core.parser.impl; import java.util.ArrayList; import java.util.List; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UserDefinedAccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.element.impl.UserDefinedAccessLogItem; +import org.apache.servicecomb.common.accessLog.core.parser.CompositeVertxRestAccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta; + public class TestCompositeExtendedAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta { private static final List META_LIST = new ArrayList<>(); diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestSingleExtendedAccessLogItemMeta.java similarity index 78% rename from transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java rename to common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestSingleExtendedAccessLogItemMeta.java index 9a2a1c73080..7d881557a14 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/TestSingleExtendedAccessLogItemMeta.java +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/TestSingleExtendedAccessLogItemMeta.java @@ -15,10 +15,11 @@ * limitations under the License. */ -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl; +package org.apache.servicecomb.common.accessLog.core.parser.impl; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UserDefinedAccessLogItemLowPriority; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta; + +import org.apache.servicecomb.common.accessLog.core.element.impl.UserDefinedAccessLogItemLowPriority; +import org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta; public class TestSingleExtendedAccessLogItemMeta extends VertxRestAccessLogItemMeta { public TestSingleExtendedAccessLogItemMeta() { diff --git a/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParserTest.java b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParserTest.java new file mode 100644 index 00000000000..d870fc2b225 --- /dev/null +++ b/common/common-access-log/src/test/java/org/apache/servicecomb/common/accessLog/core/parser/impl/VertxRestAccessLogPatternParserTest.java @@ -0,0 +1,362 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.accessLog.core.parser.impl; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.servicecomb.common.accessLog.core.element.AccessLogItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.CookieAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ConfigurableDatetimeAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.DurationMillisecondAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.DurationSecondAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.FirstLineOfRequestAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.HttpMethodAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.HttpStatusAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.InvocationContextAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.LocalHostAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.LocalPortAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.QueryStringAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RemoteHostAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RequestHeaderAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.RequestProtocolAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ResponseHeaderAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.ResponseSizeAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.TraceIdAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.TransportAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.UrlPathAccessItem; +import org.apache.servicecomb.common.accessLog.core.element.impl.UrlPathWithQueryAccessItem; +import org.apache.servicecomb.common.accessLog.core.parser.CompositeVertxRestAccessLogItemMeta; +import org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.vertx.ext.web.RoutingContext; + +public class VertxRestAccessLogPatternParserTest { + private static final String ROW_PATTERN = "[cs-method] %m %s%T%D%h%v%p%B%b%r%U%q" + + "cs-uri-stemcs-uri-querycs-uri%H%t%{yyyy MM dd HH:mm:ss zzz}t" + + "%{yyyy MM dd HH:mm:ss|GMT+0|en-US}t" + + "%{incoming-header}i" + + "%{outgoing-header}o" + + "%{cookie}C" + + "%SCB-traceId" + + "%{ctx}SCB-ctx" + + "%SCB-transport"; + + private static final VertxRestAccessLogPatternParser logPatternParser = new VertxRestAccessLogPatternParser(); + + private ServerAccessLogEvent accessLogEvent; + + private RoutingContext routingContext; + + + @BeforeEach + public void initStrBuilder() { + routingContext = Mockito.mock(RoutingContext.class); + accessLogEvent = new ServerAccessLogEvent(); + accessLogEvent.setRoutingContext(routingContext); + } + + @Test + public void testParsePatternFullTest() { + List> result = logPatternParser.parsePattern(ROW_PATTERN); + Assertions.assertEquals(29, result.size()); + StringBuilder builder = new StringBuilder(); + result.get(0).appendServerFormattedItem(accessLogEvent, builder); + Assertions.assertEquals("[", builder.toString()); + Assertions.assertEquals(HttpMethodAccessItem.class, result.get(1).getClass()); + builder = new StringBuilder(); + result.get(2).appendServerFormattedItem(accessLogEvent, builder); + Assertions.assertEquals("] ", builder.toString()); + Assertions.assertEquals(HttpMethodAccessItem.class, result.get(3).getClass()); + builder = new StringBuilder(); + result.get(4).appendServerFormattedItem(accessLogEvent, builder); + Assertions.assertEquals(" ", builder.toString()); + Assertions.assertEquals(HttpStatusAccessItem.class, result.get(5).getClass()); + Assertions.assertEquals(DurationSecondAccessItem.class, result.get(6).getClass()); + Assertions.assertEquals(DurationMillisecondAccessItem.class, result.get(7).getClass()); + Assertions.assertEquals(RemoteHostAccessItem.class, result.get(8).getClass()); + Assertions.assertEquals(LocalHostAccessItem.class, result.get(9).getClass()); + Assertions.assertEquals(LocalPortAccessItem.class, result.get(10).getClass()); + Assertions.assertEquals(ResponseSizeAccessItem.class, result.get(11).getClass()); + Assertions.assertEquals("0", ((ResponseSizeAccessItem) result.get(11)).getZeroBytes()); + Assertions.assertEquals(ResponseSizeAccessItem.class, result.get(12).getClass()); + Assertions.assertEquals("-", ((ResponseSizeAccessItem) result.get(12)).getZeroBytes()); + Assertions.assertEquals(FirstLineOfRequestAccessItem.class, result.get(13).getClass()); + Assertions.assertEquals(UrlPathAccessItem.class, result.get(14).getClass()); + Assertions.assertEquals(QueryStringAccessItem.class, result.get(15).getClass()); + Assertions.assertEquals(UrlPathAccessItem.class, result.get(16).getClass()); + Assertions.assertEquals(QueryStringAccessItem.class, result.get(17).getClass()); + Assertions.assertEquals(UrlPathWithQueryAccessItem.class, result.get(18).getClass()); + Assertions.assertEquals(RequestProtocolAccessItem.class, result.get(19).getClass()); + Assertions.assertEquals(ConfigurableDatetimeAccessItem.class, result.get(20).getClass()); + Assertions.assertEquals(ConfigurableDatetimeAccessItem.DEFAULT_DATETIME_PATTERN, + ((ConfigurableDatetimeAccessItem) result.get(20)).getPattern()); + Assertions.assertEquals(ConfigurableDatetimeAccessItem.DEFAULT_LOCALE, ((ConfigurableDatetimeAccessItem) result.get(20)).getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), ((ConfigurableDatetimeAccessItem) result.get(20)).getTimezone()); + Assertions.assertEquals("yyyy MM dd HH:mm:ss zzz", ((ConfigurableDatetimeAccessItem) result.get(21)).getPattern()); + Assertions.assertEquals(ConfigurableDatetimeAccessItem.DEFAULT_LOCALE, ((ConfigurableDatetimeAccessItem) result.get(21)).getLocale()); + Assertions.assertEquals(TimeZone.getDefault(), ((ConfigurableDatetimeAccessItem) result.get(21)).getTimezone()); + Assertions.assertEquals("yyyy MM dd HH:mm:ss", ((ConfigurableDatetimeAccessItem) result.get(22)).getPattern()); + Assertions.assertEquals(Locale.forLanguageTag("en-US"), ((ConfigurableDatetimeAccessItem) result.get(22)).getLocale()); + Assertions.assertEquals(TimeZone.getTimeZone("GMT+0"), ((ConfigurableDatetimeAccessItem) result.get(22)).getTimezone()); + Assertions.assertEquals(RequestHeaderAccessItem.class, result.get(23).getClass()); + Assertions.assertEquals("incoming-header", ((RequestHeaderAccessItem) result.get(23)).getVarName()); + Assertions.assertEquals(ResponseHeaderAccessItem.class, result.get(24).getClass()); + Assertions.assertEquals("outgoing-header", ((ResponseHeaderAccessItem) result.get(24)).getVarName()); + Assertions.assertEquals(CookieAccessItem.class, result.get(25).getClass()); + Assertions.assertEquals("cookie", ((CookieAccessItem) result.get(25)).getVarName()); + Assertions.assertEquals(TraceIdAccessItem.class, result.get(26).getClass()); + Assertions.assertEquals(InvocationContextAccessItem.class, result.get(27).getClass()); + Assertions.assertEquals("ctx", ((InvocationContextAccessItem) result.get(27)).getVarName()); + Assertions.assertEquals(TransportAccessItem.class, result.get(28).getClass()); + } + + @Test + public void testParsePattern() { + String pattern = " %m cs-uri-stem %{response-header}o "; + List> result = logPatternParser.parsePattern(pattern); + Assertions.assertEquals(7, result.size()); + StringBuilder stringBuilder = new StringBuilder(); + result.get(0).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(HttpMethodAccessItem.class, result.get(1).getClass()); + stringBuilder = new StringBuilder(); + result.get(2).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(UrlPathAccessItem.class, result.get(3).getClass()); + stringBuilder = new StringBuilder(); + result.get(4).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(ResponseHeaderAccessItem.class, result.get(5).getClass()); + Assertions.assertEquals("response-header", ((ResponseHeaderAccessItem) result.get(5)).getVarName()); + stringBuilder = new StringBuilder(); + result.get(6).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + } + + @Test + public void testParsePatternWithNoBlank() { + String pattern = "%mcs-uri-stem%{response-header}o"; + List> result = logPatternParser.parsePattern(pattern); + Assertions.assertEquals(3, result.size()); + + Assertions.assertEquals(HttpMethodAccessItem.class, result.get(0).getClass()); + Assertions.assertEquals(UrlPathAccessItem.class, result.get(1).getClass()); + Assertions.assertEquals(ResponseHeaderAccessItem.class, result.get(2).getClass()); + Assertions.assertEquals("response-header", ((ResponseHeaderAccessItem) result.get(2)).getVarName()); + } + + @Test + public void testParsePatternComplex() { + String pattern = "%m cs-uri-stem %{response-header}o abc cs-uri-query %s%{request} header}i plain cs-uri"; + List> result = logPatternParser.parsePattern(pattern); + Assertions.assertEquals(12, result.size()); + + Assertions.assertEquals(HttpMethodAccessItem.class, result.get(0).getClass()); + StringBuilder stringBuilder = new StringBuilder(); + result.get(1).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(UrlPathAccessItem.class, result.get(2).getClass()); + stringBuilder = new StringBuilder(); + result.get(3).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(ResponseHeaderAccessItem.class, result.get(4).getClass()); + Assertions.assertEquals("response-header", ((ResponseHeaderAccessItem) result.get(4)).getVarName()); + stringBuilder = new StringBuilder(); + result.get(5).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" abc ", stringBuilder.toString()); + Assertions.assertEquals(QueryStringAccessItem.class, result.get(6).getClass()); + stringBuilder = new StringBuilder(); + result.get(7).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" ", stringBuilder.toString()); + Assertions.assertEquals(HttpStatusAccessItem.class, result.get(8).getClass()); + Assertions.assertEquals(RequestHeaderAccessItem.class, result.get(9).getClass()); + Assertions.assertEquals("request} header", ((RequestHeaderAccessItem) result.get(9)).getVarName()); + stringBuilder = new StringBuilder(); + result.get(10).appendServerFormattedItem(accessLogEvent, stringBuilder); + Assertions.assertEquals(" plain ", stringBuilder.toString()); + Assertions.assertEquals(UrlPathWithQueryAccessItem.class, result.get(11).getClass()); + } + + final Comparator comparator = VertxRestAccessLogPatternParser.accessLogItemMetaComparator; + + /** + * one factor test + */ + @Test + public void testCompareMetaSimple() { + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta(null, null, null, 0), + new VertxRestAccessLogItemMeta(null, null, null, 1) + ) < 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta(null, "}abc", null, 0), + new VertxRestAccessLogItemMeta(null, null, null, 0) + ) < 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta(null, "}abc", null, 0), + new VertxRestAccessLogItemMeta(null, "}de", null, 0) + ) < 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta(null, "}abc", null, 0), + new VertxRestAccessLogItemMeta(null, "}ab", null, 0) + ) < 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%abc", null, null, 0), + new VertxRestAccessLogItemMeta("%de", null, null, 0) + ) < 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%abc", null, null, 0), + new VertxRestAccessLogItemMeta("%ab", null, null, 0) + ) < 0 + ); + Assertions.assertEquals(0, comparator.compare( + new VertxRestAccessLogItemMeta("%abc", null, null, 0), + new VertxRestAccessLogItemMeta("%abc", null, null, 0) + )); + } + + /** + * multiple factors test + */ + @Test + public void testCompareMetaComplex() { + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0), + new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0) + ) > 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%abc", null, null, 0), + new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0) + ) > 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%bcd", "}abc", null, 0), + new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0) + ) > 0 + ); + Assertions.assertTrue( + comparator.compare( + new VertxRestAccessLogItemMeta("%abc", "}abc", null, 1), + new VertxRestAccessLogItemMeta("%ab", "}ab", null, 0) + ) > 0 + ); + } + + @Test + public void testComparePlaceholderString() { + Assertions.assertTrue( + VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "bbc") < 0 + ); + Assertions.assertTrue( + VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "ab") < 0 + ); + Assertions.assertEquals(0, VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "abc")); + Assertions.assertTrue( + VertxRestAccessLogPatternParser.comparePlaceholderString("bbc", "abc") > 0 + ); + Assertions.assertTrue( + VertxRestAccessLogPatternParser.comparePlaceholderString("ab", "abc") > 0 + ); + } + + @Test + public void testExtendedVertxRestAccessLogItemCreator() { + final List metaList0 = new ArrayList<>(); + metaList0.add(new VertxRestAccessLogItemMeta("%{", "}abc", null)); + metaList0.add(new VertxRestAccessLogItemMeta("%{", "}a", null)); + metaList0.add(new VertxRestAccessLogItemMeta("%_", null, null, -1)); + + final List metaList1 = new ArrayList<>(); + metaList0.add(new VertxRestAccessLogItemMeta("%a", "}abc", null)); + metaList0.add(new VertxRestAccessLogItemMeta("%0", "}abc", null, 1)); + metaList0.add(new VertxRestAccessLogItemMeta("%m", null, null)); + + CompositeVertxRestAccessLogItemMeta compositeMeta0 = new CompositeVertxRestAccessLogItemMeta() { + @Override + public List getAccessLogItemMetas() { + return metaList0; + } + }; + CompositeVertxRestAccessLogItemMeta compositeMeta1 = new CompositeVertxRestAccessLogItemMeta() { + @Override + public List getAccessLogItemMetas() { + return metaList1; + } + }; + + List metaList = new ArrayList<>(1); + metaList.add(compositeMeta0); + metaList.add(compositeMeta1); + metaList.add(new VertxRestAccessLogItemMeta("%{", null, null)); + + VertxRestAccessLogPatternParser parser = Mockito.mock(VertxRestAccessLogPatternParser.class); + Mockito.when(parser.getMetaList()).thenAnswer(invocation -> { + List resultMetaList = new ArrayList<>(); + for (VertxRestAccessLogItemMeta meta : metaList) { + if (CompositeVertxRestAccessLogItemMeta.class.isAssignableFrom(meta.getClass())) { + resultMetaList.addAll(((CompositeVertxRestAccessLogItemMeta) meta).getAccessLogItemMetas()); + } else { + resultMetaList.add(meta); + } + } + VertxRestAccessLogPatternParser.sortAccessLogItemMeta(resultMetaList); + return resultMetaList; + }); + + List accessLogItemMetaList = parser.getMetaList(); + + Assertions.assertEquals(7, accessLogItemMetaList.size()); + Assertions.assertEquals("%_", accessLogItemMetaList.get(0).getPrefix()); + Assertions.assertEquals("%a", accessLogItemMetaList.get(1).getPrefix()); + Assertions.assertEquals("}abc", accessLogItemMetaList.get(1).getSuffix()); + Assertions.assertEquals("%{", accessLogItemMetaList.get(2).getPrefix()); + Assertions.assertEquals("}abc", accessLogItemMetaList.get(2).getSuffix()); + Assertions.assertEquals("%{", accessLogItemMetaList.get(3).getPrefix()); + Assertions.assertEquals("}a", accessLogItemMetaList.get(3).getSuffix()); + Assertions.assertEquals("%m", accessLogItemMetaList.get(4).getPrefix()); + Assertions.assertNull(accessLogItemMetaList.get(4).getSuffix()); + Assertions.assertEquals("%{", accessLogItemMetaList.get(5).getPrefix()); + Assertions.assertNull(accessLogItemMetaList.get(5).getSuffix()); + Assertions.assertEquals("%0", accessLogItemMetaList.get(6).getPrefix()); + Assertions.assertEquals("}abc", accessLogItemMetaList.get(6).getSuffix()); + } +} diff --git a/common/common-access-log/src/test/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta b/common/common-access-log/src/test/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta new file mode 100644 index 00000000000..74f9ee4cb24 --- /dev/null +++ b/common/common-access-log/src/test/resources/META-INF/services/org.apache.servicecomb.common.accessLog.core.parser.VertxRestAccessLogItemMeta @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.common.accessLog.core.parser.impl.TestCompositeExtendedAccessLogItemMeta +org.apache.servicecomb.common.accessLog.core.parser.impl.TestSingleExtendedAccessLogItemMeta diff --git a/common/common-javassist/pom.xml b/common/common-javassist/pom.xml deleted file mode 100644 index f7be11ccf11..00000000000 --- a/common/common-javassist/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - common - 1.2.0-SNAPSHOT - - common-javassist - Java Chassis::Common::Javassist - - - - org.javassist - javassist - - - org.apache.servicecomb - foundation-common - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ClassConfig.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ClassConfig.java deleted file mode 100644 index bc070ba1ffa..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ClassConfig.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -public class ClassConfig { - - private String className; - - private boolean intf; - - private List intfList = new ArrayList<>(); - - private List fieldList = new ArrayList<>(); - - private List methodList = new ArrayList<>(); - - public boolean isIntf() { - return intf; - } - - public void setIntf(boolean intf) { - this.intf = intf; - } - - public String getClassName() { - return className; - } - - public void setClassName(String className) { - this.className = className; - } - - public void addInterface(Class intf) { - addInterface(intf.getName()); - } - - public void addInterface(String intf) { - intfList.add(intf); - } - - public List getIntfList() { - return intfList; - } - - public List getFieldList() { - return fieldList; - } - - public FieldConfig addField(String name, Type genericType) { - return addField(name, TypeFactory.defaultInstance().constructType(genericType)); - } - - public FieldConfig addField(String name, JavaType javaType) { - return addField(name, new CtType(javaType)); - } - - public FieldConfig addField(String name, CtType ctType) { - FieldConfig field = new FieldConfig(); - field.setName(name); - field.setType(ctType); - - fieldList.add(field); - - return field; - } - - public void addMethod(MethodConfig methodConfig) { - methodConfig.init(); - methodList.add(methodConfig); - } - - public void addMethod(String source) { - addMethod(source, null); - } - - public void addMethod(String source, String genericSignature) { - MethodConfig methodConfig = new MethodConfig(); - methodConfig.setSource(source); - methodConfig.setGenericSignature(genericSignature); - addMethod(methodConfig); - } - - public List getMethodList() { - return methodList; - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtType.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtType.java deleted file mode 100644 index cb4653d6e8b..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtType.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import com.fasterxml.jackson.databind.JavaType; - -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtPrimitiveType; -import javassist.NotFoundException; -import javassist.bytecode.SignatureAttribute.ClassType; - -public class CtType { - private static final ClassPool PRIMITIVE_CLASSPOOL = JavassistUtils.getOrCreateClassPool(int.class.getClassLoader()); - - private CtClass ctClass; - - private boolean hasGenericTypes; - - private String genericSignature; - - public CtType(CtClass ctClass) { - ClassType classType = new ClassType(ctClass.getName(), null); - init(ctClass, false, classType.encode()); - } - - public CtType(CtClass ctClass, boolean hasGenericTypes, String genericSignature) { - init(ctClass, hasGenericTypes, genericSignature); - } - - public CtType(JavaType javaType) { - if (CtTypeJavaType.class.isInstance(javaType)) { - CtType ctType = ((CtTypeJavaType) javaType).getType(); - init(ctType.ctClass, ctType.hasGenericTypes, ctType.genericSignature); - return; - } - - ClassLoader classLoader = javaType.getRawClass().getClassLoader(); - try { - ClassPool classPool = JavassistUtils.getOrCreateClassPool(classLoader); - init(classPool.get(javaType.getRawClass().getCanonicalName()), javaType.hasGenericTypes(), - javaType.getGenericSignature() - ); - } catch (NotFoundException e) { - throw new IllegalStateException( - String.format("Failed to get CtClass for %s in classloader %s.", - javaType.getRawClass().getName(), - classLoader), - e); - } - } - - private void init(CtClass ctClass, boolean hasGenericTypes, String genericSignature) { - if (ctClass.isPrimitive() && !void.class.getName().equals(ctClass.getName())) { - try { - ctClass = PRIMITIVE_CLASSPOOL.get(((CtPrimitiveType) ctClass).getWrapperName()); - } catch (NotFoundException e) { - throw new IllegalStateException("Impossible exception.", e); - } - } - - this.ctClass = ctClass; - // no problem: - // Ljava/util/List; - // cause problem: - // Ljava/util/List<[B;>; - // it should be Ljava/util/List<[B>; - // jackson generate genericSignature to be "Ljava/util/List<[B;>;" of List, we should convert it - this.genericSignature = genericSignature.replace("[B;>", "[B>"); - this.hasGenericTypes = hasGenericTypes; - } - - public CtClass getCtClass() { - return ctClass; - } - - public boolean hasGenericTypes() { - return this.hasGenericTypes; - } - - public String getGenericSignature() { - return genericSignature; - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtTypeJavaType.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtTypeJavaType.java deleted file mode 100644 index 74c083cb08f..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/CtTypeJavaType.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import java.util.Objects; - -import com.fasterxml.jackson.databind.type.SimpleType; -import com.fasterxml.jackson.databind.type.TypeBindings; - -/** - * just a wrapper for CtType - * pending create class from CtClass to support recursive dependency class - */ -public class CtTypeJavaType extends SimpleType { - private static final long serialVersionUID = 301147079248607138L; - - private CtType type; - - public CtTypeJavaType(CtType type) { - super(CtTypeJavaType.class, TypeBindings.emptyBindings(), null, null, - type == null ? 0 : type.getGenericSignature().hashCode(), - null, null, false); - this.type = type; - } - - public CtType getType() { - return type; - } - - @Override - protected String buildCanonicalName() { - return type.getCtClass().getName(); - } - - @Override - public String getGenericSignature() { - return type.getGenericSignature(); - } - - @Override - public StringBuilder getGenericSignature(StringBuilder sb) { - return sb.append(type.getGenericSignature()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || !this.getClass().isAssignableFrom(o.getClass())) { - return false; - } - CtTypeJavaType that = (CtTypeJavaType) o; - return Objects.equals(this.getGenericSignature(), that.getGenericSignature()); - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/FieldConfig.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/FieldConfig.java deleted file mode 100644 index 8975690bd48..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/FieldConfig.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -import com.fasterxml.jackson.databind.JavaType; - -public class FieldConfig { - private String name; - - private CtType type; - - private boolean genGetter; - - private boolean genSetter; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public CtType getType() { - return type; - } - - public void setType(JavaType javaType) { - this.type = new CtType(javaType); - } - - public void setType(CtType ctType) { - this.type = ctType; - } - - public boolean isGenGetter() { - return genGetter; - } - - public void setGenGetter(boolean genGetter) { - this.genGetter = genGetter; - } - - public boolean isGenSetter() { - return genSetter; - } - - public void setGenSetter(boolean genSetter) { - this.genSetter = genSetter; - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java deleted file mode 100644 index 2d3ed01ef07..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -import static java.util.Locale.ENGLISH; - -import java.lang.reflect.Modifier; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.hash.Hashing; - -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.scopedpool.ScopedClassPoolRepositoryImpl; - -public final class JavassistUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(JavassistUtils.class); - - static { - ScopedClassPoolRepositoryImpl.getInstance().setClassPoolFactory(new StdScopedClassPoolFactory()); - } - - public static ClassPool getOrCreateClassPool(ClassLoader classLoader) { - return ScopedClassPoolRepositoryImpl.getInstance().registerClassLoader(classLoader); - } - - public static void clearByClassLoader(ClassLoader classLoader) { - ScopedClassPoolRepositoryImpl.getInstance().unregisterClassLoader(classLoader); - } - - private JavassistUtils() { - } - - @SuppressWarnings("rawtypes") - public static Class createEnum(String clsName, String... values) { - return createEnum(null, clsName, Arrays.asList(values)); - } - - @SuppressWarnings("rawtypes") - public static Class createEnum(String clsName, List values) { - return createEnum(null, clsName, values); - } - - @SuppressWarnings("rawtypes") - public static Class getOrCreateEnumWithPackageName(ClassLoader classLoader, String packageName, - List enums) { - String strEnums = enums.toString(); - String enumClsName = - packageName + ".Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8).toString(); - return JavassistUtils.getOrCreateEnumWithClassName(classLoader, enumClsName, enums); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static synchronized Class getOrCreateEnumWithClassName(ClassLoader classLoader, String clsName, - List values) { - try { - return (Class) classLoader.loadClass(clsName); - } catch (ClassNotFoundException e) { - return createEnum(classLoader, clsName, values); - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static Class createEnum(ClassLoader classLoader, String clsName, List values) { - if (values == null || values.size() == 0) { - throw new Error("values is not allowed empty."); - } - - classLoader = JvmUtils.correctClassLoader(classLoader); - - ClassPool classPool = getOrCreateClassPool(classLoader); - CtClass ctClass = classPool.makeClass(clsName); - ctClass.setModifiers(ctClass.getModifiers() | javassist.Modifier.ENUM); - - try { - ctClass.setSuperclass(classPool.get(Enum.class.getName())); - - addEnumConstructor(classPool, ctClass); - addEnumValuesMethod(ctClass, values); - - return ctClass.toClass(classLoader, null); - } catch (Throwable e) { - throw new Error(e); - } - } - - private static void addEnumConstructor(ClassPool classPool, CtClass ctClass) throws Exception { - String src = "super($1, $2);"; - CtConstructor ctConstructor = new CtConstructor( - classPool.get(new String[] {String.class.getName(), int.class.getName()}), ctClass); - ctConstructor.setBody(src); - - ctClass.addConstructor(ctConstructor); - } - - private static void addEnumValuesMethod(CtClass ctClass, List values) throws CannotCompileException { - StringBuilder sb = new StringBuilder(); - sb.append("public static Enum[] values(){return new Enum[]{"); - for (int idx = 0; idx < values.size(); idx++) { - String value = values.get(idx); - - String line = String.format("new %s(\"%s\", %d),", ctClass.getName(), value, idx); - sb.append(line); - } - sb.setLength(sb.length() - 1); - sb.append("};}"); - - CtMethod valuesMethod = CtMethod.make(sb.toString(), ctClass); - ctClass.addMethod(valuesMethod); - } - - public static Class createClass(ClassConfig config) { - return createClass(null, config); - } - - public static CtClass createCtClass(ClassLoader classLoader, ClassConfig config) { - classLoader = JvmUtils.correctClassLoader(classLoader); - - ClassPool classPool = getOrCreateClassPool(classLoader); - CtClass ctClass = classPool.getOrNull(config.getClassName()); - if (ctClass == null) { - if (config.isIntf()) { - ctClass = classPool.makeInterface(config.getClassName()); - } else { - ctClass = classPool.makeClass(config.getClassName()); - } - } - - try { - for (String intfName : config.getIntfList()) { - ctClass.addInterface(classPool.get(intfName)); - } - - for (FieldConfig fieldConfig : config.getFieldList()) { - CtField field = createCtField(ctClass, fieldConfig); - ctClass.addField(field); - - if (fieldConfig.isGenGetter()) { - addFieldGetter(config, fieldConfig); - } - - if (fieldConfig.isGenSetter()) { - addFieldSetter(config, fieldConfig); - } - } - - for (MethodConfig methodConfig : config.getMethodList()) { - try { - CtMethod ctMethod = CtMethod.make(methodConfig.getSource(), ctClass); - if (methodConfig.getGenericSignature() != null) { - ctMethod.setGenericSignature(methodConfig.getGenericSignature()); - } - ctClass.addMethod(ctMethod); - } catch (CannotCompileException e) { - LOGGER.error("Failed to create method, source:\n{}.", methodConfig.getSource()); - throw e; - } - } - - LOGGER.info("create CtClass {} in classLoader {}.", config.getClassName(), classLoader); - return ctClass; - } catch (Throwable e) { - throw new IllegalStateException( - String.format("Failed to create CtClass %s in classLoader %s.", config.getClassName(), - classLoader), e); - } - } - - public static Class createClass(ClassLoader classLoader, ClassConfig config) { - classLoader = JvmUtils.correctClassLoader(classLoader); - - CtClass ctClass = createCtClass(classLoader, config); - return createClass(classLoader, ctClass); - } - - public static Class createClass(ClassLoader classLoader, CtClass ctClass) { - classLoader = JvmUtils.correctClassLoader(classLoader); - - String clsName = ctClass.getName(); - try { - // must try load from classloader first - // because class A depend on class B - // when load class A, will load class B - // after this, if CtClass B invoke toClass again, will cause problem. - return classLoader.loadClass(clsName); - } catch (ClassNotFoundException e) { - // ignore it - } - - try { - Class cls = ctClass.toClass(classLoader, null); - LOGGER.info("create class {} in classLoader {}.", clsName, classLoader); - return cls; - } catch (Throwable e) { - throw new IllegalStateException( - String.format("Failed to create %s in classLoader %s.", clsName, classLoader), e); - } - } - - public static String capitalize(String name) { - if (name == null || name.length() == 0) { - return name; - } - return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1); - } - - private static void addFieldGetter(ClassConfig config, FieldConfig fieldConfig) { - MethodConfig methodConfig = new MethodConfig(); - - String prefix = "get"; - if (boolean.class.getName().equals(fieldConfig.getType().getCtClass().getName()) - || Boolean.class.getName().equals(fieldConfig.getType().getCtClass().getName())) { - prefix = "is"; - } - methodConfig.setName(prefix + capitalize(fieldConfig.getName())); - methodConfig.setResult(fieldConfig.getType()); - methodConfig.setBodySource("return " + fieldConfig.getName() + ";"); - - config.addMethod(methodConfig); - } - - private static void addFieldSetter(ClassConfig config, FieldConfig fieldConfig) { - MethodConfig methodConfig = new MethodConfig(); - methodConfig.setName("set" + capitalize(fieldConfig.getName())); - methodConfig.addParameter(fieldConfig.getName(), fieldConfig.getType()); - methodConfig.setBodySource(" this." + fieldConfig.getName() + " = " + fieldConfig.getName() + ";"); - - config.addMethod(methodConfig); - } - - public static void genMultiWrapperInterface(ClassConfig config) { - try { - config.addInterface(MultiWrapper.class); - - config.addMethod(genReadFieldsMethodSource(config.getFieldList())); - config.addMethod(genWriteFieldsMethodSource(config.getFieldList())); - } catch (Exception e) { - String msg = String.format("failed to genMultiWrapperInterface, name=%s", config.getClassName()); - LOGGER.error(msg, e); - - throw new Error(msg, e); - } - } - - public static void genSingleWrapperInterface(ClassConfig config) { - try { - config.addInterface(SingleWrapper.class); - - config.addMethod(genReadFieldMethodSource(config.getFieldList())); - config.addMethod(genWriteFieldMethodSource(config.getFieldList())); - } catch (Exception e) { - String msg = String.format("failed to genSingleWrapperMethod, name=%s", config.getClassName()); - LOGGER.error(msg, e); - - throw new Error(msg, e); - } - } - - private static String genReadFieldsMethodSource(List fieldList) { - StringBuilder sb = new StringBuilder(); - sb.append("public Object[] readFields(){"); - sb.append(String.format("Object values[] = new Object[%d];", fieldList.size())); - - for (int idx = 0; idx < fieldList.size(); idx++) { - String fieldName = fieldList.get(idx).getName(); - String code = String.format(" values[%d] = %s;", - idx, - fieldName); - - sb.append(code); - } - sb.append("return values;"); - sb.append("}"); - - return sb.toString(); - } - - private static String genWriteFieldsMethodSource(List fieldList) { - StringBuilder sb = new StringBuilder(); - sb.append("public void writeFields(Object[] values){"); - for (int idx = 0; idx < fieldList.size(); idx++) { - FieldConfig fieldConfig = fieldList.get(idx); - - String fieldName = fieldConfig.getName(); - String code = String.format(" %s = (%s)values[%d];", - fieldName, - fieldConfig.getType().getCtClass().getName(), - idx); - - sb.append(code); - } - sb.append("}"); - - return sb.toString(); - } - - private static String genReadFieldMethodSource(List fieldList) { - StringBuilder sb = new StringBuilder(); - sb.append("public Object readField(){"); - - String fieldName = "null"; - if (!fieldList.isEmpty()) { - fieldName = fieldList.get(0).getName(); - } - - sb.append(String.format(" return %s;", fieldName)); - sb.append("}"); - - return sb.toString(); - } - - private static String genWriteFieldMethodSource(List fieldList) { - StringBuilder sb = new StringBuilder(); - sb.append("public void writeField(Object value){"); - - if (!fieldList.isEmpty()) { - FieldConfig fieldConfig = fieldList.get(0); - sb.append( - String.format(" %s=(%s)value;", - fieldConfig.getName(), - fieldConfig.getType().getCtClass().getName())); - } - - sb.append("}"); - - return sb.toString(); - } - - private static CtField createCtField(CtClass ctClass, FieldConfig field) throws CannotCompileException { - CtField ctField = new CtField(field.getType().getCtClass(), field.getName(), ctClass); - if (field.getType().hasGenericTypes()) { - ctField.setGenericSignature(field.getType().getGenericSignature()); - } - ctField.setModifiers(Modifier.PUBLIC); - return ctField; - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MethodConfig.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MethodConfig.java deleted file mode 100644 index 437c308c368..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MethodConfig.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.JavaType; - -public class MethodConfig { - private String name; - - private CtType result; - - private List parameterList = new ArrayList<>(); - - // 不包括前后的{} - private String bodySource; - - // 根据上面的信息,生成下面两个字段 - // 包括method声明和body - // 如果是接口,则只是method声明 - private String source; - - // 泛型声明,如果method参数及应答中没有泛型类型,则此字段应该为null - private String genericSignature; - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - public String getGenericSignature() { - return genericSignature; - } - - public void setGenericSignature(String genericSignature) { - this.genericSignature = genericSignature; - } - - public void setName(String name) { - this.name = name; - } - - public void setResult(JavaType javaType) { - this.result = new CtType(javaType); - } - - public void setResult(CtType result) { - this.result = result; - } - - public void addParameter(String name, JavaType javaType) { - addParameter(name, new CtType(javaType)); - } - - public void addParameter(String name, CtType ctType) { - ParameterConfig parameterConfig = new ParameterConfig(); - parameterConfig.setName(name); - parameterConfig.setType(ctType); - parameterList.add(parameterConfig); - } - - public void setBodySource(String bodySource) { - this.bodySource = bodySource; - } - - void init() { - if (source != null) { - return; - } - - StringBuilder sbMethod = new StringBuilder(); - StringBuilder sbMethodGenericSignature = new StringBuilder(); - - sbMethod.append("public "); - sbMethod.append(result == null ? "void" : result.getCtClass().getName()); - sbMethod.append(" ") - .append(name) - .append("("); - sbMethodGenericSignature.append("("); - - boolean hasGenericSignature = result != null && result.hasGenericTypes(); - for (ParameterConfig parameter : parameterList) { - hasGenericSignature = hasGenericSignature || parameter.getType().hasGenericTypes(); - - String paramTypeName = parameter.getType().getCtClass().getName(); - String code = String.format("%s %s,", paramTypeName, parameter.getName()); - sbMethod.append(code); - sbMethodGenericSignature.append(parameter.getType().getGenericSignature()); - } - - if (!parameterList.isEmpty()) { - sbMethod.setLength(sbMethod.length() - 1); - } - sbMethod.append(")"); - sbMethodGenericSignature.append(")"); - sbMethodGenericSignature.append(result == null ? "V" : result.getGenericSignature()); - - if (bodySource != null) { - sbMethod.append("{").append(bodySource).append("}"); - } else { - sbMethod.append(";"); - } - - source = sbMethod.toString(); - if (hasGenericSignature) { - genericSignature = sbMethodGenericSignature.toString(); - } - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MultiWrapper.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MultiWrapper.java deleted file mode 100644 index 4449e042d48..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/MultiWrapper.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -public interface MultiWrapper { - void writeFields(Object[] values); - - Object[] readFields(); -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ParameterConfig.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ParameterConfig.java deleted file mode 100644 index 3234ccb655e..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/ParameterConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -public class ParameterConfig { - private String name; - - private CtType type; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public CtType getType() { - return type; - } - - public void setType(CtType type) { - this.type = type; - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/SingleWrapper.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/SingleWrapper.java deleted file mode 100644 index 26590b098fc..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/SingleWrapper.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -public interface SingleWrapper { - void writeField(Object value); - - Object readField(); -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPool.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPool.java deleted file mode 100644 index 6f54754e1a8..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPool.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import javassist.ClassPool; -import javassist.CtClass; -import javassist.scopedpool.ScopedClassPool; -import javassist.scopedpool.ScopedClassPoolRepository; - -/** - * getCached of ScopedClassPool, not only search self and parent - * but also search other ScopedClassPool in repository - * - * this is not what we want, so change getCached behavior - */ -public class StdScopedClassPool extends ScopedClassPool { - protected StdScopedClassPool(ClassLoader cl, ClassPool src, - ScopedClassPoolRepository repository, boolean isTemp) { - super(cl, src, repository, isTemp); - } - - @Override - protected CtClass getCached(String classname) { - return getCachedLocally(classname); - } -} diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPoolFactory.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPoolFactory.java deleted file mode 100644 index 411da775de6..00000000000 --- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/StdScopedClassPoolFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import javassist.ClassPool; -import javassist.scopedpool.ScopedClassPool; -import javassist.scopedpool.ScopedClassPoolFactory; -import javassist.scopedpool.ScopedClassPoolRepository; - -public class StdScopedClassPoolFactory implements ScopedClassPoolFactory { - /** - * Makes an instance. - */ - public ScopedClassPool create(ClassLoader cl, ClassPool src, - ScopedClassPoolRepository repository) { - return new StdScopedClassPool(cl, src, repository, false); - } - - /** - * Makes an instance. - */ - public ScopedClassPool create(ClassPool src, - ScopedClassPoolRepository repository) { - return new StdScopedClassPool(null, src, repository, true); - } -} \ No newline at end of file diff --git a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtType.java b/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtType.java deleted file mode 100644 index 1a6760e3917..00000000000 --- a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtType.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import javassist.ClassPool; -import javassist.CtClass; -import javassist.NotFoundException; - -public class TestCtType { - CtType ctType; - - @Test - public void fromCtClass() { - CtClass ctClass = Mockito.mock(CtClass.class); - Mockito.when(ctClass.getName()).thenReturn("a.b.c"); - ctType = new CtType(ctClass); - - Assert.assertSame(ctClass, ctType.getCtClass()); - Assert.assertFalse(ctType.hasGenericTypes()); - Assert.assertEquals("La/b/c;", ctType.getGenericSignature()); - } - - @Test - public void fromCtClass_fullInfo() { - CtClass ctClass = Mockito.mock(CtClass.class); - ctType = new CtType(ctClass, true, "Ljava/util/List<[B;>;"); - - Assert.assertSame(ctClass, ctType.getCtClass()); - Assert.assertTrue(ctType.hasGenericTypes()); - Assert.assertEquals("Ljava/util/List<[B>;", ctType.getGenericSignature()); - } - - @Test - public void fromJavaType() throws NotFoundException { - Class cls = String.class; - JavaType javaType = TypeFactory.defaultInstance().constructType(cls); - ctType = new CtType(javaType); - - Assert.assertSame(JavassistUtils.getOrCreateClassPool(cls.getClassLoader()) - .get(cls.getCanonicalName()), ctType.getCtClass()); - Assert.assertFalse(ctType.hasGenericTypes()); - Assert.assertEquals("Ljava/lang/String;", ctType.getGenericSignature()); - } - - @Test - public void fromJavaType_primitive() throws NotFoundException { - Class cls = int.class; - JavaType javaType = TypeFactory.defaultInstance().constructType(cls); - ctType = new CtType(javaType); - - Assert.assertSame(JavassistUtils.getOrCreateClassPool(Integer.class.getClassLoader()) - .get(Integer.class.getCanonicalName()), ctType.getCtClass()); - Assert.assertFalse(ctType.hasGenericTypes()); - Assert.assertEquals("I;", ctType.getGenericSignature()); - } - - @Test - public void fromJavaType_bytes() throws NotFoundException { - Class cls = byte[].class; - JavaType javaType = TypeFactory.defaultInstance().constructType(cls); - ctType = new CtType(javaType); - - Assert.assertSame(JavassistUtils.getOrCreateClassPool(cls.getClassLoader()) - .get(cls.getCanonicalName()), ctType.getCtClass()); - Assert.assertFalse(ctType.hasGenericTypes()); - Assert.assertEquals("[B;", ctType.getGenericSignature()); - } - - @Test - public void fromJavaType_listBytes() throws NotFoundException { - JavaType javaType = TypeFactory.defaultInstance().constructCollectionType(List.class, byte[].class); - ctType = new CtType(javaType); - - Assert.assertSame(JavassistUtils.getOrCreateClassPool(List.class.getClassLoader()) - .get(List.class.getCanonicalName()), ctType.getCtClass()); - Assert.assertTrue(ctType.hasGenericTypes()); - Assert.assertEquals("Ljava/util/List<[B>;", ctType.getGenericSignature()); - } - - @Test - public void fromCtTypeJavaType() throws NotFoundException { - CtClass ctClass = ClassPool.getDefault().get(String.class.getCanonicalName()); - CtType otherCtType = new CtType(ctClass, false, "Ljava/lang/String;"); - CtTypeJavaType ctTypeJavaType = new CtTypeJavaType(otherCtType); - - ctType = new CtType(ctTypeJavaType); - - Assert.assertSame(ctClass, ctType.getCtClass()); - Assert.assertFalse(ctType.hasGenericTypes()); - Assert.assertEquals("Ljava/lang/String;", ctType.getGenericSignature()); - } - - @Test - public void fromJavaType_void() { - final JavaType voidJavaType = TypeFactory.defaultInstance().constructType(void.class); - CtType voidCtType = new CtType(voidJavaType); - - Assert.assertTrue(voidCtType.getCtClass().isPrimitive()); - Assert.assertEquals("void", voidCtType.getCtClass().getName()); - } -} diff --git a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtTypeJavaType.java b/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtTypeJavaType.java deleted file mode 100644 index 9ec4ea96c5f..00000000000 --- a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestCtTypeJavaType.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.javassist; - -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -public class TestCtTypeJavaType { - Class cls = TestCtTypeJavaType.class; - - JavaType javaType = TypeFactory.defaultInstance().constructType(cls); - - CtType ctType = new CtType(javaType); - - CtTypeJavaType ctTypeJavaType = new CtTypeJavaType(ctType); - - @Test - public void construct() { - Assert.assertSame(ctType, ctTypeJavaType.getType()); - Assert.assertEquals(cls.getTypeName(), ctTypeJavaType.buildCanonicalName()); - } - - @Test - public void getGenericSignature() { - JavaType listJavaType = TypeFactory.defaultInstance().constructCollectionType(List.class, ctTypeJavaType); - Assert.assertEquals("Ljava/util/List;", - listJavaType.getGenericSignature()); - } - - /** - * The {@link CtTypeJavaType} with different CtType should holds different hash code. - */ - @Test - public void testHashCode() { - JavaType newJavaType = TypeFactory.defaultInstance().constructType(String.class); - CtType newCtType = new CtType(newJavaType); - CtTypeJavaType newCtTypeJavaType = new CtTypeJavaType(newCtType); - Assert.assertNotEquals(ctTypeJavaType.hashCode(), newCtTypeJavaType.hashCode()); - - newJavaType = TypeFactory.defaultInstance().constructType(cls); - newCtType = new CtType(newJavaType); - newCtTypeJavaType = new CtTypeJavaType(newCtType); - Assert.assertEquals(ctTypeJavaType.hashCode(), newCtTypeJavaType.hashCode()); - } - - /** - * The {@link CtTypeJavaType}s holding different type information should not equal to each others. - * While those holding the same type information should be equal. - */ - @Test - public void testEquals() { - JavaType newJavaType = TypeFactory.defaultInstance().constructType(String.class); - CtType newCtType = new CtType(newJavaType); - CtTypeJavaType newCtTypeJavaType = new CtTypeJavaType(newCtType); - Assert.assertNotEquals(ctTypeJavaType, newCtTypeJavaType); - - newJavaType = TypeFactory.defaultInstance().constructType(cls); - newCtType = new CtType(newJavaType); - newCtTypeJavaType = new CtTypeJavaType(newCtType); - Assert.assertEquals(ctTypeJavaType, newCtTypeJavaType); - - // test subClass of CtTypeJavaType - newJavaType = TypeFactory.defaultInstance().constructType(cls); - newCtType = new CtType(newJavaType); - newCtTypeJavaType = new CtTypeJavaType(newCtType) { - private static final long serialVersionUID = 1876189050753964880L; - }; - Assert.assertEquals(ctTypeJavaType, newCtTypeJavaType); - } -} diff --git a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java b/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java deleted file mode 100644 index b28a4db8418..00000000000 --- a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.javassist; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.google.common.hash.Hashing; - -import javassist.ClassPool; -import javassist.scopedpool.ScopedClassPoolRepositoryImpl; -import mockit.Deencapsulation; - -public class TestJavassistUtils { - @Test - public void testField() throws Exception { - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName("servicecomb.ut.testField"); - - FieldConfig fieldConfig = classConfig.addField("intField", int.class); - fieldConfig.setGenGetter(true); - fieldConfig.setGenSetter(true); - - fieldConfig = classConfig.addField("intArrayField", int[].class); - fieldConfig.setGenGetter(true); - fieldConfig.setGenSetter(true); - - fieldConfig = classConfig - .addField("listStringField", TypeFactory.defaultInstance().constructCollectionType(List.class, String.class)); - fieldConfig.setGenGetter(true); - fieldConfig.setGenSetter(true); - - fieldConfig = classConfig.addField("bool", TypeFactory.defaultInstance().constructType(boolean.class)); - fieldConfig.setGenGetter(true); - - fieldConfig = classConfig.addField("wrapperBool", TypeFactory.defaultInstance().constructType(Boolean.class)); - fieldConfig.setGenGetter(true); - - Class cls = JavassistUtils.createClass(classConfig); - - Field field = cls.getField("intField"); - Assert.assertEquals(Integer.class, field.getType()); - - Method method = cls.getMethod("getIntField"); - Assert.assertEquals(Integer.class, method.getReturnType()); - - field = cls.getField("intArrayField"); - Assert.assertEquals(int[].class, field.getType()); - - method = cls.getMethod("getIntArrayField"); - Assert.assertEquals(int[].class, method.getReturnType()); - - field = cls.getField("listStringField"); - Assert.assertEquals("java.util.List", field.getGenericType().getTypeName()); - - method = cls.getMethod("getListStringField"); - Assert.assertEquals("java.util.List", method.getGenericReturnType().getTypeName()); - - method = cls.getMethod("isBool"); - Assert.assertEquals(Boolean.class, method.getReturnType()); - - method = cls.getMethod("isWrapperBool"); - Assert.assertEquals(Boolean.class, method.getReturnType()); - } - - @Test - public void testAddParameter() { - ClassConfig classConfig = new ClassConfig(); - classConfig.setIntf(true); - String intfName = "servicecomb.ut.TestAddParameter"; - classConfig.setClassName(intfName); - - MethodConfig methodConfig = new MethodConfig(); - methodConfig.setName("method"); - methodConfig.setResult(TypeFactory.defaultInstance().constructCollectionType(List.class, String.class)); - methodConfig - .addParameter("map", TypeFactory.defaultInstance().constructMapType(Map.class, String.class, String.class)); - methodConfig.addParameter("set", TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class)); - classConfig.addMethod(methodConfig); - - Class intf = JavassistUtils.createClass(classConfig); - - Assert.assertEquals(intfName, intf.getName()); - Method method = ReflectUtils.findMethod(intf, "method"); - Assert.assertEquals("method", method.getName()); - Assert.assertEquals("java.util.List", method.getGenericReturnType().getTypeName()); - - Type[] types = method.getGenericParameterTypes(); - Assert.assertEquals("java.util.Map", types[0].getTypeName()); - Assert.assertEquals("java.util.Set", types[1].getTypeName()); - } - - @Test - public void testInterface() { - ClassConfig classConfig = new ClassConfig(); - classConfig.setIntf(true); - String intfName = "servicecomb.ut.TestInterface"; - classConfig.setClassName(intfName); - - String source = "java.util.List method(java.util.Map map, java.util.Set set);"; - String genericSignature = - "(Ljava/util/Map;Ljava/util/Set;)Ljava/util/List;"; - classConfig.addMethod(source, genericSignature); - - Class intf = JavassistUtils.createClass(classConfig); - - Assert.assertEquals(intfName, intf.getName()); - Method method = ReflectUtils.findMethod(intf, "method"); - Assert.assertEquals("method", method.getName()); - Assert.assertEquals("java.util.List", method.getGenericReturnType().getTypeName()); - - Type[] types = method.getGenericParameterTypes(); - Assert.assertEquals("java.util.Map", types[0].getTypeName()); - Assert.assertEquals("java.util.Set", types[1].getTypeName()); - } - - @Test - public void singleWrapperInt() throws Exception { - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName("servicecomb.ut.single.IntWrapper"); - classConfig.addField("intField", TypeFactory.defaultInstance().constructType(int.class)); - - JavassistUtils.genSingleWrapperInterface(classConfig); - - Class wrapperClass = JavassistUtils.createClass(classConfig); - - SingleWrapper instance = (SingleWrapper) wrapperClass.newInstance(); - instance.writeField(100); - int intFieldValue = (int) instance.readField(); - Assert.assertEquals(100, intFieldValue); - } - - @Test - public void multiWrapper() throws Exception { - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName("servicecomb.ut.multi.Wrapper"); - classConfig.addField("intField", int.class); - classConfig.addField("strField", String.class); - - JavassistUtils.genMultiWrapperInterface(classConfig); - - Class wrapperClass = JavassistUtils.createClass(classConfig); - - MultiWrapper instance = (MultiWrapper) wrapperClass.newInstance(); - instance.writeFields(new Object[] {100, "test"}); - Object[] fieldValues = instance.readFields(); - Assert.assertEquals(100, fieldValues[0]); - Assert.assertEquals("test", fieldValues[1]); - } - - @Test - public void getOrCreateEnumWithClassName_get() { - Class cls = Status.class; - - Assert.assertSame(cls, - JavassistUtils.getOrCreateEnumWithClassName(Thread.currentThread().getContextClassLoader(), - Status.class.getName(), - null)); - } - - @Test - public void getOrCreateEnumWithClassName_create() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - String name = "servicecomb.ut.EnumAbc"; - Assert.assertNull(ClassPool.getDefault().getOrNull(name)); - - @SuppressWarnings("rawtypes") - Class cls = - JavassistUtils - .getOrCreateEnumWithClassName(Thread.currentThread().getContextClassLoader(), - name, - Arrays.asList("a", "b")); - checkEnum(name, cls); - } - - @Test - public void getOrCreateEnumWithPackageName() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - List enums = Arrays.asList("a", "b"); - String packageName = "servicecomb.ut"; - String clsName = - packageName + ".Enum_" + Hashing.sha256().hashString(enums.toString(), StandardCharsets.UTF_8).toString(); - Assert.assertNull(ClassPool.getDefault().getOrNull(clsName)); - - @SuppressWarnings("rawtypes") - Class cls = - JavassistUtils - .getOrCreateEnumWithPackageName(Thread.currentThread().getContextClassLoader(), - packageName, - Arrays.asList("a", "b")); - - checkEnum(clsName, cls); - Assert.assertSame(cls, - JavassistUtils - .getOrCreateEnumWithPackageName(Thread.currentThread().getContextClassLoader(), - packageName, - Arrays.asList("a", "b"))); - } - - @Test - public void testEnum() throws Exception { - String name = "servicecomb.ut.EnumAbc2"; - @SuppressWarnings("rawtypes") - Class cls = JavassistUtils.createEnum(name, "a", "b"); - checkEnum(name, cls); - } - - @SuppressWarnings("rawtypes") - protected void checkEnum(String expectName, Class cls) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - Method method = cls.getMethod("values"); - Enum[] values = (Enum[]) method.invoke(null); - - Assert.assertEquals(expectName, cls.getName()); - Assert.assertEquals(2, values.length); - Assert.assertEquals("a", values[0].name()); - Assert.assertEquals(0, values[0].ordinal()); - Assert.assertEquals("b", values[1].name()); - Assert.assertEquals(1, values[1].ordinal()); - } - - @Test - public void managerClassPool() { - ClassLoader classLoader1 = new ClassLoader() { - }; - ClassLoader classLoader2 = new ClassLoader() { - }; - - ClassPool p1 = Deencapsulation.invoke(JavassistUtils.class, "getOrCreateClassPool", classLoader1); - ClassPool p2 = Deencapsulation.invoke(JavassistUtils.class, "getOrCreateClassPool", classLoader2); - Assert.assertNotSame(p1, p2); - - JavassistUtils.clearByClassLoader(classLoader1); - Assert.assertFalse(ScopedClassPoolRepositoryImpl.getInstance().getRegisteredCLs().containsKey(classLoader1)); - - JavassistUtils.clearByClassLoader(classLoader2); - Assert.assertFalse(ScopedClassPoolRepositoryImpl.getInstance().getRegisteredCLs().containsKey(classLoader2)); - } -} diff --git a/common/common-javassist/src/test/resources/log4j.properties b/common/common-javassist/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/common/common-javassist/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/common/common-protobuf/pom.xml b/common/common-protobuf/pom.xml index 18f58ee92b6..5b7ac5fcf7c 100644 --- a/common/common-protobuf/pom.xml +++ b/common/common-protobuf/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb common - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT common-protobuf Java Chassis::Common::Protobuf @@ -31,24 +31,26 @@ org.apache.servicecomb java-chassis-core - - org.apache.servicecomb - common-javassist - org.apache.servicecomb foundation-protobuf + + + com.google.protobuf + protobuf-java + test + - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test @@ -61,4 +63,29 @@ foundation-test-scaffolding + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protoc3-maven-plugin.version}:exe:${os.detected.classifier} + true + grpc-java + io.grpc:protoc-gen-grpc-java:${protoc-gen-grpc-java-plugin.version}:exe:${os.detected.classifier} + + + + + generate-test-sources + + test-compile + + + + + + diff --git a/common/common-protobuf/src/main/java/io/protostuff/MapSchemaUtils.java b/common/common-protobuf/src/main/java/io/protostuff/MapSchemaUtils.java deleted file mode 100644 index ab6362aee51..00000000000 --- a/common/common-protobuf/src/main/java/io/protostuff/MapSchemaUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.protostuff; - -import java.util.Map; - -import io.protostuff.MapSchema.MapWrapper; - -public final class MapSchemaUtils { - private MapSchemaUtils() { - } - - public static MapWrapper createMapWrapper(Map map) { - return new MapWrapper<>(map); - } -} diff --git a/common/common-protobuf/src/main/java/io/protostuff/runtime/ProtobufCompatibleUtils.java b/common/common-protobuf/src/main/java/io/protostuff/runtime/ProtobufCompatibleUtils.java deleted file mode 100644 index ac625b728b1..00000000000 --- a/common/common-protobuf/src/main/java/io/protostuff/runtime/ProtobufCompatibleUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.protostuff.runtime; - -import java.io.IOException; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Pipe; -import io.protostuff.WireFormat.FieldType; - -/** - * protostuff实现protobuf逻辑时,关于map的编码与protobuf不兼容 - * 这里修改map的编码逻辑 - */ -public final class ProtobufCompatibleUtils { - private static boolean inited = false; - - private ProtobufCompatibleUtils() { - } - - public static void init() { - if (inited) { - return; - } - - replaceRuntimeFieldFactoryMap(); - - inited = true; - } - - protected static void replaceRuntimeFieldFactoryMap() { - RuntimeFieldFactory> org = RuntimeMapFieldFactory.MAP; - RuntimeFieldFactory> map = new RuntimeFieldFactory>( - RuntimeFieldFactory.ID_MAP) { - - @Override - public FieldType getFieldType() { - return org.getFieldType(); - } - - @Override - public Map readFrom(Input input) throws IOException { - return org.readFrom(input); - } - - @Override - public void writeTo(Output output, int number, Map value, - boolean repeated) throws IOException { - org.writeTo(output, number, value, repeated); - } - - @Override - public void transfer(Pipe pipe, Input input, Output output, int number, - boolean repeated) throws IOException { - org.transfer(pipe, input, output, number, repeated); - } - - @Override - public Class typeClass() { - return org.typeClass(); - } - - @Override - public Field create(int number, String name, java.lang.reflect.Field field, IdStrategy strategy) { - @SuppressWarnings("unchecked") - RuntimeMapField runtimeMapField = - (RuntimeMapField) org.create(number, name, field, strategy); - - return new RuntimeMapFieldProtobuf<>(runtimeMapField, field); - } - }; - - ReflectUtils.setField(RuntimeMapFieldFactory.class, null, "MAP", map); - } -} diff --git a/common/common-protobuf/src/main/java/io/protostuff/runtime/RuntimeMapFieldProtobuf.java b/common/common-protobuf/src/main/java/io/protostuff/runtime/RuntimeMapFieldProtobuf.java deleted file mode 100644 index 4489cbf8140..00000000000 --- a/common/common-protobuf/src/main/java/io/protostuff/runtime/RuntimeMapFieldProtobuf.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.protostuff.runtime; - -import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; - -import org.springframework.util.ReflectionUtils; - -import io.protostuff.ByteArrayInput; -import io.protostuff.ByteBufferInput; -import io.protostuff.Input; -import io.protostuff.MapSchema; -import io.protostuff.MapSchema.MapWrapper; -import io.protostuff.MapSchemaUtils; -import io.protostuff.Output; -import io.protostuff.Pipe; -import io.protostuff.ProtostuffException; -import io.protostuff.Schema; - -public class RuntimeMapFieldProtobuf extends RuntimeMapField { - private static java.lang.reflect.Field entrySchemaField = - ReflectionUtils.findField(MapSchema.class, "entrySchema"); - - static { - entrySchemaField.setAccessible(true); - } - - private RuntimeMapField runtimeMapField; - - private java.lang.reflect.Field field; - - private Schema> entrySchema; - - @SuppressWarnings("unchecked") - public RuntimeMapFieldProtobuf(RuntimeMapField runtimeMapField, - java.lang.reflect.Field field) { - super(runtimeMapField.type, runtimeMapField.number, runtimeMapField.name, null, - runtimeMapField.schema.messageFactory); - - entrySchema = (Schema>) ReflectionUtils.getField(entrySchemaField, - runtimeMapField.schema); - - this.runtimeMapField = runtimeMapField; - this.field = field; - } - - @SuppressWarnings("unchecked") - @Override - protected void mergeFrom(Input input, T message) throws IOException { - Map value = null; - try { - value = (Map) field.get(message); - if (value == null) { - value = schema.newMessage(); - field.set(message, value); - } - } catch (Exception e) { - throw new ProtostuffException( - "Failed to get or set map field " + field.getDeclaringClass().getName() + ":" + field.getName(), - e); - } - - MapWrapper mapWrapper = MapSchemaUtils.createMapWrapper(value); - if (ByteArrayInput.class.isInstance(input)) { - ((ByteArrayInput) input).readRawVarint32(); - } else if (ByteBufferInput.class.isInstance(input)) { - ((ByteBufferInput) input).readRawVarint32(); - } else { - throw new Error("not handler " + input.getClass().getName()); - } - - int keyNumber = input.readFieldNumber(schema); - if (keyNumber != 1) { - throw new ProtostuffException( - "The map was incorrectly serialized, expect key number 1, but be " + keyNumber); - } - Object key = kFrom(input, mapWrapper); - - int valueNumber = input.readFieldNumber(schema); - if (valueNumber != 2) { - throw new ProtostuffException( - "The map was incorrectly serialized, expect value number 2, but be " + valueNumber); - } - vPutFrom(input, mapWrapper, key); - } - - @Override - @SuppressWarnings("unchecked") - protected void writeTo(Output output, T message) throws IOException { - final Map existing; - try { - existing = (Map) field.get(message); - } catch (Exception e) { - throw new RuntimeException(e); - } - - if (existing != null) { - for (Entry entry : existing.entrySet()) { - output.writeObject(number, entry, entrySchema, true); - } - } - } - - @Override - protected void transfer(Pipe pipe, Input input, Output output, - boolean repeated) throws IOException { - runtimeMapField.transfer(pipe, input, output, repeated); - } - - @Override - protected Object kFrom(Input input, - MapWrapper wrapper) throws IOException { - return runtimeMapField.kFrom(input, wrapper); - } - - @Override - protected void kTo(Output output, int fieldNumber, Object key, - boolean repeated) throws IOException { - runtimeMapField.kTo(output, fieldNumber, key, repeated); - } - - @Override - protected void kTransfer(Pipe pipe, Input input, Output output, - int number, boolean repeated) throws IOException { - runtimeMapField.kTransfer(pipe, input, output, number, repeated); - } - - @Override - protected void vPutFrom(Input input, - MapWrapper wrapper, Object key) throws IOException { - runtimeMapField.vPutFrom(input, wrapper, key); - } - - @Override - protected void vTo(Output output, int fieldNumber, Object val, - boolean repeated) throws IOException { - runtimeMapField.vTo(output, fieldNumber, val, repeated); - } - - @Override - protected void vTransfer(Pipe pipe, Input input, Output output, - int number, boolean repeated) throws IOException { - runtimeMapField.vTransfer(pipe, input, output, number, repeated); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/HighwayJsonUtils.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/HighwayJsonUtils.java new file mode 100644 index 00000000000..bb9925308a6 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/HighwayJsonUtils.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; + +import org.apache.servicecomb.foundation.common.utils.RestObjectMapper; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * Add a separate converter for highway. Now highway compile types depends on swagger information, do not use any consumer information, + * This will cause any invocation will convert swagger raw types to consumer types. This will lose performance. + * + * In later improvements, need add consumer information to OperationProtobuf. + * + * Why not using RestObjectMapper? Because the reason above, highway use java.util.Date for date-time, and will serialize to a String + * that can not convert to LocalDateTime. (This is a jackson change to format java.util.Date to `2017-07-21T16:32:28.320+0000` + * but jackson can only convert `2017-07-21T16:32:28.320Z` to LocalDateTime + */ +public class HighwayJsonUtils { + + public static final ObjectMapper OBJ_MAPPER = new RestObjectMapper(); + + + private HighwayJsonUtils() { + + } + + @SuppressWarnings("unchecked") + public static T convertValue(Object fromValue, JavaType toValueType) { + if (fromValue == null) { + return null; + } + + if (TypeFactory.defaultInstance().constructType(LocalDateTime.class).equals(toValueType)) { + // jackson do not have a proper converter for this. + if (fromValue instanceof Date) { + return (T) LocalDateTime.ofInstant(Instant.ofEpochMilli(((Date) fromValue).getTime()), ZoneOffset.UTC); + } + } + return OBJ_MAPPER.convertValue(fromValue, toValueType); + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java index 08c5a9d85b7..6c12da844de 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/OperationProtobuf.java @@ -17,52 +17,163 @@ package org.apache.servicecomb.codec.protobuf.definition; -import java.lang.reflect.Method; - -import javax.ws.rs.core.Response.Status.Family; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Map.Entry; import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.compiler.model.Message; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status.Family; -public class OperationProtobuf { - private ScopedProtobufSchemaManager scopedProtobufSchemaManager; +public final class OperationProtobuf { + private RequestRootSerializer requestRootSerializer; - private OperationMeta operationMeta; + private RequestRootDeserializer requestRootDeserializer; - private WrapSchema requestSchema; + private ResponseRootSerializer responseRootSerializer; - private WrapSchema responseSchema; + private ResponseRootDeserializer responseRootDeserializer; - public OperationProtobuf(ScopedProtobufSchemaManager scopedProtobufSchemaManager, OperationMeta operationMeta) { - this.scopedProtobufSchemaManager = scopedProtobufSchemaManager; - this.operationMeta = operationMeta; + private ResponseRootSerializer anyResponseRootSerializer; - requestSchema = scopedProtobufSchemaManager.getOrCreateArgsSchema(operationMeta); + private ResponseRootDeserializer anyResponseRootDeserializer; - Method method = operationMeta.getMethod(); - responseSchema = scopedProtobufSchemaManager.getOrCreateSchema(method.getGenericReturnType()); + public OperationProtobuf(ScopedProtobufSchemaManager scopedProtobufSchemaManager, Invocation invocation) { + initRequestCodec(scopedProtobufSchemaManager, invocation); + initResponseCodec(scopedProtobufSchemaManager, invocation); } - public OperationMeta getOperationMeta() { - return operationMeta; + public RequestRootSerializer getRequestRootSerializer() { + return this.requestRootSerializer; } - public WrapSchema getRequestSchema() { - return requestSchema; + public RequestRootDeserializer getRequestRootDeserializer() { + return this.requestRootDeserializer; } - public WrapSchema getResponseSchema() { - return responseSchema; + public ResponseRootSerializer findResponseRootSerializer(int statusCode) { + if (Family.SUCCESSFUL.equals(Family.familyOf(statusCode))) { + return this.responseRootSerializer; + } + return anyResponseRootSerializer; } - public WrapSchema findResponseSchema(int statusCode) { + public ResponseRootDeserializer findResponseRootDeserializer(int statusCode) { if (Family.SUCCESSFUL.equals(Family.familyOf(statusCode))) { - return responseSchema; + return this.responseRootDeserializer; + } + return anyResponseRootDeserializer; + } + + private void initProducerRequestCodec(Invocation invocation, Message requestMessage, ProtoMapper mapper) { + Map swaggerParameterTypes = invocation.getOperationMeta().getSwaggerProducerOperation() + .getSwaggerParameterTypes(); + if (ProtoUtils.isWrapArguments(requestMessage)) { + requestRootDeserializer = new RequestRootDeserializer<>( + mapper.createRootDeserializer(requestMessage, swaggerParameterTypes), true, null); + } else { + if (swaggerParameterTypes.isEmpty()) { + requestRootDeserializer = new RequestRootDeserializer<>( + mapper.createRootDeserializer(requestMessage, Object.class), false, null); + } else if (swaggerParameterTypes.size() == 1) { + Entry entry = swaggerParameterTypes.entrySet().iterator().next(); + requestRootDeserializer = new RequestRootDeserializer<>(mapper.createRootDeserializer(requestMessage, + entry.getValue()), false, entry.getKey()); + } else { + throw new IllegalStateException( + "unexpected operation definition " + invocation.getOperationMeta().getMicroserviceQualifiedName()); + } + } + } + + private void initConsumerRequestCodec(Invocation invocation, Message requestMessage, ProtoMapper mapper) { + if (ProtoUtils.isWrapArguments(requestMessage)) { + requestRootSerializer = new RequestRootSerializer( + mapper.createRootSerializer(requestMessage, Object.class), true, false); + } else { + if (invocation.getOperationMeta().parameterCount() == 0) { + requestRootSerializer = new RequestRootSerializer(mapper.createRootSerializer(requestMessage, Object.class), + false, false); + } else if (invocation.getOperationMeta().parameterCount() == 1) { + requestRootSerializer = new RequestRootSerializer(mapper.createRootSerializer(requestMessage, + Object.class), false, true); + } else { + throw new IllegalStateException( + "unexpected operation definition " + invocation.getOperationMeta().getMicroserviceQualifiedName()); + } + } + } + + private void initRequestCodec(ScopedProtobufSchemaManager scopedProtobufSchemaManager, Invocation invocation) { + ProtoMapper mapper = scopedProtobufSchemaManager.getOrCreateProtoMapper(invocation.getSchemaMeta()); + Message requestMessage = mapper.getRequestMessage(invocation.getOperationMeta().getOperationId()); + + if (invocation.isProducer()) { + initProducerRequestCodec(invocation, requestMessage, mapper); + } else { + initConsumerRequestCodec(invocation, requestMessage, mapper); + } + } + + private void initProviderResponseCode(Message responseMessage, ProtoMapper mapper, + JavaType responseType) { + if (ProtoUtils.isWrapProperty(responseMessage)) { + responseRootSerializer = new ResponseRootSerializer( + mapper.createRootSerializer(responseMessage, responseType), true, false); + } else { + if (ProtoUtils.isEmptyMessage(responseMessage)) { + responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, + Object.class), false, false); + } else { + responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, + responseType), false, true); + } } + } + + private void initConsumerResponseCode(Message responseMessage, ProtoMapper mapper, + JavaType responseType) { + if (ProtoUtils.isWrapProperty(responseMessage)) { + responseRootSerializer = new ResponseRootSerializer( + mapper.createRootSerializer(responseMessage, responseType), true, false); + responseRootDeserializer = new ResponseRootDeserializer<>( + mapper.createRootDeserializer(responseMessage, responseType), false); + } else { + if (ProtoUtils.isEmptyMessage(responseMessage)) { + responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, + Object.class), false, false); + responseRootDeserializer = new ResponseRootDeserializer<>( + mapper.createRootDeserializer(responseMessage, Object.class), true); + } else { + responseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(responseMessage, + responseType), false, false); + responseRootDeserializer = new ResponseRootDeserializer<>( + mapper.createRootDeserializer(responseMessage, responseType), false); + } + } + } + + private void initResponseCodec(ScopedProtobufSchemaManager scopedProtobufSchemaManager, Invocation invocation) { + ProtoMapper mapper = scopedProtobufSchemaManager.getOrCreateProtoMapper(invocation.getSchemaMeta()); + Message responseMessage = mapper.getResponseMessage(invocation.getOperationMeta().getOperationId()); - ResponseMeta responseMeta = operationMeta.findResponseMeta(statusCode); - return scopedProtobufSchemaManager.getOrCreateSchema(responseMeta.getJavaType()); + JavaType responseType = invocation.findResponseType(Status.OK.getStatusCode()); + if (invocation.isProducer()) { + initProviderResponseCode(responseMessage, mapper, responseType); + } else { + initConsumerResponseCode(responseMessage, mapper, responseType); + } + anyResponseRootSerializer = new ResponseRootSerializer(mapper.createRootSerializer(ProtoConst.ANY, + Object.class), false, true); + anyResponseRootDeserializer = new ResponseRootDeserializer<>( + mapper.createRootDeserializer(ProtoConst.ANY, Object.class), false); } } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ProtobufManager.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ProtobufManager.java index 0d6278cebde..09ccb9d70cd 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ProtobufManager.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ProtobufManager.java @@ -17,47 +17,90 @@ package org.apache.servicecomb.codec.protobuf.definition; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import jakarta.ws.rs.core.Response.Status; + import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager; +import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; +import org.apache.servicecomb.swagger.invocation.InvocationType; -public final class ProtobufManager { - private static ProtobufManager instance = new ProtobufManager(); +import com.fasterxml.jackson.databind.JavaType; +import com.google.common.annotations.VisibleForTesting; +public final class ProtobufManager { public static final String EXT_ID = "protobuf"; private static final Object LOCK = new Object(); - private static ScopedProtobufSchemaManager defaultScopedProtobufSchemaManager = new ScopedProtobufSchemaManager( - JvmUtils.findClassLoader()); + static class RuntimeCacheKey { + final InvocationType invocationType; - private ProtobufManager() { - } + final String uniqueOperationId; - /** - * only for app classloader - * @return - */ - public static ScopedProtobufSchemaManager getDefaultScopedProtobufSchemaManager() { - return defaultScopedProtobufSchemaManager; + // Using response type as the cache key. + // May consider request type as well, but now not implemented + final JavaType responseType; + + public RuntimeCacheKey(InvocationType invocationType, String operationId, JavaType responseType) { + this.invocationType = invocationType; + this.uniqueOperationId = operationId; + this.responseType = responseType; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RuntimeCacheKey that = (RuntimeCacheKey) o; + + if (invocationType != that.invocationType) { + return false; + } + if (!uniqueOperationId.equals(that.uniqueOperationId)) { + return false; + } + return Objects.equals(responseType, that.responseType); + } + + @Override + public int hashCode() { + int result = invocationType.hashCode(); + result = 31 * result + uniqueOperationId.hashCode(); + result = 31 * result + (responseType != null ? responseType.hashCode() : 0); + return result; + } } - public static OperationProtobuf getOrCreateOperation(OperationMeta operationMeta) throws Exception { - OperationProtobuf operationProtobuf = operationMeta.getExtData(EXT_ID); + private static final Map RUNTIME_CACHE = new HashMap<>(); + + public static OperationProtobuf getOrCreateOperation(Invocation invocation) { + RuntimeCacheKey cacheKey = new RuntimeCacheKey(invocation.getInvocationType(), + invocation.getOperationMeta().getMicroserviceQualifiedName(), + invocation.findResponseType(Status.OK.getStatusCode())); + OperationProtobuf operationProtobuf = RUNTIME_CACHE.get(cacheKey); if (operationProtobuf == null) { synchronized (LOCK) { - MicroserviceMeta microserviceMeta = operationMeta.getMicroserviceMeta(); + MicroserviceMeta microserviceMeta = invocation.getMicroserviceMeta(); ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID); if (scopedProtobufSchemaManager == null) { - scopedProtobufSchemaManager = new ScopedProtobufSchemaManager(microserviceMeta.getClassLoader()); + scopedProtobufSchemaManager = new ScopedProtobufSchemaManager(); microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager); } - operationProtobuf = operationMeta.getExtData(EXT_ID); + operationProtobuf = RUNTIME_CACHE.get(cacheKey); if (operationProtobuf == null) { - operationProtobuf = new OperationProtobuf(scopedProtobufSchemaManager, operationMeta); - operationMeta.putExtData(EXT_ID, operationProtobuf); + operationProtobuf = new OperationProtobuf(scopedProtobufSchemaManager, invocation); + RUNTIME_CACHE.put(cacheKey, operationProtobuf); } } } @@ -65,7 +108,8 @@ public static OperationProtobuf getOrCreateOperation(OperationMeta operationMeta return operationProtobuf; } - public static ProtobufManager getInstance() { - return instance; + @VisibleForTesting + public static void clear() { + RUNTIME_CACHE.clear(); } } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java new file mode 100644 index 00000000000..ef4e75befdb --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootDeserializer.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; + +public class RequestRootDeserializer { + private final boolean wrapArgument; + + private final String parameterName; + + private final RootDeserializer rootDeserializer; + + public RequestRootDeserializer(RootDeserializer rootDeserializer, boolean wrapArgument, String parameterName) { + this.rootDeserializer = rootDeserializer; + this.wrapArgument = wrapArgument; + this.parameterName = parameterName; + } + + @SuppressWarnings("unchecked") + public Map deserialize(byte[] bytes) throws IOException { + if (!wrapArgument) { + Map result = new HashMap<>(1); + Object obj = rootDeserializer.deserialize(bytes); + if (obj instanceof PropertyWrapper) { + obj = ((PropertyWrapper) obj).getValue(); + } + if (parameterName == null) { + return result; + } + result.put(parameterName, obj); + return result; + } else { + return (Map) rootDeserializer.deserialize(bytes); + } + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootSerializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootSerializer.java new file mode 100644 index 00000000000..ac5763d9b57 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/RequestRootSerializer.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.io.IOException; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.RootSerializer; + +import io.vertx.core.json.JsonObject; + +public class RequestRootSerializer { + private final RootSerializer rootSerializer; + + private final boolean noTypesInfo; + + private final boolean isWrap; + + public RequestRootSerializer(RootSerializer serializer, boolean isWrap, boolean noTypesInfo) { + this.rootSerializer = serializer; + this.noTypesInfo = noTypesInfo; + this.isWrap = isWrap; + } + + @SuppressWarnings("unchecked") + public byte[] serialize(Object value) throws IOException { + if (noTypesInfo && !isWrap) { + Object param = ((Map) value).values().iterator().next(); + if (param instanceof JsonObject) { + param = ((JsonObject) param).getMap(); + } + return this.rootSerializer.serialize(param); + } else { + return this.rootSerializer.serialize(value); + } + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java new file mode 100644 index 00000000000..e64e45d8c62 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootDeserializer.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.io.IOException; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; + +import com.fasterxml.jackson.databind.JavaType; + +public class ResponseRootDeserializer { + private final RootDeserializer rootDeserializer; + + private final boolean empty; + + public ResponseRootDeserializer(RootDeserializer rootDeserializer, boolean empty) { + this.rootDeserializer = rootDeserializer; + this.empty = empty; + } + + @SuppressWarnings("unchecked") + public T deserialize(byte[] bytes, JavaType invocationTimeType) throws IOException { + if (empty) { + rootDeserializer.deserialize(bytes); // read buffers if possible. + return null; + } + + Object obj = rootDeserializer.deserialize(bytes); + if (obj instanceof PropertyWrapper) { + obj = ((PropertyWrapper) obj).getValue(); + } + if (needConvert(obj, invocationTimeType)) { + obj = HighwayJsonUtils.convertValue(obj, invocationTimeType); + } + return (T) obj; + } + + public static boolean needConvert(Object obj, JavaType invocationTimeType) { + if (obj == null || ClassUtils.isPrimitiveOrWrapper(obj.getClass()) || invocationTimeType.isPrimitive() + || ProtoConst.OBJECT_TYPE.equals(invocationTimeType)) { + return false; + } + + if (obj.getClass() == invocationTimeType.getRawClass()) { + return false; + } + + if (invocationTimeType.getRawClass().isAssignableFrom(obj.getClass())) { + if (invocationTimeType.getContentType() == null) { + return false; + } + } + + return true; + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootSerializer.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootSerializer.java new file mode 100644 index 00000000000..8af18a4a016 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/definition/ResponseRootSerializer.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.RootSerializer; + +public class ResponseRootSerializer { + private final RootSerializer rootSerializer; + + private final boolean noTypesInfo; + + private final boolean isWrap; + + public ResponseRootSerializer(RootSerializer serializer, boolean isWrap, boolean noTypesInfo) { + this.rootSerializer = serializer; + this.noTypesInfo = noTypesInfo; + this.isWrap = isWrap; + } + + public byte[] serialize(Object value) throws IOException { + if (noTypesInfo && !isWrap) { + return this.rootSerializer.serialize(value); + } else { + Map responseValue = new HashMap<>(1); + // key is fixed to "value" in IDL + responseValue.put("value", value); + return this.rootSerializer.serialize(responseValue); + } + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/BodyParameterAdapter.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/BodyParameterAdapter.java deleted file mode 100644 index cf4865670bc..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/BodyParameterAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.codec.protobuf.internal.converter; - -import java.util.List; - -import io.swagger.models.ArrayModel; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.RefModel; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; - -public class BodyParameterAdapter implements SwaggerTypeAdapter { - private final Model model; - - public BodyParameterAdapter(BodyParameter parameter) { - this.model = parameter.getSchema(); - } - - @Override - public String getRefType() { - if (model instanceof RefModel) { - return ((RefModel) model).getSimpleRef(); - } - - return null; - } - - @Override - public Property getArrayItem() { - if (model instanceof ArrayModel) { - return ((ArrayModel) model).getItems(); - } - - return null; - } - - @Override - public Property getMapItem() { - if (model instanceof ModelImpl) { - return ((ModelImpl) model).getAdditionalProperties(); - } - - return null; - } - - @Override - public List getEnum() { - if (model instanceof ModelImpl) { - return ((ModelImpl) model).getEnum(); - } - - return null; - } - - @Override - public String getType() { - if (model instanceof ModelImpl) { - return ((ModelImpl) model).getType(); - } - - return null; - } - - @Override - public String getFormat() { - if (model instanceof ModelImpl) { - return ((ModelImpl) model).getFormat(); - } - - return null; - } - - @Override - public boolean isObject() { - if (model instanceof ModelImpl) { - ModelImpl modelImpl = (ModelImpl) model; - return (ObjectProperty.TYPE.equals(modelImpl.getType()) - && modelImpl.getProperties() == null - && modelImpl.getName() == null); - } - - return false; - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/PropertyAdapter.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/PropertyAdapter.java deleted file mode 100644 index c23b08f36dd..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/PropertyAdapter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.codec.protobuf.internal.converter; - -import java.util.List; - -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; -import io.swagger.models.properties.StringProperty; - -public class PropertyAdapter implements SwaggerTypeAdapter { - private final Property property; - - public PropertyAdapter(Property property) { - this.property = property; - } - - @Override - public String getRefType() { - if (property instanceof RefProperty) { - return ((RefProperty) property).getSimpleRef(); - } - - return null; - } - - @Override - public Property getArrayItem() { - if (property instanceof ArrayProperty) { - return ((ArrayProperty) property).getItems(); - } - - return null; - } - - @Override - public Property getMapItem() { - if (property instanceof MapProperty) { - return ((MapProperty) property).getAdditionalProperties(); - } - - return null; - } - - @Override - public List getEnum() { - if (property instanceof StringProperty) { - return ((StringProperty) property).getEnum(); - } - - return null; - } - - @Override - public String getType() { - return property.getType(); - } - - @Override - public String getFormat() { - return property.getFormat(); - } - - @Override - public boolean isObject() { - return property instanceof ObjectProperty; - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoMethod.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoMethod.java index 4ae87ae7efd..885dae823c9 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoMethod.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoMethod.java @@ -18,21 +18,20 @@ import java.util.HashMap; import java.util.Map; - -import javax.ws.rs.core.Response.Status; +import java.util.Map.Entry; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.ws.rs.core.Response.Status; + public class ProtoMethod { private String argTypeName; - private boolean argWrapped; - @JsonProperty // key is status - private Map responses = new HashMap<>(); + private final Map responses = new HashMap<>(); private ProtoResponse defaultResponse; @@ -44,14 +43,6 @@ public void setArgTypeName(String argTypeName) { this.argTypeName = argTypeName; } - public boolean isArgWrapped() { - return argWrapped; - } - - public void setArgWrapped(boolean argWrapped) { - this.argWrapped = argWrapped; - } - public void addResponse(String status, ProtoResponse response) { if (status.equals("default")) { defaultResponse = response; @@ -72,6 +63,14 @@ public ProtoResponse findResponse(int statusCode) { return response; } + if (statusCode == Status.OK.getStatusCode()) { + for (Entry code : responses.entrySet()) { + if (HttpStatus.isSuccess(code.getKey())) { + return responses.get(code.getKey()); + } + } + } + if (HttpStatus.isSuccess(statusCode)) { return responses.get(Status.OK.getStatusCode()); } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoResponse.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoResponse.java index feaa4065f5f..19510f62d10 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoResponse.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoResponse.java @@ -19,8 +19,6 @@ public class ProtoResponse { private String typeName; - private boolean wrapped; - public String getTypeName() { return typeName; } @@ -28,12 +26,4 @@ public String getTypeName() { public void setTypeName(String typeName) { this.typeName = typeName; } - - public boolean isWrapped() { - return wrapped; - } - - public void setWrapped(boolean wrapped) { - this.wrapped = wrapped; - } } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoToStringGenerator.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoToStringGenerator.java index 4e1b9edb20a..589cad8a12d 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoToStringGenerator.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/ProtoToStringGenerator.java @@ -18,6 +18,10 @@ import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; +import java.util.List; + +import com.google.common.base.Strings; + import io.protostuff.compiler.model.Enum; import io.protostuff.compiler.model.EnumConstant; import io.protostuff.compiler.model.Field; @@ -59,9 +63,7 @@ public String protoToString() { private void serviceToString(Service service, StringBuilder sb) { appendLine(sb, "service %s {", service.getName()); for (ServiceMethod serviceMethod : service.getMethods()) { - if (!serviceMethod.getCommentLines().isEmpty()) { - appendLine(sb, " //" + serviceMethod.getComments()); - } + commentsToString(serviceMethod.getCommentLines(), sb, 2); appendLine(sb, " rpc %s (%s) returns (%s);\n", serviceMethod.getName(), serviceMethod.getArgTypeName(), serviceMethod.getReturnTypeName()); } @@ -79,7 +81,20 @@ protected void enumToString(Enum enumValue, StringBuilder sb) { sb.append("}\n\n"); } + private void commentsToString(List comments, StringBuilder sb, int padLeft) { + if (comments.isEmpty()) { + return; + } + + String pad = Strings.repeat(" ", padLeft) + "//"; + for (String comment : comments) { + sb.append(pad); + appendLine(sb, comment); + } + } + private void messageToString(Message message, StringBuilder sb) { + commentsToString(message.getCommentLines(), sb, 0); appendLine(sb, "message %s {", message.getName()); for (Field field : message.getFields()) { sb.append(" "); diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SchemaSwaggerTypeAdapter.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SchemaSwaggerTypeAdapter.java new file mode 100644 index 00000000000..68608e3db87 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SchemaSwaggerTypeAdapter.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.internal.converter; + +import java.util.List; + +import io.swagger.v3.oas.models.media.Schema; + +public class SchemaSwaggerTypeAdapter implements SwaggerTypeAdapter { + private final Schema schema; + + public SchemaSwaggerTypeAdapter(Schema schema) { + this.schema = schema; + } + + @Override + public String getRefType() { + return schema.get$ref(); + } + + @Override + public Schema getArrayItem() { + return schema.getItems(); + } + + @Override + public Schema getMapItem() { + return (Schema) schema.getAdditionalProperties(); + } + + @Override + @SuppressWarnings("unchecked") + public List getEnum() { + return (List) schema.getEnum(); + } + + @Override + public String getType() { + return schema.getType(); + } + + @Override + public String getFormat() { + return schema.getFormat(); + } + + @Override + public boolean isJavaLangObject() { + return "object".equals(getType()); + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SerializableParameterAdapter.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SerializableParameterAdapter.java deleted file mode 100644 index 205afa794ed..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SerializableParameterAdapter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.codec.protobuf.internal.converter; - -import java.util.List; - -import io.swagger.models.parameters.SerializableParameter; -import io.swagger.models.properties.Property; - -public class SerializableParameterAdapter implements SwaggerTypeAdapter { - private final SerializableParameter parameter; - - public SerializableParameterAdapter(SerializableParameter parameter) { - this.parameter = parameter; - } - - @Override - public String getRefType() { - return null; - } - - @Override - public Property getArrayItem() { - if ("array".equals(parameter.getType())) { - return parameter.getItems(); - } - - return null; - } - - @Override - public Property getMapItem() { - return null; - } - - @Override - public List getEnum() { - return parameter.getEnum(); - } - - @Override - public String getType() { - return parameter.getType(); - } - - @Override - public String getFormat() { - return parameter.getFormat(); - } - - @Override - public boolean isObject() { - return false; - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java index cd8942a9f0d..482808ab816 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java @@ -22,35 +22,42 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import javax.ws.rs.core.Response.Status; - import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.protobuf.internal.parser.ProtoParser; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.hash.Hashing; import io.protostuff.compiler.model.Message; import io.protostuff.compiler.model.Proto; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.vertx.core.json.Json; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; +@SuppressWarnings({"rawtypes", "unchecked"}) public class SwaggerToProtoGenerator { + private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerToProtoGenerator.class); + private final String protoPackage; - private final Swagger swagger; + private final OpenAPI swagger; private final StringBuilder msgStringBuilder = new StringBuilder(); @@ -60,48 +67,76 @@ public class SwaggerToProtoGenerator { private final Set messages = new HashSet<>(); - private final List pending = new ArrayList<>(); + private List pending = new ArrayList<>(); // not java package // better to be: app_${app}.mid_{microservice}.sid_{schemaId} - public SwaggerToProtoGenerator(String protoPackage, Swagger swagger) { - this.protoPackage = protoPackage; + public SwaggerToProtoGenerator(String protoPackage, OpenAPI swagger) { + this.protoPackage = escapePackageName(protoPackage); this.swagger = swagger; } public Proto convert() { convertDefinitions(); convertOperations(); - for (Runnable runnable : pending) { - runnable.run(); - } + do { + List oldPending = pending; + pending = new ArrayList<>(); + for (Runnable runnable : oldPending) { + runnable.run(); + } + } while (!pending.isEmpty()); return createProto(); } + public static String escapePackageName(String name) { + return name.replaceAll("[\\-:]", "_"); + } + + public static String escapeMessageName(String name) { + return name.replaceAll("\\.", "_"); + } + + public static boolean isValidEnum(String name) { + return !name.contains(".") && !name.contains("-"); + } + private void convertDefinitions() { - if (swagger.getDefinitions() == null) { + if (swagger.getComponents() == null || swagger.getComponents().getSchemas() == null) { return; } - for (Entry entry : swagger.getDefinitions().entrySet()) { - convertDefinition(entry.getKey(), (ModelImpl) entry.getValue()); + for (Entry entry : swagger.getComponents().getSchemas().entrySet()) { + convertDefinition(entry.getKey(), entry.getValue()); } } - private void convertDefinition(String modelName, ModelImpl model) { - Map properties = model.getProperties(); + @SuppressWarnings("unchecked") + private void convertDefinition(String modelName, Schema model) { + Map properties = model.getProperties(); if (properties == null) { // it's a empty message properties = Collections.emptyMap(); } - // complex - messages.add(modelName); - appendLine(msgStringBuilder, "message %s {", modelName); + createMessage(modelName, properties); + } + + private void createMessage(String protoName, Map properties, String... annotations) { + if (!messages.add(protoName)) { + // already created + return; + } + + for (String annotation : annotations) { + msgStringBuilder.append("//"); + appendLine(msgStringBuilder, annotation); + } + appendLine(msgStringBuilder, "message %s {", protoName); int tag = 1; - for (Entry entry : properties.entrySet()) { - Property property = entry.getValue(); + for (Entry entry : properties.entrySet()) { + Schema property = entry.getValue(); String propertyType = convertSwaggerType(property); appendLine(msgStringBuilder, " %s %s = %d;", propertyType, entry.getKey(), tag); @@ -137,20 +172,20 @@ private String convertSwaggerType(Object swaggerType) { type = adapter.getRefType(); if (type != null) { - return type; + return type.substring(Components.COMPONENTS_SCHEMAS_REF.length()); } - Property property = adapter.getArrayItem(); - if (property != null) { - return "repeated " + convertSwaggerType(property); + Schema itemProperty = adapter.getArrayItem(); + if (itemProperty != null) { + return "repeated " + convertArrayOrMapItem(itemProperty); } - property = adapter.getMapItem(); - if (property != null) { - return String.format("map", convertSwaggerType(property)); + itemProperty = adapter.getMapItem(); + if (itemProperty != null) { + return String.format("map", convertArrayOrMapItem(itemProperty)); } - if (adapter.isObject()) { + if (adapter.isJavaLangObject()) { addImports(ProtoConst.ANY_PROTO); return ProtoConst.ANY.getCanonicalName(); } @@ -160,10 +195,49 @@ private String convertSwaggerType(Object swaggerType) { Json.encode(swaggerType))); } + private String convertArrayOrMapItem(Schema itemProperty) { + SwaggerTypeAdapter itemAdapter = SwaggerTypeAdapter.create(itemProperty); + // List>, need to wrap + if (itemAdapter.getArrayItem() != null) { + String protoName = generateWrapPropertyName(List.class.getSimpleName(), itemAdapter.getArrayItem()); + pending.add(() -> wrapPropertyToMessage(protoName, itemProperty)); + return protoName; + } + + // List>, need to wrap + if (itemAdapter.getMapItem() != null) { + String protoName = generateWrapPropertyName(Map.class.getSimpleName(), itemAdapter.getMapItem()); + pending.add(() -> wrapPropertyToMessage(protoName, itemProperty)); + return protoName; + } + + return convertSwaggerType(itemProperty); + } + + private String generateWrapPropertyName(String prefix, Schema property) { + SwaggerTypeAdapter adapter = SwaggerTypeAdapter.create(property); + // List>, need to wrap + if (adapter.getArrayItem() != null) { + return generateWrapPropertyName(prefix + List.class.getSimpleName(), adapter.getArrayItem()); + } + + // List>, need to wrap + if (adapter.getMapItem() != null) { + return generateWrapPropertyName(prefix + Map.class.getSimpleName(), adapter.getMapItem()); + } + + // message name cannot have . (package separator) + return prefix + StringUtils.capitalize(escapeMessageName(convertSwaggerType(adapter))); + } + + private void wrapPropertyToMessage(String protoName, Schema property) { + createMessage(protoName, Collections.singletonMap("value", property), ProtoConst.ANNOTATION_WRAP_PROPERTY); + } + private String tryFindEnumType(List enums) { if (enums != null && !enums.isEmpty()) { String strEnums = enums.toString(); - String enumName = "Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8).toString(); + String enumName = "Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8); pending.add(() -> createEnum(enumName, enums)); return enumName; } @@ -178,107 +252,175 @@ private void createEnum(String enumName, List enums) { appendLine(msgStringBuilder, "enum %s {", enumName); for (int idx = 0; idx < enums.size(); idx++) { - appendLine(msgStringBuilder, " %s =%d;", enums.get(idx), idx); + if (isValidEnum(enums.get(idx))) { + appendLine(msgStringBuilder, " %s =%d;", enums.get(idx), idx); + } else { + throw new IllegalStateException( + String.format("enum class [%s] name [%s] not supported by protobuffer.", enumName, enums.get(idx))); + } } appendLine(msgStringBuilder, "}"); } private String findBaseType(String swaggerType, String swaggerFmt) { String key = swaggerType + ":" + swaggerFmt; - switch (key) { - case "boolean:null": - return "bool"; - // there is no int8/int16 in protobuf - case "integer:null": - return "int64"; - case "integer:int8": - case "integer:int16": - case "integer:int32": - return "int32"; - case "integer:int64": - return "int64"; - case "number:null": - return "double"; - case "number:float": - return "float"; - case "number:double": - return "double"; - case "string:null": - return "string"; - case "string:byte": - return "bytes"; - case "string:date": // LocalDate - case "string:date-time": // Date - return "int64"; - case "file:null": - throw new IllegalStateException("not support swagger type: " + swaggerType); - } - return null; + return switch (key) { + case "boolean:null" -> "bool"; + case "integer:int32" -> "sint32"; + case "integer:int64" -> "sint64"; + case "integer:null" -> "string"; // BigInteger like values + case "number:double" -> "double"; + case "number:float" -> "float"; + case "number:null" -> "string"; // BigDecimal like values + case "string:null" -> "string"; + case "string:byte" -> "bytes"; + case "string:date" -> "int64"; + case "string:date-time" -> "int64"; + case "string:binary" -> throw new IllegalArgumentException("proto buffer not support file upload/download"); + default -> null; + }; } private void convertOperations() { - Map paths = swagger.getPaths(); + Paths paths = swagger.getPaths(); if (paths == null || paths.isEmpty()) { return; } appendLine(serviceBuilder, "service MainService {"); - for (Path path : paths.values()) { - for (Operation operation : path.getOperationMap().values()) { - convertOpeation(operation); + for (PathItem path : paths.values()) { + for (Operation operation : path.readOperations()) { + if (isUpload(operation)) { + LOGGER.warn("Not support operation for highway {}.{}, {}", this.protoPackage, operation.getOperationId(), + "file upload not supported"); + continue; + } else if (isDownload(operation)) { + LOGGER.warn("Not support operation for highway {}.{}, {}", this.protoPackage, operation.getOperationId(), + "file download not supported"); + continue; + } + try { + convertOperation(operation); + } catch (Exception e) { + LOGGER.error("Not support operation for highway {}.{}", this.protoPackage, operation.getOperationId(), e); + } } } + serviceBuilder.setLength(serviceBuilder.length() - 1); + appendLine(serviceBuilder, "}"); } - private void convertOpeation(Operation operation) { + private boolean isUpload(Operation operation) { + return operation.getRequestBody() != null && operation.getRequestBody().getContent() != null + && operation.getRequestBody().getContent().get(MediaType.MULTIPART_FORM_DATA) != null; + } + + private boolean isDownload(Operation operation) { + return operation.getResponses().get(SwaggerConst.SUCCESS_KEY) != null && + operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent() != null && + operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent().get(MediaType.MULTIPART_FORM_DATA) + != null; + } + + private void convertOperation(Operation operation) { ProtoMethod protoMethod = new ProtoMethod(); fillRequestType(operation, protoMethod); fillResponseType(operation, protoMethod); - appendLine(serviceBuilder, " //%s%s", ProtoConst.OP_HINT, Json.encode(protoMethod)); + appendLine(serviceBuilder, " //%s%s", ProtoConst.ANNOTATION_RPC, Json.encode(protoMethod)); appendLine(serviceBuilder, " rpc %s (%s) returns (%s);\n", operation.getOperationId(), protoMethod.getArgTypeName(), protoMethod.findResponse(Status.OK.getStatusCode()).getTypeName()); } private void fillRequestType(Operation operation, ProtoMethod protoMethod) { - List parameters = operation.getParameters(); - if (parameters.isEmpty()) { + int parametersCount = parametersCount(operation); + if (parametersCount == 0) { addImports(ProtoConst.EMPTY_PROTO); protoMethod.setArgTypeName(ProtoConst.EMPTY.getCanonicalName()); return; } - if (parameters.size() == 1) { - String type = convertSwaggerType(parameters.get(0)); + if (parametersCount == 1) { + String type = convertSwaggerType(oneSchema(operation)); if (messages.contains(type)) { protoMethod.setArgTypeName(type); return; } } - String wrapName = operation.getOperationId() + "RequestWrap"; - createWrapArgs(wrapName, parameters); + String wrapName = StringUtils.capitalize(operation.getOperationId()) + "RequestWrap"; + createWrapArgs(wrapName, wrapSchema(operation)); - protoMethod.setArgWrapped(true); protoMethod.setArgTypeName(wrapName); } + private Map wrapSchema(Operation operation) { + Map properties = new LinkedHashMap<>(); + if (operation.getParameters() != null) { + for (Parameter parameter : operation.getParameters()) { + properties.put(parameter.getName(), parameter.getSchema()); + } + } + if (operation.getRequestBody() != null + && operation.getRequestBody().getContent().size() != 0) { + if (operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties() + .forEach((k, v) -> properties.put((String) k, (Schema) v)); + } else { + properties.put((String) operation.getRequestBody().getExtensions().get(SwaggerConst.EXT_BODY_NAME), + operation.getRequestBody().getContent().get( + operation.getRequestBody().getContent().keySet().iterator().next()).getSchema()); + } + } + return properties; + } + + private Schema oneSchema(Operation operation) { + if (operation.getParameters() != null && operation.getParameters().size() == 1) { + return operation.getParameters().get(0).getSchema(); + } + if (operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + return (Schema) operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema() + .getProperties() + .values().iterator().next(); + } + return operation.getRequestBody().getContent().get( + operation.getRequestBody().getContent().keySet().iterator().next()).getSchema(); + } + + private int parametersCount(Operation operation) { + int parameters = operation.getParameters() == null ? 0 : operation.getParameters().size(); + if (operation.getRequestBody() != null) { + if (operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + parameters = parameters + operation.getRequestBody() + .getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties().size(); + } else if (operation.getRequestBody().getContent().size() != 0) { + parameters = parameters + 1; + } + } + return parameters; + } + private void fillResponseType(Operation operation, ProtoMethod protoMethod) { - for (Entry entry : operation.getResponses().entrySet()) { - String type = convertSwaggerType(entry.getValue().getSchema()); + for (Entry entry : operation.getResponses().entrySet()) { + Schema schema = null; + if (entry.getValue().getContent() != null && + entry.getValue().getContent().size() != 0) { + schema = entry.getValue().getContent().get( + entry.getValue().getContent().keySet().iterator().next()).getSchema(); + } + String type = convertSwaggerType(schema); + boolean wrapped = !messages.contains(type); ProtoResponse protoResponse = new ProtoResponse(); - protoResponse.setWrapped(!messages.contains(type)); protoResponse.setTypeName(type); - if (protoResponse.isWrapped()) { - String wrapName = operation.getOperationId() + "ResponseWrap" + entry.getKey(); - appendLine(msgStringBuilder, "message %s {", wrapName); - appendLine(msgStringBuilder, " %s response = 1;", type); - appendLine(msgStringBuilder, "}"); + if (wrapped) { + String wrapName = StringUtils.capitalize(operation.getOperationId()) + "ResponseWrap" + entry.getKey(); + wrapPropertyToMessage(wrapName, schema); protoResponse.setTypeName(wrapName); } @@ -286,17 +428,8 @@ private void fillResponseType(Operation operation, ProtoMethod protoMethod) { } } - private void createWrapArgs(String wrapName, List parameters) { - appendLine(msgStringBuilder, "message %s {", wrapName); - - int idx = 1; - for (Parameter parameter : parameters) { - String type = convertSwaggerType(parameter); - appendLine(msgStringBuilder, " %s %s = %d;", type, parameter.getName(), idx); - idx++; - } - - appendLine(msgStringBuilder, "}"); + private void createWrapArgs(String wrapName, Map properties) { + createMessage(wrapName, properties, ProtoConst.ANNOTATION_WRAP_ARGUMENTS); } protected Proto createProto() { diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerTypeAdapter.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerTypeAdapter.java index 235ebe89f45..80a20fd2822 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerTypeAdapter.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerTypeAdapter.java @@ -18,22 +18,16 @@ import java.util.List; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.SerializableParameter; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.Schema; public interface SwaggerTypeAdapter { static SwaggerTypeAdapter create(Object swaggerType) { - if (swaggerType instanceof Property) { - return new PropertyAdapter((Property) swaggerType); + if (swaggerType instanceof SwaggerTypeAdapter) { + return (SwaggerTypeAdapter) swaggerType; } - if (swaggerType instanceof SerializableParameter) { - return new SerializableParameterAdapter((SerializableParameter) swaggerType); - } - - if (swaggerType instanceof BodyParameter) { - return new BodyParameterAdapter((BodyParameter) swaggerType); + if (swaggerType instanceof Schema) { + return new SchemaSwaggerTypeAdapter((Schema) swaggerType); } throw new IllegalStateException("not support swagger type: " + swaggerType.getClass().getName()); @@ -41,9 +35,9 @@ static SwaggerTypeAdapter create(Object swaggerType) { String getRefType(); - Property getArrayItem(); + Schema getArrayItem(); - Property getMapItem(); + Schema getMapItem(); List getEnum(); @@ -51,5 +45,5 @@ static SwaggerTypeAdapter create(Object swaggerType) { String getFormat(); - boolean isObject(); + boolean isJavaLangObject(); } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java new file mode 100644 index 00000000000..0220cd96b30 --- /dev/null +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java @@ -0,0 +1,416 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema; + + +import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.parser.ProtoParser; +import org.apache.servicecomb.swagger.SwaggerUtils; + +import com.google.common.hash.Hashing; + +import io.protostuff.compiler.model.Proto; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class SchemaToProtoGenerator { + record IdentifierRunnable(Schema identifier, Runnable target) + implements Runnable { + + @Override + public void run() { + this.target.run(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdentifierRunnable that = (IdentifierRunnable) o; + return SwaggerUtils.schemaEquals(identifier, that.identifier); + } + + @Override + public int hashCode() { + return SwaggerUtils.schemaHashCode(identifier); + } + } + + private final String protoPackage; + + private final OpenAPI openAPI; + + private final Schema rootSchema; + + private final String rootName; + + private final Set messages = new HashSet<>(); + + private final StringBuilder msgStringBuilder = new StringBuilder(); + + private List pending = new ArrayList<>(); + + public SchemaToProtoGenerator(String protoPackage, OpenAPI openAPI, Schema rootSchema, String rootName) { + this.protoPackage = protoPackage; + this.openAPI = openAPI; + this.rootSchema = rootSchema; + this.rootName = rootName; + } + + public Proto convert() { + createMessage(this.rootSchema); + + int iteration = 0; + do { + List oldPending = pending; + pending = new ArrayList<>(); + for (Runnable runnable : oldPending) { + runnable.run(); + } + if (pending.size() >= oldPending.size()) { + iteration++; + } + } while (!pending.isEmpty() && iteration < 1000); + + if (iteration == 1000) { + throw new IllegalArgumentException( + String.format("Failed to create schema %s. May be cyclic object.", this.rootName)); + } + + Map wrap = new HashMap<>(1); + wrap.put("value", this.rootSchema); + createMessage(rootName, wrap, ProtoConst.ANNOTATION_WRAP_PROPERTY); + + return createProto(); + } + + protected Proto createProto() { + StringBuilder sb = new StringBuilder(); + appendLine(sb, "syntax = \"proto3\";"); + if (StringUtils.isNotEmpty(protoPackage)) { + sb.append("package ").append(protoPackage).append(";\n"); + } + sb.append(msgStringBuilder); + ProtoParser protoParser = new ProtoParser(); + return protoParser.parseFromContent(sb.toString()); + } + + private String findSchemaType(Schema schema) { + @SuppressWarnings("unchecked") + String type = tryFindEnumType((List) schema.getEnum()); + if (type != null) { + return type; + } + + type = findBaseType(schema.getType(), schema.getFormat()); + if (type != null) { + return type; + } + + Schema itemProperty = schema.getItems(); + if (itemProperty != null) { + String containerType = findArrayOrMapItemType(itemProperty); + if (containerType != null) { + return "repeated " + containerType; + } + return null; + } + + itemProperty = (Schema) schema.getAdditionalProperties(); + if (itemProperty != null) { + String containerType = findArrayOrMapItemType(itemProperty); + if (containerType != null) { + return String.format("map", containerType); + } + return null; + } + + type = schema.get$ref(); + if (type != null) { + String typeName = type.substring(Components.COMPONENTS_SCHEMAS_REF.length()); + Schema refSchema = openAPI.getComponents().getSchemas().get(typeName); + if (refSchema == null) { + throw new IllegalArgumentException("not found ref in components " + type); + } + if (StringUtils.isEmpty(refSchema.getName())) { + refSchema.setName(typeName); + } + return findSchemaType(refSchema); + } + + return findObjectType(schema); + } + + private String findObjectType(Schema schema) { + String name = schema.getName(); + if (messages.contains(name)) { + return name; + } + return null; + } + + private void createEnum(String enumName, List enums) { + if (!messages.add(enumName)) { + // already created + return; + } + + appendLine(msgStringBuilder, "enum %s {", enumName); + for (int idx = 0; idx < enums.size(); idx++) { + if (isValidEnum(enums.get(idx))) { + appendLine(msgStringBuilder, " %s =%d;", enums.get(idx), idx); + } else { + throw new IllegalStateException( + String.format("enum class [%s] name [%s] not supported by protobuffer.", enumName, enums.get(idx))); + } + } + appendLine(msgStringBuilder, "}"); + } + + public static boolean isValidEnum(String name) { + return !name.contains(".") && !name.contains("-"); + } + + private String tryFindEnumType(List enums) { + if (enums != null && !enums.isEmpty()) { + String strEnums = enums.toString(); + String enumName = "Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8); + pending.add(() -> createEnum(enumName, enums)); + return enumName; + } + return null; + } + + private String findBaseType(String swaggerType, String swaggerFmt) { + String key = swaggerType + ":" + swaggerFmt; + return switch (key) { + case "boolean:null" -> "bool"; + case "integer:int32" -> "sint32"; + case "integer:int64" -> "sint64"; + case "integer:null" -> "string"; // BigInteger like values + case "number:double" -> "double"; + case "number:float" -> "float"; + case "number:null" -> "string"; // BigDecimal like values + case "string:null" -> "string"; + case "string:byte" -> "bytes"; + case "string:date" -> "int64"; + case "string:date-time" -> "int64"; + case "string:binary" -> throw new IllegalArgumentException("proto buffer not support file upload/download"); + default -> null; + }; + } + + private String findArrayOrMapItemType(Schema itemProperty) { + // List>, need to wrap + if (itemProperty.getItems() != null) { + return findWrapPropertyType(List.class.getSimpleName(), itemProperty.getItems()); + } + + // List>, need to wrap + if (itemProperty.getAdditionalProperties() != null) { + return findWrapPropertyType(Map.class.getSimpleName(), (Schema) itemProperty.getAdditionalProperties()); + } + + return findSchemaType(itemProperty); + } + + + private String findWrapPropertyType(String prefix, Schema property) { + // List>, need to wrap + if (property.getItems() != null) { + return findWrapPropertyType(prefix + List.class.getSimpleName(), property.getItems()); + } + + // List>, need to wrap + if (property.getAdditionalProperties() != null) { + return findWrapPropertyType(prefix + Map.class.getSimpleName(), + (Schema) property.getAdditionalProperties()); + } + + String type = findSchemaType(property); + if (type == null) { + return null; + } + + // message name cannot have . (package separator) + return prefix + StringUtils.capitalize(escapeMessageName(type)); + } + + public static String escapeMessageName(String name) { + return name.replaceAll("\\.", "_"); + } + + + private void wrapPropertyToMessage(String protoName, Schema property) { + createMessage(protoName, Collections.singletonMap("value", property), ProtoConst.ANNOTATION_WRAP_PROPERTY); + } + + private void createMessage(String protoName, Map properties, String... annotations) { + for (String annotation : annotations) { + msgStringBuilder.append("//"); + appendLine(msgStringBuilder, annotation); + } + appendLine(msgStringBuilder, "message %s {", protoName); + int tag = 1; + for (Entry entry : properties.entrySet()) { + Schema property = entry.getValue(); + String propertyType = findSchemaType(property); + + appendLine(msgStringBuilder, " %s %s = %d;", propertyType, entry.getKey(), tag); + tag++; + } + appendLine(msgStringBuilder, "}"); + } + + public void createMessage(Schema schema) { + String ref = schema.get$ref(); + if (ref != null) { + String typeName = ref.substring(Components.COMPONENTS_SCHEMAS_REF.length()); + Schema refSchema = openAPI.getComponents().getSchemas().get(typeName); + if (refSchema == null) { + throw new IllegalArgumentException("not found ref in components " + ref); + } + if (StringUtils.isEmpty(refSchema.getName())) { + refSchema.setName(typeName); + } + createMessage(refSchema); + return; + } + + boolean wait = false; + + //array or map + if (isArrayOrMap(schema)) { + Schema mapOrArrayItem = arrayOrMapItem(schema); + if (findSchemaType(mapOrArrayItem) == null) { + createMessageTask(mapOrArrayItem); + wait = true; + } else { + if (createMapOrArrayMessageTask(mapOrArrayItem, true, schema)) { + wait = true; + } + } + } + + //object + if (schema.getProperties() != null) { + for (Entry entry : schema.getProperties().entrySet()) { + if (findSchemaType(entry.getValue()) == null) { + createMessageTask(entry.getValue()); + wait = true; + } else if (isArrayOrMap(entry.getValue())) { + if (createMapOrArrayMessageTask(arrayOrMapItem(entry.getValue()), false, null)) { + wait = true; + } + } + } + } + + if (wait) { + IdentifierRunnable runnable = new IdentifierRunnable(schema, () -> createMessage(schema)); + if (!pending.contains(runnable)) { + pending.add(runnable); + } + return; + } + + if (findSchemaType(schema) != null) { + return; + } + + messages.add(schema.getName()); + + appendLine(msgStringBuilder, "message %s {", schema.getName()); + List> sortedProperties = new ArrayList<>(schema.getProperties().entrySet()); + sortedProperties.sort(Comparator.comparing(Map.Entry::getKey)); + int tag = 1; + for (Entry entry : sortedProperties) { + Schema property = entry.getValue(); + String propertyType = findSchemaType(property); + + appendLine(msgStringBuilder, " %s %s = %d;", propertyType, entry.getKey(), tag); + tag++; + } + appendLine(msgStringBuilder, "}"); + } + + private boolean isArrayOrMap(Schema value) { + return value.getItems() != null || value.getAdditionalProperties() != null; + } + + private Schema arrayOrMapItem(Schema schema) { + return schema.getItems() == null ? + (Schema) schema.getAdditionalProperties() : schema.getItems(); + } + + private void createMessageTask(Schema schema) { + IdentifierRunnable runnable = new IdentifierRunnable(schema, () -> createMessage(schema)); + if (!pending.contains(runnable)) { + pending.add(runnable); + } + } + + private boolean createMapOrArrayMessageTask(Schema schema, boolean nested, Schema owner) { + if (schema.getAdditionalProperties() != null) { + String protoName = findWrapPropertyType(Map.class.getSimpleName(), + (Schema) schema.getAdditionalProperties()); + if (messages.add(protoName)) { + pending.add(() -> wrapPropertyToMessage(protoName, schema)); + createMessageTask((Schema) schema.getAdditionalProperties()); + return true; + } + } + if (schema.getItems() != null) { + String protoName = findWrapPropertyType(List.class.getSimpleName(), schema.getItems()); + if (messages.add(protoName)) { + pending.add(() -> wrapPropertyToMessage(protoName, schema)); + createMessageTask(schema.getItems()); + return true; + } + } + if (nested) { + String protoName = owner.getAdditionalProperties() != null ? + findWrapPropertyType(Map.class.getSimpleName(), schema) : + findWrapPropertyType(List.class.getSimpleName(), schema); + if (messages.add(protoName)) { + pending.add(() -> wrapPropertyToMessage(protoName, owner)); + return true; + } + } + return false; + } +} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java deleted file mode 100644 index f54ed51b953..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ProtobufSchemaUtils.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Date; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.springframework.util.ClassUtils; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Pipe; -import io.protostuff.WireFormat.FieldType; -import io.protostuff.runtime.DefaultIdStrategy; -import io.protostuff.runtime.Delegate; -import io.protostuff.runtime.ProtobufCompatibleUtils; -import io.protostuff.runtime.RuntimeEnv; - -public final class ProtobufSchemaUtils { - static { - initProtobufObjectCodec(); - ProtobufCompatibleUtils.init(); - } - - protected static void initProtobufObjectCodec() { - ((DefaultIdStrategy) RuntimeEnv.ID_STRATEGY).registerDelegate(new Delegate() { - @Override - public FieldType getFieldType() { - return FieldType.BYTES; - } - - @Override - public Object readFrom(Input input) throws IOException { - return JsonUtils.readValue(input.readByteArray(), Object.class); - } - - @Override - public void writeTo(Output output, int number, Object value, boolean repeated) throws IOException { - output.writeByteArray(number, JsonUtils.writeValueAsBytes(value), false); - } - - @Override - public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) { - throw new IllegalStateException("not support."); - } - - @Override - public Class typeClass() { - return Object.class; - } - }); - } - - private ProtobufSchemaUtils() { - } - - public static boolean isArgsNeedWrap(Method method) { - if (method.getParameterCount() != 1) { - return true; - } - - // 单参数时,需要根据实际情况判断 - return isNeedWrap(method.getParameterTypes()[0]); - } - - public static boolean isNeedWrap(Class cls) { - // protobuf不支持原子类型、enum、string、数组、collection等等作为msg - // 只有pojo类型才可以 - // java.lang.Object也不可以,因为这可以是任意类型,结果不确定 - return ClassUtils.isPrimitiveOrWrapper(cls) || cls.isArray() || cls.isEnum() - || String.class.isAssignableFrom(cls) - || Collection.class.isAssignableFrom(cls) - || Map.class.isAssignableFrom(cls) - || Date.class.isAssignableFrom(cls) - || Object.class.equals(cls); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java index 002c009c95f..3c7e5adbb64 100644 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java +++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java @@ -17,98 +17,101 @@ package org.apache.servicecomb.codec.protobuf.utils; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; import java.util.Map; -import org.apache.servicecomb.codec.protobuf.utils.schema.WrapSchemaFactory; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.codec.protobuf.internal.converter.SwaggerToProtoGenerator; +import org.apache.servicecomb.codec.protobuf.schema.SchemaToProtoGenerator; +import org.apache.servicecomb.core.definition.SchemaMeta; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; +import org.apache.servicecomb.swagger.SwaggerUtils; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import io.protostuff.Schema; -import io.protostuff.runtime.RuntimeSchema; +import io.protostuff.compiler.model.Proto; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; +/** + * Manage swagger -> protoBuffer mappings. + * + * This class have the same lifecycle as MicroserviceMeta, so we need to create an instance + * for each MicroserviceMeta. + */ public class ScopedProtobufSchemaManager { - private ClassLoader classLoader; + static class SchemaKey { + String schemaId; - private Map schemaCache = new ConcurrentHashMapEx<>(); + String rootMessage; - public ScopedProtobufSchemaManager(ClassLoader classLoader) { - this.classLoader = JvmUtils.correctClassLoader(classLoader); - } + Schema schema; - // 为了支持method args的场景,全部实现ProtobufMessageWrapper接口,有的场景有点浪费,不过无关紧要 - private WrapSchema createWrapSchema(WrapClassConfig config) { - Class cls = JavassistUtils.createClass(classLoader, config); - Schema schema = RuntimeSchema.createFrom(cls); - return WrapSchemaFactory.createSchema(schema, config.getType()); - } + int hashCode = -1; - // 适用于将单个类型包装的场景 - // 比如return - public WrapSchema getOrCreateSchema(Type type) { - JavaType javaType = TypeFactory.defaultInstance().constructType(type); - // List -> java.util.List - // List> -> java.util.List> - String key = javaType.toCanonical(); - return schemaCache.computeIfAbsent(key, k -> { - if (!ProtobufSchemaUtils.isNeedWrap(javaType.getRawClass())) { - // 可以直接使用 - Schema schema = RuntimeSchema.createFrom(javaType.getRawClass()); - return WrapSchemaFactory.createSchema(schema, WrapType.NOT_WRAP); - } - - // 需要包装 - WrapClassConfig config = new WrapClassConfig(); - config.setType(WrapType.NORMAL_WRAP); + SchemaKey(String schemaId, String rootMessage, Schema schema) { + this.schemaId = schemaId; + this.rootMessage = rootMessage; + this.schema = schema; + } - config.setClassName( - "gen.wrap.protobuf." + - org.apache.servicecomb.swagger.generator.core.utils.ClassUtils.correctClassName(key)); - if (!Void.TYPE.isAssignableFrom(javaType.getRawClass())) { - config.addField("field0", javaType); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - JavassistUtils.genSingleWrapperInterface(config); - - return createWrapSchema(config); - }); + if (o == null || getClass() != o.getClass()) { + return false; + } + SchemaKey other = (SchemaKey) o; + return StringUtils.equals(schemaId, other.schemaId) && StringUtils.equals(rootMessage, other.rootMessage) + && SwaggerUtils.schemaEquals(schema, other.schema); + } + + @Override + public int hashCode() { + if (hashCode != -1) { + return hashCode; + } + hashCode = schemaId.hashCode() ^ rootMessage.hashCode() ^ SwaggerUtils.schemaHashCode(schema); + return hashCode; + } } - public WrapSchema getOrCreateArgsSchema(OperationMeta operationMeta) { - Method method = operationMeta.getMethod(); - String type = "gen." + method.getDeclaringClass().getName() + "." + method.getName() + ".Args"; + // Because this class belongs to each SchemaMeta, the key is the schema id. + private final Map mapperCache = new ConcurrentHashMapEx<>(); - return schemaCache.computeIfAbsent(type, (t) -> { - if (!ProtobufSchemaUtils.isArgsNeedWrap(method)) { - // 可以直接使用 - Class cls = method.getParameterTypes()[0]; - Schema schema = RuntimeSchema.createFrom(cls); - return WrapSchemaFactory.createSchema(schema, WrapType.ARGS_NOT_WRAP); - } + private final Map schemaMapperCache = new ConcurrentHashMapEx<>(); - // 需要包装 - WrapClassConfig config = new WrapClassConfig(); - config.setType(WrapType.ARGS_WRAP); - config.setClassName(type); - - Parameter[] params = method.getParameters(); - for (int idx = 0; idx < params.length; idx++) { - Parameter param = params[idx]; - String paramName = org.apache.servicecomb.swagger.generator.core.utils.ClassUtils - .correctMethodParameterName(operationMeta.getParamName(idx)); - config.addField(paramName, param.getParameterizedType()); - } + public ScopedProtobufSchemaManager() { - JavassistUtils.genMultiWrapperInterface(config); + } + + /** + * get the ProtoMapper from Swagger + */ + public ProtoMapper getOrCreateProtoMapper(SchemaMeta schemaMeta) { + return mapperCache.computeIfAbsent(schemaMeta.getSchemaId(), key -> { + OpenAPI swagger = schemaMeta.getSwagger(); + SwaggerToProtoGenerator generator = new SwaggerToProtoGenerator(schemaMeta.getMicroserviceQualifiedName(), + swagger); + Proto proto = generator.convert(); + ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); + return protoMapperFactory.create(proto); + }); + } - return createWrapSchema(config); + /** + * get the ProtoMapper from Schema + */ + public ProtoMapper getOrCreateProtoMapper(OpenAPI openAPI, String schemaId, String rootMessageName, + Schema schema) { + SchemaKey schemaKey = new SchemaKey(schemaId, rootMessageName, schema); + return schemaMapperCache.computeIfAbsent(schemaKey, key -> { + SchemaToProtoGenerator generator = new SchemaToProtoGenerator("scb.schema", openAPI, + key.schema, rootMessageName); + Proto proto = generator.convert(); + ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); + return protoMapperFactory.create(proto); }); } } diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapClassConfig.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapClassConfig.java deleted file mode 100644 index 3c1b5360c39..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapClassConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils; - -import org.apache.servicecomb.common.javassist.ClassConfig; - -public class WrapClassConfig extends ClassConfig { - private WrapType type; - - public WrapType getType() { - return type; - } - - public void setType(WrapType type) { - this.type = type; - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapSchema.java deleted file mode 100644 index 67783300115..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapSchema.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils; - -import java.nio.ByteBuffer; - -import io.protostuff.ByteBufferInput; -import io.protostuff.Input; -import io.protostuff.Output; -import io.vertx.core.buffer.Buffer; - -public interface WrapSchema { - @SuppressWarnings("unchecked") - default T readObject(Buffer buffer) throws Exception { - if (buffer == null || buffer.length() == 0) { - // void以及函数入参为null的场景 - // 空串时,protobuf至少为编码为1字节 - return (T) readFromEmpty(); - } - - ByteBuffer nioBuffer = buffer.getByteBuf().nioBuffer(); - Input input = new ByteBufferInput(nioBuffer, false); - - return (T) readObject(input); - } - - Object readFromEmpty(); - - Object readObject(Input input) throws Exception; - - void writeObject(Output output, Object value) throws Exception; -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapType.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapType.java deleted file mode 100644 index 7d049ede26c..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/WrapType.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils; - -public enum WrapType { - NOT_WRAP, - NORMAL_WRAP, - ARGS_NOT_WRAP, - ARGS_WRAP -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/AbstractWrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/AbstractWrapSchema.java deleted file mode 100644 index b8f5ed3a17d..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/AbstractWrapSchema.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; - -import io.protostuff.Schema; - -public abstract class AbstractWrapSchema implements WrapSchema { - protected Schema schema; -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsNotWrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsNotWrapSchema.java deleted file mode 100644 index 5d76039338e..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsNotWrapSchema.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import java.io.IOException; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; - -public class ArgsNotWrapSchema extends AbstractWrapSchema { - - @SuppressWarnings("unchecked") - public ArgsNotWrapSchema(Schema schema) { - this.schema = (Schema) schema; - } - - @Override - public Object readFromEmpty() { - return new Object[] {null}; - } - - public Object readObject(Input input) throws IOException { - Object readValue = schema.newMessage(); - schema.mergeFrom(input, readValue); - - return new Object[] {readValue}; - } - - public void writeObject(Output output, Object value) throws IOException { - Object writeValue = ((Object[]) value)[0]; - if (writeValue == null) { - return; - } - - schema.writeTo(output, writeValue); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsWrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsWrapSchema.java deleted file mode 100644 index 16360a301b6..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/ArgsWrapSchema.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import java.io.IOException; - -import org.apache.servicecomb.common.javassist.MultiWrapper; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; - -public class ArgsWrapSchema extends AbstractWrapSchema { - - @SuppressWarnings("unchecked") - public ArgsWrapSchema(Schema schema) { - this.schema = (Schema) schema; - } - - @Override - public Object readFromEmpty() { - MultiWrapper wrapper = (MultiWrapper) schema.newMessage(); - return wrapper.readFields(); - } - - public Object readObject(Input input) throws IOException { - MultiWrapper wrapper = (MultiWrapper) schema.newMessage(); - schema.mergeFrom(input, wrapper); - - return wrapper.readFields(); - } - - public void writeObject(Output output, Object value) throws IOException { - MultiWrapper wrapper = (MultiWrapper) schema.newMessage(); - wrapper.writeFields((Object[]) value); - - schema.writeTo(output, wrapper); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NormalWrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NormalWrapSchema.java deleted file mode 100644 index f69f8e92da8..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NormalWrapSchema.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import java.io.IOException; - -import org.apache.servicecomb.common.javassist.SingleWrapper; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; - -public class NormalWrapSchema extends AbstractWrapSchema { - - @SuppressWarnings("unchecked") - public NormalWrapSchema(Schema schema) { - this.schema = (Schema) schema; - } - - @Override - public Object readFromEmpty() { - SingleWrapper wrapper = (SingleWrapper) schema.newMessage(); - return wrapper.readField(); - } - - public Object readObject(Input input) throws IOException { - SingleWrapper wrapper = (SingleWrapper) schema.newMessage(); - schema.mergeFrom(input, wrapper); - - return wrapper.readField(); - } - - public void writeObject(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - SingleWrapper wrapper = (SingleWrapper) schema.newMessage(); - wrapper.writeField(value); - - schema.writeTo(output, wrapper); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NotWrapSchema.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NotWrapSchema.java deleted file mode 100644 index 697fe986cbe..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/NotWrapSchema.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import java.io.IOException; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; - -public class NotWrapSchema extends AbstractWrapSchema { - - @SuppressWarnings("unchecked") - public NotWrapSchema(Schema schema) { - this.schema = (Schema) schema; - } - - @Override - public Object readFromEmpty() { - return null; - } - - public Object readObject(Input input) throws IOException { - Object value = schema.newMessage(); - schema.mergeFrom(input, value); - - return value; - } - - public void writeObject(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - schema.writeTo(output, value); - } -} diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/WrapSchemaFactory.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/WrapSchemaFactory.java deleted file mode 100644 index 30923aa11b6..00000000000 --- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/schema/WrapSchemaFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.codec.protobuf.utils.WrapType; - -import io.protostuff.Schema; - -public final class WrapSchemaFactory { - public static WrapSchema createSchema(Schema schema, WrapType type) { - switch (type) { - case NOT_WRAP: - return new NotWrapSchema(schema); - case NORMAL_WRAP: - return new NormalWrapSchema(schema); - case ARGS_NOT_WRAP: - return new ArgsNotWrapSchema(schema); - case ARGS_WRAP: - return new ArgsWrapSchema(schema); - default: - throw new Error("impossible"); - } - } - - private WrapSchemaFactory() { - } -} diff --git a/common/common-protobuf/src/test/java/io/protostuff/runtime/TestProtobufCompatibleUtils.java b/common/common-protobuf/src/test/java/io/protostuff/runtime/TestProtobufCompatibleUtils.java deleted file mode 100644 index 22192c29234..00000000000 --- a/common/common-protobuf/src/test/java/io/protostuff/runtime/TestProtobufCompatibleUtils.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.protostuff.runtime; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - -import io.protostuff.ByteArrayInput; -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; -import io.protostuff.runtime.model.ModelProtobuf; -import io.protostuff.runtime.model.ModelProtostuff; -import io.protostuff.runtime.model.User; - -public class TestProtobufCompatibleUtils { - @Test - public void test() throws IOException { - ProtobufCompatibleUtils.init(); - - Map stringMap = new HashMap<>(); - stringMap.put("k1", "v1"); - stringMap.put("k2", "v2"); - - Map userMap = new HashMap<>(); - userMap.put("u1", new User("n1")); - userMap.put("u2", new User("n2")); - - byte[] protostuffBytes = testProtostuff(stringMap, userMap); - - io.protostuff.runtime.model.ModelProtobuf.RequestHeader r = - ModelProtobuf.RequestHeader.newBuilder() - .putAllCseContext(stringMap) - .putUserMap("u1", ModelProtobuf.User.newBuilder().setName("n1").build()) - .putUserMap("u2", ModelProtobuf.User.newBuilder().setName("n2").build()) - .addList("l1") - .addList("l2") - .build(); - - byte[] protoBufBytes = r.toByteArray(); - Assert.assertArrayEquals(protostuffBytes, protoBufBytes); - } - - protected byte[] testProtostuff(Map map, Map userMap) throws IOException { - ProtobufCompatibleUtils.init(); - - RuntimeSchema schema = RuntimeSchema.createFrom(ModelProtostuff.class); - ModelProtostuff model = new ModelProtostuff(); - - model.setContext(map); - model.setUserMap(userMap); - model.getList().add("l1"); - model.getList().add("l2"); - - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - - schema.writeTo(output, model); - - ByteArrayOutputStream s = new ByteArrayOutputStream(); - LinkedBuffer.writeTo(s, linkedBuffer); - byte[] bytes = s.toByteArray(); - - ModelProtostuff newModel = new ModelProtostuff(); - ByteArrayInput bai = new ByteArrayInput(bytes, false); - - schema.mergeFrom(bai, newModel); - - Assert.assertEquals("v1", newModel.getContext().get("k1")); - Assert.assertEquals("v2", newModel.getContext().get("k2")); - Assert.assertEquals("n1", newModel.getUserMap().get("u1").getName()); - Assert.assertEquals("n2", newModel.getUserMap().get("u2").getName()); - Assert.assertEquals("l1", newModel.getList().get(0)); - Assert.assertEquals("l2", newModel.getList().get(1)); - - return bytes; - } -} diff --git a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.java b/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.java deleted file mode 100644 index b7a6ff3f264..00000000000 --- a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.java +++ /dev/null @@ -1,2899 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: ModelProtobuf.proto - -package io.protostuff.runtime.model; - -import com.google.protobuf.CodedOutputStream; - -@SuppressWarnings({"cast"}) -public final class ModelProtobuf { - private ModelProtobuf() { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistryLite registry) { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - registerAllExtensions( - (com.google.protobuf.ExtensionRegistryLite) registry); - } - - public interface UserOrBuilder extends - // @@protoc_insertion_point(interface_extends:io.protostuff.runtime.model.User) - com.google.protobuf.MessageOrBuilder { - - /** - * string name = 1; - */ - java.lang.String getName(); - - /** - * string name = 1; - */ - com.google.protobuf.ByteString getNameBytes(); - } - - /** - * Protobuf type {@code io.protostuff.runtime.model.User} - */ - public static final class User extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:io.protostuff.runtime.model.User) - UserOrBuilder { - // Use User.newBuilder() to construct. - private User(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - - private User() { - name_ = ""; - } - - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet getUnknownFields() { - return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); - } - - @SuppressWarnings("unused") - private User( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - int mutable_bitField0_ = 0; - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!input.skipField(tag)) { - done = true; - } - break; - } - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - - name_ = s; - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - makeExtensionsImmutable(); - } - } - - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_User_descriptor; - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_User_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.protostuff.runtime.model.ModelProtobuf.User.class, - io.protostuff.runtime.model.ModelProtobuf.User.Builder.class); - } - - public static final int NAME_FIELD_NUMBER = 1; - - private volatile java.lang.Object name_; - - /** - * string name = 1; - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - - /** - * string name = 1; - */ - public com.google.protobuf.ByteString getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) { - return true; - } - if (isInitialized == 0) { - return false; - } - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { - if (!getNameBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_); - } - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) { - return size; - } - - size = 0; - if (!getNameBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_); - } - memoizedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.protostuff.runtime.model.ModelProtobuf.User)) { - return super.equals(obj); - } - io.protostuff.runtime.model.ModelProtobuf.User other = - (io.protostuff.runtime.model.ModelProtobuf.User) obj; - - boolean result = true; - result = result && getName() - .equals(other.getName()); - return result; - } - - @SuppressWarnings("unchecked") - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - java.io.InputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseDelimitedFrom( - java.io.InputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - com.google.protobuf.CodedInputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { - return newBuilder(); - } - - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - - public static Builder newBuilder(io.protostuff.runtime.model.ModelProtobuf.User prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - - public Builder toBuilder() { - return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - - /** - * Protobuf type {@code io.protostuff.runtime.model.User} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:io.protostuff.runtime.model.User) - io.protostuff.runtime.model.ModelProtobuf.UserOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_User_descriptor; - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_User_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.protostuff.runtime.model.ModelProtobuf.User.class, - io.protostuff.runtime.model.ModelProtobuf.User.Builder.class); - } - - // Construct using io.protostuff.runtime.model.ModelProtobuf.User.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) { - } - } - - public Builder clear() { - super.clear(); - name_ = ""; - - return this; - } - - public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_User_descriptor; - } - - public io.protostuff.runtime.model.ModelProtobuf.User getDefaultInstanceForType() { - return io.protostuff.runtime.model.ModelProtobuf.User.getDefaultInstance(); - } - - public io.protostuff.runtime.model.ModelProtobuf.User build() { - io.protostuff.runtime.model.ModelProtobuf.User result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public io.protostuff.runtime.model.ModelProtobuf.User buildPartial() { - io.protostuff.runtime.model.ModelProtobuf.User result = - new io.protostuff.runtime.model.ModelProtobuf.User(this); - result.name_ = name_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.protostuff.runtime.model.ModelProtobuf.User) { - return mergeFrom((io.protostuff.runtime.model.ModelProtobuf.User) other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.protostuff.runtime.model.ModelProtobuf.User other) { - if (other == io.protostuff.runtime.model.ModelProtobuf.User.getDefaultInstance()) { - return this; - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - onChanged(); - } - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - io.protostuff.runtime.model.ModelProtobuf.User parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (io.protostuff.runtime.model.ModelProtobuf.User) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private java.lang.Object name_ = ""; - - /** - * string name = 1; - */ - public java.lang.String getName() { - java.lang.Object ref = name_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - - /** - * string name = 1; - */ - public com.google.protobuf.ByteString getNameBytes() { - java.lang.Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string name = 1; - */ - public Builder setName( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - - name_ = value; - onChanged(); - return this; - } - - /** - * string name = 1; - */ - public Builder clearName() { - - name_ = getDefaultInstance().getName(); - onChanged(); - return this; - } - - /** - * string name = 1; - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - name_ = value; - onChanged(); - return this; - } - - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return this; - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return this; - } - - // @@protoc_insertion_point(builder_scope:io.protostuff.runtime.model.User) - } - - // @@protoc_insertion_point(class_scope:io.protostuff.runtime.model.User) - private static final io.protostuff.runtime.model.ModelProtobuf.User DEFAULT_INSTANCE; - - static { - DEFAULT_INSTANCE = new io.protostuff.runtime.model.ModelProtobuf.User(); - } - - public static io.protostuff.runtime.model.ModelProtobuf.User getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public User parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new User(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public io.protostuff.runtime.model.ModelProtobuf.User getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - } - - public interface RequestHeaderOrBuilder extends - // @@protoc_insertion_point(interface_extends:io.protostuff.runtime.model.RequestHeader) - com.google.protobuf.MessageOrBuilder { - - /** - * string destMicroservice = 1; - */ - java.lang.String getDestMicroservice(); - - /** - * string destMicroservice = 1; - */ - com.google.protobuf.ByteString getDestMicroserviceBytes(); - - /** - * int32 msgType = 2; - */ - int getMsgType(); - - /** - * int32 flags = 3; - */ - int getFlags(); - - /** - * string schemaId = 5; - */ - java.lang.String getSchemaId(); - - /** - * string schemaId = 5; - */ - com.google.protobuf.ByteString getSchemaIdBytes(); - - /** - * string operationName = 6; - */ - java.lang.String getOperationName(); - - /** - * string operationName = 6; - */ - com.google.protobuf.ByteString getOperationNameBytes(); - - /** - * map<string, string> cseContext = 7; - */ - int getCseContextCount(); - - /** - * map<string, string> cseContext = 7; - */ - boolean containsCseContext( - java.lang.String key); - - /** - * Use {@link #getCseContextMap()} instead. - */ - @java.lang.Deprecated - java.util.Map getCseContext(); - - /** - * map<string, string> cseContext = 7; - */ - java.util.Map getCseContextMap(); - - /** - * map<string, string> cseContext = 7; - */ - - java.lang.String getCseContextOrDefault( - java.lang.String key, - java.lang.String defaultValue); - - /** - * map<string, string> cseContext = 7; - */ - - java.lang.String getCseContextOrThrow( - java.lang.String key); - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - int getUserMapCount(); - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - boolean containsUserMap( - java.lang.String key); - - /** - * Use {@link #getUserMapMap()} instead. - */ - @java.lang.Deprecated - java.util.Map getUserMap(); - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - java.util.Map getUserMapMap(); - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrDefault( - java.lang.String key, - io.protostuff.runtime.model.ModelProtobuf.User defaultValue); - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrThrow( - java.lang.String key); - - /** - * repeated string list = 9; - */ - java.util.List getListList(); - - /** - * repeated string list = 9; - */ - int getListCount(); - - /** - * repeated string list = 9; - */ - java.lang.String getList(int index); - - /** - * repeated string list = 9; - */ - com.google.protobuf.ByteString getListBytes(int index); - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - java.util.List getUserListList(); - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - io.protostuff.runtime.model.ModelProtobuf.User getUserList(int index); - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - int getUserListCount(); - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - java.util.List getUserListOrBuilderList(); - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - io.protostuff.runtime.model.ModelProtobuf.UserOrBuilder getUserListOrBuilder( - int index); - } - - /** - * Protobuf type {@code io.protostuff.runtime.model.RequestHeader} - */ - public static final class RequestHeader extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:io.protostuff.runtime.model.RequestHeader) - RequestHeaderOrBuilder { - // Use RequestHeader.newBuilder() to construct. - private RequestHeader(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - - private RequestHeader() { - destMicroservice_ = ""; - msgType_ = 0; - flags_ = 0; - schemaId_ = ""; - operationName_ = ""; - list_ = com.google.protobuf.LazyStringArrayList.EMPTY; - userList_ = java.util.Collections.emptyList(); - } - - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet getUnknownFields() { - return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); - } - - private RequestHeader( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - int mutable_bitField0_ = 0; - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!input.skipField(tag)) { - done = true; - } - break; - } - case 10: { - java.lang.String s = input.readStringRequireUtf8(); - - destMicroservice_ = s; - break; - } - case 16: { - - msgType_ = input.readInt32(); - break; - } - case 24: { - - flags_ = input.readInt32(); - break; - } - case 42: { - java.lang.String s = input.readStringRequireUtf8(); - - schemaId_ = s; - break; - } - case 50: { - java.lang.String s = input.readStringRequireUtf8(); - - operationName_ = s; - break; - } - case 58: { - if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) { - cseContext_ = com.google.protobuf.MapField.newMapField( - CseContextDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00000020; - } - com.google.protobuf.MapEntry cseContext__ = - input.readMessage( - CseContextDefaultEntryHolder.defaultEntry.getParserForType(), - extensionRegistry); - cseContext_.getMutableMap().put( - cseContext__.getKey(), - cseContext__.getValue()); - break; - } - case 66: { - if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) { - userMap_ = com.google.protobuf.MapField.newMapField( - UserMapDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00000040; - } - com.google.protobuf.MapEntry userMap__ = - input.readMessage( - UserMapDefaultEntryHolder.defaultEntry.getParserForType(), - extensionRegistry); - userMap_.getMutableMap().put( - userMap__.getKey(), - userMap__.getValue()); - break; - } - case 74: { - java.lang.String s = input.readStringRequireUtf8(); - if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) { - list_ = new com.google.protobuf.LazyStringArrayList(); - mutable_bitField0_ |= 0x00000080; - } - list_.add(s); - break; - } - case 82: { - if (!((mutable_bitField0_ & 0x00000100) == 0x00000100)) { - userList_ = new java.util.ArrayList<>(); - mutable_bitField0_ |= 0x00000100; - } - userList_.add( - input.readMessage(io.protostuff.runtime.model.ModelProtobuf.User.parser(), - extensionRegistry)); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) { - list_ = list_.getUnmodifiableView(); - } - if (((mutable_bitField0_ & 0x00000100) == 0x00000100)) { - userList_ = java.util.Collections.unmodifiableList(userList_); - } - makeExtensionsImmutable(); - } - } - - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 7: - return internalGetCseContext(); - case 8: - return internalGetUserMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.protostuff.runtime.model.ModelProtobuf.RequestHeader.class, - io.protostuff.runtime.model.ModelProtobuf.RequestHeader.Builder.class); - } - - @SuppressWarnings("unused") - private int bitField0_; - - public static final int DESTMICROSERVICE_FIELD_NUMBER = 1; - - private volatile java.lang.Object destMicroservice_; - - /** - * string destMicroservice = 1; - */ - public java.lang.String getDestMicroservice() { - java.lang.Object ref = destMicroservice_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - destMicroservice_ = s; - return s; - } - } - - /** - * string destMicroservice = 1; - */ - public com.google.protobuf.ByteString getDestMicroserviceBytes() { - java.lang.Object ref = destMicroservice_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - destMicroservice_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int MSGTYPE_FIELD_NUMBER = 2; - - private int msgType_; - - /** - * int32 msgType = 2; - */ - public int getMsgType() { - return msgType_; - } - - public static final int FLAGS_FIELD_NUMBER = 3; - - private int flags_; - - /** - * int32 flags = 3; - */ - public int getFlags() { - return flags_; - } - - public static final int SCHEMAID_FIELD_NUMBER = 5; - - private volatile java.lang.Object schemaId_; - - /** - * string schemaId = 5; - */ - public java.lang.String getSchemaId() { - java.lang.Object ref = schemaId_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - schemaId_ = s; - return s; - } - } - - /** - * string schemaId = 5; - */ - public com.google.protobuf.ByteString getSchemaIdBytes() { - java.lang.Object ref = schemaId_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - schemaId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int OPERATIONNAME_FIELD_NUMBER = 6; - - private volatile java.lang.Object operationName_; - - /** - * string operationName = 6; - */ - public java.lang.String getOperationName() { - java.lang.Object ref = operationName_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - operationName_ = s; - return s; - } - } - - /** - * string operationName = 6; - */ - public com.google.protobuf.ByteString getOperationNameBytes() { - java.lang.Object ref = operationName_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - operationName_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CSECONTEXT_FIELD_NUMBER = 7; - - private static final class CseContextDefaultEntryHolder { - static final com.google.protobuf.MapEntry defaultEntry = - com.google.protobuf.MapEntry.newDefaultInstance( - io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - - private com.google.protobuf.MapField cseContext_; - - private com.google.protobuf.MapField internalGetCseContext() { - if (cseContext_ == null) { - return com.google.protobuf.MapField.emptyMapField( - CseContextDefaultEntryHolder.defaultEntry); - } - return cseContext_; - } - - public int getCseContextCount() { - return internalGetCseContext().getMap().size(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public boolean containsCseContext( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - return internalGetCseContext().getMap().containsKey(key); - } - - /** - * Use {@link #getCseContextMap()} instead. - */ - @java.lang.Deprecated - public java.util.Map getCseContext() { - return getCseContextMap(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.util.Map getCseContextMap() { - return internalGetCseContext().getMap(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.lang.String getCseContextOrDefault( - java.lang.String key, - java.lang.String defaultValue) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetCseContext().getMap(); - return map.getOrDefault(key, defaultValue); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.lang.String getCseContextOrThrow( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetCseContext().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - public static final int USERMAP_FIELD_NUMBER = 8; - - private static final class UserMapDefaultEntryHolder { - static final com.google.protobuf.MapEntry defaultEntry = - com.google.protobuf.MapEntry.newDefaultInstance( - io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.MESSAGE, - io.protostuff.runtime.model.ModelProtobuf.User.getDefaultInstance()); - } - - private com.google.protobuf.MapField userMap_; - - private com.google.protobuf.MapField internalGetUserMap() { - if (userMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - UserMapDefaultEntryHolder.defaultEntry); - } - return userMap_; - } - - public int getUserMapCount() { - return internalGetUserMap().getMap().size(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public boolean containsUserMap( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - return internalGetUserMap().getMap().containsKey(key); - } - - /** - * Use {@link #getUserMapMap()} instead. - */ - @java.lang.Deprecated - public java.util.Map getUserMap() { - return getUserMapMap(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public java.util.Map getUserMapMap() { - return internalGetUserMap().getMap(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrDefault( - java.lang.String key, - io.protostuff.runtime.model.ModelProtobuf.User defaultValue) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetUserMap().getMap(); - return map.getOrDefault(key, defaultValue); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrThrow( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetUserMap().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - public static final int LIST_FIELD_NUMBER = 9; - - private com.google.protobuf.LazyStringList list_; - - /** - * repeated string list = 9; - */ - public com.google.protobuf.ProtocolStringList getListList() { - return list_; - } - - /** - * repeated string list = 9; - */ - public int getListCount() { - return list_.size(); - } - - /** - * repeated string list = 9; - */ - public java.lang.String getList(int index) { - return list_.get(index); - } - - /** - * repeated string list = 9; - */ - public com.google.protobuf.ByteString getListBytes(int index) { - return list_.getByteString(index); - } - - public static final int USERLIST_FIELD_NUMBER = 10; - - private java.util.List userList_; - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public java.util.List getUserListList() { - return userList_; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public java.util.List getUserListOrBuilderList() { - return userList_; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public int getUserListCount() { - return userList_.size(); - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.User getUserList(int index) { - return userList_.get(index); - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.UserOrBuilder getUserListOrBuilder( - int index) { - return userList_.get(index); - } - - private byte memoizedIsInitialized = -1; - - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) { - return true; - } - if (isInitialized == 0) { - return false; - } - - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { - if (!getDestMicroserviceBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, destMicroservice_); - } - if (msgType_ != 0) { - output.writeInt32(2, msgType_); - } - if (flags_ != 0) { - output.writeInt32(3, flags_); - } - if (!getSchemaIdBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 5, schemaId_); - } - if (!getOperationNameBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 6, operationName_); - } - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetCseContext(), - CseContextDefaultEntryHolder.defaultEntry, - 7); - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetUserMap(), - UserMapDefaultEntryHolder.defaultEntry, - 8); - for (int i = 0; i < list_.size(); i++) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 9, list_.getRaw(i)); - } - for (User anUserList_ : userList_) { - output.writeMessage(10, anUserList_); - } - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) { - return size; - } - - size = 0; - if (!getDestMicroserviceBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, destMicroservice_); - } - if (msgType_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(2, msgType_); - } - if (flags_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(3, flags_); - } - if (!getSchemaIdBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, schemaId_); - } - if (!getOperationNameBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, operationName_); - } - for (java.util.Map.Entry entry : internalGetCseContext().getMap() - .entrySet()) { - com.google.protobuf.MapEntry cseContext__ = - CseContextDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(7, cseContext__); - } - for (java.util.Map.Entry entry : internalGetUserMap() - .getMap() - .entrySet()) { - com.google.protobuf.MapEntry userMap__ = - UserMapDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(8, userMap__); - } - { - int dataSize = 0; - for (int i = 0; i < list_.size(); i++) { - dataSize += computeStringSizeNoTag(list_.getRaw(i)); - } - size += dataSize; - size += 1 * getListList().size(); - } - size += userList_.stream().mapToInt(anUserList_ -> CodedOutputStream - .computeMessageSize(10, anUserList_)).sum(); - memoizedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof io.protostuff.runtime.model.ModelProtobuf.RequestHeader)) { - return super.equals(obj); - } - io.protostuff.runtime.model.ModelProtobuf.RequestHeader other = - (io.protostuff.runtime.model.ModelProtobuf.RequestHeader) obj; - - boolean result = true; - result = result && getDestMicroservice() - .equals(other.getDestMicroservice()); - result = result && (getMsgType() == other.getMsgType()); - result = result && (getFlags() == other.getFlags()); - result = result && getSchemaId() - .equals(other.getSchemaId()); - result = result && getOperationName() - .equals(other.getOperationName()); - result = result && internalGetCseContext().equals( - other.internalGetCseContext()); - result = result && internalGetUserMap().equals( - other.internalGetUserMap()); - result = result && getListList() - .equals(other.getListList()); - result = result && getUserListList() - .equals(other.getUserListList()); - return result; - } - - @SuppressWarnings("unchecked") - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + DESTMICROSERVICE_FIELD_NUMBER; - hash = (53 * hash) + getDestMicroservice().hashCode(); - hash = (37 * hash) + MSGTYPE_FIELD_NUMBER; - hash = (53 * hash) + getMsgType(); - hash = (37 * hash) + FLAGS_FIELD_NUMBER; - hash = (53 * hash) + getFlags(); - hash = (37 * hash) + SCHEMAID_FIELD_NUMBER; - hash = (53 * hash) + getSchemaId().hashCode(); - hash = (37 * hash) + OPERATIONNAME_FIELD_NUMBER; - hash = (53 * hash) + getOperationName().hashCode(); - if (!internalGetCseContext().getMap().isEmpty()) { - hash = (37 * hash) + CSECONTEXT_FIELD_NUMBER; - hash = (53 * hash) + internalGetCseContext().hashCode(); - } - if (!internalGetUserMap().getMap().isEmpty()) { - hash = (37 * hash) + USERMAP_FIELD_NUMBER; - hash = (53 * hash) + internalGetUserMap().hashCode(); - } - if (getListCount() > 0) { - hash = (37 * hash) + LIST_FIELD_NUMBER; - hash = (53 * hash) + getListList().hashCode(); - } - if (getUserListCount() > 0) { - hash = (37 * hash) + USERLIST_FIELD_NUMBER; - hash = (53 * hash) + getUserListList().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - java.io.InputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseDelimitedFrom( - java.io.InputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - com.google.protobuf.CodedInputStream input) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { - return newBuilder(); - } - - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - - public static Builder newBuilder(io.protostuff.runtime.model.ModelProtobuf.RequestHeader prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - - public Builder toBuilder() { - return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - - /** - * Protobuf type {@code io.protostuff.runtime.model.RequestHeader} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:io.protostuff.runtime.model.RequestHeader) - io.protostuff.runtime.model.ModelProtobuf.RequestHeaderOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 7: - return internalGetCseContext(); - case 8: - return internalGetUserMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMutableMapField( - int number) { - switch (number) { - case 7: - return internalGetMutableCseContext(); - case 8: - return internalGetMutableUserMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_fieldAccessorTable - .ensureFieldAccessorsInitialized( - io.protostuff.runtime.model.ModelProtobuf.RequestHeader.class, - io.protostuff.runtime.model.ModelProtobuf.RequestHeader.Builder.class); - } - - // Construct using io.protostuff.runtime.model.ModelProtobuf.RequestHeader.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) { - getUserListFieldBuilder(); - } - } - - public Builder clear() { - super.clear(); - destMicroservice_ = ""; - - msgType_ = 0; - - flags_ = 0; - - schemaId_ = ""; - - operationName_ = ""; - - internalGetMutableCseContext().clear(); - internalGetMutableUserMap().clear(); - list_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00000080); - if (userListBuilder_ == null) { - userList_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000100); - } else { - userListBuilder_.clear(); - } - return this; - } - - public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return io.protostuff.runtime.model.ModelProtobuf.internal_static_io_protostuff_runtime_model_RequestHeader_descriptor; - } - - public io.protostuff.runtime.model.ModelProtobuf.RequestHeader getDefaultInstanceForType() { - return io.protostuff.runtime.model.ModelProtobuf.RequestHeader.getDefaultInstance(); - } - - public io.protostuff.runtime.model.ModelProtobuf.RequestHeader build() { - io.protostuff.runtime.model.ModelProtobuf.RequestHeader result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @SuppressWarnings("unused") - public io.protostuff.runtime.model.ModelProtobuf.RequestHeader buildPartial() { - io.protostuff.runtime.model.ModelProtobuf.RequestHeader result = - new io.protostuff.runtime.model.ModelProtobuf.RequestHeader(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - result.destMicroservice_ = destMicroservice_; - result.msgType_ = msgType_; - result.flags_ = flags_; - result.schemaId_ = schemaId_; - result.operationName_ = operationName_; - result.cseContext_ = internalGetCseContext(); - result.cseContext_.makeImmutable(); - result.userMap_ = internalGetUserMap(); - result.userMap_.makeImmutable(); - if (((bitField0_ & 0x00000080) == 0x00000080)) { - list_ = list_.getUnmodifiableView(); - bitField0_ = (bitField0_ & ~0x00000080); - } - result.list_ = list_; - if (userListBuilder_ == null) { - if (((bitField0_ & 0x00000100) == 0x00000100)) { - userList_ = java.util.Collections.unmodifiableList(userList_); - bitField0_ = (bitField0_ & ~0x00000100); - } - result.userList_ = userList_; - } else { - result.userList_ = userListBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof io.protostuff.runtime.model.ModelProtobuf.RequestHeader) { - return mergeFrom((io.protostuff.runtime.model.ModelProtobuf.RequestHeader) other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(io.protostuff.runtime.model.ModelProtobuf.RequestHeader other) { - if (other == io.protostuff.runtime.model.ModelProtobuf.RequestHeader.getDefaultInstance()) { - return this; - } - if (!other.getDestMicroservice().isEmpty()) { - destMicroservice_ = other.destMicroservice_; - onChanged(); - } - if (other.getMsgType() != 0) { - setMsgType(other.getMsgType()); - } - if (other.getFlags() != 0) { - setFlags(other.getFlags()); - } - if (!other.getSchemaId().isEmpty()) { - schemaId_ = other.schemaId_; - onChanged(); - } - if (!other.getOperationName().isEmpty()) { - operationName_ = other.operationName_; - onChanged(); - } - internalGetMutableCseContext().mergeFrom( - other.internalGetCseContext()); - internalGetMutableUserMap().mergeFrom( - other.internalGetUserMap()); - if (!other.list_.isEmpty()) { - if (list_.isEmpty()) { - list_ = other.list_; - bitField0_ = (bitField0_ & ~0x00000080); - } else { - ensureListIsMutable(); - list_.addAll(other.list_); - } - onChanged(); - } - if (userListBuilder_ == null) { - if (!other.userList_.isEmpty()) { - if (userList_.isEmpty()) { - userList_ = other.userList_; - bitField0_ = (bitField0_ & ~0x00000100); - } else { - ensureUserListIsMutable(); - userList_.addAll(other.userList_); - } - onChanged(); - } - } else { - if (!other.userList_.isEmpty()) { - if (userListBuilder_.isEmpty()) { - userListBuilder_.dispose(); - userListBuilder_ = null; - userList_ = other.userList_; - bitField0_ = (bitField0_ & ~0x00000100); - userListBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders - ? getUserListFieldBuilder() - : null; - } else { - userListBuilder_.addAllMessages(other.userList_); - } - } - } - onChanged(); - return this; - } - - public final boolean isInitialized() { - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - io.protostuff.runtime.model.ModelProtobuf.RequestHeader parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = - (io.protostuff.runtime.model.ModelProtobuf.RequestHeader) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private int bitField0_; - - private java.lang.Object destMicroservice_ = ""; - - /** - * string destMicroservice = 1; - */ - public java.lang.String getDestMicroservice() { - java.lang.Object ref = destMicroservice_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - destMicroservice_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - - /** - * string destMicroservice = 1; - */ - public com.google.protobuf.ByteString getDestMicroserviceBytes() { - java.lang.Object ref = destMicroservice_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - destMicroservice_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string destMicroservice = 1; - */ - public Builder setDestMicroservice( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - - destMicroservice_ = value; - onChanged(); - return this; - } - - /** - * string destMicroservice = 1; - */ - public Builder clearDestMicroservice() { - - destMicroservice_ = getDefaultInstance().getDestMicroservice(); - onChanged(); - return this; - } - - /** - * string destMicroservice = 1; - */ - public Builder setDestMicroserviceBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - destMicroservice_ = value; - onChanged(); - return this; - } - - private int msgType_; - - /** - * int32 msgType = 2; - */ - public int getMsgType() { - return msgType_; - } - - /** - * int32 msgType = 2; - */ - public Builder setMsgType(int value) { - - msgType_ = value; - onChanged(); - return this; - } - - /** - * int32 msgType = 2; - */ - public Builder clearMsgType() { - - msgType_ = 0; - onChanged(); - return this; - } - - private int flags_; - - /** - * int32 flags = 3; - */ - public int getFlags() { - return flags_; - } - - /** - * int32 flags = 3; - */ - public Builder setFlags(int value) { - - flags_ = value; - onChanged(); - return this; - } - - /** - * int32 flags = 3; - */ - public Builder clearFlags() { - - flags_ = 0; - onChanged(); - return this; - } - - private java.lang.Object schemaId_ = ""; - - /** - * string schemaId = 5; - */ - public java.lang.String getSchemaId() { - java.lang.Object ref = schemaId_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - schemaId_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - - /** - * string schemaId = 5; - */ - public com.google.protobuf.ByteString getSchemaIdBytes() { - java.lang.Object ref = schemaId_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - schemaId_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string schemaId = 5; - */ - public Builder setSchemaId( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - - schemaId_ = value; - onChanged(); - return this; - } - - /** - * string schemaId = 5; - */ - public Builder clearSchemaId() { - - schemaId_ = getDefaultInstance().getSchemaId(); - onChanged(); - return this; - } - - /** - * string schemaId = 5; - */ - public Builder setSchemaIdBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - schemaId_ = value; - onChanged(); - return this; - } - - private java.lang.Object operationName_ = ""; - - /** - * string operationName = 6; - */ - public java.lang.String getOperationName() { - java.lang.Object ref = operationName_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - operationName_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - - /** - * string operationName = 6; - */ - public com.google.protobuf.ByteString getOperationNameBytes() { - java.lang.Object ref = operationName_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - operationName_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string operationName = 6; - */ - public Builder setOperationName( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - - operationName_ = value; - onChanged(); - return this; - } - - /** - * string operationName = 6; - */ - public Builder clearOperationName() { - - operationName_ = getDefaultInstance().getOperationName(); - onChanged(); - return this; - } - - /** - * string operationName = 6; - */ - public Builder setOperationNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - operationName_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.MapField cseContext_; - - private com.google.protobuf.MapField internalGetCseContext() { - if (cseContext_ == null) { - return com.google.protobuf.MapField.emptyMapField( - CseContextDefaultEntryHolder.defaultEntry); - } - return cseContext_; - } - - private com.google.protobuf.MapField internalGetMutableCseContext() { - onChanged(); - if (cseContext_ == null) { - cseContext_ = com.google.protobuf.MapField.newMapField( - CseContextDefaultEntryHolder.defaultEntry); - } - if (!cseContext_.isMutable()) { - cseContext_ = cseContext_.copy(); - } - return cseContext_; - } - - public int getCseContextCount() { - return internalGetCseContext().getMap().size(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public boolean containsCseContext( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - return internalGetCseContext().getMap().containsKey(key); - } - - /** - * Use {@link #getCseContextMap()} instead. - */ - @java.lang.Deprecated - public java.util.Map getCseContext() { - return getCseContextMap(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.util.Map getCseContextMap() { - return internalGetCseContext().getMap(); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.lang.String getCseContextOrDefault( - java.lang.String key, - java.lang.String defaultValue) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetCseContext().getMap(); - return map.getOrDefault(key, defaultValue); - } - - /** - * map<string, string> cseContext = 7; - */ - - public java.lang.String getCseContextOrThrow( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetCseContext().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearCseContext() { - internalGetMutableCseContext().getMutableMap() - .clear(); - return this; - } - - /** - * map<string, string> cseContext = 7; - */ - - public Builder removeCseContext( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - internalGetMutableCseContext().getMutableMap() - .remove(key); - return this; - } - - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map getMutableCseContext() { - return internalGetMutableCseContext().getMutableMap(); - } - - /** - * map<string, string> cseContext = 7; - */ - public Builder putCseContext( - java.lang.String key, - java.lang.String value) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - if (value == null) { - throw new java.lang.NullPointerException(); - } - internalGetMutableCseContext().getMutableMap() - .put(key, value); - return this; - } - - /** - * map<string, string> cseContext = 7; - */ - - public Builder putAllCseContext( - java.util.Map values) { - internalGetMutableCseContext().getMutableMap() - .putAll(values); - return this; - } - - private com.google.protobuf.MapField userMap_; - - private com.google.protobuf.MapField internalGetUserMap() { - if (userMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - UserMapDefaultEntryHolder.defaultEntry); - } - return userMap_; - } - - private com.google.protobuf.MapField internalGetMutableUserMap() { - onChanged(); - if (userMap_ == null) { - userMap_ = com.google.protobuf.MapField.newMapField( - UserMapDefaultEntryHolder.defaultEntry); - } - if (!userMap_.isMutable()) { - userMap_ = userMap_.copy(); - } - return userMap_; - } - - public int getUserMapCount() { - return internalGetUserMap().getMap().size(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public boolean containsUserMap( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - return internalGetUserMap().getMap().containsKey(key); - } - - /** - * Use {@link #getUserMapMap()} instead. - */ - @java.lang.Deprecated - public java.util.Map getUserMap() { - return getUserMapMap(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public java.util.Map getUserMapMap() { - return internalGetUserMap().getMap(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrDefault( - java.lang.String key, - io.protostuff.runtime.model.ModelProtobuf.User defaultValue) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetUserMap().getMap(); - return map.getOrDefault(key, defaultValue); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public io.protostuff.runtime.model.ModelProtobuf.User getUserMapOrThrow( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - java.util.Map map = - internalGetUserMap().getMap(); - if (!map.containsKey(key)) { - throw new java.lang.IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearUserMap() { - internalGetMutableUserMap().getMutableMap() - .clear(); - return this; - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public Builder removeUserMap( - java.lang.String key) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - internalGetMutableUserMap().getMutableMap() - .remove(key); - return this; - } - - /** - * Use alternate mutation accessors instead. - */ - @java.lang.Deprecated - public java.util.Map getMutableUserMap() { - return internalGetMutableUserMap().getMutableMap(); - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - public Builder putUserMap( - java.lang.String key, - io.protostuff.runtime.model.ModelProtobuf.User value) { - if (key == null) { - throw new java.lang.NullPointerException(); - } - if (value == null) { - throw new java.lang.NullPointerException(); - } - internalGetMutableUserMap().getMutableMap() - .put(key, value); - return this; - } - - /** - * map<string, .io.protostuff.runtime.model.User> userMap = 8; - */ - - public Builder putAllUserMap( - java.util.Map values) { - internalGetMutableUserMap().getMutableMap() - .putAll(values); - return this; - } - - private com.google.protobuf.LazyStringList list_ = com.google.protobuf.LazyStringArrayList.EMPTY; - - private void ensureListIsMutable() { - if (!((bitField0_ & 0x00000080) == 0x00000080)) { - list_ = new com.google.protobuf.LazyStringArrayList(list_); - bitField0_ |= 0x00000080; - } - } - - /** - * repeated string list = 9; - */ - public com.google.protobuf.ProtocolStringList getListList() { - return list_.getUnmodifiableView(); - } - - /** - * repeated string list = 9; - */ - public int getListCount() { - return list_.size(); - } - - /** - * repeated string list = 9; - */ - public java.lang.String getList(int index) { - return list_.get(index); - } - - /** - * repeated string list = 9; - */ - public com.google.protobuf.ByteString getListBytes(int index) { - return list_.getByteString(index); - } - - /** - * repeated string list = 9; - */ - public Builder setList( - int index, java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureListIsMutable(); - list_.set(index, value); - onChanged(); - return this; - } - - /** - * repeated string list = 9; - */ - public Builder addList( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureListIsMutable(); - list_.add(value); - onChanged(); - return this; - } - - /** - * repeated string list = 9; - */ - public Builder addAllList( - java.lang.Iterable values) { - ensureListIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, - list_); - onChanged(); - return this; - } - - /** - * repeated string list = 9; - */ - public Builder clearList() { - list_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00000080); - onChanged(); - return this; - } - - /** - * repeated string list = 9; - */ - public Builder addListBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - ensureListIsMutable(); - list_.add(value); - onChanged(); - return this; - } - - private java.util.List userList_ = - java.util.Collections.emptyList(); - - private void ensureUserListIsMutable() { - if (!((bitField0_ & 0x00000100) == 0x00000100)) { - userList_ = new java.util.ArrayList<>(userList_); - bitField0_ |= 0x00000100; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3 userListBuilder_; - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public java.util.List getUserListList() { - if (userListBuilder_ == null) { - return java.util.Collections.unmodifiableList(userList_); - } else { - return userListBuilder_.getMessageList(); - } - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public int getUserListCount() { - if (userListBuilder_ == null) { - return userList_.size(); - } else { - return userListBuilder_.getCount(); - } - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.User getUserList(int index) { - if (userListBuilder_ == null) { - return userList_.get(index); - } else { - return userListBuilder_.getMessage(index); - } - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder setUserList( - int index, io.protostuff.runtime.model.ModelProtobuf.User value) { - if (userListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureUserListIsMutable(); - userList_.set(index, value); - onChanged(); - } else { - userListBuilder_.setMessage(index, value); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder setUserList( - int index, io.protostuff.runtime.model.ModelProtobuf.User.Builder builderForValue) { - if (userListBuilder_ == null) { - ensureUserListIsMutable(); - userList_.set(index, builderForValue.build()); - onChanged(); - } else { - userListBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder addUserList(io.protostuff.runtime.model.ModelProtobuf.User value) { - if (userListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureUserListIsMutable(); - userList_.add(value); - onChanged(); - } else { - userListBuilder_.addMessage(value); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder addUserList( - int index, io.protostuff.runtime.model.ModelProtobuf.User value) { - if (userListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureUserListIsMutable(); - userList_.add(index, value); - onChanged(); - } else { - userListBuilder_.addMessage(index, value); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder addUserList( - io.protostuff.runtime.model.ModelProtobuf.User.Builder builderForValue) { - if (userListBuilder_ == null) { - ensureUserListIsMutable(); - userList_.add(builderForValue.build()); - onChanged(); - } else { - userListBuilder_.addMessage(builderForValue.build()); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder addUserList( - int index, io.protostuff.runtime.model.ModelProtobuf.User.Builder builderForValue) { - if (userListBuilder_ == null) { - ensureUserListIsMutable(); - userList_.add(index, builderForValue.build()); - onChanged(); - } else { - userListBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder addAllUserList( - java.lang.Iterable values) { - if (userListBuilder_ == null) { - ensureUserListIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, - userList_); - onChanged(); - } else { - userListBuilder_.addAllMessages(values); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder clearUserList() { - if (userListBuilder_ == null) { - userList_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000100); - onChanged(); - } else { - userListBuilder_.clear(); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public Builder removeUserList(int index) { - if (userListBuilder_ == null) { - ensureUserListIsMutable(); - userList_.remove(index); - onChanged(); - } else { - userListBuilder_.remove(index); - } - return this; - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.User.Builder getUserListBuilder( - int index) { - return getUserListFieldBuilder().getBuilder(index); - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.UserOrBuilder getUserListOrBuilder( - int index) { - if (userListBuilder_ == null) { - return userList_.get(index); - } else { - return userListBuilder_.getMessageOrBuilder(index); - } - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public java.util.List getUserListOrBuilderList() { - if (userListBuilder_ != null) { - return userListBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(userList_); - } - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.User.Builder addUserListBuilder() { - return getUserListFieldBuilder().addBuilder( - io.protostuff.runtime.model.ModelProtobuf.User.getDefaultInstance()); - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public io.protostuff.runtime.model.ModelProtobuf.User.Builder addUserListBuilder( - int index) { - return getUserListFieldBuilder().addBuilder( - index, - io.protostuff.runtime.model.ModelProtobuf.User.getDefaultInstance()); - } - - /** - * repeated .io.protostuff.runtime.model.User userList = 10; - */ - public java.util.List getUserListBuilderList() { - return getUserListFieldBuilder().getBuilderList(); - } - - private com.google.protobuf.RepeatedFieldBuilderV3 getUserListFieldBuilder() { - if (userListBuilder_ == null) { - userListBuilder_ = - new com.google.protobuf.RepeatedFieldBuilderV3<>( - userList_, - ((bitField0_ & 0x00000100) == 0x00000100), - getParentForChildren(), - isClean()); - userList_ = null; - } - return userListBuilder_; - } - - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return this; - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return this; - } - - // @@protoc_insertion_point(builder_scope:io.protostuff.runtime.model.RequestHeader) - } - - // @@protoc_insertion_point(class_scope:io.protostuff.runtime.model.RequestHeader) - private static final io.protostuff.runtime.model.ModelProtobuf.RequestHeader DEFAULT_INSTANCE; - - static { - DEFAULT_INSTANCE = new io.protostuff.runtime.model.ModelProtobuf.RequestHeader(); - } - - public static io.protostuff.runtime.model.ModelProtobuf.RequestHeader getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public RequestHeader parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new RequestHeader(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public io.protostuff.runtime.model.ModelProtobuf.RequestHeader getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - } - - private static final com.google.protobuf.Descriptors.Descriptor internal_static_io_protostuff_runtime_model_User_descriptor; - - private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_protostuff_runtime_model_User_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor internal_static_io_protostuff_runtime_model_RequestHeader_descriptor; - - private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_protostuff_runtime_model_RequestHeader_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_descriptor; - - @SuppressWarnings("unused") - private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_descriptor; - - @SuppressWarnings("unused") - private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { - return descriptor; - } - - private static com.google.protobuf.Descriptors.FileDescriptor descriptor; - - static { - java.lang.String[] descriptorData = { - "\n\023ModelProtobuf.proto\022\033io.protostuff.run" + - "time.model\"\024\n\004User\022\014\n\004name\030\001 \001(\t\"\325\003\n\rReq" + - "uestHeader\022\030\n\020destMicroservice\030\001 \001(\t\022\017\n\007" + - "msgType\030\002 \001(\005\022\r\n\005flags\030\003 \001(\005\022\020\n\010schemaId" + - "\030\005 \001(\t\022\025\n\roperationName\030\006 \001(\t\022N\n\ncseCont" + - "ext\030\007 \003(\0132:.io.protostuff.runtime.model." + - "RequestHeader.CseContextEntry\022H\n\007userMap" + - "\030\010 \003(\01327.io.protostuff.runtime.model.Req" + - "uestHeader.UserMapEntry\022\014\n\004list\030\t \003(\t\0223\n" + - "\010userList\030\n \003(\0132!.io.protostuff.runtime.", - "model.User\0321\n\017CseContextEntry\022\013\n\003key\030\001 \001" + - "(\t\022\r\n\005value\030\002 \001(\t:\0028\001\032Q\n\014UserMapEntry\022\013\n" + - "\003key\030\001 \001(\t\0220\n\005value\030\002 \001(\0132!.io.protostuf" + - "f.runtime.model.User:\0028\001b\006proto3" - }; - com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = - new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { - public com.google.protobuf.ExtensionRegistry assignDescriptors( - com.google.protobuf.Descriptors.FileDescriptor root) { - descriptor = root; - return null; - } - }; - com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - }, - assigner); - internal_static_io_protostuff_runtime_model_User_descriptor = - getDescriptor().getMessageTypes().get(0); - internal_static_io_protostuff_runtime_model_User_fieldAccessorTable = - new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_io_protostuff_runtime_model_User_descriptor, - new java.lang.String[] {"Name",}); - internal_static_io_protostuff_runtime_model_RequestHeader_descriptor = - getDescriptor().getMessageTypes().get(1); - internal_static_io_protostuff_runtime_model_RequestHeader_fieldAccessorTable = - new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_io_protostuff_runtime_model_RequestHeader_descriptor, - new java.lang.String[] {"DestMicroservice", "MsgType", "Flags", "SchemaId", "OperationName", - "CseContext", "UserMap", "List", "UserList",}); - internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_descriptor = - internal_static_io_protostuff_runtime_model_RequestHeader_descriptor.getNestedTypes().get(0); - internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_fieldAccessorTable = - new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_io_protostuff_runtime_model_RequestHeader_CseContextEntry_descriptor, - new java.lang.String[] {"Key", "Value",}); - internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_descriptor = - internal_static_io_protostuff_runtime_model_RequestHeader_descriptor.getNestedTypes().get(1); - internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_fieldAccessorTable = - new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_io_protostuff_runtime_model_RequestHeader_UserMapEntry_descriptor, - new java.lang.String[] {"Key", "Value",}); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtostuff.java b/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtostuff.java index ec4efd65480..c9f41070fa0 100644 --- a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtostuff.java +++ b/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtostuff.java @@ -24,7 +24,6 @@ public class ModelProtostuff { - //CHECKSTYLE:OFF: magicnumber @Tag(1) private String destMicroservice; diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestOperationProtobuf.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestOperationProtobuf.java deleted file mode 100644 index 31834e1575e..00000000000 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestOperationProtobuf.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.definition; - -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.codec.protobuf.utils.schema.ArgsNotWrapSchema; -import org.apache.servicecomb.codec.protobuf.utils.schema.NormalWrapSchema; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.annotations.ApiResponse; - -public class TestOperationProtobuf { - class Impl { - @ApiResponse(code = 300, response = String.class, message = "") - public int test(int x) { - return 100; - } - } - - @Test - public void testOperationProtobuf() throws Exception { - UnitTestMeta meta = new UnitTestMeta(); - SchemaMeta schemaMeta = meta.getOrCreateSchemaMeta(Impl.class); - OperationMeta operationMeta = schemaMeta.findOperation("test"); - - OperationProtobuf operationProtobuf = ProtobufManager.getOrCreateOperation(operationMeta); - Assert.assertEquals(operationMeta, operationProtobuf.getOperationMeta()); - Assert.assertEquals(ArgsNotWrapSchema.class, operationProtobuf.getRequestSchema().getClass()); - Assert.assertEquals(NormalWrapSchema.class, operationProtobuf.getResponseSchema().getClass()); - - WrapSchema responseSchema = operationProtobuf.findResponseSchema(200); - Assert.assertEquals(operationProtobuf.getResponseSchema(), responseSchema); - - responseSchema = operationProtobuf.findResponseSchema(300); - Assert.assertNotNull(responseSchema); - Assert.assertNotEquals(operationProtobuf.getResponseSchema(), responseSchema); - } -} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestResponseRootDeserializer.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestResponseRootDeserializer.java new file mode 100644 index 00000000000..bf8a98f5c67 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/definition/TestResponseRootDeserializer.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.definition; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.junit.jupiter.api.Assertions; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.type.SimpleType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.junit.jupiter.api.Test; + +class Model { + +} + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class TestResponseRootDeserializer { + @Test + public void testNeedConvert() { + Assertions.assertEquals(SimpleType.constructUnsafe(Object.class), ProtoConst.OBJECT_TYPE); + Assertions.assertFalse(ResponseRootDeserializer.needConvert(1, TypeFactory.defaultInstance().constructType(int.class))); + Assertions.assertFalse(ResponseRootDeserializer.needConvert(1, TypeFactory.defaultInstance().constructType(Integer.class))); + Assertions.assertFalse(ResponseRootDeserializer + .needConvert(1, TypeFactory.defaultInstance().constructType(int.class))); + Assertions.assertFalse(ResponseRootDeserializer + .needConvert(1, TypeFactory.defaultInstance().constructType(Integer.class))); + Assertions.assertTrue(ResponseRootDeserializer + .needConvert(new HashMap<>(), TypeFactory.defaultInstance().constructType(Model.class))); + Assertions.assertFalse(ResponseRootDeserializer + .needConvert(new Model(), TypeFactory.defaultInstance().constructType(Model.class))); + Assertions.assertFalse(ResponseRootDeserializer + .needConvert(new Model(), TypeFactory.defaultInstance().constructType(Object.class))); + List modelList = new ArrayList<>(); + List modelMapList = new ArrayList<>(); + Assertions.assertTrue(ResponseRootDeserializer + .needConvert(modelMapList, TypeFactory.defaultInstance().constructType(new TypeReference>() { + }))); + // This case should be false, however it is not exists in real applications, for simpler, take it true. + Assertions.assertTrue(ResponseRootDeserializer + .needConvert(modelList, TypeFactory.defaultInstance().constructType(new TypeReference>() { + }))); + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestProtoToStringGenerator.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestProtoToStringGenerator.java index 9618313ab1b..d3ed28720b8 100644 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestProtoToStringGenerator.java +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestProtoToStringGenerator.java @@ -17,13 +17,13 @@ package org.apache.servicecomb.codec.protobuf.internal.converter; import org.apache.servicecomb.foundation.protobuf.internal.parser.ProtoParser; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; import io.protostuff.compiler.model.Proto; +import org.junit.jupiter.api.Test; public class TestProtoToStringGenerator { - static String content = "syntax = \"proto3\";\n" + static final String content = "syntax = \"proto3\";\n" + "import \"google/protobuf/any.proto\";\n" + "package org.apache.servicecomb.foundation.protobuf.internal.model;\n" + "\n" @@ -78,6 +78,6 @@ public void protoToString() { Proto proto = protoParser.parseFromContent(content); String newContent = new ProtoToStringGenerator(proto).protoToString(); - Assert.assertEquals(content, newContent); + Assertions.assertEquals(content, newContent); } } diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java new file mode 100644 index 00000000000..141b7cf4b2c --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodec.java @@ -0,0 +1,546 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.codec.protobuf.internal.converter; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.temporal.ChronoField; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootSerializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer; +import org.apache.servicecomb.codec.protobuf.internal.converter.model.ProtoSchema; +import org.apache.servicecomb.codec.protobuf.internal.converter.model.ProtoSchemaPojo; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.MicroserviceVersionsMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; +import org.apache.servicecomb.foundation.test.scaffolding.model.People; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; +import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGenerator; +import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.InvocationType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * SchemaMetaCodec test cases. This test cases covers POJO invoker and producer. + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class TestSchemaMetaCodec { + + private SchemaMeta providerSchemaMeta; + + private SchemaMeta consumerSchemaMeta; + + @BeforeEach + public void setUp() { + ProtobufManager.clear(); + } + + private void mockSchemaMeta(String schemaId, AbstractSwaggerGenerator swaggerGenerator, Object producerInstance) + throws Exception { + MicroserviceVersionsMeta microserviceVersionsMeta = Mockito.mock(MicroserviceVersionsMeta.class); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getExecutorManager()).thenReturn(executorManager); + + MicroserviceMeta providerMicroserviceMeta = Mockito.mock(MicroserviceMeta.class); + Mockito.when(providerMicroserviceMeta.getScbEngine()).thenReturn(scbEngine); + Mockito.when(providerMicroserviceMeta.getMicroserviceVersionsMeta()).thenReturn(microserviceVersionsMeta); + Mockito.when(providerMicroserviceMeta.getMicroserviceName()).thenReturn("test"); + Mockito.when(providerMicroserviceMeta.getExtData(ProtobufManager.EXT_ID)).thenReturn(null); + + MicroserviceMeta consumerMicroserviceMeta = Mockito.mock(MicroserviceMeta.class); + Mockito.when(consumerMicroserviceMeta.getScbEngine()).thenReturn(scbEngine); + Mockito.when(consumerMicroserviceMeta.getMicroserviceVersionsMeta()).thenReturn(microserviceVersionsMeta); + Mockito.when(consumerMicroserviceMeta.getMicroserviceName()).thenReturn("test"); + Mockito.when(consumerMicroserviceMeta.getExtData(ProtobufManager.EXT_ID)).thenReturn(null); + SwaggerEnvironment swaggerEnvironment = new SwaggerEnvironment(); + SwaggerProducer swaggerProducer = swaggerEnvironment.createProducer(producerInstance); + providerSchemaMeta = new SchemaMeta(providerMicroserviceMeta, schemaId, swaggerProducer.getSwagger()); + for (SwaggerProducerOperation producerOperation : swaggerProducer.getAllOperations()) { + OperationMeta operationMeta = providerSchemaMeta.ensureFindOperation(producerOperation.getOperationId()); + operationMeta.setSwaggerProducerOperation(producerOperation); + } + + consumerSchemaMeta = new SchemaMeta(consumerMicroserviceMeta, schemaId, swaggerProducer.getSwagger()); + } + + @Test + public void testProtoSchemaOperationUserSpringMVC() throws Exception { + mockSchemaMeta("ProtoSchema", new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationUserImpl(); + } + + @Test + public void testProtoSchemaOperationUserPOJO() throws Exception { + mockSchemaMeta("ProtoSchemaPojo", new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationUserImpl(); + } + + private Invocation mockInvocation(String operation, InvocationType invocationType) { + OperationMeta operationMeta; + boolean isProvider; + Invocation invocation = Mockito.mock(Invocation.class); + InvocationRuntimeType invocationRuntimeType; + + if (InvocationType.CONSUMER == invocationType) { + operationMeta = consumerSchemaMeta.getOperations().get(operation); + isProvider = false; + Mockito.when(invocation.getSchemaMeta()).thenReturn(consumerSchemaMeta); + invocationRuntimeType = operationMeta.buildBaseConsumerRuntimeType(); + } else { + operationMeta = providerSchemaMeta.getOperations().get(operation); + isProvider = true; + Mockito.when(invocation.getSchemaMeta()).thenReturn(providerSchemaMeta); + invocationRuntimeType = operationMeta.buildBaseProviderRuntimeType(); + } + + MicroserviceMeta microserviceMeta = operationMeta.getMicroserviceMeta(); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getInvocationRuntimeType()) + .thenReturn(invocationRuntimeType); + Mockito.when(invocation.findResponseType(200)) + .thenReturn(invocationRuntimeType.findResponseType(200)); + Mockito.when(invocation.getInvocationType()).thenReturn(invocationType); + Mockito.when(invocation.getMicroserviceMeta()).thenReturn(microserviceMeta); + + Mockito.when(invocation.isProducer()).thenReturn(isProvider); + return invocation; + } + + private void testProtoSchemaOperationUserImpl() throws IOException { + Invocation consumerInvocation = mockInvocation("user", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("user", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + byte[] values; + + // request message + Map args = new HashMap<>(); + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + user.friends = friends; + args.put("user", user); + values = requestSerializer.serialize(args); + + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedUserArgs = requestDeserializer.deserialize(values); + Assertions.assertEquals(user.name, ((User) decodedUserArgs.get("user")).name); + Assertions.assertEquals(user.friends.get(0).name, ((User) decodedUserArgs.get("user")).friends.get(0).name); + + // write request map (pojo) + args = new HashMap<>(); + Map userMap = new HashMap<>(); + userMap.put("name", "user"); + Map friendMap = new HashMap<>(); + friendMap.put("name", "friend"); + List> friendsList = new ArrayList<>(); + friendsList.add(friendMap); + userMap.put("friends", friendsList); + args.put("user", userMap); + values = requestSerializer.serialize(args); + + decodedUserArgs = requestDeserializer.deserialize(values); + Assertions.assertEquals(user.name, ((User) decodedUserArgs.get("user")).name); + Assertions.assertEquals(user.friends.get(0).name, ((User) decodedUserArgs.get("user")).friends.get(0).name); + + // response message + ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); + values = responseSerializer.serialize(user); + ResponseRootDeserializer responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); + User decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); + Assertions.assertEquals(user.name, decodedUser.name); + Assertions.assertEquals(user.friends.get(0).name, decodedUser.friends.get(0).name); + + user.friends = new ArrayList<>(); + values = responseSerializer.serialize(user); + decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); + Assertions.assertEquals(user.name, decodedUser.name); + // proto buffer encode and decode empty list to be null + Assertions.assertNull(decodedUser.friends); + } + + @Test + public void testProtoSchemaOperationmapUserSpringMVC() throws Exception { + mockSchemaMeta("ProtoSchema", new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationmapUserImpl(false); + } + + @Test + public void testProtoSchemaOperationmapUserPOJO() throws Exception { + mockSchemaMeta("ProtoSchemaPojo", new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationmapUserImpl(true); + } + + private void testProtoSchemaOperationmapUserImpl(boolean isPojo) throws IOException { + Invocation consumerInvocation = mockInvocation("mapUser", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("mapUser", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + byte[] values; + Map userMap = new HashMap<>(); + userMap.put("test", user); + + // request message + Map args = new HashMap<>(); + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + user.friends = friends; + args.put("users", userMap); + if (isPojo) { + Map swaggerArgs = new HashMap<>(1); + swaggerArgs.put("listListUserBody", args); + values = requestSerializer.serialize(swaggerArgs); + } else { + values = requestSerializer.serialize(args); + } + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedUserArgs = requestDeserializer.deserialize(values); + if (isPojo) { + decodedUserArgs = (Map) decodedUserArgs.get("mapUserBody"); + Assertions.assertEquals(user.name, + ((Map>) decodedUserArgs.get("users")).get("test").get("name")); + Assertions.assertEquals(user.friends.get(0).name, + ((List>) ((Map>) decodedUserArgs.get("users")).get("test") + .get("friends")).get(0).get("name")); + } else { + Assertions.assertEquals(user.name, ((Map) decodedUserArgs.get("users")).get("test").name); + Assertions.assertEquals(user.friends.get(0).name, + ((Map) decodedUserArgs.get("users")).get("test").friends.get(0).name); + } + // response message + ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); + values = responseSerializer.serialize(userMap); + ResponseRootDeserializer responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); + Map decodedUser = (Map) responseDeserializer.deserialize(values, + TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, User.class)); + Assertions.assertEquals(user.name, decodedUser.get("test").name); + Assertions.assertEquals(user.friends.get(0).name, decodedUser.get("test").friends.get(0).name); + + user.friends = new ArrayList<>(); + values = responseSerializer.serialize(userMap); + decodedUser = (Map) responseDeserializer.deserialize(values, + TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, User.class)); + Assertions.assertEquals(user.name, decodedUser.get("test").name); + // proto buffer encode and decode empty list to be null + Assertions.assertNull(decodedUser.get("test").friends); + } + + @Test + public void testProtoSchemaOperationBaseSpringMVC() throws Exception { + mockSchemaMeta("ProtoSchema", new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationBaseImpl(false); + } + + @Test + public void testProtoSchemaOperationBasePOJO() throws Exception { + mockSchemaMeta("ProtoSchemaPojo", new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationBaseImpl(true); + } + + private void testProtoSchemaOperationBaseImpl(boolean isPojo) throws IOException { + Invocation consumerInvocation = mockInvocation("base", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("base", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + byte[] values; + + // request message + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + boolean boolValue = true; + int iValue = 20; + long lValue = 30L; + float fValue = 40f; + double dValue = 50D; + String sValue = "hello"; + int[] iArray = new int[] {60, 70}; + Color color = Color.BLUE; + LocalDate localDate = LocalDate.of(2019, 10, 1); + Date date = new Date(); + Empty empty = new Empty(); + Map args = new HashMap<>(); + args.put("boolValue", boolValue); + args.put("iValue", iValue); + args.put("lValue", lValue); + args.put("fValue", fValue); + args.put("dValue", dValue); + args.put("sValue", sValue); + args.put("iArray", iArray); + args.put("color", color); + args.put("localDate", localDate); + args.put("date", date); + args.put("empty", empty); + if (isPojo) { + Map swaggerArgs = new HashMap<>(); + swaggerArgs.put("baseBody", args); + values = requestSerializer.serialize(swaggerArgs); + } else { + values = requestSerializer.serialize(args); + } + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedSwaggerArgs = requestDeserializer.deserialize(values); + Map decodedArgs; + if (isPojo) { + Assertions.assertEquals(1, decodedSwaggerArgs.size()); + decodedArgs = (Map) decodedSwaggerArgs.get("baseBody"); + } else { + decodedArgs = decodedSwaggerArgs; + } + Assertions.assertEquals(boolValue, decodedArgs.get("boolValue")); + Assertions.assertEquals(iValue, decodedArgs.get("iValue")); + Assertions.assertEquals(lValue, decodedArgs.get("lValue")); + Assertions.assertEquals(fValue, decodedArgs.get("fValue")); + Assertions.assertEquals(dValue, decodedArgs.get("dValue")); + if (isPojo) { + Assertions.assertEquals(2, ((List) decodedArgs.get("iArray")).size()); + Assertions.assertEquals(60, (((List) decodedArgs.get("iArray")).get(0).intValue())); + Assertions.assertEquals(70, (((List) decodedArgs.get("iArray")).get(1).intValue())); + Assertions.assertEquals(color.ordinal(), decodedArgs.get("color")); + Assertions.assertEquals(date.getTime(), decodedArgs.get("date")); + Assertions.assertEquals(localDate.getLong(ChronoField.EPOCH_DAY), decodedArgs.get("localDate")); + Assertions.assertTrue(((Map) decodedArgs.get("empty")).isEmpty()); + } else { + Assertions.assertArrayEquals(iArray, (int[]) decodedArgs.get("iArray")); + Assertions.assertEquals(color, decodedArgs.get("color")); + Assertions.assertEquals(date, decodedArgs.get("date")); + Assertions.assertTrue(decodedArgs.get("localDate") instanceof LocalDate); + Assertions.assertEquals(localDate, decodedArgs.get("localDate")); + Assertions.assertTrue(decodedArgs.get("empty") instanceof Empty); + } + + // default value testing + args.put("boolValue", false); + args.put("iValue", 0); + args.put("lValue", 0L); + args.put("fValue", 0F); + args.put("dValue", 0D); + args.put("sValue", null); + args.put("iArray", new int[0]); + args.put("color", null); + args.put("localDate", null); + args.put("date", null); + args.put("empty", null); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + Assertions.assertNull(decodedArgs.get("boolValue")); + Assertions.assertNull(decodedArgs.get("iValue")); + Assertions.assertNull(decodedArgs.get("lValue")); + Assertions.assertNull(decodedArgs.get("fValue")); + Assertions.assertNull(decodedArgs.get("dValue")); + Assertions.assertNull(decodedArgs.get("iArray")); + Assertions.assertNull(decodedArgs.get("color")); + Assertions.assertNull(decodedArgs.get("localDate")); + Assertions.assertNull(decodedArgs.get("date")); + Assertions.assertNull(decodedArgs.get("empty")); + + // response message + ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); + values = responseSerializer.serialize(30); + ResponseRootDeserializer responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); + Object decodedValue = responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(int.class)); + Assertions.assertEquals(30, (int) decodedValue); + } + + @Test + public void testProtoSchemaOperationlistListUserSpringMVC() throws Exception { + mockSchemaMeta("ProtoSchema", new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationlistListUserImpl(false); + } + + @Test + public void testProtoSchemaOperationlistListUserPOJO() throws Exception { + mockSchemaMeta("ProtoSchemaPojo", new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationlistListUserImpl(true); + } + + private void testProtoSchemaOperationlistListUserImpl(boolean isPojo) throws IOException { + Invocation consumerInvocation = mockInvocation("listListUser", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("listListUser", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + byte[] values; + + // request message + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + List users = new ArrayList<>(); + users.add(user); + List> listOfUsers = new ArrayList<>(); + listOfUsers.add(users); + Map args = new HashMap<>(); + args.put("value", listOfUsers); + + if (isPojo) { + Map swaggerArgs = new HashMap<>(); + swaggerArgs.put("listListUserBody", args); + values = requestSerializer.serialize(swaggerArgs); + } else { + values = requestSerializer.serialize(args); + } + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedSwaggerArgs = requestDeserializer.deserialize(values); + Map decodedArgs; + if (isPojo) { + Assertions.assertEquals(1, decodedSwaggerArgs.size()); + decodedArgs = (Map) decodedSwaggerArgs.get("listListUserBody"); + } else { + decodedArgs = decodedSwaggerArgs; + } + List> listOfUsersRaw = (List>) decodedArgs.get("value"); + Assertions.assertEquals(1, listOfUsersRaw.size()); + List mapUsersRaw = (List) listOfUsersRaw.get(0); + Assertions.assertEquals(1, mapUsersRaw.size()); + if (isPojo) { + Map userMap = (Map) mapUsersRaw.get(0); + Assertions.assertEquals("user", userMap.get("name")); + // proto buffer encode and decode empty list to be null + friends = (List) userMap.get("friends"); + Map friendMap = (Map) friends.get(0); + Assertions.assertEquals("friend", friendMap.get("name")); + } else { + user = (User) mapUsersRaw.get(0); + Assertions.assertEquals("user", user.name); + // proto buffer encode and decode empty list to be null + Assertions.assertEquals("friend", user.friends.get(0).name); + } + } + + @Test + public void testProtoSchemaOperationObjSpringMVC() throws Exception { + mockSchemaMeta("ProtoSchema", new SpringmvcSwaggerGenerator(ProtoSchema.class), new ProtoSchema()); + testProtoSchemaOperationObjImpl(false); + } + + @Test + public void testProtoSchemaOperationObjPOJO() throws Exception { + mockSchemaMeta("ProtoSchemaPojo", new PojoSwaggerGenerator(ProtoSchemaPojo.class), new ProtoSchemaPojo()); + testProtoSchemaOperationObjImpl(true); + } + + private void testProtoSchemaOperationObjImpl(boolean isPojo) throws IOException { + Invocation consumerInvocation = mockInvocation("obj", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("obj", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + byte[] values; + + // request message + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + Map args = new HashMap<>(); + args.put("value", 2); + + values = requestSerializer.serialize(args); + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedArgs = requestDeserializer.deserialize(values); + int result = (int) decodedArgs.get("value"); + Assertions.assertEquals(2, result); + + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + args.put("value", user); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + Map userMap = (Map) decodedArgs.get("value"); + Assertions.assertEquals("user", userMap.get("name")); + // proto buffer encode and decode empty list to be null + friends = (List) userMap.get("friends"); + Map friendMap = (Map) friends.get(0); + Assertions.assertEquals("friend", friendMap.get("name")); + + args.clear(); + People people = new People(); + people.name = "user"; + People pFriend = new People(); + pFriend.name = "friend"; + List pFriends = new ArrayList<>(); + pFriends.add(pFriend); + people.friends = pFriends; + args.put("value", people); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + people = (People) decodedArgs.get("value"); + Assertions.assertEquals("user", people.name); + // proto buffer encode and decode empty list to be null + Assertions.assertEquals("friend", people.friends.get(0).name); + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java new file mode 100644 index 00000000000..2a861d202be --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSchemaMetaCodecRestTemplate.java @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.codec.protobuf.internal.converter; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootSerializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer; +import org.apache.servicecomb.codec.protobuf.internal.converter.model.ProtoSchema; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.MicroserviceVersionsMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.InvocationType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * SchemaMetaCodec test cases. This test cases covers RestTemplate invoker and producer. + */ +public class TestSchemaMetaCodecRestTemplate { + + private SchemaMeta providerSchemaMeta; + + private SchemaMeta consumerSchemaMeta; + + @BeforeEach + public void setUp() { + ProtobufManager.clear(); + MicroserviceVersionsMeta microserviceVersionsMeta = Mockito.mock(MicroserviceVersionsMeta.class); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getExecutorManager()).thenReturn(executorManager); + + MicroserviceMeta providerMicroserviceMeta = Mockito.mock(MicroserviceMeta.class); + Mockito.when(providerMicroserviceMeta.getScbEngine()).thenReturn(scbEngine); + Mockito.when(providerMicroserviceMeta.getMicroserviceVersionsMeta()).thenReturn(microserviceVersionsMeta); + Mockito.when(providerMicroserviceMeta.getMicroserviceName()).thenReturn("test"); + Mockito.when(providerMicroserviceMeta.getExtData(ProtobufManager.EXT_ID)).thenReturn(null); + + MicroserviceMeta consumerMicroserviceMeta = Mockito.mock(MicroserviceMeta.class); + Mockito.when(consumerMicroserviceMeta.getScbEngine()).thenReturn(scbEngine); + Mockito.when(consumerMicroserviceMeta.getMicroserviceVersionsMeta()).thenReturn(microserviceVersionsMeta); + Mockito.when(consumerMicroserviceMeta.getMicroserviceName()).thenReturn("test"); + Mockito.when(consumerMicroserviceMeta.getExtData(ProtobufManager.EXT_ID)).thenReturn(null); + + SpringmvcSwaggerGenerator swaggerGenerator = new SpringmvcSwaggerGenerator(ProtoSchema.class); + SwaggerEnvironment swaggerEnvironment = new SwaggerEnvironment(); + + SwaggerProducer swaggerProducer = swaggerEnvironment.createProducer(new ProtoSchema()); + providerSchemaMeta = new SchemaMeta(providerMicroserviceMeta, "ProtoSchema", swaggerProducer.getSwagger()); + + for (SwaggerProducerOperation producerOperation : swaggerProducer.getAllOperations()) { + OperationMeta operationMeta = providerSchemaMeta.ensureFindOperation(producerOperation.getOperationId()); + operationMeta.setSwaggerProducerOperation(producerOperation); + } + + consumerSchemaMeta = new SchemaMeta(consumerMicroserviceMeta, "ProtoSchema", swaggerProducer.getSwagger()); + } + + private Invocation mockInvocation(String operation, InvocationType invocationType) { + OperationMeta operationMeta; + boolean isProvider; + Invocation invocation = Mockito.mock(Invocation.class); + InvocationRuntimeType invocationRuntimeType; + + if (InvocationType.CONSUMER == invocationType) { + operationMeta = consumerSchemaMeta.getOperations().get(operation); + isProvider = false; + Mockito.when(invocation.getSchemaMeta()).thenReturn(consumerSchemaMeta); + invocationRuntimeType = operationMeta.buildBaseConsumerRuntimeType(); + } else { + operationMeta = providerSchemaMeta.getOperations().get(operation); + isProvider = true; + Mockito.when(invocation.getSchemaMeta()).thenReturn(providerSchemaMeta); + invocationRuntimeType = operationMeta.buildBaseProviderRuntimeType(); + } + + MicroserviceMeta microserviceMeta = operationMeta.getMicroserviceMeta(); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getInvocationRuntimeType()) + .thenReturn(invocationRuntimeType); + Mockito.when(invocation.findResponseType(200)) + .thenReturn(invocationRuntimeType.findResponseType(200)); + Mockito.when(invocation.getInvocationType()).thenReturn(invocationType); + Mockito.when(invocation.getMicroserviceMeta()).thenReturn(microserviceMeta); + + Mockito.when(invocation.isProducer()).thenReturn(isProvider); + return invocation; + } + + @Test + public void testProtoSchemaOperationUser() throws Exception { + Invocation consumerInvocation = mockInvocation("user", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("user", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + User user = new User(); + user.name = "user"; + User friend = new User(); + friend.name = "friend"; + List friends = new ArrayList<>(); + friends.add(friend); + user.friends = friends; + byte[] values; + + // request message + Map args = new HashMap<>(); + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + user.friends = friends; + args.put("user", user); + values = requestSerializer.serialize(args); + + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedUserArgs = requestDeserializer.deserialize(values); + Assertions.assertEquals(user.name, ((User) decodedUserArgs.get("user")).name); + Assertions.assertEquals(user.friends.get(0).name, ((User) decodedUserArgs.get("user")).friends.get(0).name); + + // response message + ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); + values = responseSerializer.serialize(user); + ResponseRootDeserializer responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); + User decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); + Assertions.assertEquals(user.name, decodedUser.name); + Assertions.assertEquals(user.friends.get(0).name, decodedUser.friends.get(0).name); + + user.friends = new ArrayList<>(); + values = responseSerializer.serialize(user); + decodedUser = (User) responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(User.class)); + Assertions.assertEquals(user.name, decodedUser.name); + // proto buffer encode and decode empty list to be null + Assertions.assertNull(decodedUser.friends); + } + + @Test + @SuppressWarnings({"rawtypes", "unchecked"}) + public void testProtoSchemaOperationBase() throws Exception { + Invocation consumerInvocation = mockInvocation("base", InvocationType.CONSUMER); + Invocation providerInvocation = mockInvocation("base", InvocationType.PROVIDER); + + OperationProtobuf providerOperationProtobuf = ProtobufManager + .getOrCreateOperation(providerInvocation); + OperationProtobuf consumerOperationProtobuf = ProtobufManager + .getOrCreateOperation(consumerInvocation); + byte[] values; + + // request message + RequestRootSerializer requestSerializer = consumerOperationProtobuf.getRequestRootSerializer(); + boolean boolValue = true; + int iValue = 20; + long lValue = 30L; + float fValue = 40f; + double dValue = 50D; + String sValue = "hello"; + int[] iArray = new int[] {60, 70}; + Color color = Color.BLUE; + LocalDate localDate = LocalDate.of(2019, 10, 1); + Date date = new Date(); + Empty empty = new Empty(); + Map args = new HashMap<>(); + args.put("boolValue", boolValue); + args.put("iValue", iValue); + args.put("lValue", lValue); + args.put("fValue", fValue); + args.put("dValue", dValue); + args.put("sValue", sValue); + args.put("iArray", iArray); + args.put("color", color); + args.put("localDate", localDate); + args.put("date", date); + args.put("empty", empty); + values = requestSerializer.serialize(args); + RequestRootDeserializer requestDeserializer = providerOperationProtobuf.getRequestRootDeserializer(); + Map decodedArgs = requestDeserializer.deserialize(values); + Assertions.assertEquals(boolValue, decodedArgs.get("boolValue")); + Assertions.assertEquals(iValue, decodedArgs.get("iValue")); + Assertions.assertEquals(lValue, decodedArgs.get("lValue")); + Assertions.assertEquals(fValue, decodedArgs.get("fValue")); + Assertions.assertEquals(dValue, decodedArgs.get("dValue")); + Assertions.assertArrayEquals(iArray, (int[]) decodedArgs.get("iArray")); + Assertions.assertEquals(color, decodedArgs.get("color")); + Assertions.assertEquals(date, decodedArgs.get("date")); + Assertions.assertTrue(decodedArgs.get("localDate") instanceof LocalDate); + Assertions.assertEquals(localDate, decodedArgs.get("localDate")); + Assertions.assertTrue(decodedArgs.get("empty") instanceof Empty); + + // default value testing + args.put("boolValue", false); + args.put("iValue", 0); + args.put("lValue", 0L); + args.put("fValue", 0F); + args.put("dValue", 0D); + args.put("sValue", null); + args.put("iArray", new int[0]); + args.put("color", null); + args.put("localDate", null); + args.put("date", null); + args.put("empty", null); + values = requestSerializer.serialize(args); + decodedArgs = requestDeserializer.deserialize(values); + Assertions.assertNull(decodedArgs.get("boolValue")); + Assertions.assertNull(decodedArgs.get("iValue")); + Assertions.assertNull(decodedArgs.get("lValue")); + Assertions.assertNull(decodedArgs.get("fValue")); + Assertions.assertNull(decodedArgs.get("dValue")); + Assertions.assertNull(decodedArgs.get("iArray")); + Assertions.assertNull(decodedArgs.get("color")); + Assertions.assertNull(decodedArgs.get("localDate")); + Assertions.assertNull(decodedArgs.get("date")); + Assertions.assertNull(decodedArgs.get("empty")); + + // response message + ResponseRootSerializer responseSerializer = providerOperationProtobuf.findResponseRootSerializer(200); + values = responseSerializer.serialize(30); + ResponseRootDeserializer responseDeserializer = consumerOperationProtobuf.findResponseRootDeserializer(200); + Object decodedValue = responseDeserializer + .deserialize(values, TypeFactory.defaultInstance().constructType(int.class)); + Assertions.assertEquals(30, (int) decodedValue); + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSwaggerToProtoGenerator.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSwaggerToProtoGenerator.java index 4b604a4daa4..535404f7bc0 100644 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSwaggerToProtoGenerator.java +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/TestSwaggerToProtoGenerator.java @@ -16,176 +16,46 @@ */ package org.apache.servicecomb.codec.protobuf.internal.converter; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; import org.apache.servicecomb.codec.protobuf.internal.converter.model.ProtoSchema; -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import io.protostuff.compiler.model.Proto; -import io.swagger.models.Swagger; -import io.vertx.core.json.Json; +import io.swagger.v3.oas.models.OpenAPI; public class TestSwaggerToProtoGenerator { - static String protoContent = "syntax = \"proto3\";\n" - + "import \"google/protobuf/empty.proto\";\n" - + "import \"google/protobuf/any.proto\";\n" - + "package a.b;\n" - + "\n" - + "message Empty {\n" - + "}\n" - + "\n" - + "message User {\n" - + " string name = 1;\n" - + " repeated User friends = 2;\n" - + "}\n" - + "\n" - + "message Ref1 {\n" - + " Ref2 ref = 1;\n" - + "}\n" - + "\n" - + "message Ref2 {\n" - + " Ref1 ref = 1;\n" - + "}\n" - + "\n" - + "message baseRequestWrap {\n" - + " bool boolValue = 1;\n" - + " int32 iValue = 2;\n" - + " int64 lValue = 3;\n" - + " float fValue = 4;\n" - + " double dValue = 5;\n" - + " string sValue = 6;\n" - + " repeated int32 iArray = 7;\n" - + " Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 color = 8;\n" - + " int64 localDate = 9;\n" - + " int64 date = 10;\n" - + " Empty empty = 11;\n" - + "}\n" - + "\n" - + "message baseResponseWrap444 {\n" - + " Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 response = 1;\n" - + "}\n" - + "\n" - + "message baseResponseWrap200 {\n" - + " int32 response = 1;\n" - + "}\n" - + "\n" - + "message bytesRequestWrap {\n" - + " bytes value = 1;\n" - + "}\n" - + "\n" - + "message bytesResponseWrap200 {\n" - + " bytes response = 1;\n" - + "}\n" - + "\n" - + "message colorBodyRequestWrap {\n" - + " Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 color = 1;\n" - + "}\n" - + "\n" - + "message colorBodyResponseWrap200 {\n" - + " Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 response = 1;\n" - + "}\n" - + "\n" - + "message listObjRequestWrap {\n" - + " repeated google.protobuf.Any objs = 1;\n" - + "}\n" - + "\n" - + "message listObjResponseWrap200 {\n" - + " repeated google.protobuf.Any response = 1;\n" - + "}\n" - + "\n" - + "message listUserRequestWrap {\n" - + " repeated User users = 1;\n" - + "}\n" - + "\n" - + "message listUserResponseWrap200 {\n" - + " repeated User response = 1;\n" - + "}\n" - + "\n" - + "message mapObjRequestWrap {\n" - + " map objs = 1;\n" - + "}\n" - + "\n" - + "message mapObjResponseWrap200 {\n" - + " map response = 1;\n" - + "}\n" - + "\n" - + "message mapUserRequestWrap {\n" - + " map users = 1;\n" - + "}\n" - + "\n" - + "message mapUserResponseWrap200 {\n" - + " map response = 1;\n" - + "}\n" - + "\n" - + "message userWrapInProtobufRequestWrap {\n" - + " User user = 1;\n" - + " int32 ivalue = 2;\n" - + "}\n" - + "\n" - + "enum Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 {\n" - + " RED = 0;\n" - + " YELLOW = 1;\n" - + " BLUE = 2;\n" - + "}\n" - + "\n" - + "service MainService {\n" - + " //scb:{\"argTypeName\":\"baseRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"baseResponseWrap200\",\"wrapped\":true},\"444\":{\"typeName\":\"baseResponseWrap444\",\"wrapped\":true}}}\n" - + " rpc base (baseRequestWrap) returns (baseResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"bytesRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"bytesResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc bytes (bytesRequestWrap) returns (bytesResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"colorBodyRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"colorBodyResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc colorBody (colorBodyRequestWrap) returns (colorBodyResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"listObjRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"listObjResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc listObj (listObjRequestWrap) returns (listObjResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"listUserRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"listUserResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc listUser (listUserRequestWrap) returns (listUserResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"mapObjRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"mapObjResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc mapObj (mapObjRequestWrap) returns (mapObjResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"mapUserRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"mapUserResponseWrap200\",\"wrapped\":true}}}\n" - + " rpc mapUser (mapUserRequestWrap) returns (mapUserResponseWrap200);\n" - + "\n" - + " //scb:{\"argTypeName\":\"google.protobuf.Empty\",\"argWrapped\":false,\"responses\":{\"200\":{\"typeName\":\"google.protobuf.Empty\",\"wrapped\":false}}}\n" - + " rpc noParamVoid (google.protobuf.Empty) returns (google.protobuf.Empty);\n" - + "\n" - + " //scb:{\"argTypeName\":\"google.protobuf.Any\",\"argWrapped\":false,\"responses\":{\"200\":{\"typeName\":\"google.protobuf.Any\",\"wrapped\":false}}}\n" - + " rpc obj (google.protobuf.Any) returns (google.protobuf.Any);\n" - + "\n" - + " //scb:{\"argTypeName\":\"Ref1\",\"argWrapped\":false,\"responses\":{\"200\":{\"typeName\":\"Ref2\",\"wrapped\":false}}}\n" - + " rpc ref (Ref1) returns (Ref2);\n" - + "\n" - + " //scb:{\"argTypeName\":\"User\",\"argWrapped\":false,\"responses\":{\"200\":{\"typeName\":\"User\",\"wrapped\":false}}}\n" - + " rpc user (User) returns (User);\n" - + "\n" - + " //scb:{\"argTypeName\":\"userWrapInProtobufRequestWrap\",\"argWrapped\":true,\"responses\":{\"200\":{\"typeName\":\"User\",\"wrapped\":false}}}\n" - + " rpc userWrapInProtobuf (userWrapInProtobufRequestWrap) returns (User);\n" - + "}\n"; - @Test - public void convert() { - SwaggerGeneratorContext context = new SpringmvcSwaggerGeneratorContext(); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(context, ProtoSchema.class); - Swagger swagger = swaggerGenerator.generate(); + public void convert() throws IOException { + URL url = TestSwaggerToProtoGenerator.class.getClassLoader().getResource("ProtoSchema.proto"); + String protoContent = IOUtils.toString(url, StandardCharsets.UTF_8); + int idx = protoContent.indexOf("syntax = "); + protoContent = protoContent.substring(idx); + + SpringmvcSwaggerGenerator swaggerGenerator = new SpringmvcSwaggerGenerator(ProtoSchema.class); + OpenAPI swagger = swaggerGenerator.generate(); SwaggerToProtoGenerator generator = new SwaggerToProtoGenerator("a.b", swagger); Proto proto = generator.convert(); - Assert.assertEquals(protoContent, new ProtoToStringGenerator(proto).protoToString()); + Assertions.assertEquals(protoContent.replaceAll("\r\n", "\n"), + new ProtoToStringGenerator(proto).protoToString().replaceAll("\r\n", "\n")); } - public static void main(String[] args) { - String json = Json.encode(Color.BLUE); - System.out.println(json); - System.out.println(Json.decodeValue(json, Color.class)); - System.out.println(Json.decodeValue("2", Color.class)); - System.out.println(Json.mapper.convertValue("BLUE", Color.class)); + @Test + public void testEscape() { + Assertions.assertEquals("hello_my_service", SwaggerToProtoGenerator.escapeMessageName("hello.my.service")); + Assertions.assertEquals("hello_my_service", SwaggerToProtoGenerator.escapeMessageName("hello_my_service")); + Assertions.assertEquals("hello.my_service", SwaggerToProtoGenerator.escapePackageName("hello.my-service")); + Assertions.assertEquals("hello.test.test", SwaggerToProtoGenerator.escapePackageName("hello.test.test")); + Assertions.assertEquals("hello_my.test.test", SwaggerToProtoGenerator.escapePackageName("hello:my.test.test")); + Assertions.assertFalse(SwaggerToProtoGenerator.isValidEnum("hello.test.test")); + Assertions.assertFalse(SwaggerToProtoGenerator.isValidEnum("hello.my-service")); + Assertions.assertTrue(SwaggerToProtoGenerator.isValidEnum("My_ENum")); } } diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/FieldNeedWrap.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/FieldNeedWrap.java new file mode 100644 index 00000000000..f97b6b50a7d --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/FieldNeedWrap.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.internal.converter.model; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public class FieldNeedWrap { + public List> listListUser; + + public List> listMapUser; + + public Map> mapListUser; + + public Map> mapMapUser; + + public List>> listListListUser; + + public List>> listListMapUser; + + public List>> listMapListUser; + + public List>> listMapMapUser; + + public Map>> mapMapListUser; + + public Map>> mapMapMapUser; +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchema.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchema.java index 3b046ec72e3..169e742c9b5 100644 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchema.java +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchema.java @@ -26,15 +26,20 @@ import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; import org.apache.servicecomb.foundation.test.scaffolding.model.User; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; @RequestMapping(path = "/") -public class ProtoSchema { - @ApiResponses(value = {@ApiResponse(code = 444, response = Color.class, message = "xxx")}) +public class ProtoSchema implements ProtoSchemaIntf { + @ApiResponses(value = { + @ApiResponse(responseCode = "444", content = @Content(schema = @Schema(implementation = Color.class)), description = "xxx")}) @GetMapping(path = "/base") public int base(boolean boolValue, int iValue, long lValue, float fValue, double dValue, String sValue, int[] iArray, Color color, @@ -95,4 +100,87 @@ public Ref2 ref(@RequestBody Ref1 ref) { @GetMapping(path = "/noParamVoid") public void noParamVoid() { } + + @PostMapping(path = "/listListString") + public List> listListString(@RequestBody List> value) { + return value; + } + + @PostMapping(path = "/listListUser") + public List> listListUser(@RequestBody List> value) { + return value; + } + + @PostMapping(path = "/listMapString") + public List> listMapString(@RequestBody List> value) { + return value; + } + + @PostMapping(path = "/listMapUser") + public List> listMapUser(@RequestBody List> value) { + return value; + } + + @PostMapping(path = "/mapListString") + public Map> mapListString(@RequestBody Map> value) { + return value; + } + + @PostMapping(path = "/mapListUser") + public Map> mapListUser(@RequestBody Map> value) { + return value; + } + + @PostMapping(path = "/mapMapString") + public Map> mapMapString(@RequestBody Map> value) { + return value; + } + + @PostMapping(path = "/mapMapUser") + public Map> mapMapUser(@RequestBody Map> value) { + return value; + } + + @PostMapping(path = "/listListListString") + public List>> listListListString(@RequestBody List>> value) { + return value; + } + + @PostMapping(path = "/listListMapString") + public List>> listListMapString(@RequestBody List>> value) { + return value; + } + + @PostMapping(path = "/listMapListString") + public List>> listMapListString(@RequestBody List>> value) { + return value; + } + + @PostMapping(path = "/listMapMapString") + public List>> listMapMapString( + @RequestBody List>> value) { + return value; + } + + @PostMapping(path = "/mapMapListString") + public Map>> mapMapListString( + @RequestBody Map>> value) { + return value; + } + + @PostMapping(path = "/mapMapMapString") + public Map>> mapMapMapString( + @RequestBody Map>> value) { + return value; + } + + @PostMapping(path = "/fieldNeedWrap") + public FieldNeedWrap fieldNeedWrap(@RequestBody FieldNeedWrap fieldNeedWrap) { + return fieldNeedWrap; + } + + @PostMapping(path = "/testTextPlain", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_PLAIN) + public String testTextPlain(@RequestBody String fieldNeedWrap) { + return null; + } } diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaIntf.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaIntf.java new file mode 100644 index 00000000000..55c91561138 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaIntf.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.internal.converter.model; + + +import java.time.LocalDate; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public interface ProtoSchemaIntf { + int base(boolean boolValue, int iValue, long lValue, float fValue, double dValue, String sValue, int[] iArray, + Color color, + LocalDate localDate, Date date, Empty empty); + + byte[] bytes(byte[] value); + + + Color colorBody(Color color); + + + Object obj(Object value); + + + User user(User user); + + User userWrapInProtobuf(User user, int ivalue); + + + List listObj(List objs); + + List listUser(List users); + + + Map mapUser(Map users); + + Map mapObj(Map objs); + + Ref2 ref(Ref1 ref); + + + void noParamVoid(); + + List> listListString(List> value); + + + List> listListUser(List> value); + + + List> listMapString(List> value); + + + List> listMapUser(List> value); + + + Map> mapListString(Map> value); + + + Map> mapListUser(Map> value); + + Map> mapMapString(Map> value); + + + Map> mapMapUser(Map> value); + + + List>> listListListString(List>> value); + + + List>> listListMapString(List>> value); + + List>> listMapListString(List>> value); + + + List>> listMapMapString( + List>> value); + + + Map>> mapMapListString( + Map>> value); + + Map>> mapMapMapString( + Map>> value); + + FieldNeedWrap fieldNeedWrap(FieldNeedWrap fieldNeedWrap); +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaPojo.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaPojo.java new file mode 100644 index 00000000000..af01e2e2325 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/internal/converter/model/ProtoSchemaPojo.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.internal.converter.model; + + +import java.time.LocalDate; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.Empty; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +public class ProtoSchemaPojo implements ProtoSchemaIntf { + @ApiResponses(value = { + @ApiResponse(responseCode = "444", content = @Content(schema = @Schema(implementation = Color.class)), description = "xxx")}) + public int base(boolean boolValue, int iValue, long lValue, float fValue, double dValue, String sValue, int[] iArray, + Color color, + LocalDate localDate, Date date, Empty empty) { + return 0; + } + + public byte[] bytes(byte[] value) { + return null; + } + + + public Color colorBody(Color color) { + return null; + } + + + public Object obj(Object value) { + return null; + } + + + public User user(User user) { + return null; + } + + + public User userWrapInProtobuf(User user, int ivalue) { + return null; + } + + + public List listObj(List objs) { + return null; + } + + public List listUser(List users) { + return null; + } + + + public Map mapUser(Map users) { + return null; + } + + public Map mapObj(Map objs) { + return null; + } + + public Ref2 ref(Ref1 ref) { + return null; + } + + + public void noParamVoid() { + } + + + public List> listListString(List> value) { + return value; + } + + + public List> listListUser(List> value) { + return value; + } + + + public List> listMapString(List> value) { + return value; + } + + + public List> listMapUser(List> value) { + return value; + } + + + public Map> mapListString(Map> value) { + return value; + } + + + public Map> mapListUser(Map> value) { + return value; + } + + + public Map> mapMapString(Map> value) { + return value; + } + + + public Map> mapMapUser(Map> value) { + return value; + } + + + public List>> listListListString(List>> value) { + return value; + } + + + public List>> listListMapString(List>> value) { + return value; + } + + public List>> listMapListString(List>> value) { + return value; + } + + + public List>> listMapMapString( + List>> value) { + return value; + } + + + public Map>> mapMapListString( + Map>> value) { + return value; + } + + public Map>> mapMapMapString( + Map>> value) { + return value; + } + + public FieldNeedWrap fieldNeedWrap(FieldNeedWrap fieldNeedWrap) { + return fieldNeedWrap; + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java new file mode 100644 index 00000000000..9eab70ae00a --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.codec.protobuf.schema.model.DeptInfo; +import org.apache.servicecomb.codec.protobuf.schema.model.SchemaService; +import org.apache.servicecomb.codec.protobuf.schema.model.ScoreInfo; +import org.apache.servicecomb.codec.protobuf.schema.model.UserInfo; +import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; +import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.StringSchema; +import jakarta.ws.rs.core.MediaType; + +public class TestSchemaCodec { + ScopedProtobufSchemaManager manager = new ScopedProtobufSchemaManager(); + + @Test + public void test_string_schema_codec() throws Exception { + OpenAPI openAPI = new OpenAPI(); + StringSchema schema = new StringSchema(); + ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "test", "input", schema); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage("input"), + String.class); + Map arguments = new HashMap<>(); + arguments.put("value", "abcdefg"); + byte[] result = serializer.serialize(arguments); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage("input"), String.class); + PropertyWrapper deserializedResult = deserializer.deserialize(result); + assertEquals("abcdefg", deserializedResult.getValue()); + } + + @Test + public void test_number_schema_codec() throws Exception { + OpenAPI openAPI = new OpenAPI(); + NumberSchema schema = new NumberSchema(); + ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "test", "input", schema); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage("input"), + BigDecimal.class); + Map arguments = new HashMap<>(); + BigDecimal number = new BigDecimal(10); + arguments.put("value", number); + byte[] result = serializer.serialize(arguments); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage("input"), BigDecimal.class); + PropertyWrapper deserializedResult = deserializer.deserialize(result); + assertEquals(number, deserializedResult.getValue()); + } + + public static class User { + public String name; + } + + @Test + public void test_object_schema_codec() throws Exception { + OpenAPI openAPI = new OpenAPI(); + + ObjectSchema schema = new ObjectSchema(); + schema.setName("User"); + schema.addProperty("name", new StringSchema()); + openAPI.setComponents(new Components()); + openAPI.getComponents().addSchemas("User", schema); + + ObjectSchema ref = new ObjectSchema(); + ref.set$ref(Components.COMPONENTS_SCHEMAS_REF + "User"); + + ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "test", "input", ref); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage("input"), + User.class); + Map arguments = new HashMap<>(); + User user = new User(); + user.name = "abcdefg"; + arguments.put("value", user); + byte[] result = serializer.serialize(arguments); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage("input"), User.class); + PropertyWrapper deserializedResult = deserializer.deserialize(result); + assertEquals("abcdefg", deserializedResult.getValue().name); + } + + @Test + public void test_springmvc_model_schema_codec_correct() throws Exception { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SchemaService.class); + OpenAPI openAPI = generator.generate(); + + ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "schemaService", "input", + openAPI.getPaths().get("/testUserInfo").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema()); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage("input"), + UserInfo.class); + Map arguments = new HashMap<>(); + UserInfo userInfo = new UserInfo(); + DeptInfo deptInfo = new DeptInfo(); + deptInfo.setCode("123"); + ScoreInfo scoreInfo = new ScoreInfo(); + scoreInfo.setType(233); + deptInfo.setScores(List.of(scoreInfo)); + userInfo.setSubDeptInfos(List.of(deptInfo)); + arguments.put("value", userInfo); + byte[] result = serializer.serialize(arguments); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage("input"), UserInfo.class); + PropertyWrapper deserializedResult = deserializer.deserialize(result); + assertEquals(1, deserializedResult.getValue().getSubDeptInfos().size()); + assertEquals("123", deserializedResult.getValue().getSubDeptInfos().get(0).getCode()); + assertEquals(233, deserializedResult.getValue().getSubDeptInfos().get(0).getScores().get(0).getType()); + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java new file mode 100644 index 00000000000..23ac41135ad --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.servicecomb.codec.protobuf.internal.converter.ProtoToStringGenerator; +import org.apache.servicecomb.codec.protobuf.schema.model.SchemaService; +import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import io.protostuff.compiler.model.Proto; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.StringSchema; +import jakarta.ws.rs.core.MediaType; + +//CHECKSTYLE:OFF +@SuppressWarnings("unused") +public class TestSchemaToProtoGenerator { + @Test + public void test_string_schema_is_correct() { + OpenAPI openAPI = new OpenAPI(); + StringSchema schema = new StringSchema(); + SchemaToProtoGenerator generator = + new SchemaToProtoGenerator("test.string", openAPI, schema, "input"); + Proto proto = generator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.string; + + //@WrapProperty + message input { + string value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + @Test + public void test_object_schema_is_correct() { + OpenAPI openAPI = new OpenAPI(); + + ObjectSchema schema = new ObjectSchema(); + schema.setName("User"); + schema.addProperty("name", new StringSchema()); + openAPI.setComponents(new Components()); + openAPI.getComponents().addSchemas("User", schema); + + ObjectSchema ref = new ObjectSchema(); + ref.set$ref(Components.COMPONENTS_SCHEMAS_REF + "User"); + + SchemaToProtoGenerator generator = + new SchemaToProtoGenerator("test.object", openAPI, ref, "input"); + Proto proto = generator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.object; + + message User { + string name = 1; + } + + //@WrapProperty + message input { + User value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + static class Model { + public String name; + + public int age; + } + + interface SpringMvcSchema { + @PostMapping("/testInt") + int testInt(@RequestBody int param); + + @PostMapping("/testModel") + Model testModel(@RequestBody Model model); + } + + @Test + public void test_springmvc_int_schema_correct() { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SpringMvcSchema.class); + OpenAPI openAPI = generator.generate(); + + SchemaToProtoGenerator protoGenerator = + new SchemaToProtoGenerator("test.int", openAPI, + openAPI.getPaths().get("/testInt").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "testIntRequest"); + Proto proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.int; + + //@WrapProperty + message testIntRequest { + sint32 value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + + protoGenerator = + new SchemaToProtoGenerator("test.int", openAPI, + openAPI.getPaths().get("/testInt").getPost() + .getResponses().get("200").getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "testIntResponse"); + proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.int; + + //@WrapProperty + message testIntResponse { + sint32 value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + + @Test + public void test_springmvc_model_schema_correct() { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SpringMvcSchema.class); + OpenAPI openAPI = generator.generate(); + + SchemaToProtoGenerator protoGenerator = + new SchemaToProtoGenerator("test.model", openAPI, + openAPI.getPaths().get("/testModel").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "testModelRequest"); + Proto proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.model; + + message Model { + sint32 age = 1; + string name = 2; + } + + //@WrapProperty + message testModelRequest { + Model value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + + protoGenerator = + new SchemaToProtoGenerator("test.model", openAPI, + openAPI.getPaths().get("/testModel").getPost() + .getResponses().get("200").getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "testIntResponse"); + proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.model; + + message Model { + sint32 age = 1; + string name = 2; + } + + //@WrapProperty + message testIntResponse { + Model value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + @Test + public void testNestedModelCorrect() { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SchemaService.class); + OpenAPI openAPI = generator.generate(); + SchemaToProtoGenerator protoGenerator = + new SchemaToProtoGenerator("test.model", openAPI, + openAPI.getPaths().get("/testUserInfo").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "request"); + Proto proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.model; + + //@WrapProperty + message MapString { + map value = 1; + } + + //@WrapProperty + message ListListString { + repeated ListString value = 1; + } + + //@WrapProperty + message ListString { + repeated string value = 1; + } + + message ScoreInfo { + sint32 type = 1; + } + + message DeptInfo { + string code = 1; + string name = 2; + repeated ScoreInfo scores = 3; + } + + message UserInfo { + repeated MapString extraInfos = 1; + repeated ListListString nestedLists = 2; + repeated DeptInfo subDeptInfos = 3; + } + + //@WrapProperty + message ListScoreInfo { + repeated ScoreInfo value = 1; + } + + //@WrapProperty + message ListDeptInfo { + repeated DeptInfo value = 1; + } + + //@WrapProperty + message request { + UserInfo value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + @Test + public void testListMapTypeCorrect() { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SchemaService.class); + OpenAPI openAPI = generator.generate(); + SchemaToProtoGenerator protoGenerator = + new SchemaToProtoGenerator("test.model", openAPI, + openAPI.getPaths().get("/testListType").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "request"); + Proto proto = protoGenerator.convert(); + assertEquals(""" + syntax = "proto3"; + package test.model; + + message ScoreInfo { + sint32 type = 1; + } + + message DeptInfo { + string code = 1; + string name = 2; + repeated ScoreInfo scores = 3; + } + + //@WrapProperty + message ListScoreInfo { + repeated ScoreInfo value = 1; + } + + //@WrapProperty + message ListDeptInfo { + repeated DeptInfo value = 1; + } + + //@WrapProperty + message request { + repeated DeptInfo value = 1; + } + """.trim(), new ProtoToStringGenerator(proto).protoToString().trim()); + } + + @Test + public void testCyclicModelWrong() { + SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SchemaService.class); + OpenAPI openAPI = generator.generate(); + SchemaToProtoGenerator protoGenerator = + new SchemaToProtoGenerator("test.model", openAPI, + openAPI.getPaths().get("/testCyclic").getPost() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON) + .getSchema(), "request"); + IllegalArgumentException throwable = Assertions.catchThrowableOfType(() -> protoGenerator.convert(), + IllegalArgumentException.class); + assertEquals("Failed to create schema request. May be cyclic object.", throwable.getMessage()); + } +} +//CHECKSTYLE:ON diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/CyclicInfo.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/CyclicInfo.java new file mode 100644 index 00000000000..ae8f2fbd5c0 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/CyclicInfo.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema.model; + +public class CyclicInfo { + private String name; + private CyclicInfo child; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public CyclicInfo getChild() { + return child; + } + + public void setChild(CyclicInfo child) { + this.child = child; + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/DeptInfo.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/DeptInfo.java new file mode 100644 index 00000000000..713b45e0224 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/DeptInfo.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema.model; + +import java.util.List; + +public class DeptInfo { + private String name; + + private String code; + + private List scores; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public List getScores() { + return scores; + } + + public void setScores(List scores) { + this.scores = scores; + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/SchemaService.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/SchemaService.java new file mode 100644 index 00000000000..99edc87023d --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/SchemaService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema.model; + +import java.util.List; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping("/schemaService") +public class SchemaService { + @PostMapping("testUserInfo") + public void testUserInfo(@RequestBody UserInfo request) { + } + + @PostMapping("testListType") + public void testListType(@RequestBody List request) { + } + + @PostMapping("testCyclic") + public void testCyclic(@RequestBody CyclicInfo request) { + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/ScoreInfo.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/ScoreInfo.java new file mode 100644 index 00000000000..960ce778857 --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/ScoreInfo.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema.model; + +public class ScoreInfo { + private Integer type; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/UserInfo.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/UserInfo.java new file mode 100644 index 00000000000..37662bb32ed --- /dev/null +++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/model/UserInfo.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.codec.protobuf.schema.model; + +import java.util.List; +import java.util.Map; + +public class UserInfo { + private List subDeptInfos; + + private List> extraInfos; + + private List>> nestedLists; + + public List getSubDeptInfos() { + return subDeptInfos; + } + + public void setSubDeptInfos(List subDeptInfos) { + this.subDeptInfos = subDeptInfos; + } + + public List> getExtraInfos() { + return extraInfos; + } + + public void setExtraInfos(List> extraInfos) { + this.extraInfos = extraInfos; + } + + public List>> getNestedLists() { + return nestedLists; + } + + public void setNestedLists(List>> nestedLists) { + this.nestedLists = nestedLists; + } +} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java deleted file mode 100644 index daeedec94b0..00000000000 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/TestProtobufSchemaUtils.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils; - -import java.lang.reflect.Array; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.common.javassist.FieldConfig; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.protostuff.ByteArrayInput; -import io.protostuff.Input; -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; - -public class TestProtobufSchemaUtils { - class MyClassLoader extends ClassLoader { - public MyClassLoader() { - super(Thread.currentThread().getContextClassLoader()); - } - } - - //ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//new MyClassLoader(); - ClassLoader classLoader = new MyClassLoader(); - - ScopedProtobufSchemaManager scopedProtobufSchemaManager = new ScopedProtobufSchemaManager(classLoader); - - public static class TestMap { - public Map map = new HashMap<>(); - - public TestMap() { - map.put("asdf", "jjj"); - } - } - - @Test - public void testMap() throws Exception { - TestMap tm = new TestMap(); - TestMap tmResult = writeThenRead(tm); - Assert.assertEquals(tm.map, tmResult.map); - - Map map = new HashMap<>(); - map.put("aaa", "bbb"); - testSchema(map); - } - - @Test - public void wrapPrimitive() throws Exception { - Assert.assertNotNull(WrapType.ARGS_WRAP); - Assert.assertNotNull(WrapType.NORMAL_WRAP); - testSchema(1); - testSchema("test"); - testSchema(WrapType.ARGS_WRAP); - Assert.assertTrue(true); - } - - @Test - public void wrapArray() throws Exception { - Assert.assertNotNull(WrapType.ARGS_WRAP); - Assert.assertNotNull(WrapType.NORMAL_WRAP); - testArraySchema(new byte[] {0, 1, 2}); - testArraySchema(new int[] {0, 1, 2}); - testArraySchema(new String[] {"a", "b"}); - testArraySchema(new WrapType[] {WrapType.ARGS_WRAP, WrapType.NORMAL_WRAP}); - Assert.assertTrue(true); - } - - @Test - public void notWrap() throws Exception { - FieldConfig expect = new FieldConfig(); - expect.setName("test"); - - FieldConfig result = writeThenRead(expect); - Assert.assertEquals(expect.getName(), result.getName()); - } - - private void testSchema(Object expect) throws Exception { - Object result = writeThenRead(expect); - Assert.assertEquals(expect, result); - } - - private void testArraySchema(Object expect) throws Exception { - Object result = writeThenRead(expect); - - int expectLen = Array.getLength(expect); - Assert.assertEquals(expectLen, Array.getLength(result)); - for (int idx = 0; idx < expectLen; idx++) { - Assert.assertEquals(Array.get(expect, idx), Array.get(result, idx)); - } - } - - @SuppressWarnings("unchecked") - private T writeThenRead(T value) throws Exception { - WrapSchema schema = scopedProtobufSchemaManager.getOrCreateSchema(value.getClass()); - - byte[] bytes = toByteArray(schema, value); - Object result = toObject(schema, bytes); - return (T) result; - } - - private byte[] toByteArray(WrapSchema schema, Object value) throws Exception { - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - - schema.writeObject(output, value); - return output.toByteArray(); - } - - private Object toObject(WrapSchema schema, byte[] bytes) throws Exception { - Input input = new ByteArrayInput(bytes, false); - - return schema.readObject(input); - } - - @Test - public void object() throws Exception { - WrapSchema schema = scopedProtobufSchemaManager.getOrCreateSchema(Object.class); - - LinkedBuffer linkedBuf = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuf); - schema.writeObject(output, 1); - - Input input = new ByteArrayInput(output.toByteArray(), false); - Object result = schema.readObject(input); - - Assert.assertEquals(1, result); - Assert.assertThat(result, Matchers.instanceOf(Integer.class)); - } -} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsNotWrapSchema.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsNotWrapSchema.java deleted file mode 100644 index a4c655ebfde..00000000000 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsNotWrapSchema.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import io.protostuff.Input; -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Schema; - -public class TestArgsNotWrapSchema { - - private ArgsNotWrapSchema argsNotWrapSchema = null; - - @Before - public void setUp() throws Exception { - argsNotWrapSchema = new ArgsNotWrapSchema(Mockito.mock(Schema.class)); - } - - @After - public void tearDown() throws Exception { - argsNotWrapSchema = null; - } - - @Test - public void testReadFromEmpty() { - Assert.assertNotNull(argsNotWrapSchema); - Object object = argsNotWrapSchema.readFromEmpty(); - Assert.assertNotNull(object); - // object is created but no values inside to assert - } - - @Test - public void testReadObject() { - boolean status = true; - Input input = null; - try { - Object object = argsNotWrapSchema.readObject(input); - Assert.assertNotNull(object); - // object is created but no values inside to assert - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testWriteObject() { - boolean status = true; - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - String[] stringArray = new String[1]; - try { - argsNotWrapSchema.writeObject(output, stringArray); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testWriteObjectToSchema() { - boolean status = true; - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - String[] stringArray = new String[1]; - stringArray[0] = "abc"; - try { - argsNotWrapSchema.writeObject(output, stringArray); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } -} diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsWrapSchema.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsWrapSchema.java deleted file mode 100644 index ec8dcfc5a21..00000000000 --- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/utils/schema/TestArgsWrapSchema.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.codec.protobuf.utils.schema; - -import java.io.IOException; - -import org.apache.servicecomb.common.javassist.MultiWrapper; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import io.protostuff.Input; -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Schema; - -public class TestArgsWrapSchema { - - private ArgsWrapSchema argsWrapSchema = null; - - @SuppressWarnings("rawtypes") - private Schema schema = null; - - @Before - public void setUp() throws Exception { - schema = Mockito.mock(Schema.class); - argsWrapSchema = new ArgsWrapSchema(schema); - } - - @After - public void tearDown() throws Exception { - argsWrapSchema = null; - } - - @Test - public void testReadFromEmpty() { - - MultiWrapper multiWrapper = Mockito.mock(MultiWrapper.class); - Mockito.when(schema.newMessage()).thenReturn(multiWrapper); - Assert.assertNotNull(argsWrapSchema); - Object object = argsWrapSchema.readFromEmpty(); - Assert.assertNull(object); - } - - @Test - public void testWriteObject() { - boolean status = true; - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - String[] stringArray = new String[1]; - stringArray[0] = "abc"; - - MultiWrapper multiWrapper = Mockito.mock(MultiWrapper.class); - Mockito.when(schema.newMessage()).thenReturn(multiWrapper); - try { - argsWrapSchema.writeObject(output, stringArray); - } catch (IOException e) { - status = true; - } - Assert.assertTrue(status); - } - - @Test - public void testReadObject() { - boolean status = true; - Input input = null; - String[] stringArray = new String[1]; - stringArray[0] = "abc"; - - MultiWrapper multiWrapper = Mockito.mock(MultiWrapper.class); - Mockito.when(schema.newMessage()).thenReturn(multiWrapper); - try { - Object object = argsWrapSchema.readObject(input); - Assert.assertNull(object); - } catch (IOException e) { - status = true; - } - Assert.assertTrue(status); - } -} diff --git a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.proto b/common/common-protobuf/src/test/proto/ModelProtobuf.proto similarity index 90% rename from common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.proto rename to common/common-protobuf/src/test/proto/ModelProtobuf.proto index 1c2cb5abf23..c1fb2ed34dd 100644 --- a/common/common-protobuf/src/test/java/io/protostuff/runtime/model/ModelProtobuf.proto +++ b/common/common-protobuf/src/test/proto/ModelProtobuf.proto @@ -5,9 +5,9 @@ The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,7 +16,10 @@ */ syntax = "proto3"; -package io.protostuff.runtime.model; +package proto; + +option java_package = "io.protostuff.runtime.model"; +option java_outer_classname = "ModelProtobuf"; message User{ string name = 1; diff --git a/common/common-protobuf/src/test/resources/ProtoSchema.proto b/common/common-protobuf/src/test/resources/ProtoSchema.proto new file mode 100644 index 00000000000..bbb1a476948 --- /dev/null +++ b/common/common-protobuf/src/test/resources/ProtoSchema.proto @@ -0,0 +1,443 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; +import "google/protobuf/empty.proto"; +import "google/protobuf/any.proto"; +package a.b; + +message Empty { +} + +message FieldNeedWrap { + repeated ListUser listListUser = 1; + repeated MapUser listMapUser = 2; + map mapListUser = 3; + map mapMapUser = 4; + repeated ListListUser listListListUser = 5; + repeated ListMapUser listListMapUser = 6; + repeated MapListUser listMapListUser = 7; + repeated MapMapUser listMapMapUser = 8; + map mapMapListUser = 9; + map mapMapMapUser = 10; +} + +message User { + string name = 1; + repeated User friends = 2; +} + +message Ref1 { + Ref2 ref = 1; +} + +message Ref2 { + Ref1 ref = 1; +} + +//@WrapArguments +message BaseRequestWrap { + bool boolValue = 1; + sint32 iValue = 2; + sint64 lValue = 3; + float fValue = 4; + double dValue = 5; + string sValue = 6; + repeated sint32 iArray = 7; + Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 color = 8; + int64 localDate = 9; + int64 date = 10; + Empty empty = 11; +} + +//@WrapProperty +message BaseResponseWrap200 { + sint32 value = 1; +} + +//@WrapProperty +message BaseResponseWrap444 { + Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 value = 1; +} + +//@WrapArguments +message BytesRequestWrap { + bytes value = 1; +} + +//@WrapProperty +message BytesResponseWrap200 { + bytes value = 1; +} + +//@WrapArguments +message ColorBodyRequestWrap { + Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 color = 1; +} + +//@WrapProperty +message ColorBodyResponseWrap200 { + Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 value = 1; +} + +//@WrapArguments +message ListListListStringRequestWrap { + repeated ListListString value = 1; +} + +//@WrapProperty +message ListListListStringResponseWrap200 { + repeated ListListString value = 1; +} + +//@WrapArguments +message ListListMapStringRequestWrap { + repeated ListMapString value = 1; +} + +//@WrapProperty +message ListListMapStringResponseWrap200 { + repeated ListMapString value = 1; +} + +//@WrapArguments +message ListListStringRequestWrap { + repeated ListString value = 1; +} + +//@WrapProperty +message ListListStringResponseWrap200 { + repeated ListString value = 1; +} + +//@WrapArguments +message ListListUserRequestWrap { + repeated ListUser value = 1; +} + +//@WrapProperty +message ListListUserResponseWrap200 { + repeated ListUser value = 1; +} + +//@WrapArguments +message ListMapListStringRequestWrap { + repeated MapListString value = 1; +} + +//@WrapProperty +message ListMapListStringResponseWrap200 { + repeated MapListString value = 1; +} + +//@WrapArguments +message ListMapMapStringRequestWrap { + repeated MapMapString value = 1; +} + +//@WrapProperty +message ListMapMapStringResponseWrap200 { + repeated MapMapString value = 1; +} + +//@WrapArguments +message ListMapStringRequestWrap { + repeated MapString value = 1; +} + +//@WrapProperty +message ListMapStringResponseWrap200 { + repeated MapString value = 1; +} + +//@WrapArguments +message ListMapUserRequestWrap { + repeated MapUser value = 1; +} + +//@WrapProperty +message ListMapUserResponseWrap200 { + repeated MapUser value = 1; +} + +//@WrapArguments +message ListObjRequestWrap { + repeated google.protobuf.Any objs = 1; +} + +//@WrapProperty +message ListObjResponseWrap200 { + repeated google.protobuf.Any value = 1; +} + +//@WrapArguments +message ListUserRequestWrap { + repeated User users = 1; +} + +//@WrapProperty +message ListUserResponseWrap200 { + repeated User value = 1; +} + +//@WrapArguments +message MapListStringRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapListStringResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapListUserRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapListUserResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapMapListStringRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapMapListStringResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapMapMapStringRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapMapMapStringResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapMapStringRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapMapStringResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapMapUserRequestWrap { + map value = 1; +} + +//@WrapProperty +message MapMapUserResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapObjRequestWrap { + map objs = 1; +} + +//@WrapProperty +message MapObjResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message MapUserRequestWrap { + map users = 1; +} + +//@WrapProperty +message MapUserResponseWrap200 { + map value = 1; +} + +//@WrapArguments +message TestTextPlainRequestWrap { + string fieldNeedWrap = 1; +} + +//@WrapProperty +message TestTextPlainResponseWrap200 { + string value = 1; +} + +//@WrapArguments +message UserWrapInProtobufRequestWrap { + sint32 ivalue = 1; + User user = 2; +} + +//@WrapProperty +message ListUser { + repeated User value = 1; +} + +//@WrapProperty +message MapUser { + map value = 1; +} + +//@WrapProperty +message ListListUser { + repeated ListUser value = 1; +} + +//@WrapProperty +message ListMapUser { + repeated MapUser value = 1; +} + +//@WrapProperty +message MapListUser { + map value = 1; +} + +//@WrapProperty +message MapMapUser { + map value = 1; +} + +//@WrapProperty +message ListListString { + repeated ListString value = 1; +} + +//@WrapProperty +message ListMapString { + repeated MapString value = 1; +} + +//@WrapProperty +message ListString { + repeated string value = 1; +} + +//@WrapProperty +message MapListString { + map value = 1; +} + +//@WrapProperty +message MapMapString { + map value = 1; +} + +//@WrapProperty +message MapString { + map value = 1; +} + +enum Enum_2610aa5dc6cd086cf20168892802c9c765a557f4951557340ad9f0982c53e055 { + RED = 0; + YELLOW = 1; + BLUE = 2; +} + +service MainService { + //@Rpc{"argTypeName":"BaseRequestWrap","responses":{"200":{"typeName":"BaseResponseWrap200"},"444":{"typeName":"BaseResponseWrap444"}}} + rpc base (BaseRequestWrap) returns (BaseResponseWrap200); + + //@Rpc{"argTypeName":"BytesRequestWrap","responses":{"200":{"typeName":"BytesResponseWrap200"}}} + rpc bytes (BytesRequestWrap) returns (BytesResponseWrap200); + + //@Rpc{"argTypeName":"ColorBodyRequestWrap","responses":{"200":{"typeName":"ColorBodyResponseWrap200"}}} + rpc colorBody (ColorBodyRequestWrap) returns (ColorBodyResponseWrap200); + + //@Rpc{"argTypeName":"FieldNeedWrap","responses":{"200":{"typeName":"FieldNeedWrap"}}} + rpc fieldNeedWrap (FieldNeedWrap) returns (FieldNeedWrap); + + //@Rpc{"argTypeName":"ListListListStringRequestWrap","responses":{"200":{"typeName":"ListListListStringResponseWrap200"}}} + rpc listListListString (ListListListStringRequestWrap) returns (ListListListStringResponseWrap200); + + //@Rpc{"argTypeName":"ListListMapStringRequestWrap","responses":{"200":{"typeName":"ListListMapStringResponseWrap200"}}} + rpc listListMapString (ListListMapStringRequestWrap) returns (ListListMapStringResponseWrap200); + + //@Rpc{"argTypeName":"ListListStringRequestWrap","responses":{"200":{"typeName":"ListListStringResponseWrap200"}}} + rpc listListString (ListListStringRequestWrap) returns (ListListStringResponseWrap200); + + //@Rpc{"argTypeName":"ListListUserRequestWrap","responses":{"200":{"typeName":"ListListUserResponseWrap200"}}} + rpc listListUser (ListListUserRequestWrap) returns (ListListUserResponseWrap200); + + //@Rpc{"argTypeName":"ListMapListStringRequestWrap","responses":{"200":{"typeName":"ListMapListStringResponseWrap200"}}} + rpc listMapListString (ListMapListStringRequestWrap) returns (ListMapListStringResponseWrap200); + + //@Rpc{"argTypeName":"ListMapMapStringRequestWrap","responses":{"200":{"typeName":"ListMapMapStringResponseWrap200"}}} + rpc listMapMapString (ListMapMapStringRequestWrap) returns (ListMapMapStringResponseWrap200); + + //@Rpc{"argTypeName":"ListMapStringRequestWrap","responses":{"200":{"typeName":"ListMapStringResponseWrap200"}}} + rpc listMapString (ListMapStringRequestWrap) returns (ListMapStringResponseWrap200); + + //@Rpc{"argTypeName":"ListMapUserRequestWrap","responses":{"200":{"typeName":"ListMapUserResponseWrap200"}}} + rpc listMapUser (ListMapUserRequestWrap) returns (ListMapUserResponseWrap200); + + //@Rpc{"argTypeName":"ListObjRequestWrap","responses":{"200":{"typeName":"ListObjResponseWrap200"}}} + rpc listObj (ListObjRequestWrap) returns (ListObjResponseWrap200); + + //@Rpc{"argTypeName":"ListUserRequestWrap","responses":{"200":{"typeName":"ListUserResponseWrap200"}}} + rpc listUser (ListUserRequestWrap) returns (ListUserResponseWrap200); + + //@Rpc{"argTypeName":"MapListStringRequestWrap","responses":{"200":{"typeName":"MapListStringResponseWrap200"}}} + rpc mapListString (MapListStringRequestWrap) returns (MapListStringResponseWrap200); + + //@Rpc{"argTypeName":"MapListUserRequestWrap","responses":{"200":{"typeName":"MapListUserResponseWrap200"}}} + rpc mapListUser (MapListUserRequestWrap) returns (MapListUserResponseWrap200); + + //@Rpc{"argTypeName":"MapMapListStringRequestWrap","responses":{"200":{"typeName":"MapMapListStringResponseWrap200"}}} + rpc mapMapListString (MapMapListStringRequestWrap) returns (MapMapListStringResponseWrap200); + + //@Rpc{"argTypeName":"MapMapMapStringRequestWrap","responses":{"200":{"typeName":"MapMapMapStringResponseWrap200"}}} + rpc mapMapMapString (MapMapMapStringRequestWrap) returns (MapMapMapStringResponseWrap200); + + //@Rpc{"argTypeName":"MapMapStringRequestWrap","responses":{"200":{"typeName":"MapMapStringResponseWrap200"}}} + rpc mapMapString (MapMapStringRequestWrap) returns (MapMapStringResponseWrap200); + + //@Rpc{"argTypeName":"MapMapUserRequestWrap","responses":{"200":{"typeName":"MapMapUserResponseWrap200"}}} + rpc mapMapUser (MapMapUserRequestWrap) returns (MapMapUserResponseWrap200); + + //@Rpc{"argTypeName":"MapObjRequestWrap","responses":{"200":{"typeName":"MapObjResponseWrap200"}}} + rpc mapObj (MapObjRequestWrap) returns (MapObjResponseWrap200); + + //@Rpc{"argTypeName":"MapUserRequestWrap","responses":{"200":{"typeName":"MapUserResponseWrap200"}}} + rpc mapUser (MapUserRequestWrap) returns (MapUserResponseWrap200); + + //@Rpc{"argTypeName":"google.protobuf.Empty","responses":{"200":{"typeName":"google.protobuf.Empty"}}} + rpc noParamVoid (google.protobuf.Empty) returns (google.protobuf.Empty); + + //@Rpc{"argTypeName":"google.protobuf.Any","responses":{"200":{"typeName":"google.protobuf.Any"}}} + rpc obj (google.protobuf.Any) returns (google.protobuf.Any); + + //@Rpc{"argTypeName":"Ref1","responses":{"200":{"typeName":"Ref2"}}} + rpc ref (Ref1) returns (Ref2); + + //@Rpc{"argTypeName":"TestTextPlainRequestWrap","responses":{"200":{"typeName":"TestTextPlainResponseWrap200"}}} + rpc testTextPlain (TestTextPlainRequestWrap) returns (TestTextPlainResponseWrap200); + + //@Rpc{"argTypeName":"User","responses":{"200":{"typeName":"User"}}} + rpc user (User) returns (User); + + //@Rpc{"argTypeName":"UserWrapInProtobufRequestWrap","responses":{"200":{"typeName":"User"}}} + rpc userWrapInProtobuf (UserWrapInProtobufRequestWrap) returns (User); +} diff --git a/common/common-protobuf/src/test/resources/log4j.properties b/common/common-protobuf/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/common/common-protobuf/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/common/common-rest/pom.xml b/common/common-rest/pom.xml index 9483afb03cd..f1f2c84b45b 100644 --- a/common/common-rest/pom.xml +++ b/common/common-rest/pom.xml @@ -23,7 +23,7 @@ org.apache.servicecomb common - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT common-rest @@ -35,8 +35,8 @@ java-chassis-core - javax.servlet - javax.servlet-api + org.apache.servicecomb + common-protobuf @@ -46,18 +46,33 @@ - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + registry-local + test + + + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test org.apache.servicecomb foundation-test-scaffolding + + org.apache.servicecomb + swagger-generator-jaxrs + test + + + org.mockito + mockito-inline + test + diff --git a/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSFix.java b/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSFix.java deleted file mode 100644 index 6c46eca15c7..00000000000 --- a/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSFix.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.fasterxml.jackson.core.base; - -import org.apache.servicecomb.foundation.common.utils.JvmUtils; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper; -import com.fasterxml.jackson.core.json.ReaderBasedJsonParser; -import com.fasterxml.jackson.core.json.UTF8StreamJsonParser; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import com.netflix.config.DynamicPropertyFactory; - -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.LoaderClassPath; -import javassist.NotFoundException; - -/** - * will be deleted after jackson fix the DoS problem: - * https://github.com/FasterXML/jackson-databind/issues/2157 - */ -public class DoSFix { - private static final String SUFFIX = "Fixed"; - - private static boolean enabled = DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.jackson.fix.DoS.enabled", true).get(); - - private static boolean fixed; - - private static Class mappingJsonFactoryClass; - - public static synchronized void init() { - if (fixed || !enabled) { - return; - } - - fix(); - } - - public static JsonFactory createJsonFactory() { - try { - return (JsonFactory) mappingJsonFactoryClass.newInstance(); - } catch (Throwable e) { - throw new IllegalStateException("Failed to create JsonFactory.", e); - } - } - - private static void fix() { - try { - ClassLoader classLoader = JvmUtils.correctClassLoader(DoSFix.class.getClassLoader()); - ClassPool pool = new ClassPool(ClassPool.getDefault()); - pool.appendClassPath(new LoaderClassPath(classLoader)); - - fixParserBase(classLoader, pool); - fixReaderParser(classLoader, pool); - fixStreamParser(classLoader, pool); - fixByteSourceJsonBootstrapper(classLoader, pool); - - CtClass ctJsonFactoryFixedClass = fixJsonFactory(classLoader, pool); - fixMappingJsonFactoryClass(classLoader, pool, ctJsonFactoryFixedClass); - - fixed = true; - } catch (Throwable e) { - throw new IllegalStateException( - "Failed to fix jackson DoS bug.", - e); - } - } - - private static void fixMappingJsonFactoryClass(ClassLoader classLoader, ClassPool pool, - CtClass ctJsonFactoryFixedClass) throws NotFoundException, CannotCompileException { - CtClass ctMappingJsonFactoryClass = pool - .getAndRename(MappingJsonFactory.class.getName(), MappingJsonFactory.class.getName() + SUFFIX); - ctMappingJsonFactoryClass.setSuperclass(ctJsonFactoryFixedClass); - mappingJsonFactoryClass = ctMappingJsonFactoryClass.toClass(classLoader, null); - } - - private static CtClass fixJsonFactory(ClassLoader classLoader, ClassPool pool) - throws NotFoundException, CannotCompileException { - CtClass ctJsonFactoryClass = pool.getCtClass(JsonFactory.class.getName()); - CtClass ctJsonFactoryFixedClass = pool.makeClass(JsonFactory.class.getName() + SUFFIX); - ctJsonFactoryFixedClass.setSuperclass(ctJsonFactoryClass); - for (CtMethod ctMethod : ctJsonFactoryClass.getDeclaredMethods()) { - if (ctMethod.getName().equals("_createParser")) { - ctJsonFactoryFixedClass.addMethod(new CtMethod(ctMethod, ctJsonFactoryFixedClass, null)); - } - } - ctJsonFactoryFixedClass - .replaceClassName(ReaderBasedJsonParser.class.getName(), ReaderBasedJsonParser.class.getName() + SUFFIX); - ctJsonFactoryFixedClass - .replaceClassName(UTF8StreamJsonParser.class.getName(), UTF8StreamJsonParser.class.getName() + SUFFIX); - ctJsonFactoryFixedClass.replaceClassName(ByteSourceJsonBootstrapper.class.getName(), - ByteSourceJsonBootstrapper.class.getName() + SUFFIX); - ctJsonFactoryFixedClass.toClass(classLoader, null); - - return ctJsonFactoryFixedClass; - } - - private static void fixByteSourceJsonBootstrapper(ClassLoader classLoader, ClassPool pool) - throws NotFoundException, CannotCompileException { - CtClass ctByteSourceJsonBootstrapper = pool - .getAndRename(ByteSourceJsonBootstrapper.class.getName(), ByteSourceJsonBootstrapper.class.getName() + SUFFIX); - ctByteSourceJsonBootstrapper - .replaceClassName(UTF8StreamJsonParser.class.getName(), UTF8StreamJsonParser.class.getName() + SUFFIX); - ctByteSourceJsonBootstrapper - .replaceClassName(ReaderBasedJsonParser.class.getName(), ReaderBasedJsonParser.class.getName() + SUFFIX); - ctByteSourceJsonBootstrapper.toClass(classLoader, null); - } - - private static void fixStreamParser(ClassLoader classLoader, ClassPool pool) - throws NotFoundException, CannotCompileException { - CtClass ctStreamClass = pool - .getAndRename(UTF8StreamJsonParser.class.getName(), UTF8StreamJsonParser.class.getName() + SUFFIX); - ctStreamClass.replaceClassName(ParserBase.class.getName(), ParserBase.class.getName() + SUFFIX); - ctStreamClass.toClass(classLoader, null); - } - - private static void fixReaderParser(ClassLoader classLoader, ClassPool pool) - throws NotFoundException, CannotCompileException { - CtClass ctReaderClass = pool - .getAndRename(ReaderBasedJsonParser.class.getName(), ReaderBasedJsonParser.class.getName() + SUFFIX); - ctReaderClass.replaceClassName(ParserBase.class.getName(), ParserBase.class.getName() + SUFFIX); - ctReaderClass.toClass(classLoader, null); - } - - private static void fixParserBase(ClassLoader classLoader, ClassPool pool) - throws NotFoundException, CannotCompileException { - CtMethod ctMethodFixed = pool.get(DoSParserFixed.class.getName()).getDeclaredMethod("_parseSlowInt"); - CtClass baseClass = pool.getAndRename(ParserBase.class.getName(), ParserBase.class.getName() + SUFFIX); - baseClass.removeMethod(baseClass.getDeclaredMethod("_parseSlowInt")); - baseClass.addMethod(new CtMethod(ctMethodFixed, baseClass, null)); - baseClass.toClass(classLoader, null); - } -} diff --git a/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSParserFixed.java b/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSParserFixed.java deleted file mode 100644 index 71fbdc675b0..00000000000 --- a/common/common-rest/src/main/java/com/fasterxml/jackson/core/base/DoSParserFixed.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.fasterxml.jackson.core.base; - -import java.io.IOException; -import java.io.Reader; -import java.math.BigInteger; - -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.io.IOContext; -import com.fasterxml.jackson.core.io.NumberInput; -import com.fasterxml.jackson.core.json.ReaderBasedJsonParser; -import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer; - -/** - * will not be use directly - * just get _parseSlowInt/_parseSlowFloat bytecode and replace to ParserBase - */ -public abstract class DoSParserFixed extends ReaderBasedJsonParser { - public DoSParserFixed(IOContext ctxt, int features, Reader r, - ObjectCodec codec, CharsToNameCanonicalizer st, - char[] inputBuffer, int start, int end, boolean bufferRecyclable) { - super(ctxt, features, r, codec, st, inputBuffer, start, end, bufferRecyclable); - } - - private void _parseSlowInt(int expType) throws IOException { - String numStr = _textBuffer.contentsAsString(); - try { - int len = _intLength; - char[] buf = _textBuffer.getTextBuffer(); - int offset = _textBuffer.getTextOffset(); - if (_numberNegative) { - ++offset; - } - // Some long cases still... - if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) { - // Probably faster to construct a String, call parse, than to use BigInteger - _numberLong = Long.parseLong(numStr); - _numTypesValid = NR_LONG; - } else { - // nope, need the heavy guns... (rare case) - - // *** fix DoS attack begin *** - if (NR_DOUBLE == expType || NR_FLOAT == expType) { - _numberDouble = Double.parseDouble(numStr); - _numTypesValid = NR_DOUBLE; - return; - } - if (NR_BIGINT != expType) { - throw new NumberFormatException("invalid numeric value '" + numStr + "'"); - } - // *** fix DoS attack end *** - - _numberBigInt = new BigInteger(numStr); - _numTypesValid = NR_BIGINT; - } - } catch (NumberFormatException nex) { - // Can this ever occur? Due to overflow, maybe? - _wrapError("Malformed numeric value '" + numStr + "'", nex); - } - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java deleted file mode 100644 index 3908bb5537b..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CompletableFuture; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.filter.HttpServerFilterBeforeSendResponseExecutor; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractRestInvocation { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRestInvocation.class); - - public static final String UNKNOWN_OPERATION_ID = "UNKNOWN_OPERATION"; - - protected long start; - - protected RestOperationMeta restOperationMeta; - - protected Invocation invocation; - - protected HttpServletRequestEx requestEx; - - protected HttpServletResponseEx responseEx; - - protected ProduceProcessor produceProcessor; - - protected List httpServerFilters = Collections.emptyList(); - - public AbstractRestInvocation() { - this.start = System.nanoTime(); - } - - public void setHttpServerFilters(List httpServerFilters) { - this.httpServerFilters = httpServerFilters; - } - - protected void findRestOperation(MicroserviceMeta microserviceMeta) { - ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); - if (servicePathManager == null) { - LOGGER.error("No schema defined for {}:{}.", microserviceMeta.getAppId(), microserviceMeta.getName()); - throw new InvocationException(Status.NOT_FOUND, Status.NOT_FOUND.getReasonPhrase()); - } - - OperationLocator locator = locateOperation(servicePathManager); - requestEx.setAttribute(RestConst.PATH_PARAMETERS, locator.getPathVarMap()); - this.restOperationMeta = locator.getOperation(); - } - - protected void initProduceProcessor() { - produceProcessor = restOperationMeta.ensureFindProduceProcessor(requestEx); - if (produceProcessor == null) { - String msg = String.format("Accept %s is not supported", requestEx.getHeader(HttpHeaders.ACCEPT)); - throw new InvocationException(Status.NOT_ACCEPTABLE, msg); - } - } - - protected void setContext() throws Exception { - String strCseContext = requestEx.getHeader(Const.CSE_CONTEXT); - if (StringUtils.isEmpty(strCseContext)) { - return; - } - - @SuppressWarnings("unchecked") - Map cseContext = - JsonUtils.readValue(strCseContext.getBytes(StandardCharsets.UTF_8), Map.class); - invocation.mergeContext(cseContext); - } - - public String getContext(String key) { - if (null == invocation || null == invocation.getContext()) { - return null; - } - - return invocation.getContext(key); - } - - protected void scheduleInvocation() { - try { - createInvocation(); - } catch (IllegalStateException e) { - sendFailResponse(e); - return; - } - - invocation.onStart(requestEx, start); - invocation.getInvocationStageTrace().startSchedule(); - OperationMeta operationMeta = restOperationMeta.getOperationMeta(); - - try { - this.setContext(); - } catch (Exception e) { - LOGGER.error("failed to set invocation context", e); - sendFailResponse(e); - return; - } - - Holder qpsFlowControlReject = checkQpsFlowControl(operationMeta); - if (qpsFlowControlReject.value) { - return; - } - - operationMeta.getExecutor().execute(() -> { - synchronized (this.requestEx) { - try { - if (isInQueueTimeout()) { - throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "Timeout when processing the request."); - } - if (requestEx.getAttribute(RestConst.REST_REQUEST) != requestEx) { - // already timeout - // in this time, request maybe recycled and reused by web container, do not use requestEx - LOGGER.error("Rest request already timeout, abandon execute, method {}, operation {}.", - operationMeta.getHttpMethod(), - operationMeta.getMicroserviceQualifiedName()); - return; - } - - runOnExecutor(); - } catch (Throwable e) { - LOGGER.error("rest server onRequest error", e); - sendFailResponse(e); - } - } - }); - } - - private Holder checkQpsFlowControl(OperationMeta operationMeta) { - Holder qpsFlowControlReject = new Holder<>(false); - @SuppressWarnings("deprecation") - Handler providerQpsFlowControlHandler = operationMeta.getProviderQpsFlowControlHandler(); - if (null != providerQpsFlowControlHandler) { - try { - providerQpsFlowControlHandler.handle(invocation, response -> { - qpsFlowControlReject.value = true; - produceProcessor = ProduceProcessorManager.JSON_PROCESSOR; - sendResponse(response); - }); - } catch (Exception e) { - LOGGER.error("failed to execute ProviderQpsFlowControlHandler", e); - qpsFlowControlReject.value = true; - sendFailResponse(e); - } - } - return qpsFlowControlReject; - } - - private boolean isInQueueTimeout() { - return System.nanoTime() - invocation.getInvocationStageTrace().getStart() > - CommonRestConfig.getRequestWaitInPoolTimeout() * 1_000_000; - } - - protected void runOnExecutor() { - invocation.onExecuteStart(); - - invoke(); - } - - protected abstract OperationLocator locateOperation(ServicePathManager servicePathManager); - - // create a invocation without args setted - protected abstract void createInvocation(); - - public void invoke() { - try { - Response response = prepareInvoke(); - if (response != null) { - sendResponseQuietly(response); - return; - } - - doInvoke(); - } catch (Throwable e) { - LOGGER.error("unknown rest exception.", e); - sendFailResponse(e); - } - } - - protected Response prepareInvoke() throws Throwable { - this.initProduceProcessor(); - invocation.getHandlerContext().put(RestConst.REST_REQUEST, requestEx); - - invocation.getInvocationStageTrace().startServerFiltersRequest(); - for (HttpServerFilter filter : httpServerFilters) { - if (filter.enabled()) { - Response response = filter.afterReceiveRequest(invocation, requestEx); - if (response != null) { - return response; - } - } - } - - return null; - } - - protected void doInvoke() throws Throwable { - invocation.getInvocationStageTrace().startHandlersRequest(); - invocation.next(resp -> sendResponseQuietly(resp)); - } - - public void sendFailResponse(Throwable throwable) { - if (produceProcessor == null) { - produceProcessor = ProduceProcessorManager.DEFAULT_PROCESSOR; - } - - Response response = Response.createProducerFail(throwable); - sendResponseQuietly(response); - } - - protected void sendResponseQuietly(Response response) { - if (invocation != null) { - invocation.getInvocationStageTrace().finishHandlersResponse(); - } - try { - sendResponse(response); - } catch (Throwable e) { - LOGGER.error("Failed to send rest response, operation:{}, request uri:{}", - getMicroserviceQualifiedName(), requestEx.getRequestURI(), e); - } - } - - @SuppressWarnings("deprecation") - protected void sendResponse(Response response) { - if (response.getHeaders().getHeaderMap() != null) { - for (Entry> entry : response.getHeaders().getHeaderMap().entrySet()) { - for (Object value : entry.getValue()) { - if (!entry.getKey().equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) - && !entry.getKey().equalsIgnoreCase("Transfer-Encoding")) { - responseEx.addHeader(entry.getKey(), String.valueOf(value)); - } - } - } - } - responseEx.setStatus(response.getStatusCode(), response.getReasonPhrase()); - responseEx.setAttribute(RestConst.INVOCATION_HANDLER_RESPONSE, response); - responseEx.setAttribute(RestConst.INVOCATION_HANDLER_PROCESSOR, produceProcessor); - - executeHttpServerFilters(response); - } - - protected void executeHttpServerFilters(Response response) { - HttpServerFilterBeforeSendResponseExecutor exec = - new HttpServerFilterBeforeSendResponseExecutor(httpServerFilters, invocation, responseEx); - CompletableFuture future = exec.run(); - future.whenComplete((v, e) -> { - if (invocation != null) { - invocation.getInvocationStageTrace().finishServerFiltersResponse(); - } - - onExecuteHttpServerFiltersFinish(response, e); - }); - } - - protected void onExecuteHttpServerFiltersFinish(Response response, Throwable e) { - if (e != null) { - LOGGER.error("Failed to execute HttpServerFilters, operation:{}, request uri:{}", - getMicroserviceQualifiedName(), requestEx.getRequestURI(), e); - } - - try { - responseEx.flushBuffer(); - } catch (Throwable flushException) { - LOGGER.error("Failed to flush rest response, operation:{}, request uri:{}", - getMicroserviceQualifiedName(), requestEx.getRequestURI(), flushException); - } - - try { - requestEx.getAsyncContext().complete(); - } catch (Throwable completeException) { - LOGGER.error("Failed to complete async rest response, operation:{}, request uri:{}", - getMicroserviceQualifiedName(), requestEx.getRequestURI(), completeException); - } - - // if failed to locate path, then will not create invocation - // TODO: statistics this case - if (invocation != null) { - invocation.onFinish(response); - } - } - - private String getMicroserviceQualifiedName() { - return null == invocation ? UNKNOWN_OPERATION_ID : invocation.getMicroserviceQualifiedName(); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfig.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfig.java deleted file mode 100644 index a673a5acc93..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import com.netflix.config.DynamicLongProperty; -import com.netflix.config.DynamicPropertyFactory; - -public class CommonRestConfig { - public static final String KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT = "servicecomb.rest.server.requestWaitInPoolTimeout"; - - public static final long DEFAULT_REQUEST_WAIT_IN_POOL_TIMEOUT = 30000; - - private static final DynamicLongProperty requestWaitInPoolTimeoutProperty = - DynamicPropertyFactory.getInstance().getLongProperty(KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT, - DEFAULT_REQUEST_WAIT_IN_POOL_TIMEOUT); - - public static long getRequestWaitInPoolTimeout() { - return requestWaitInPoolTimeoutProperty.get(); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfiguration.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfiguration.java new file mode 100644 index 00000000000..a642265ae0f --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/CommonRestConfiguration.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import java.util.List; + +import org.apache.servicecomb.common.rest.codec.query.QueryCodec; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecCsv; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecMulti; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecPipes; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecSsv; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecs; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecsUtils; +import org.apache.servicecomb.common.rest.filter.inner.RestServerCodecFilter; +import org.apache.servicecomb.common.rest.filter.inner.WebSocketServerCodecFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CommonRestConfiguration { + @Bean + public QueryCodecCsv scbQueryCodecCsv() { + return new QueryCodecCsv(); + } + + @Bean + public QueryCodecSsv scbQueryCodecSsv() { + return new QueryCodecSsv(); + } + + @Bean + public QueryCodecPipes scbQueryCodecPipes() { + return new QueryCodecPipes(); + } + + @Bean + public QueryCodecMulti scbQueryCodecMulti() { + return new QueryCodecMulti(); + } + + @Bean + public QueryCodecsUtils scbQueryCodecsUtils(QueryCodecs queryCodecs) { + return new QueryCodecsUtils(queryCodecs); + } + + @Bean + public RestServerCodecFilter scbRestServerCodecFilter() { + return new RestServerCodecFilter(); + } + + @Bean + public WebSocketServerCodecFilter scbWebSocketServerCodecFilter() { + return new WebSocketServerCodecFilter(); + } + + @Bean + public QueryCodecs scbQueryCodecs(List orderedCodecs) { + return new QueryCodecs(orderedCodecs); + } + + @Bean + public RestEngineSchemaListener scbRestEngineSchemaListener() { + return new RestEngineSchemaListener(); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/EdgeServerWebSocketInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/EdgeServerWebSocketInvocationCreator.java new file mode 100644 index 00000000000..ff0b0f38174 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/EdgeServerWebSocketInvocationCreator.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.common.rest.locator.OperationLocator; +import org.apache.servicecomb.common.rest.locator.ServicePathManager; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; + +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.ServerWebSocket; + +public class EdgeServerWebSocketInvocationCreator extends ProviderServerWebSocketInvocationCreator { + private final String microserviceName; + + protected MicroserviceReferenceConfig microserviceReferenceConfig; + + protected final String path; + + public EdgeServerWebSocketInvocationCreator(String microserviceName, String path, + Endpoint endpoint, ServerWebSocket webSocket) { + super(null, endpoint, webSocket); + this.microserviceName = microserviceName; + this.path = path; + } + + @Override + public CompletableFuture createAsync() { + return createMicroserviceReferenceConfig() + .thenCompose(v -> super.createAsync()); + } + + protected CompletableFuture createMicroserviceReferenceConfig() { + return SCBEngine.getInstance() + .getOrCreateReferenceConfigAsync(microserviceName) + .thenAccept(mrc -> { + this.microserviceReferenceConfig = mrc; + this.microserviceMeta = mrc.getMicroserviceMeta(); + }); + } + + @Override + protected OperationLocator locateOperation(ServicePathManager servicePathManager) { + return servicePathManager.consumerLocateOperation(path, HttpMethod.POST.name()); + } + + @Override + protected Invocation createInstance() { + ReferenceConfig referenceConfig = microserviceReferenceConfig + .createReferenceConfig(restOperationMeta.getOperationMeta()); + + Invocation invocation = InvocationFactory.forConsumer(referenceConfig, + restOperationMeta.getOperationMeta(), + restOperationMeta.getOperationMeta().buildBaseConsumerRuntimeType(), + null); + invocation.setSync(false); + invocation.setEdge(); + invocation.setEndpoint(endpoint); // ensure transport name is correct + + return invocation; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java new file mode 100644 index 00000000000..d9b0df27c92 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.context.TransportContext; + +public class HttpTransportContext implements TransportContext { + private final HttpServletRequestEx requestEx; + + private final HttpServletResponseEx responseEx; + + public HttpTransportContext(HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + this.requestEx = requestEx; + this.responseEx = responseEx; + } + + public HttpServletRequestEx getRequestEx() { + return requestEx; + } + + public HttpServletResponseEx getResponseEx() { + return responseEx; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ProviderServerWebSocketInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ProviderServerWebSocketInvocationCreator.java new file mode 100644 index 00000000000..bcd4fc827b3 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ProviderServerWebSocketInvocationCreator.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; + +import io.vertx.core.http.ServerWebSocket; + +public class ProviderServerWebSocketInvocationCreator extends ServerWebSocketInvocationCreator { + public ProviderServerWebSocketInvocationCreator(MicroserviceMeta microserviceMeta, + Endpoint endpoint, ServerWebSocket webSocket) { + super(microserviceMeta, endpoint, webSocket); + } + + @Override + protected void initTransportContext(Invocation invocation) { + WebSocketTransportContext transportContext = new WebSocketTransportContext(websocket); + invocation.setTransportContext(transportContext); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestConst.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestConst.java index afdc96bff41..bc598f973f6 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestConst.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestConst.java @@ -17,6 +17,8 @@ package org.apache.servicecomb.common.rest; +import org.apache.commons.lang3.SystemUtils; + public final class RestConst { private RestConst() { } @@ -29,25 +31,26 @@ private RestConst() { public static final String SCHEME = "cse"; + public static final String SCHEME_NEW = "servicecomb"; + public static final String URI_PREFIX = SCHEME + "://"; + public static final String URI_PREFIX_NEW = SCHEME_NEW + "://"; + // in HttpServletRequest attribute public static final String PATH_PARAMETERS = "servicecomb-paths"; // in HttpServletRequest attribute public static final String BODY_PARAMETER = "servicecomb-body"; - // in HttpServletRequest attribute - public static final String FORM_PARAMETERS = "servicecomb-forms"; - //in invocation response - public static final String INVOCATION_HANDLER_RESPONSE = "servicecomb-invocation-hanlder-response"; + public static final String INVOCATION_HANDLER_RESPONSE = "servicecomb-invocation-handler-response"; //in invocation response - public static final String INVOCATION_HANDLER_PROCESSOR = "servicecomb-invocation-hanlder-processor"; + public static final String INVOCATION_HANDLER_PROCESSOR = "servicecomb-invocation-handler-processor"; //in invocation response - public static final String INVOCATION_HANDLER_REQUESTCLIENT = "servicecomb-invocation-hanlder-requestclient"; + public static final String INVOCATION_HANDLER_REQUESTCLIENT = "servicecomb-invocation-handler-requestclient"; public static final String REST_PRODUCER_INVOCATION = "servicecomb-rest-producer-invocation"; @@ -61,6 +64,8 @@ private RestConst() { public static final String UPLOAD_DIR = "servicecomb.uploads.directory"; + public static final String UPLOAD_DEFAULT_DIR = SystemUtils.JAVA_IO_TMPDIR; + // limit of one upload file, only available for servlet rest transport public static final String UPLOAD_MAX_FILE_SIZE = "servicecomb.uploads.maxFileSize"; @@ -72,4 +77,12 @@ private RestConst() { public static final String UPLOAD_FILE_SIZE_THRESHOLD = "servicecomb.uploads.fileSizeThreshold"; public static final String PROVIDER_SCAN_REST_CONTROLLER = "servicecomb.provider.rest.scanRestController"; + + public static final String PRINT_CODEC_ERROR_MESSGAGE = "servicecomb.codec.printErrorMessage"; + + public static final String HEADER_CONTEXT_MAPPER = "servicecomb.context.headerContextMapper"; + + public static final String QUERY_CONTEXT_MAPPER = "servicecomb.context.queryContextMapper"; + + public static final String DECODE_INVOCATION_CONTEXT = "servicecomb.context.decodeInvocationContext"; } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestEngineSchemaListener.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestEngineSchemaListener.java index 14e4c39e39a..178d52f614d 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestEngineSchemaListener.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestEngineSchemaListener.java @@ -17,65 +17,37 @@ package org.apache.servicecomb.common.rest; -import java.util.HashMap; -import java.util.Map; - import org.apache.servicecomb.common.rest.locator.ServicePathManager; import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.SCBEngine.CreateMicroserviceMetaEvent; import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.loader.SchemaListener; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.foundation.common.event.EnableExceptionPropagation; -@Component -public class RestEngineSchemaListener implements SchemaListener, BootListener { +import com.google.common.eventbus.Subscribe; +public class RestEngineSchemaListener implements BootListener { @Override - public void onBootEvent(BootEvent event) { - if (!event.getEventType().equals(EventType.BEFORE_REGISTRY)) { - return; - } - - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); - if (servicePathManager != null) { - servicePathManager.buildProducerPaths(); - } + public int getOrder() { + return -10000; } @Override - public void onSchemaLoaded(SchemaMeta... schemaMetas) { - // 此时相应的ServicePathManager可能正在被使用,为避免太高的复杂度,使用copy on write逻辑 - Map mgrMap = new HashMap<>(); - for (SchemaMeta schemaMeta : schemaMetas) { - MicroserviceMeta microserviceMeta = schemaMeta.getMicroserviceMeta(); - ServicePathManager mgr = findPathManager(mgrMap, microserviceMeta); - mgr.addSchema(schemaMeta); - } - - for (ServicePathManager mgr : mgrMap.values()) { - // 对具有动态path operation进行排序 - mgr.sortPath(); - - mgr.saveToMicroserviceMeta(); - } + public void onBeforeRegistry(BootEvent event) { + createServicePathManager(event.getScbEngine().getProducerMicroserviceMeta()) + .buildProducerPaths(); + event.getScbEngine().getEventBus().register(this); } - protected ServicePathManager findPathManager(Map mgrMap, - MicroserviceMeta microserviceMeta) { - ServicePathManager mgr = mgrMap.get(microserviceMeta.getName()); - if (mgr != null) { - return mgr; - } + @EnableExceptionPropagation + @Subscribe + public void onCreateMicroserviceMetaEvent(CreateMicroserviceMetaEvent event) { + MicroserviceMeta microserviceMeta = event.getMicroserviceMeta(); + createServicePathManager(microserviceMeta); + } - mgr = ServicePathManager.getServicePathManager(microserviceMeta); - if (mgr == null) { - mgr = new ServicePathManager(microserviceMeta); - } else { - mgr = mgr.cloneServicePathManager(); - } - mgrMap.put(microserviceMeta.getName(), mgr); - return mgr; + private ServicePathManager createServicePathManager(MicroserviceMeta microserviceMeta) { + // already connect ServicePathManager and MicroserviceMeta instance + // no need to save ServicePathManager instance again + return new ServicePathManager(microserviceMeta); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocation.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocation.java deleted file mode 100644 index 965cebf13b2..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocation.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import java.util.List; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class RestProducerInvocation extends AbstractRestInvocation { - - protected Transport transport; - - public void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, - List httpServerFilters) { - this.transport = transport; - this.requestEx = requestEx; - this.responseEx = responseEx; - this.httpServerFilters = httpServerFilters; - requestEx.setAttribute(RestConst.REST_REQUEST, requestEx); - - try { - findRestOperation(); - } catch (InvocationException e) { - sendFailResponse(e); - return; - } - - scheduleInvocation(); - } - - protected void findRestOperation() { - MicroserviceMeta selfMicroserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - findRestOperation(selfMicroserviceMeta); - } - - @Override - protected OperationLocator locateOperation(ServicePathManager servicePathManager) { - return servicePathManager.producerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod()); - } - - @Override - protected void createInvocation() { - this.invocation = InvocationFactory.forProvider(transport.getEndpoint(), - restOperationMeta.getOperationMeta(), - null); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java new file mode 100644 index 00000000000..5a6c09d3912 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; +import static org.apache.servicecomb.core.exception.ExceptionCodes.NOT_DEFINED_ANY_SCHEMA; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.common.rest.locator.OperationLocator; +import org.apache.servicecomb.common.rest.locator.ServicePathManager; +import org.apache.servicecomb.config.YAMLUtil; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.json.Json; + +public abstract class RestProducerInvocationCreator implements InvocationCreator { + private static final Logger LOGGER = LoggerFactory.getLogger(RestVertxProducerInvocationCreator.class); + + protected MicroserviceMeta microserviceMeta; + + protected final Endpoint endpoint; + + protected final HttpServletRequestEx requestEx; + + protected final HttpServletResponseEx responseEx; + + protected RestOperationMeta restOperationMeta; + + protected ProduceProcessor produceProcessor; + + public RestProducerInvocationCreator(MicroserviceMeta microserviceMeta, Endpoint endpoint, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + this.microserviceMeta = microserviceMeta; + this.endpoint = endpoint; + this.requestEx = requestEx; + this.responseEx = responseEx; + } + + @Override + public CompletableFuture createAsync() { + initRestOperation(); + + Invocation invocation = createInstance(); + initInvocationContext(invocation); + addParameterContext(invocation); + initTransportContext(invocation); + + invocation.addLocalContext(RestConst.REST_REQUEST, requestEx); + + return CompletableFuture.completedFuture(invocation); + } + + protected Invocation createInstance() { + return InvocationFactory.forProvider(endpoint, restOperationMeta.getOperationMeta(), null); + } + + protected void initInvocationContext(Invocation invocation) { + if (!LegacyPropertyFactory.getBooleanProperty(RestConst.DECODE_INVOCATION_CONTEXT, true)) { + return; + } + + String strCseContext = requestEx.getHeader(CoreConst.CSE_CONTEXT); + if (StringUtils.isEmpty(strCseContext)) { + return; + } + + @SuppressWarnings("unchecked") + Map invocationContext = Json.decodeValue(strCseContext, Map.class); + invocation.mergeContext(invocationContext); + } + + protected void addParameterContext(Invocation invocation) { + String headerContextMapper = LegacyPropertyFactory + .getStringProperty(RestConst.HEADER_CONTEXT_MAPPER); + String queryContextMapper = LegacyPropertyFactory + .getStringProperty(RestConst.QUERY_CONTEXT_MAPPER); + + Map headerContextMappers; + if (headerContextMapper != null) { + headerContextMappers = YAMLUtil.yaml2Properties(headerContextMapper); + } else { + headerContextMappers = new HashMap<>(); + } + + Map queryContextMappers; + if (queryContextMapper != null) { + queryContextMappers = YAMLUtil.yaml2Properties(queryContextMapper); + } else { + queryContextMappers = new HashMap<>(); + } + + headerContextMappers.forEach((k, v) -> { + if (v instanceof String && requestEx.getHeader(k) != null) { + invocation.addContext((String) v, requestEx.getHeader(k)); + } + }); + queryContextMappers.forEach((k, v) -> { + if (v instanceof String && requestEx.getParameter(k) != null) { + invocation.addContext((String) v, requestEx.getParameter(k)); + } + }); + } + + protected abstract void initTransportContext(Invocation invocation); + + protected void initRestOperation() { + OperationLocator locator = locateOperation(microserviceMeta); + requestEx.setAttribute(RestConst.PATH_PARAMETERS, locator.getPathVarMap()); + restOperationMeta = locator.getOperation(); + } + + protected OperationLocator locateOperation(MicroserviceMeta microserviceMeta) { + ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); + if (servicePathManager == null) { + LOGGER.error("No schema defined for {}:{}.", this.microserviceMeta.getAppId(), + this.microserviceMeta.getMicroserviceName()); + throw Exceptions.create(NOT_FOUND, NOT_DEFINED_ANY_SCHEMA, NOT_FOUND.getReasonPhrase()); + } + + return locateOperation(servicePathManager); + } + + protected OperationLocator locateOperation(ServicePathManager servicePathManager) { + return servicePathManager.producerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod()); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationFlow.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationFlow.java new file mode 100644 index 00000000000..727346c82d5 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationFlow.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; +import org.apache.servicecomb.common.rest.filter.inner.RestServerCodecFilter; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.ProducerInvocationFlow; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RestProducerInvocationFlow extends ProducerInvocationFlow { + private static final Logger LOGGER = LoggerFactory.getLogger(RestProducerInvocationFlow.class); + + private static final ProduceProcessor DEFAULT_PRODUCE_PROCESSOR = ProduceProcessorManager.INSTANCE + .findDefaultProcessor(); + + public RestProducerInvocationFlow(InvocationCreator invocationCreator, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + super(invocationCreator, requestEx, responseEx); + } + + @Override + protected Invocation sendCreateInvocationException(Throwable throwable) { + try { + Response response = Exceptions.toProducerResponse(null, throwable); + RestServerCodecFilter.encodeResponse(null, response, DEFAULT_PRODUCE_PROCESSOR, responseEx); + } catch (Throwable e) { + LOGGER.error("Failed to send response when prepare invocation failed, request uri:{}", + requestEx.getRequestURI(), e); + } + + endResponse(null); + return null; + } + + @Override + protected void endResponse(Invocation invocation, Response response) { + invocation.getInvocationStageTrace().startProviderSendResponse(); + + endResponse(invocation); + } + + private void endResponse(Invocation invocation) { + try { + responseEx.endResponse(); + } catch (Throwable flushException) { + LOGGER.error("Failed to flush rest response, operation:{}, request uri:{}", + invocation == null ? "NA" : + invocation.getMicroserviceQualifiedName(), requestEx.getRequestURI(), flushException); + } + + try { + requestEx.getAsyncContext().complete(); + } catch (Throwable completeException) { + LOGGER.error("Failed to complete async rest response, operation:{}, request uri:{}", + invocation == null ? "NA" : + invocation.getMicroserviceQualifiedName(), requestEx.getRequestURI(), completeException); + } + + if (invocation != null) { + invocation.getInvocationStageTrace().finishProviderSendResponse(); + } + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java new file mode 100644 index 00000000000..83f14c64eca --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; + +import io.vertx.ext.web.RoutingContext; + +public class RestVertxProducerInvocationCreator extends RestProducerInvocationCreator { + private final RoutingContext routingContext; + + public RestVertxProducerInvocationCreator(RoutingContext routingContext, + MicroserviceMeta microserviceMeta, Endpoint endpoint, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + super(microserviceMeta, endpoint, requestEx, responseEx); + this.routingContext = routingContext; + } + + @Override + protected void initTransportContext(Invocation invocation) { + VertxHttpTransportContext transportContext = new VertxHttpTransportContext(routingContext, requestEx, responseEx); + invocation.setTransportContext(transportContext); + routingContext.put(RestConst.REST_INVOCATION_CONTEXT, invocation); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ServerWebSocketInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ServerWebSocketInvocationCreator.java new file mode 100644 index 00000000000..46d8b705138 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/ServerWebSocketInvocationCreator.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest; + +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; +import static org.apache.servicecomb.core.exception.ExceptionCodes.NOT_DEFINED_ANY_SCHEMA; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.common.rest.locator.OperationLocator; +import org.apache.servicecomb.common.rest.locator.ServicePathManager; +import org.apache.servicecomb.config.YAMLUtil; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.ServerWebSocket; +import io.vertx.core.json.Json; + +public abstract class ServerWebSocketInvocationCreator implements InvocationCreator { + private static final Logger LOGGER = LoggerFactory.getLogger(RestVertxProducerInvocationCreator.class); + + protected MicroserviceMeta microserviceMeta; + + protected final Endpoint endpoint; + + protected final ServerWebSocket websocket; + + protected RestOperationMeta restOperationMeta; + + public ServerWebSocketInvocationCreator(MicroserviceMeta microserviceMeta, Endpoint endpoint, + ServerWebSocket websocket) { + this.microserviceMeta = microserviceMeta; + this.endpoint = endpoint; + this.websocket = websocket; + } + + @Override + public CompletableFuture createAsync() { + initRestOperation(); + + Invocation invocation = createInstance(); + initInvocationContext(invocation); + addParameterContext(invocation); + initTransportContext(invocation); + + return CompletableFuture.completedFuture(invocation); + } + + protected Invocation createInstance() { + return InvocationFactory.forProvider(endpoint, restOperationMeta.getOperationMeta(), null); + } + + protected void initInvocationContext(Invocation invocation) { + if (!LegacyPropertyFactory.getBooleanProperty(RestConst.DECODE_INVOCATION_CONTEXT, true)) { + return; + } + + String strCseContext = websocket.headers().get(CoreConst.CSE_CONTEXT); + if (StringUtils.isEmpty(strCseContext)) { + return; + } + + @SuppressWarnings("unchecked") + Map invocationContext = Json.decodeValue(strCseContext, Map.class); + invocation.mergeContext(invocationContext); + } + + // No queries for websocket + protected void addParameterContext(Invocation invocation) { + String headerContextMapper = LegacyPropertyFactory + .getStringProperty(RestConst.HEADER_CONTEXT_MAPPER); + + Map headerContextMappers; + if (headerContextMapper != null) { + headerContextMappers = YAMLUtil.yaml2Properties(headerContextMapper); + } else { + headerContextMappers = new HashMap<>(); + } + + headerContextMappers.forEach((k, v) -> { + if (v instanceof String && websocket.headers().get(k) != null) { + invocation.addContext((String) v, websocket.headers().get(k)); + } + }); + } + + protected abstract void initTransportContext(Invocation invocation); + + protected void initRestOperation() { + OperationLocator locator = locateOperation(microserviceMeta); + restOperationMeta = locator.getOperation(); + } + + protected OperationLocator locateOperation(MicroserviceMeta microserviceMeta) { + ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); + if (servicePathManager == null) { + LOGGER.error("No schema defined for {}:{}.", this.microserviceMeta.getAppId(), + this.microserviceMeta.getMicroserviceName()); + throw Exceptions.create(NOT_FOUND, NOT_DEFINED_ANY_SCHEMA, NOT_FOUND.getReasonPhrase()); + } + + return locateOperation(servicePathManager); + } + + protected OperationLocator locateOperation(ServicePathManager servicePathManager) { + return servicePathManager.producerLocateOperation(websocket.path(), HttpMethod.POST.name()); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/UploadConfig.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/UploadConfig.java index b487a966fba..ff564234124 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/UploadConfig.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/UploadConfig.java @@ -16,87 +16,51 @@ */ package org.apache.servicecomb.common.rest; -import javax.servlet.MultipartConfigElement; +import org.springframework.core.env.Environment; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; +import jakarta.servlet.MultipartConfigElement; public class UploadConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(UploadConfig.class); + private final Environment environment; + + public UploadConfig(Environment environment) { + this.environment = environment; + } /** * null means not support upload */ - private String location; + public String getLocation() { + return environment.getProperty(RestConst.UPLOAD_DIR, RestConst.UPLOAD_DEFAULT_DIR); + } /** * limit of one upload file, only available for servlet rest transport */ - private long maxFileSize; + public long getMaxFileSize() { + return environment.getProperty(RestConst.UPLOAD_MAX_FILE_SIZE, long.class, -1L); + } /** * limit of upload request body */ - private long maxSize; - - /** - * the size threshold after which files will be written to disk, only available for servlet rest transport - */ - private int fileSizeThreshold; - - public UploadConfig() { - location = DynamicPropertyFactory.getInstance().getStringProperty(RestConst.UPLOAD_DIR, null).get(); - maxFileSize = DynamicPropertyFactory.getInstance().getLongProperty(RestConst.UPLOAD_MAX_FILE_SIZE, -1L).get(); - maxSize = DynamicPropertyFactory.getInstance().getLongProperty(RestConst.UPLOAD_MAX_SIZE, -1L).get(); - fileSizeThreshold = DynamicPropertyFactory.getInstance().getIntProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, 0) - .get(); - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public long getMaxFileSize() { - return maxFileSize; - } - - public void setMaxFileSize(long maxFileSize) { - this.maxFileSize = maxFileSize; - } - public long getMaxSize() { - return maxSize; + return environment.getProperty(RestConst.UPLOAD_MAX_SIZE, long.class, -1L); } - public void setMaxSize(long maxSize) { - this.maxSize = maxSize; - } + /** + * the size threshold after which files will be written to disk, only available for servlet rest transport + */ public int getFileSizeThreshold() { - return fileSizeThreshold; - } - - public void setFileSizeThreshold(int fileSizeThreshold) { - this.fileSizeThreshold = fileSizeThreshold; + return environment.getProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, int.class, 0); } public MultipartConfigElement toMultipartConfigElement() { - String location = DynamicPropertyFactory.getInstance().getStringProperty(RestConst.UPLOAD_DIR, null).get(); - if (location == null) { - LOGGER.info("{} is null, not support upload.", RestConst.UPLOAD_DIR); - return null; - } - return new MultipartConfigElement( - location, - DynamicPropertyFactory.getInstance().getLongProperty(RestConst.UPLOAD_MAX_FILE_SIZE, -1L).get(), - DynamicPropertyFactory.getInstance().getLongProperty(RestConst.UPLOAD_MAX_SIZE, -1L).get(), - DynamicPropertyFactory.getInstance().getIntProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, 0).get()); + getLocation(), + getMaxFileSize(), + getMaxSize(), + getFileSizeThreshold()); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java new file mode 100644 index 00000000000..55576022edd --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext; + +import io.vertx.core.Context; +import io.vertx.core.Vertx; +import io.vertx.ext.web.RoutingContext; + +public class VertxHttpTransportContext extends HttpTransportContext implements VertxTransportContext { + private final RoutingContext routingContext; + + private final Context vertxContext; + + public VertxHttpTransportContext(RoutingContext routingContext, HttpServletRequestEx requestEx, + HttpServletResponseEx responseEx) { + super(requestEx, responseEx); + + this.routingContext = routingContext; + this.vertxContext = Vertx.currentContext(); + } + + public RoutingContext getRoutingContext() { + return routingContext; + } + + @Override + public Context getVertxContext() { + return vertxContext; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxRestInvocation.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxRestInvocation.java deleted file mode 100644 index 2cd5f31bbe2..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxRestInvocation.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; - -public class VertxRestInvocation extends RestProducerInvocation { - @Override - protected void createInvocation() { - super.createInvocation(); - - ((VertxServerRequestToHttpServletRequest) this.requestEx).getContext() - .put(RestConst.REST_INVOCATION_CONTEXT, this.invocation); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/WebSocketTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/WebSocketTransportContext.java new file mode 100644 index 00000000000..738b09788ff --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/WebSocketTransportContext.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest; + +import org.apache.servicecomb.swagger.invocation.context.TransportContext; + +import io.vertx.core.http.ServerWebSocket; + +public class WebSocketTransportContext implements TransportContext { + private final ServerWebSocket serverWebSocket; + + public WebSocketTransportContext(ServerWebSocket serverWebSocket) { + this.serverWebSocket = serverWebSocket; + } + + public ServerWebSocket getServerWebSocket() { + return this.serverWebSocket; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestClientRequest.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestClientRequest.java index a300273e856..74967694a90 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestClientRequest.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestClientRequest.java @@ -17,10 +17,10 @@ package org.apache.servicecomb.common.rest.codec; -import javax.servlet.http.Part; - +import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientRequest; /** * vertx的HttpClientRequest没有getHeader的能力 @@ -29,7 +29,7 @@ public interface RestClientRequest { void write(Buffer bodyBuffer); - void end(); + Future end(); void addCookie(String name, String value); @@ -41,5 +41,7 @@ public interface RestClientRequest { Buffer getBodyBuffer() throws Exception; - void attach(String name, Part part); + void attach(String name, Object partOrList); + + HttpClientRequest getHttpClientRequest(); } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java index ac65d61a029..260ac0d4cb1 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java @@ -17,59 +17,54 @@ package org.apache.servicecomb.common.rest.codec; +import java.util.HashMap; import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; +import java.util.Map; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.common.rest.definition.RestParam; -import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public final class RestCodec { - private static final Logger LOG = LoggerFactory.getLogger(RestCodec.class); +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; +public final class RestCodec { private RestCodec() { } - public static void argsToRest(Object[] args, RestOperationMeta restOperation, + public static void argsToRest(Map args, RestOperationMeta restOperation, RestClientRequest clientRequest) throws Exception { int paramSize = restOperation.getParamList().size(); if (paramSize == 0) { return; } - if (paramSize != args.length) { - throw new Exception("wrong number of arguments"); - } - for (int idx = 0; idx < paramSize; idx++) { RestParam param = restOperation.getParamList().get(idx); - param.getParamProcessor().setValue(clientRequest, args[idx]); + param.getParamProcessor().setValue(clientRequest, args.get(param.getParamName())); } } - public static Object[] restToArgs(HttpServletRequest request, + public static Map restToArgs(HttpServletRequest request, RestOperationMeta restOperation) throws InvocationException { List paramList = restOperation.getParamList(); - try { - Object[] paramValues = new Object[paramList.size()]; - for (int idx = 0; idx < paramList.size(); idx++) { - RestParam param = paramList.get(idx); - paramValues[idx] = param.getParamProcessor().getValue(request); + Map paramValues = new HashMap<>(); + for (RestParam param : paramList) { + try { + paramValues.put(param.getParamName(), param.getParamProcessor().getValue(request)); + } catch (Exception e) { + String message = String + .format("Parameter is not valid for operation [%s]. Parameter is [%s]. Processor is [%s]. Message is [%s].", + restOperation.getOperationMeta().getMicroserviceQualifiedName(), + param.getParamName(), + param.getParamProcessor().getProcessorType(), + e.getMessage()); + throw new InvocationException(Status.BAD_REQUEST, new CommonExceptionData(message), e); } - - return paramValues; - } catch (Exception e) { - LOG.error("Parameter is not valid for operation {}. ", - restOperation.getOperationMeta().getMicroserviceQualifiedName(), - ExceptionUtils.getExceptionMessageWithoutTrace(e)); - // give standard http error code for invalid parameter - throw new InvocationException(Status.BAD_REQUEST, "Parameter is not valid."); } + + return paramValues; } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java deleted file mode 100644 index ae1a45f7fcf..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapper.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.codec; - -import java.io.IOException; -import java.text.FieldPosition; -import java.util.Date; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser.Feature; -import com.fasterxml.jackson.core.base.DoSFix; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import io.vertx.core.json.JsonObject; - -public class RestObjectMapper extends AbstractRestObjectMapper { - static { - DoSFix.init(); - } - - private static class JsonObjectSerializer extends JsonSerializer { - @Override - public void serialize(JsonObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException { - jgen.writeObject(value.getMap()); - } - } - - private static final long serialVersionUID = -8158869347066287575L; - - private static final JavaType STRING_JAVA_TYPE = TypeFactory.defaultInstance().constructType(String.class); - - @SuppressWarnings("deprecation") - public RestObjectMapper() { - super(DoSFix.createJsonFactory()); - - // swagger中要求date使用ISO8601格式传递,这里与之做了功能绑定,这在cse中是没有问题的 - setDateFormat(new com.fasterxml.jackson.databind.util.ISO8601DateFormat() { - private static final long serialVersionUID = 7798938088541203312L; - - // to support millis - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - String value = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date, true); - toAppendTo.append(value); - return toAppendTo; - } - }); - - getFactory().disable(Feature.AUTO_CLOSE_SOURCE); - // Enable features that can tolerance errors and not enable those make more constraints for compatible reasons. - // Developers can use validation api to do more checks. - disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); - enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); - - SimpleModule module = new SimpleModule(); - // custom types - module.addSerializer(JsonObject.class, new JsonObjectSerializer()); - registerModule(module); - } - - @Override - public String convertToString(Object value) throws Exception { - return convertValue(value, STRING_JAVA_TYPE); - } - - @Override - public T convertValue(Object fromValue, JavaType toValueType) throws IllegalArgumentException { - return super.convertValue(fromValue, toValueType); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java index 8bbad592473..d54800a07cb 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java @@ -17,14 +17,37 @@ package org.apache.servicecomb.common.rest.codec; +import java.util.List; + +import org.apache.servicecomb.foundation.common.utils.AbstractRestObjectMapper; +import org.apache.servicecomb.foundation.common.utils.RestObjectMapper; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; + +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * Manage RestObjectMapper instances. Give users an option to specify custom mappers. */ public class RestObjectMapperFactory { private static AbstractRestObjectMapper defaultMapper = new RestObjectMapper(); + private static final AbstractRestObjectMapper viewMapper = new RestObjectMapper(); + private static AbstractRestObjectMapper consumerWriterMapper = defaultMapper; + static { + registerModules(defaultMapper); + registerModules(viewMapper); + } + + private static void registerModules(ObjectMapper mapper) { + // not use mapper.findAndRegisterModules() + // because we need to sort modules, so that customers can override our default module + List modules = SPIServiceUtils.getOrLoadSortedService(Module.class); + mapper.registerModules(modules.toArray(new Module[0])); + } + public static AbstractRestObjectMapper getConsumerWriterMapper() { return consumerWriterMapper; } @@ -33,11 +56,17 @@ public static AbstractRestObjectMapper getRestObjectMapper() { return defaultMapper; } + public static AbstractRestObjectMapper getRestViewMapper() { + return viewMapper; + } + public static void setConsumerWriterMapper(AbstractRestObjectMapper customMapper) { + registerModules(customMapper); consumerWriterMapper = customMapper; } public static void setDefaultRestObjectMapper(AbstractRestObjectMapper customMapper) { + registerModules(customMapper); defaultMapper = customMapper; } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java new file mode 100644 index 00000000000..6b6e06f41e1 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; + +import jakarta.servlet.http.HttpServletRequest; + +public interface HeaderCodec { + static String encodeValue(Object value) throws UnsupportedEncodingException { + return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8.name()); + } + + // can not be replaced by value.toString() because of date serialize + static String convertToString(Object value) throws Exception { + return RestObjectMapperFactory.getRestObjectMapper().convertToString(value); + } + + String getCodecName(); + + void encode(RestClientRequest clientRequest, String name, Object value) throws Exception; + + Object decode(HeaderProcessor processor, HttpServletRequest request); +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java new file mode 100644 index 00000000000..26d86bbf2b7 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +public class HeaderCodecCsv extends HeaderCodecWithDelimiter { + public static final String CODEC_NAME = "form:0"; + + public static final String DELIMITER = ","; + + public HeaderCodecCsv() { + super(CODEC_NAME, DELIMITER, DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java new file mode 100644 index 00000000000..7a61e0fa125 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; + +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; + +public class HeaderCodecMulti implements HeaderCodec { + public static final String NAME = "form:1"; + + @Override + public String getCodecName() { + return NAME; + } + + @Override + public void encode(RestClientRequest clientRequest, String name, Object value) throws Exception { + if (null == value) { + // if value is empty, header should not be set to clientRequest to avoid NullPointerException in Netty. + return; + } + if (!(value instanceof Collection)) { + throw new InvocationException(Status.BAD_REQUEST, + new CommonExceptionData("Array type of header should be Collection")); + } + for (Object item : ((Collection) value)) { + clientRequest.putHeader(name, + RestObjectMapperFactory.getConsumerWriterMapper().convertToString(item)); + } + } + + @Override + public Object decode(HeaderProcessor processor, HttpServletRequest request) { + Enumeration headerValues = request.getHeaders(processor.getParameterPath()); + if (headerValues == null) { + //Even if the paramPath does not exist, headerValues won't be null at now + return null; + } + return processor.convertValue(Collections.list(headerValues), processor.getTargetType()); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java new file mode 100644 index 00000000000..f458946ba61 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +public class HeaderCodecPipes extends HeaderCodecWithDelimiter { + public static final String CODEC_NAME = "pipeDelimited:0"; + + public static final String JOIN_DELIMITER = "|"; + + public static final String SPLIT_DELIMITER = "\\|"; + + public HeaderCodecPipes() { + super(CODEC_NAME, JOIN_DELIMITER, SPLIT_DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java new file mode 100644 index 00000000000..0dd46a86b90 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; + +import jakarta.servlet.http.HttpServletRequest; + +public class HeaderCodecSimple implements HeaderCodec { + public static final String NAME = "simple"; + + @Override + public String getCodecName() { + return NAME; + } + + @Override + public void encode(RestClientRequest clientRequest, String name, Object value) throws Exception { + if (null == value) { + // if value is empty, header should not be set to clientRequest to avoid NullPointerException in Netty. + return; + } + clientRequest.putHeader(name, + RestObjectMapperFactory.getConsumerWriterMapper().convertToString(value)); + } + + @Override + public Object decode(HeaderProcessor processor, HttpServletRequest request) { + Object value = request.getHeader(processor.getParameterPath()); + if (value == null) { + value = processor.checkRequiredAndDefaultValue(); + } + return processor.convertValue(value, processor.getTargetType()); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java new file mode 100644 index 00000000000..a9266f043ef --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +public class HeaderCodecSsv extends HeaderCodecWithDelimiter { + public static final String CODEC_NAME = "spaceDelimited:0"; + + public static final String DELIMITER = " "; + + public HeaderCodecSsv() { + super(CODEC_NAME, DELIMITER, DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java new file mode 100644 index 00000000000..c85742b5549 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +import java.util.Collection; +import java.util.List; +import java.util.StringJoiner; + +import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; + +public abstract class HeaderCodecWithDelimiter implements HeaderCodec { + private final String name; + + private final String joinDelimiter; + + private final String splitDelimiter; + + public HeaderCodecWithDelimiter(String name, String joinDelimiter, String splitDelimiter) { + this.name = name; + this.joinDelimiter = joinDelimiter; + this.splitDelimiter = splitDelimiter; + } + + + @Override + public String getCodecName() { + return name; + } + + @Override + public void encode(RestClientRequest clientRequest, String name, Object value) throws Exception { + if (null == value) { + // if value is empty, header should not be set to clientRequest to avoid NullPointerException in Netty. + return; + } + if (!(value instanceof Collection)) { + throw new InvocationException(Status.BAD_REQUEST, + new CommonExceptionData("Array type of header should be Collection")); + } + clientRequest.putHeader(name, join((Collection) value)); + } + + protected String join(Collection values) throws Exception { + StringJoiner joiner = new StringJoiner(joinDelimiter); + for (Object value : values) { + String strValue = RestObjectMapperFactory.getConsumerWriterMapper().convertToString(value); + joiner.add(strValue); + } + + return joiner.toString(); + } + + @Override + public Object decode(HeaderProcessor processor, HttpServletRequest request) { + String headerValues = request.getHeader(processor.getParameterPath()); + if (headerValues == null) { + headerValues = (String) processor.checkRequiredAndDefaultValue(); + } + + return processor.convertValue(List.of(headerValues.split(splitDelimiter)), processor.getTargetType()); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java new file mode 100644 index 00000000000..fb9509a1f90 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.header; + +import java.util.HashMap; +import java.util.Map; + +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; + +public class HeaderCodecsUtils { + private static final Map CODECS; + + static { + CODECS = new HashMap<>(); + CODECS.put(HeaderCodecSimple.NAME, new HeaderCodecSimple()); + CODECS.put(HeaderCodecMulti.NAME, new HeaderCodecMulti()); + CODECS.put(HeaderCodecCsv.CODEC_NAME, new HeaderCodecCsv()); + CODECS.put(HeaderCodecPipes.CODEC_NAME, new HeaderCodecPipes()); + CODECS.put(HeaderCodecSsv.CODEC_NAME, new HeaderCodecSsv()); + } + + private HeaderCodecsUtils() { + } + + public static HeaderCodec find(Parameter.StyleEnum styleEnum, Boolean explode) { + return CODECS.get(formatName(styleEnum, explode)); + } + + private static String formatName(StyleEnum styleEnum, Boolean explode) { + if (styleEnum == null) { + return HeaderCodecSimple.NAME; + } + return styleEnum + ":" + + (explode != null && explode ? "1" : "0"); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java index 147aa0ac39f..2513388db4a 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java @@ -18,10 +18,12 @@ package org.apache.servicecomb.common.rest.codec.param; import com.fasterxml.jackson.databind.JavaType; +import com.google.common.base.Defaults; public abstract class AbstractParamProcessor implements ParamValueProcessor { protected String paramPath; + // for consumer, targetType should be null protected JavaType targetType; protected Object defaultValue; @@ -37,12 +39,21 @@ public AbstractParamProcessor(String paramPath, JavaType targetType, Object defa this.targetType = targetType; this.defaultValue = defaultValue; this.required = required; + if (defaultValue == null && + targetType != null && targetType.getRawClass().isPrimitive()) { + this.defaultValue = Defaults.defaultValue(targetType.getRawClass()); + } } + @Override public String getParameterPath() { return paramPath; } + public JavaType getTargetType() { + return targetType; + } + public boolean isRequired() { return required; } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java index 29697445aa5..e789038c467 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java @@ -20,65 +20,159 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; -import java.util.Locale; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.entity.ContentType; +import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.type.SimpleType; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.netflix.config.DynamicPropertyFactory; -import io.swagger.models.parameters.Parameter; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.parameters.RequestBody; import io.vertx.core.buffer.Buffer; import io.vertx.core.buffer.impl.BufferImpl; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; + +public class BodyProcessorCreator implements ParamValueProcessorCreator { -public class BodyProcessorCreator implements ParamValueProcessorCreator { private static final Logger LOGGER = LoggerFactory.getLogger(BodyProcessorCreator.class); - public static final String PARAMTYPE = "body"; + public static final String REQUEST_BODY_NAME = "X_REQUEST"; + + public static final String EXT_ID = "protobuf"; + + public static final String PARAM_TYPE = "body"; private static final JavaType OBJECT_TYPE = SimpleType.constructUnsafe(Object.class); - // This configuration is used for temporary use only. Do not use it if you are sure how it works. And may be deleted in future. - private static boolean decodeAsObject = DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.parameter.decodeAsObject", false).get(); + private static final Object LOCK = new Object(); + + // This configuration is used for temporary use only. + // Do not use it if you are sure how it works. And may be deleted in the future. + public static final String PARAM_DECODE_AS_OBJECT = "servicecomb.rest.parameter.decodeAsObject"; + + public static final String PARAM_DEFAULT_REQUEST_ENCODING = "servicecomb.rest.parameter.default-request-encoding"; + + private static Boolean decodeAsObject; + + private static String defaultRequestEncoding; public static class BodyProcessor implements ParamValueProcessor { + // Producer target type. For consumer, is null. protected JavaType targetType; + protected Class serialViewClass; + protected boolean isRequired; - public BodyProcessor(JavaType targetType, boolean isRequired) { + protected OpenAPI openAPI; + + protected ScopedProtobufSchemaManager scopedProtobufSchemaManager; + + protected List supportedContentTypes = new ArrayList<>(); + + protected OperationMeta operationMeta; + + protected RequestBody requestBody; + + public BodyProcessor(OperationMeta operationMeta, JavaType targetType, RequestBody requestBody) { + this.requestBody = requestBody; + if (!StringUtils.isEmpty((String) this.requestBody.getExtensions() + .get(SwaggerConst.EXT_JSON_VIEW))) { + try { + this.serialViewClass = Class.forName((String) this.requestBody.getExtensions() + .get(SwaggerConst.EXT_JSON_VIEW)); + } catch (Throwable e) { + //ignore + LOGGER.warn("Failed to create body processor {}, annotation @JsonView may be invalid", serialViewClass, e); + } + } + this.targetType = targetType; - this.isRequired = isRequired; + this.isRequired = this.requestBody.getRequired() != null && this.requestBody.getRequired(); + if (this.requestBody.getContent() != null) { + supportedContentTypes.addAll(this.requestBody.getContent().keySet()); + } + + if (operationMeta != null) { + this.operationMeta = operationMeta; + this.openAPI = operationMeta.getSchemaMeta().getSwagger(); + if (supportedContentTypes.contains(SwaggerConst.PROTOBUF_TYPE)) { + this.scopedProtobufSchemaManager = getOrCreateScopedProtobufSchemaManager( + operationMeta.getMicroserviceMeta()); + } + } + } + + private ScopedProtobufSchemaManager getOrCreateScopedProtobufSchemaManager(MicroserviceMeta microserviceMeta) { + ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID); + if (scopedProtobufSchemaManager == null) { + synchronized (LOCK) { + scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID); + if (scopedProtobufSchemaManager == null) { + scopedProtobufSchemaManager = new ScopedProtobufSchemaManager(); + microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager); + } + } + } + return scopedProtobufSchemaManager; + } + + @Override + public Class getSerialViewClass() { + return serialViewClass; } @Override public Object getValue(HttpServletRequest request) throws Exception { + Object result = getValueImpl(request); + if (result == null && this.isRequired) { + throw new InvocationException(Status.BAD_REQUEST, "Body parameter is required."); + } + return result; + } + + private Object getValueImpl(HttpServletRequest request) throws IOException { Object body = request.getAttribute(RestConst.BODY_PARAMETER); if (body != null) { return convertValue(body, targetType); } // edge support convert from form-data or x-www-form-urlencoded to json automatically - String contentType = request.getContentType(); - contentType = contentType == null ? "" : contentType.toLowerCase(Locale.US); - if (contentType.startsWith(MediaType.MULTIPART_FORM_DATA) - || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED)) { + String contentType = validContentType(request.getContentType()); + + // support RFC 7231, ignore case for content-type + if (StringUtils.equalsIgnoreCase(contentType, MediaType.MULTIPART_FORM_DATA) + || StringUtils.equalsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED)) { return convertValue(request.getParameterMap(), targetType); } @@ -90,69 +184,124 @@ public Object getValue(HttpServletRequest request) throws Exception { return null; } - if (!contentType.isEmpty() && !contentType.startsWith(MediaType.APPLICATION_JSON)) { - // TODO: we should consider body encoding - return IOUtils.toString(inputStream, "UTF-8"); + if (StringUtils.equalsIgnoreCase(contentType, MediaType.APPLICATION_JSON)) { + try { + ObjectReader reader = serialViewClass != null + ? RestObjectMapperFactory.getRestObjectMapper().readerWithView(serialViewClass) + : RestObjectMapperFactory.getRestObjectMapper().reader(); + if (decodeAsObject()) { + return reader.forType(OBJECT_TYPE).readValue(inputStream); + } + return reader.forType(targetType == null ? OBJECT_TYPE : targetType) + .readValue(inputStream); + } catch (MismatchedInputException e) { + // there is no way to detect InputStream is empty, so have to catch the exception + if (!isRequired && e.getMessage().contains("No content to map due to end-of-input")) { + LOGGER.info("Empty content and required is false, taken as null"); + return null; + } + throw e; + } + } + + if (StringUtils.equalsIgnoreCase(contentType, SwaggerConst.PROTOBUF_TYPE)) { + ProtoMapper protoMapper = scopedProtobufSchemaManager + .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(), + REQUEST_BODY_NAME, + requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getSchema()); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage(REQUEST_BODY_NAME), + targetType == null ? OBJECT_TYPE : targetType); + PropertyWrapper result = deserializer.deserialize(inputStream.readAllBytes()); + return result.getValue(); } - try { - if (decodeAsObject) { - return RestObjectMapperFactory.getRestObjectMapper() - .readValue(inputStream, OBJECT_TYPE); + if (StringUtils.equalsIgnoreCase(contentType, MediaType.TEXT_PLAIN)) { + try { + if (targetType != null && String.class.equals(targetType.getRawClass())) { + return IOUtils.toString(inputStream, StandardCharsets.UTF_8); + } + ObjectReader reader = serialViewClass != null + ? RestObjectMapperFactory.getRestObjectMapper().readerWithView(serialViewClass) + : RestObjectMapperFactory.getRestObjectMapper().reader(); + if (decodeAsObject()) { + return reader.forType(OBJECT_TYPE).readValue(inputStream); + } + return reader.forType(targetType == null ? OBJECT_TYPE : targetType) + .readValue(inputStream); + } catch (MismatchedInputException e) { + // there is no way to detect InputStream is empty, so have to catch the exception + if (!isRequired && e.getMessage().contains("No content to map due to end-of-input")) { + LOGGER.info("Empty content and required is false, taken as null"); + return null; + } + throw e; } - return RestObjectMapperFactory.getRestObjectMapper() - .readValue(inputStream, targetType); - } catch (MismatchedInputException e) { - // there is no way to detect InputStream is empty, so have to catch the exception - if (!isRequired && e.getMessage().contains("No content to map due to end-of-input")) { - LOGGER.info("Empty content and required is false, taken as null"); - return null; + } + + throw new IllegalArgumentException(String.format("operation %s not support content-type %s", + operationMeta.getSchemaQualifiedName(), contentType)); + } + + private String validContentType(String type) { + if (StringUtils.isEmpty(type)) { + if (supportedContentTypes.size() == 0) { + throw new IllegalArgumentException("operation do not have any content type support."); } - LOGGER.warn("Mismatched content. Msg=" + e.getMessage()); - throw e; + if (supportedContentTypes.contains(clientEncodingDefault())) { + return clientEncodingDefault(); + } + return supportedContentTypes.get(0); } + ContentType contentType = ContentType.parse(type); + return contentType.getMimeType(); } @Override public void setValue(RestClientRequest clientRequest, Object arg) throws Exception { - ensureContentType(clientRequest); + String userContentType = clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE); + String contentType = validContentType(userContentType); + if (StringUtils.isEmpty(userContentType)) { + clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, contentType); + } if (arg != null) { - Buffer buffer = createBodyBuffer( - clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE), - arg); + Buffer buffer = createBodyBuffer(contentType, arg); clientRequest.write(buffer); } } /** - * Deserialize body object into body buffer, according to the Content-Type. - * - * @param contentType the Content-Type of request - * @param arg body param object - * @return the deserialized body buffer - * @throws IOException + * Serialize body object into body buffer, according to the Content-Type. */ private Buffer createBodyBuffer(String contentType, Object arg) throws IOException { - if (MediaType.TEXT_PLAIN.equals(contentType)) { - if (!String.class.isInstance(arg)) { - throw new IllegalArgumentException("Content-Type is text/plain while arg type is not String"); + if (MediaType.APPLICATION_JSON.equals(contentType)) { + try (BufferOutputStream output = new BufferOutputStream()) { + RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg); + return output.getBuffer(); } - return new BufferImpl().appendBytes(((String) arg).getBytes()); } - try (BufferOutputStream output = new BufferOutputStream()) { - RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg); - return output.getBuffer(); + if (SwaggerConst.PROTOBUF_TYPE.equals(contentType)) { + ProtoMapper protoMapper = scopedProtobufSchemaManager + .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(), + REQUEST_BODY_NAME, + requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getSchema()); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage(REQUEST_BODY_NAME), + Object.class); + Map bodyArg = new HashMap<>(1); + bodyArg.put("value", arg); + return new BufferImpl().appendBytes(serializer.serialize(bodyArg)); } - } - /** - * If the Content-Type has not been set yet, set application/json as default value. - */ - private void ensureContentType(RestClientRequest clientRequest) { - if (null == clientRequest.getHeaders() - || StringUtils.isEmpty(clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE))) { - clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + // For text/plain + try (BufferOutputStream output = new BufferOutputStream()) { + if (arg instanceof String) { + output.write(((String) arg).getBytes(StandardCharsets.UTF_8)); + } else { + RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg); + } + return output.getBuffer(); } } @@ -163,14 +312,32 @@ public String getParameterPath() { @Override public String getProcessorType() { - return PARAMTYPE; + return PARAM_TYPE; } } - public static class RawJsonBodyProcessor extends BodyProcessor { + public static class RawJsonBodyProcessor implements ParamValueProcessor { + protected JavaType targetType; + + protected Class serialViewClass; + + protected boolean isRequired; public RawJsonBodyProcessor(JavaType targetType, boolean isRequired) { - super(targetType, isRequired); + this(targetType, null, isRequired); + } + + public RawJsonBodyProcessor(JavaType targetType, String serialViewClass, boolean isRequired) { + if (!StringUtils.isEmpty(serialViewClass)) { + try { + this.serialViewClass = Class.forName(serialViewClass); + } catch (Throwable e) { + //ignore + LOGGER.warn("Failed to create body processor {}, annotation @JsonView may be invalid", serialViewClass, e); + } + } + this.targetType = targetType; + this.isRequired = isRequired; } @Override @@ -185,29 +352,63 @@ public Object getValue(HttpServletRequest request) throws Exception { return null; } - // TODO: we should consider body encoding - return IOUtils.toString(inputStream, "UTF-8"); + return IOUtils.toString(inputStream, StandardCharsets.UTF_8); } @Override public void setValue(RestClientRequest clientRequest, Object arg) throws Exception { - clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); - clientRequest.write(Buffer.buffer((String) arg)); + if (arg instanceof String) { + clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + clientRequest.write(Buffer.buffer((String) arg)); + return; + } + + throw new IllegalArgumentException("@RawJsonRequestBody only supports string type."); + } + + @Override + public String getParameterPath() { + return ""; + } + + @Override + public String getProcessorType() { + return PARAM_TYPE; } } public BodyProcessorCreator() { - ParamValueProcessorCreatorManager.INSTANCE.register(PARAMTYPE, this); + ParamValueProcessorCreatorManager.INSTANCE.register(PARAM_TYPE, this); } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); - boolean rawJson = ClassUtils.isRawJsonType(parameter); - if (genericParamType.getTypeName().equals(String.class.getTypeName()) && rawJson) { - return new RawJsonBodyProcessor(targetType, parameter.getRequired()); + public ParamValueProcessor create(OperationMeta operationMeta, String parameterName, + RequestBody parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); + boolean rawJson = SwaggerUtils.isRawJsonType(parameter); + if (rawJson) { + return new RawJsonBodyProcessor(targetType, (String) parameter.getExtensions() + .get(SwaggerConst.EXT_JSON_VIEW), + parameter.getRequired() != null && parameter.getRequired()); } - return new BodyProcessor(targetType, parameter.getRequired()); + return new BodyProcessor(operationMeta, targetType, parameter); + } + + private static boolean decodeAsObject() { + if (decodeAsObject == null) { + decodeAsObject = LegacyPropertyFactory + .getBooleanProperty(PARAM_DECODE_AS_OBJECT, false); + } + return decodeAsObject; + } + + private static String clientEncodingDefault() { + if (defaultRequestEncoding == null) { + defaultRequestEncoding = LegacyPropertyFactory + .getStringProperty(PARAM_DEFAULT_REQUEST_ENCODING, MediaType.APPLICATION_JSON); + } + return defaultRequestEncoding; } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java index 90f3946e7b5..9426cc2e232 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java @@ -18,23 +18,22 @@ package org.apache.servicecomb.common.rest.codec.param; import java.lang.reflect.Type; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; +import java.util.Objects; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.util.ObjectUtils; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.CookieParameter; -import io.swagger.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; -public class CookieProcessorCreator implements ParamValueProcessorCreator { +public class CookieProcessorCreator implements ParamValueProcessorCreator { public static final String PARAMTYPE = "cookie"; public static class CookieProcessor extends AbstractParamProcessor { @@ -52,7 +51,7 @@ public Object getValue(HttpServletRequest request) { } for (Cookie cookie : cookies) { - if (paramPath.equals(cookie.getName())) { + if (Objects.equals(paramPath, cookie.getName())) { value = cookie.getValue(); break; } @@ -87,9 +86,11 @@ public CookieProcessorCreator() { } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); - return new CookieProcessor(parameter.getName(), targetType, ((CookieParameter) parameter).getDefaultValue(), - parameter.getRequired()); + public ParamValueProcessor create(OperationMeta operationMeta, + String parameterName, Parameter parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); + return new CookieProcessor(parameterName, targetType, parameter.getSchema().getDefault(), + parameter.getRequired() != null && parameter.getRequired()); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java index 04ea5bfd671..740f57e039f 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java @@ -18,40 +18,55 @@ package org.apache.servicecomb.common.rest.codec.param; import java.lang.reflect.Type; +import java.util.List; import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; -import javax.ws.rs.core.Response.Status; +import java.util.function.Function; +import java.util.stream.Collectors; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.invocation.converter.Converter; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.FileProperty; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.Response.Status; -public class FormProcessorCreator implements ParamValueProcessorCreator { +@SuppressWarnings("unchecked") +public class FormProcessorCreator implements ParamValueProcessorCreator { public static final String PARAMTYPE = "formData"; public static class FormProcessor extends AbstractParamProcessor { - public FormProcessor(String paramPath, JavaType targetType, Object defaultValue, boolean required) { - super(paramPath, targetType, defaultValue, required); + private final boolean repeatedType; + + public FormProcessor(String paraName, RequestBody formParameter, String mediaType, JavaType targetType) { + super(paraName, targetType, + formParameter.getContent().get(mediaType).getSchema().getDefault(), + formParameter.getRequired() != null && formParameter.getRequired()); + + this.repeatedType = formParameter.getContent().get(mediaType) + .getSchema().getProperties().get(paraName) instanceof ArraySchema; } @Override public Object getValue(HttpServletRequest request) { - @SuppressWarnings("unchecked") - Map forms = (Map) request.getAttribute(RestConst.FORM_PARAMETERS); + Map forms = (Map) request.getAttribute(RestConst.BODY_PARAMETER); if (forms != null && !forms.isEmpty()) { return convertValue(forms.get(paramPath), targetType); } - if (targetType.isContainerType()) { + if (repeatedType) { //Even if the paramPath does not exist, it won't be null at now return convertValue(request.getParameterValues(paramPath), targetType); } @@ -60,7 +75,6 @@ public Object getValue(HttpServletRequest request) { if (value == null) { value = checkRequiredAndDefaultValue(); } - return convertValue(value, targetType); } @@ -87,34 +101,114 @@ public FormProcessorCreator() { } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); + public ParamValueProcessor create(OperationMeta operationMeta, + String paramName, RequestBody parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); - if (isPart(parameter)) { - return new PartProcessor(parameter.getName(), targetType, ((FormParameter) parameter).getDefaultValue(), - parameter.getRequired()); + if (isPart(parameter, paramName)) { + return new PartProcessor(paramName, parameter, genericParamType); } - return new FormProcessor(parameter.getName(), targetType, ((FormParameter) parameter).getDefaultValue(), - parameter.getRequired()); + String mediaType = SwaggerConst.FORM_MEDIA_TYPE; + if (parameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE) != null) { + mediaType = SwaggerConst.FILE_MEDIA_TYPE; + } + return new FormProcessor(paramName, parameter, mediaType, targetType); } - private boolean isPart(Parameter parameter) { - return new FileProperty().getType().equals(((FormParameter) parameter).getType()); + private boolean isPart(RequestBody parameter, String paramName) { + MediaType file = parameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE); + if (file != null) { + Schema schema = (Schema) file.getSchema().getProperties().get(paramName); + if (schema instanceof ArraySchema) { + return "string".equals(schema.getItems().getType()) && + "binary".equals(schema.getItems().getFormat()); + } else { + return ("string".equals(schema.getType()) && "binary".equals(schema.getFormat())); + } + } + return false; } - private static class PartProcessor extends AbstractParamProcessor { - PartProcessor(String paramPath, JavaType targetType, Object defaultValue, boolean required) { - super(paramPath, targetType, defaultValue, required); + public static class PartProcessor extends AbstractParamProcessor { + private static final Type partListType = ParameterizedTypeUtil.make(List.class, Part.class); + + // key is target type + private static final Map partsToTargetConverters = SPIServiceUtils.getSortedService( + Converter.class) + .stream() + .filter(c -> partListType.equals(c.getSrcType())) + .collect(Collectors.toMap(Converter::getTargetType, Function.identity())); + + // key is target type + private static final Map partToTargetConverters = SPIServiceUtils.getSortedService(Converter.class) + .stream() + .filter(c -> c.getSrcType() instanceof Class && Part.class.isAssignableFrom((Class) c.getSrcType())) + .collect(Collectors.toMap(Converter::getTargetType, Function.identity())); + + private final boolean repeatedType; + + private Converter converter; + + PartProcessor(String paramName, RequestBody formParameter, Type genericParamType) { + super(paramName, null, + formParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE).getSchema().getDefault(), + formParameter.getRequired() != null && formParameter.getRequired()); + + this.repeatedType = formParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE) + .getSchema().getProperties().get(paramName) instanceof ArraySchema; + initConverter(genericParamType); + } + + private void initConverter(Type genericParamType) { + if (repeatedType) { + initRepeatedConverter(genericParamType); + return; + } + + initNormalConverter(genericParamType); + } + + private void initNormalConverter(Type genericParamType) { + if (genericParamType instanceof JavaType) { + genericParamType = ((JavaType) genericParamType).getRawClass(); + } + converter = partToTargetConverters.get(genericParamType); + } + + private void initRepeatedConverter(Type genericParamType) { + if (genericParamType instanceof JavaType) { + genericParamType = ParameterizedTypeUtil.make(((JavaType) genericParamType).getRawClass(), + ((JavaType) genericParamType).getContentType()); + } + converter = partsToTargetConverters.get(genericParamType); } @Override public Object getValue(HttpServletRequest request) throws Exception { - return request.getPart(paramPath); + if (repeatedType) { + // get all parts + List parts = request.getParts() + .stream() + .filter(part -> part.getName().equals(paramPath)) + .collect(Collectors.toList()); + return convertValue(converter, parts); + } + + return convertValue(converter, request.getPart(paramPath)); + } + + public Object convertValue(Converter converter, Object value) { + if (value == null || converter == null) { + return value; + } + + return converter.convert(value); } @Override public void setValue(RestClientRequest clientRequest, Object arg) throws Exception { - clientRequest.attach(paramPath, (Part) arg); + clientRequest.attach(paramPath, arg); } @Override diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java index 4d91261437f..3bfb2675046 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java @@ -18,56 +18,53 @@ package org.apache.servicecomb.common.rest.codec.param; import java.lang.reflect.Type; -import java.util.Collections; -import java.util.Enumeration; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; import org.apache.servicecomb.common.rest.codec.RestClientRequest; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.header.HeaderCodec; +import org.apache.servicecomb.common.rest.codec.header.HeaderCodecsUtils; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.Parameter; - -public class HeaderProcessorCreator implements ParamValueProcessorCreator { - private static final Logger LOGGER = LoggerFactory.getLogger(HeaderProcessorCreator.class); +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; +public class HeaderProcessorCreator implements ParamValueProcessorCreator { public static final String PARAMTYPE = "header"; public static class HeaderProcessor extends AbstractParamProcessor { - public HeaderProcessor(String paramPath, JavaType targetType, Object defaultValue, boolean required) { - super(paramPath, targetType, defaultValue, required); - } + // This configuration is used for temporary use only. Do not use it if you are sure how it works. And may be deleted in future. + private final boolean ignoreRequiredCheck = LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.parameter.header.ignoreRequiredCheck", false); - @Override - public Object getValue(HttpServletRequest request) { - Object value = null; - if (targetType.isContainerType()) { - Enumeration headerValues = request.getHeaders(paramPath); - if (headerValues == null) { - //Even if the paramPath does not exist, headerValues won't be null at now - return null; - } - value = Collections.list(headerValues); + private final HeaderCodec headerCodec; + + public HeaderProcessor(HeaderParameter headerParameter, JavaType targetType) { + super(headerParameter.getName(), targetType, headerParameter.getSchema().getDefault(), + headerParameter.getRequired() != null && headerParameter.getRequired()); + + if ((headerParameter.getSchema() instanceof ArraySchema) && headerParameter.getStyle() == null) { + // compatible to default settings + this.headerCodec = HeaderCodecsUtils.find(StyleEnum.FORM, true); } else { - value = request.getHeader(paramPath); - if (value == null) { - value = checkRequiredAndDefaultValue(); - } + this.headerCodec = HeaderCodecsUtils.find(headerParameter.getStyle(), headerParameter.getExplode()); } + } - return convertValue(value, targetType); + @Override + public Object getValue(HttpServletRequest request) { + return headerCodec.decode(this, request); } - private Object checkRequiredAndDefaultValue() { - if (isRequired()) { + public Object checkRequiredAndDefaultValue() { + if (!ignoreRequiredCheck && isRequired()) { throw new InvocationException(Status.BAD_REQUEST, "Parameter is required."); } return getDefaultValue(); @@ -75,13 +72,7 @@ private Object checkRequiredAndDefaultValue() { @Override public void setValue(RestClientRequest clientRequest, Object arg) throws Exception { - if (null == arg) { - // null header should not be set to clientRequest to avoid NullPointerException in Netty. - LOGGER.debug("Header arg is null, will not be set into clientRequest. paramPath = [{}]", paramPath); - return; - } - clientRequest.putHeader(paramPath, - RestObjectMapperFactory.getConsumerWriterMapper().convertToString(arg)); + headerCodec.encode(clientRequest, paramPath, arg); } @Override @@ -95,9 +86,10 @@ public HeaderProcessorCreator() { } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); - return new HeaderProcessor(parameter.getName(), targetType, ((HeaderParameter) parameter).getDefaultValue(), - parameter.getRequired()); + public ParamValueProcessor create(OperationMeta operationMeta, + String parameterName, Parameter parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); + return new HeaderProcessor((HeaderParameter) parameter, targetType); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java index e2d8b67b38a..5d5dfc32cf0 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.common.rest.codec.param; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; @@ -30,6 +30,14 @@ public interface ParamValueProcessor { void setValue(RestClientRequest clientRequest, Object arg) throws Exception; default Object convertValue(Object value, JavaType targetType) { + if (value == null || targetType == null) { + return value; + } + if (getSerialViewClass() != null) { + return RestObjectMapperFactory.getRestViewMapper().setConfig( + RestObjectMapperFactory.getRestViewMapper().getDeserializationConfig().withView(getSerialViewClass())) + .convertValue(value, targetType); + } return RestObjectMapperFactory.getRestObjectMapper() .convertValue(value, targetType); } @@ -37,4 +45,8 @@ default Object convertValue(Object value, JavaType targetType) { String getParameterPath(); String getProcessorType(); + + default Class getSerialViewClass() { + return null; + } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java index b5d87b2f286..1c3378dc6bb 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java @@ -19,8 +19,11 @@ import java.lang.reflect.Type; -import io.swagger.models.parameters.Parameter; +import org.apache.servicecomb.core.definition.OperationMeta; -public interface ParamValueProcessorCreator { - ParamValueProcessor create(Parameter parameter, Type genericParamType); +public interface ParamValueProcessorCreator { + default ParamValueProcessor create(OperationMeta operationMeta, String paramName, T parameter, + Type genericParamType) { + throw new IllegalStateException("not implemented"); + } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java index 6f5f3fd6050..861b7490fea 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java @@ -18,21 +18,21 @@ package org.apache.servicecomb.common.rest.codec.param; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.util.Map; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; -import org.apache.servicecomb.foundation.common.http.HttpUtils; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.springframework.util.StringUtils; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import jakarta.servlet.http.HttpServletRequest; -public class PathProcessorCreator implements ParamValueProcessorCreator { +public class PathProcessorCreator implements ParamValueProcessorCreator { public static final String PARAMTYPE = "path"; public static class PathProcessor extends AbstractParamProcessor { @@ -41,7 +41,7 @@ public PathProcessor(String paramPath, JavaType targetType, Object defaultValue, } @Override - public Object getValue(HttpServletRequest request) throws Exception { + public Object getValue(HttpServletRequest request) { @SuppressWarnings("unchecked") Map pathVarMap = (Map) request.getAttribute(RestConst.PATH_PARAMETERS); if (pathVarMap == null) { @@ -52,7 +52,7 @@ public Object getValue(HttpServletRequest request) throws Exception { if (value == null) { return null; } - return convertValue(HttpUtils.uriDecodePath(value), targetType); + return convertValue(StringUtils.uriDecode(value, StandardCharsets.UTF_8), targetType); } @Override @@ -71,8 +71,10 @@ public PathProcessorCreator() { } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); - return new PathProcessor(parameter.getName(), targetType, ((PathParameter) parameter).getDefaultValue(), true); + public ParamValueProcessor create(OperationMeta operationMeta, + String parameterName, Parameter parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); + return new PathProcessor(parameterName, targetType, parameter.getSchema().getDefault(), true); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java index e226730c3b8..8fef056867c 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java @@ -18,78 +18,87 @@ package org.apache.servicecomb.common.rest.codec.param; import java.lang.reflect.Type; +import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; - -import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; -import org.apache.servicecomb.swagger.converter.property.SwaggerParamCollectionFormat; +import org.apache.servicecomb.common.rest.codec.query.QueryCodec; +import org.apache.servicecomb.common.rest.codec.query.QueryCodecsUtils; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.netflix.config.DynamicPropertyFactory; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; -public class QueryProcessorCreator implements ParamValueProcessorCreator { +@SuppressWarnings("unchecked") +public class QueryProcessorCreator implements ParamValueProcessorCreator { public static final String PARAMTYPE = "query"; public static class QueryProcessor extends AbstractParamProcessor { // This configuration is used for temporary use only. Do not use it if you are sure how it works. And may be deleted in future. - private boolean emptyAsNull = DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.parameter.query.emptyAsNull", false).get(); + private final boolean emptyAsNull = LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.parameter.query.emptyAsNull", false); // This configuration is used for temporary use only. Do not use it if you are sure how it works. And may be deleted in future. - private boolean ignoreDefaultValue = DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", false).get(); + private final boolean ignoreDefaultValue = LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", false); - private SwaggerParamCollectionFormat collectionFormat; + // This configuration is used for temporary use only. Do not use it if you are sure how it works. And may be deleted in future. + private final boolean ignoreRequiredCheck = LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", false); - public QueryProcessor(String paramPath, JavaType targetType, Object defaultValue, boolean required, - String collectionFormat) { - super(paramPath, targetType, defaultValue, required); - if (StringUtils.isNoneEmpty(collectionFormat)) { - this.collectionFormat = SwaggerParamCollectionFormat.valueOf(collectionFormat.toUpperCase()); - } + private final boolean repeatedType; + + private final QueryCodec queryCodec; + + public QueryProcessor(QueryParameter queryParameter, JavaType targetType) { + super(queryParameter.getName(), targetType, queryParameter.getSchema().getDefault(), + queryParameter.getRequired() != null && queryParameter.getRequired()); + + this.repeatedType = queryParameter.getSchema() instanceof ArraySchema; + this.queryCodec = QueryCodecsUtils.find(queryParameter.getStyle(), queryParameter.getExplode()); } @Override public Object getValue(HttpServletRequest request) { - Object value = null; - if (targetType.isContainerType() - && SwaggerParamCollectionFormat.MULTI.equals(collectionFormat)) { - value = request.getParameterValues(paramPath); - //Even if the paramPath does not exist, value won't be null at now - } else { - value = request.getParameter(paramPath); - // make some old systems happy - if (emptyAsNull) { - if (StringUtils.isEmpty((String) value)) { - value = null; - } - } - if (value == null) { - value = checkRequiredAndDefaultValue(); - } - if (null != collectionFormat) { - value = collectionFormat.splitParam((String) value); - } + return queryCodec.decode(this, request); + } + + public Object getAndCheckParameter(HttpServletRequest request) { + Object value = request.getParameter(paramPath); + + // compatible to SpringMVC @RequestParam. BODY_PARAMETER is only set for SpringMVC. + if (value == null) { + Map forms = (Map) request.getAttribute(RestConst.BODY_PARAMETER); + value = (forms == null || forms.get(paramPath) == null) + ? null : forms.get(paramPath); } - return convertValue(value, targetType); + // make some old systems happy + if (emptyAsNull && "".equals(value)) { + value = null; + } + + return value != null ? value : checkRequiredAndDefaultValue(); } private Object checkRequiredAndDefaultValue() { - if (isRequired()) { - throw new InvocationException(Status.BAD_REQUEST, "Parameter is required."); + if (!ignoreRequiredCheck && isRequired()) { + throw new InvocationException(Status.BAD_REQUEST, + String.format("Parameter %s is required.", paramPath)); } Object defaultValue = getDefaultValue(); if (!ignoreDefaultValue && defaultValue != null) { return defaultValue; } + return null; } @@ -103,8 +112,16 @@ public String getProcessorType() { return PARAMTYPE; } - public SwaggerParamCollectionFormat getCollectionFormat() { - return collectionFormat; + public QueryCodec getQueryCodec() { + return queryCodec; + } + + public boolean isRepeatedType() { + return repeatedType; + } + + public Object convertValue(Object value) { + return convertValue(value, targetType); } } @@ -113,11 +130,10 @@ public QueryProcessorCreator() { } @Override - public ParamValueProcessor create(Parameter parameter, Type genericParamType) { - QueryParameter queryParameter = (QueryParameter) parameter; - JavaType targetType = TypeFactory.defaultInstance().constructType(genericParamType); - return new QueryProcessor(parameter.getName(), targetType, queryParameter.getDefaultValue(), - parameter.getRequired(), - queryParameter.getCollectionFormat()); + public ParamValueProcessor create(OperationMeta operationMeta, + String parameterName, Parameter parameter, Type genericParamType) { + JavaType targetType = + genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType); + return new QueryProcessor((QueryParameter) parameter, targetType); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java deleted file mode 100644 index 8b124ec8aaa..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.codec.param; - -import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; -import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA; - -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; - -import javax.servlet.http.Part; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.common.rest.codec.RestClientRequest; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; -import org.apache.servicecomb.foundation.vertx.stream.PumpFromPart; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.Context; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpHeaders; - -public class RestClientRequestImpl implements RestClientRequest { - private static final Logger LOGGER = LoggerFactory.getLogger(RestClientRequestImpl.class); - - protected Context context; - - protected AsyncResponse asyncResp; - - private final Map uploads = new HashMap<>(); - - protected HttpClientRequest request; - - protected Map cookieMap; - - protected Map formMap; - - protected Buffer bodyBuffer; - - public RestClientRequestImpl(HttpClientRequest request, Context context, AsyncResponse asyncResp) { - this.context = context; - this.asyncResp = asyncResp; - this.request = request; - } - - @Override - public void write(Buffer bodyBuffer) { - this.bodyBuffer = bodyBuffer; - } - - @Override - public Buffer getBodyBuffer() throws Exception { - genBodyBuffer(); - return bodyBuffer; - } - - @Override - public void attach(String name, Part part) { - if (null == part) { - LOGGER.debug("null file is ignored, file name = [{}]", name); - return; - } - uploads.put(name, part); - } - - @Override - public void end() { - writeCookies(); - - if (!uploads.isEmpty()) { - doEndWithUpload(); - return; - } - - doEndNormal(); - } - - protected void doEndWithUpload() { - request.setChunked(true); - - String boundary = "boundary" + UUID.randomUUID().toString(); - putHeader(CONTENT_TYPE, MULTIPART_FORM_DATA + "; charset=UTF-8; boundary=" + boundary); - - genBodyForm(boundary); - - attachFiles(boundary); - } - - private void genBodyForm(String boundary) { - if (formMap == null) { - return; - } - - try { - try (BufferOutputStream output = new BufferOutputStream()) { - for (Entry entry : formMap.entrySet()) { - output.write(bytesOf("\r\n")); - output.write(bytesOf("--" + boundary + "\r\n")); - output.write(bytesOf("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n")); - if (entry.getValue() != null) { - String value = RestObjectMapperFactory.getRestObjectMapper().convertToString(entry.getValue()); - output.write(value.getBytes(StandardCharsets.UTF_8)); - } - } - request.write(output.getBuffer()); - } - } catch (Exception e) { - asyncResp.consumerFail(e); - } - } - - private byte[] bytesOf(String string) { - return string.getBytes(StandardCharsets.UTF_8); - } - - protected void doEndNormal() { - try { - genBodyBuffer(); - } catch (Exception e) { - asyncResp.consumerFail(e); - return; - } - - if (bodyBuffer == null) { - request.end(); - return; - } - - request.end(bodyBuffer); - } - - private void attachFiles(String boundary) { - Iterator> uploadsIterator = uploads.entrySet().iterator(); - attachFile(boundary, uploadsIterator); - } - - private void attachFile(String boundary, Iterator> uploadsIterator) { - if (!uploadsIterator.hasNext()) { - request.write(boundaryEndInfo(boundary)); - request.end(); - return; - } - - Entry entry = uploadsIterator.next(); - // do not use part.getName() to get parameter name - // because pojo consumer not easy to set name to part - String name = entry.getKey(); - Part part = entry.getValue(); - String filename = part.getSubmittedFileName(); - - Buffer fileHeader = fileBoundaryInfo(boundary, name, part); - request.write(fileHeader); - - new PumpFromPart(context, part).toWriteStream(request).whenComplete((v, e) -> { - if (e != null) { - LOGGER.debug("Failed to sending file [{}:{}].", name, filename, e); - asyncResp.consumerFail(e); - return; - } - - LOGGER.debug("finish sending file [{}:{}].", name, filename); - attachFile(boundary, uploadsIterator); - }); - } - - private Buffer boundaryEndInfo(String boundary) { - return Buffer.buffer() - .appendString("\r\n") - .appendString("--" + boundary + "--\r\n"); - } - - protected Buffer fileBoundaryInfo(String boundary, String name, Part part) { - Buffer buffer = Buffer.buffer(); - buffer.appendString("\r\n"); - buffer.appendString("--" + boundary + "\r\n"); - buffer.appendString("Content-Disposition: form-data; name=\"") - .appendString(name) - .appendString("\"; filename=\"") - .appendString(part.getSubmittedFileName() != null ? part.getSubmittedFileName() : "null") - .appendString("\"\r\n"); - buffer.appendString("Content-Type: ").appendString(part.getContentType()).appendString("\r\n"); - buffer.appendString("Content-Transfer-Encoding: binary\r\n"); - buffer.appendString("\r\n"); - return buffer; - } - - private void genBodyBuffer() throws Exception { - if (bodyBuffer != null) { - return; - } - - if (formMap == null) { - return; - } - - request.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); - try (BufferOutputStream output = new BufferOutputStream()) { - for (Entry entry : formMap.entrySet()) { - output.write(entry.getKey().getBytes(StandardCharsets.UTF_8)); - output.write('='); - if (entry.getValue() != null) { - String value = RestObjectMapperFactory.getRestObjectMapper().convertToString(entry.getValue()); - value = URLEncoder.encode(value, StandardCharsets.UTF_8.name()); - output.write(value.getBytes(StandardCharsets.UTF_8)); - } - output.write('&'); - } - bodyBuffer = output.getBuffer(); - } - } - - private void writeCookies() { - if (cookieMap == null) { - return; - } - - StringBuilder builder = new StringBuilder(); - for (Entry entry : cookieMap.entrySet()) { - builder.append(entry.getKey()) - .append('=') - .append(entry.getValue()) - .append("; "); - } - request.putHeader(HttpHeaders.COOKIE, builder.toString()); - } - - @Override - public void addCookie(String name, String value) { - if (cookieMap == null) { - cookieMap = new HashMap<>(); - } - - cookieMap.put(name, value); - } - - @Override - public void addForm(String name, Object value) { - if (formMap == null) { - formMap = new HashMap<>(); - } - - if (value != null) { - formMap.put(name, value); - } - } - - @Override - public void putHeader(String name, String value) { - request.putHeader(name, value); - } - - @Override - public MultiMap getHeaders() { - return request.headers(); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceEventStreamProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceEventStreamProcessor.java new file mode 100644 index 00000000000..64795bf817d --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceEventStreamProcessor.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.produce; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; + +import com.fasterxml.jackson.databind.JavaType; + +import jakarta.ws.rs.core.MediaType; + +public class ProduceEventStreamProcessor implements ProduceProcessor { + private int writeIndex = 0; + + @Override + public String getName() { + return MediaType.SERVER_SENT_EVENTS; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void doEncodeResponse(OutputStream output, Object result) throws Exception { + String buffer = "id: " + (writeIndex++) + "\n" + + "data: " + + RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(result) + + "\n\n"; + output.write(buffer.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public Object doDecodeResponse(InputStream input, JavaType type) throws Exception { + String buffer = new String(input.readAllBytes(), StandardCharsets.UTF_8); + for (String line : buffer.split("\n")) { + if (line.startsWith("data: ")) { + return RestObjectMapperFactory.getRestObjectMapper().readValue(line.substring(5), type); + } + } + return null; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java index d4006c74a5c..e14451389e5 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java @@ -20,7 +20,7 @@ import java.io.InputStream; import java.io.OutputStream; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; @@ -28,6 +28,22 @@ public class ProduceJsonProcessor implements ProduceProcessor { + private Class serializationView; + + @Override + public String getSerializationView() { + return serializationView == null ? ProduceProcessor.super.getSerializationView() + : serializationView.getName(); + } + + @Override + public void setSerializationView(Class serializationView) { + if (serializationView == null) { + return; + } + this.serializationView = serializationView; + } + @Override public String getName() { return MediaType.APPLICATION_JSON; @@ -35,13 +51,20 @@ public String getName() { @Override public void doEncodeResponse(OutputStream output, Object result) throws Exception { - RestObjectMapperFactory.getRestObjectMapper().writeValue(output, result); + if (serializationView == null) { + RestObjectMapperFactory.getRestObjectMapper().writeValue(output, result); + return; + } + RestObjectMapperFactory.getRestObjectMapper().writerWithView(serializationView).writeValue(output, result); } @Override public Object doDecodeResponse(InputStream input, JavaType type) throws Exception { - return RestObjectMapperFactory.getRestObjectMapper() - .readValue(input, type); + if (serializationView == null) { + return RestObjectMapperFactory.getRestObjectMapper().readValue(input, type); + } + return RestObjectMapperFactory.getRestObjectMapper().readerWithView(serializationView) + .forType(type).readValue(input); } @Override diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessor.java index 4172cb56fad..574c1e1b630 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessor.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessor.java @@ -32,6 +32,14 @@ public interface ProduceProcessor { int getOrder(); + default String getSerializationView() { + return ProduceProcessorManager.DEFAULT_SERIAL_CLASS; + } + + default void setSerializationView(Class serializationView) { + // do nothing default + } + default void encodeResponse(OutputStream output, Object result) throws Exception { if (result == null) { return; @@ -64,7 +72,7 @@ default Object decodeResponse(Buffer buffer, JavaType type) throws Exception { return null; } - try (BufferInputStream input = new BufferInputStream(buffer.getByteBuf())) { + try (BufferInputStream input = new BufferInputStream(buffer)) { return doDecodeResponse(input, type); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java index 6bd5babc056..3fdcfec135f 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java @@ -17,40 +17,159 @@ package org.apache.servicecomb.common.rest.codec.produce; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; -import java.util.Set; - -import javax.ws.rs.core.MediaType; +import java.util.Map; +import org.apache.http.entity.ContentType; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.RegisterManager; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; + +public final class ProduceProcessorManager extends RegisterManager> { + private static final Logger LOGGER = LoggerFactory.getLogger(ProduceProcessorManager.class); -public final class ProduceProcessorManager extends RegisterManager { private static final List produceProcessor = SPIServiceUtils.getSortedService(ProduceProcessor.class); private static final String NAME = "produce processor mgr"; - public static final String DEFAULT_TYPE = MediaType.APPLICATION_JSON; + public static final String DEFAULT_SERIAL_CLASS = "servicecomb_default_class"; public static final ProduceProcessorManager INSTANCE = new ProduceProcessorManager(); - public static final ProduceProcessor JSON_PROCESSOR = - SPIServiceUtils.getTargetService(ProduceProcessor.class, ProduceJsonProcessor.class); + public static final String PARAM_DEFAULT_RESPONSE_ENCODING = "servicecomb.rest.parameter.default-response-encoding"; + + private static String defaultResponseEncoding; - public static final ProduceProcessor PLAIN_PROCESSOR = - SPIServiceUtils.getTargetService(ProduceProcessor.class, ProduceTextPlainProcessor.class); + private final Map jsonProcessorMap; - public static final ProduceProcessor DEFAULT_PROCESSOR = JSON_PROCESSOR; + private final Map plainProcessorMap; + + private final Map defaultProcessorMap; private ProduceProcessorManager() { super(NAME); - Set set = new HashSet<>(); produceProcessor.forEach(processor -> { - if (set.add(processor.getName())) { - register(processor.getName(), processor); - } + Map prodProcessorMap = getObjMap() + .computeIfAbsent(processor.getName(), key -> new HashMap<>()); + prodProcessorMap.putIfAbsent(processor.getSerializationView(), processor); }); + jsonProcessorMap = ensureFindValue(MediaType.APPLICATION_JSON); + plainProcessorMap = ensureFindValue(MediaType.TEXT_PLAIN); + defaultProcessorMap = jsonProcessorMap; + } + + private static ProduceProcessor cloneNewProduceProcessor(Class serialViewClass, + Map produceViewMap) { + ProduceProcessor newInstance; + try { + newInstance = produceViewMap.get(DEFAULT_SERIAL_CLASS).getClass().getDeclaredConstructor().newInstance(); + newInstance.setSerializationView(serialViewClass); + return newInstance; + } catch (Throwable e) { + // ignore exception + LOGGER.warn("Failed to create produceProcessor with {}", serialViewClass.getName(), e); + } + return produceViewMap.get(DEFAULT_SERIAL_CLASS); + } + + private static String defaultResponseEncoding() { + if (defaultResponseEncoding == null) { + defaultResponseEncoding = LegacyPropertyFactory + .getStringProperty(PARAM_DEFAULT_RESPONSE_ENCODING, MediaType.APPLICATION_JSON); + } + return defaultResponseEncoding; + } + + public ProduceProcessor findJsonProcessorByViewClass(Class serialViewClass) { + if (serialViewClass == null) { + return jsonProcessorMap.get(DEFAULT_SERIAL_CLASS); + } + return jsonProcessorMap.computeIfAbsent(serialViewClass.getName(), + viewKey -> cloneNewProduceProcessor(serialViewClass, jsonProcessorMap)); + } + + public ProduceProcessor findPlainProcessorByViewClass(Class serialViewClass) { + if (serialViewClass == null) { + return plainProcessorMap.get(DEFAULT_SERIAL_CLASS); + } + return plainProcessorMap.computeIfAbsent(serialViewClass.getName(), + viewKey -> cloneNewProduceProcessor(serialViewClass, plainProcessorMap)); + } + + public ProduceProcessor findDefaultJsonProcessor() { + return jsonProcessorMap.get(DEFAULT_SERIAL_CLASS); + } + + public ProduceProcessor findDefaultProcessor() { + return defaultProcessorMap.get(DEFAULT_SERIAL_CLASS); + } + + public ProduceProcessor findDefaultPlainProcessor() { + return plainProcessorMap.get(DEFAULT_SERIAL_CLASS); + } + + public ProduceProcessor createProduceProcessor(OperationMeta operationMeta, + int statusCode, String accept, Class serialViewClass) { + // If no produces defined, using default processor + ApiResponses responses = operationMeta.getSwaggerOperation().getResponses(); + ApiResponse response = responses.get(String.valueOf(statusCode)); + if (response == null || response.getContent() == null || + response.getContent().size() == 0) { + return findDefaultProcessor(); + } + + // check intersection of `Accept` and `Produces` + if (accept == null) { + if (response.getContent().get(defaultResponseEncoding()) != null) { + accept = defaultResponseEncoding(); + } else { + accept = response.getContent().keySet().iterator().next(); + } + } + + String actualAccept = null; + for (String item : accept.split(",")) { + ContentType contentType = ContentType.parse(item); + if (MediaType.WILDCARD.equals(contentType.getMimeType()) || + MediaType.MEDIA_TYPE_WILDCARD.equals(contentType.getMimeType())) { + if (response.getContent().get(defaultResponseEncoding()) != null) { + actualAccept = defaultResponseEncoding(); + } else { + actualAccept = response.getContent().keySet().iterator().next(); + } + break; + } + if (response.getContent().get(contentType.getMimeType()) != null) { + actualAccept = contentType.getMimeType(); + break; + } + } + + if (actualAccept == null) { + LOGGER.warn("Operation {} do not support accept type {}", operationMeta.getSchemaQualifiedName(), accept); + return findDefaultProcessor(); + } + if (MediaType.APPLICATION_JSON.equals(actualAccept)) { + return findJsonProcessorByViewClass(serialViewClass); + } + if (SwaggerConst.PROTOBUF_TYPE.equals(actualAccept)) { + return new ProduceProtoBufferProcessor(operationMeta, + operationMeta.getSchemaMeta().getSwagger(), response.getContent().get(actualAccept).getSchema()); + } + if (MediaType.SERVER_SENT_EVENTS.equals(actualAccept)) { + return new ProduceEventStreamProcessor(); + } + // text plain + return findPlainProcessorByViewClass(serialViewClass); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java new file mode 100644 index 00000000000..61f56fcacdf --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.produce; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; +import org.apache.servicecomb.swagger.generator.SwaggerConst; + +import com.fasterxml.jackson.databind.JavaType; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +public class ProduceProtoBufferProcessor implements ProduceProcessor { + public static final String RESPONSE_MESSAGE_NAME = "X_RESPONSE"; + + public static final String EXT_ID = "protobuf"; + + private static final Object LOCK = new Object(); + + private final OperationMeta operationMeta; + + private final OpenAPI openAPI; + + private final Schema schema; + + private final ScopedProtobufSchemaManager scopedProtobufSchemaManager; + + public ProduceProtoBufferProcessor(OperationMeta operationMeta, OpenAPI openAPI, Schema schema) { + this.operationMeta = operationMeta; + this.openAPI = openAPI; + this.schema = schema; + this.scopedProtobufSchemaManager = getOrCreateScopedProtobufSchemaManager(operationMeta.getMicroserviceMeta()); + } + + private ScopedProtobufSchemaManager getOrCreateScopedProtobufSchemaManager(MicroserviceMeta microserviceMeta) { + ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID); + if (scopedProtobufSchemaManager == null) { + synchronized (LOCK) { + scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID); + if (scopedProtobufSchemaManager == null) { + scopedProtobufSchemaManager = new ScopedProtobufSchemaManager(); + microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager); + } + } + } + return scopedProtobufSchemaManager; + } + + @Override + public String getName() { + return SwaggerConst.PROTOBUF_TYPE; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void doEncodeResponse(OutputStream output, Object result) throws Exception { + ProtoMapper protoMapper = scopedProtobufSchemaManager + .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(), + RESPONSE_MESSAGE_NAME, schema); + RootSerializer serializer = protoMapper.getSerializerSchemaManager() + .createRootSerializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME), + Object.class); + Map bodyArg = new HashMap<>(1); + bodyArg.put("value", result); + output.write(serializer.serialize(bodyArg)); + } + + @Override + public Object doDecodeResponse(InputStream input, JavaType type) throws Exception { + ProtoMapper protoMapper = scopedProtobufSchemaManager + .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(), + RESPONSE_MESSAGE_NAME, schema); + RootDeserializer> deserializer = protoMapper.getDeserializerSchemaManager() + .createRootDeserializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME), type); + PropertyWrapper result = deserializer.deserialize(input.readAllBytes()); + return result.getValue(); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java index 0311182ebfa..21d73688dc4 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java @@ -21,13 +21,13 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; -import javax.ws.rs.core.MediaType; - import org.apache.commons.io.IOUtils; import com.fasterxml.jackson.databind.JavaType; -public class ProduceTextPlainProcessor implements ProduceProcessor { +import jakarta.ws.rs.core.MediaType; + +public class ProduceTextPlainProcessor extends ProduceJsonProcessor { @Override public String getName() { return MediaType.TEXT_PLAIN; @@ -35,33 +35,18 @@ public String getName() { @Override public void doEncodeResponse(OutputStream output, Object result) throws Exception { - output.write(String.valueOf(result).getBytes(StandardCharsets.UTF_8)); + if (result instanceof String) { + output.write(((String) result).getBytes(StandardCharsets.UTF_8)); + return; + } + super.doEncodeResponse(output, result); } @Override public Object doDecodeResponse(InputStream input, JavaType type) throws Exception { - // plainText类型,肯定是返回string的,想不出有其他类型的场景 - return IOUtils.toString(input, StandardCharsets.UTF_8); - // TODO: 该方法尚需进一步修改 - // Class returnCls = type.getRawClass(); - // if (returnCls.isPrimitive()) { - // // 处理char类型 - // if (returnCls == char.class) { - // return ((String)result).charAt(0); - // } - // // 处理其他如int, long, boolean等类型 - // return RestObjectMapper.INSTANCE.readValue((String)result, type); - // } - // else { - // // 处理如String等其他复杂类型 - // // 对于更多处理不了的复杂类型建议使用"application/json" - // return returnCls.getConstructor(new Class[] {String.class}) - // .newInstance((String)result); - // } - } - - @Override - public int getOrder() { - return 0; + if (String.class.equals(type.getRawClass())) { + return IOUtils.toString(input, StandardCharsets.UTF_8); + } + return super.doDecodeResponse(input, type); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/AbstractQueryCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/AbstractQueryCodec.java new file mode 100644 index 00000000000..0ba395bb43f --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/AbstractQueryCodec.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; + +public abstract class AbstractQueryCodec implements QueryCodec { + private final String codecName; + + public AbstractQueryCodec(String codecName) { + this.codecName = codecName; + } + + @Override + public String getCodecName() { + return codecName; + } + + @Override + @SuppressWarnings("unchecked") + public void encode(URLPathStringBuilder builder, String name, Object value) throws Exception { + if (value == null) { + // not write query key to express "null" + return; + } + + if (value.getClass().isArray()) { + if (!(value instanceof Object[])) { + value = RestObjectMapperFactory.getRestObjectMapper() + .convertValue(value, Object[].class); + } + encode(builder, name, Arrays.asList((Object[]) value)); + return; + } + + if (value instanceof Collection) { + encode(builder, name, (Collection) value); + return; + } + + encode(builder, name, Collections.singletonList(value)); + } + + abstract void encode(URLPathStringBuilder builder, String name, Collection values) throws Exception; +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodec.java new file mode 100644 index 00000000000..b9bfd1b7130 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodec.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; +import org.springframework.core.Ordered; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * bigger order will override the same name codec + */ +public interface QueryCodec extends Ordered { + static String encodeValue(Object value) throws UnsupportedEncodingException { + return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8.name()); + } + + // can not be replaced by value.toString() because of date serialize + static String convertToString(Object value) throws Exception { + return RestObjectMapperFactory.getRestObjectMapper().convertToString(value); + } + + @Override + default int getOrder() { + return 0; + } + + String getCodecName(); + + void encode(URLPathStringBuilder builder, String name, Object value) throws Exception; + + Object decode(QueryProcessor processor, HttpServletRequest request); +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsv.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsv.java new file mode 100644 index 00000000000..dd745c54b73 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsv.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +/** + * ?query=x1,x2 + */ +public class QueryCodecCsv extends QueryCodecWithDelimiter { + public static final String CODEC_NAME = "form:0"; + + public static final String DELIMITER = ","; + + public QueryCodecCsv() { + super(CODEC_NAME, DELIMITER, DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMulti.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMulti.java new file mode 100644 index 00000000000..4c2f4287916 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMulti.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Collection; +import java.util.Map; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; + +import jakarta.servlet.http.HttpServletRequest; + +@SuppressWarnings("unchecked") +public class QueryCodecMulti extends AbstractQueryCodec { + public static final String CODEC_NAME = "form:1"; + + public QueryCodecMulti() { + super(CODEC_NAME); + } + + @Override + public void encode(URLPathStringBuilder builder, String name, Collection values) throws Exception { + for (Object value : values) { + if (value == null) { + continue; + } + + String strValue = QueryCodec.convertToString(value); + builder.appendQuery(name, QueryCodec.encodeValue(strValue)); + } + } + + @Override + public Object decode(QueryProcessor processor, HttpServletRequest request) { + if (processor.isRepeatedType()) { + //Even if the paramPath does not exist, value won't be null at now + String[] values = request.getParameterValues(processor.getParameterPath()); + + // compatible to SpringMVC @RequestParam. BODY_PARAMETER is only set for SpringMVC. + if (values == null || values.length == 0) { + Map forms = (Map) request.getAttribute(RestConst.BODY_PARAMETER); + if (forms == null) { + return processor.convertValue(values); + } + Object formValue = forms.get(processor.getParameterPath()); + if (formValue == null) { + return processor.convertValue(values); + } + if (formValue instanceof String[]) { + values = (String[]) formValue; + } else { + values = new String[] {formValue.toString()}; + } + } + return processor.convertValue(values); + } + + Object value = processor.getAndCheckParameter(request); + return processor.convertValue(value); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipes.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipes.java new file mode 100644 index 00000000000..68032f004f4 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipes.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +/** + * ?query=x1|x2 + */ +public class QueryCodecPipes extends QueryCodecWithDelimiter { + public static final String CODEC_NAME = "pipeDelimited:0"; + + public static final String JOIN_DELIMITER = "|"; + + public static final String SPLIT_DELIMITER = "\\|"; + + public QueryCodecPipes() { + super(CODEC_NAME, JOIN_DELIMITER, SPLIT_DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsv.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsv.java new file mode 100644 index 00000000000..514e931d3a0 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsv.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +/** + * ?query=x1%20x2 + */ +public class QueryCodecSsv extends QueryCodecWithDelimiter { + public static final String CODEC_NAME = "spaceDelimited:0"; + + public static final String DELIMITER = " "; + + public QueryCodecSsv() { + super(CODEC_NAME, DELIMITER, DELIMITER); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecWithDelimiter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecWithDelimiter.java new file mode 100644 index 00000000000..f3452bf371e --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecWithDelimiter.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Collection; +import java.util.StringJoiner; + +import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * can not support value with delimiter
+ * a csv example, a collection with two values:
+ * 1. a
+ * 2. b,c
+ * will encode to be a%2Cb%2Cc, this is ambiguous + */ +public class QueryCodecWithDelimiter extends AbstractQueryCodec { + private final String joinDelimiter; + + private final String splitDelimiter; + + public QueryCodecWithDelimiter(String codecName, String joinDelimiter, String splitDelimiter) { + super(codecName); + this.joinDelimiter = joinDelimiter; + this.splitDelimiter = splitDelimiter; + } + + @Override + public void encode(URLPathStringBuilder builder, String name, Collection values) throws Exception { + String joined = join(values); + if (joined == null) { + return; + } + + builder.appendQuery(name, joined); + } + + /** + *
+   *   SwaggerIde:
+   *   1. encode query value by uri rule, not url rule
+   *      part of the difference:
+   *               uri  url
+   *        space  %20  +
+   *        [      [    %5B
+   *      some difference will cause tomcat parse url failed
+   *      so we encode query value by url rule
+   *   2. encode each element
+   *        for pipes, SwaggerIde will encode [a, b] to a|b
+   *        but this will cause problem when run with tomcat
+   *        so we encode the joined value, not encode each element
+   * 
+ * @param values values to be joined + * @return joined value + */ + protected String join(Collection values) throws Exception { + StringJoiner joiner = new StringJoiner(joinDelimiter); + boolean hasValue = false; + for (Object value : values) { + if (value != null) { + String strValue = QueryCodec.convertToString(value); + joiner.add(strValue); + hasValue = true; + } + } + + return hasValue ? QueryCodec.encodeValue(joiner.toString()) : null; + } + + @Override + public Object decode(QueryProcessor processor, HttpServletRequest request) { + Object value = processor.getAndCheckParameter(request); + value = value != null ? value.toString().split(splitDelimiter, -1) : new String[0]; + return processor.convertValue(value); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecs.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecs.java new file mode 100644 index 00000000000..41c5098ef52 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecs.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueryCodecs { + private static final Logger LOGGER = LoggerFactory.getLogger(QueryCodecs.class); + + static QueryCodecs createForTest() { + return new QueryCodecs(Arrays.asList( + new QueryCodecMulti(), + new QueryCodecCsv(), + new QueryCodecSsv(), + new QueryCodecPipes() + )); + } + + private final Map codecs = new HashMap<>(); + + private final QueryCodec defaultCodec; + + public QueryCodecs(List orderedCodecs) { + orderedCodecs.forEach(this::register); + defaultCodec = codecs.get(QueryCodecMulti.CODEC_NAME); + } + + private void register(QueryCodec codec) { + QueryCodec exists = codecs.put(codec.getCodecName(), codec); + if (exists != null) { + LOGGER.info("override QueryCodec, exists={}, new={}.", + exists.getClass().getName(), codec.getClass().getName()); + } + } + + public QueryCodec find(String name) { + if (name == null) { + return defaultCodec; + } + + QueryCodec codec = codecs.get(name); + if (codec == null) { + throw new IllegalStateException("not support QueryCodec, name=" + name); + } + return codec; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsUtils.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsUtils.java new file mode 100644 index 00000000000..4b54210c7a0 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsUtils.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; + +public class QueryCodecsUtils { + // create a default instance, so that more friendly to UT + private static QueryCodecs queryCodecs = QueryCodecs.createForTest(); + + public QueryCodecsUtils(QueryCodecs queryCodecs) { + QueryCodecsUtils.queryCodecs = queryCodecs; + } + + public static QueryCodec find(Parameter.StyleEnum styleEnum, Boolean explode) { + return queryCodecs.find(formatName(styleEnum, explode)); + } + + private static String formatName(StyleEnum styleEnum, Boolean explode) { + if (styleEnum == null) { + return null; + } + return styleEnum + ":" + + (explode != null && explode ? "1" : "0"); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestMetaUtils.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestMetaUtils.java new file mode 100644 index 00000000000..3626d1e59f0 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestMetaUtils.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.definition; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.definition.OperationMeta; + +public final class RestMetaUtils { + private RestMetaUtils() { + } + + public static RestOperationMeta getRestOperationMeta(OperationMeta operationMeta) { + return operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java index a417ef22c6d..580175ec680 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java @@ -17,58 +17,49 @@ package org.apache.servicecomb.common.rest.definition; -import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; +import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator.PartProcessor; import org.apache.servicecomb.common.rest.definition.path.PathRegExp; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder; +import org.apache.servicecomb.common.rest.locator.OperationLocator; import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.Operation; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.Parameter; -import io.vertx.ext.web.impl.MimeTypesUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; +@SuppressWarnings("rawtypes") public class RestOperationMeta { private static final Logger LOGGER = LoggerFactory.getLogger(RestOperationMeta.class); protected OperationMeta operationMeta; - protected List produces; - protected boolean formData; // make sure if response is file protected boolean downloadFile; + protected boolean serverSendEvents; + protected List paramList = new ArrayList<>(); // key为参数名 protected Map paramMap = new LinkedHashMap<>(); - // key为数据类型,比如json之类 - private Map produceProcessorMap = new LinkedHashMap<>(); - - // 不一定等于mgr中的default,因为本operation可能不支持mgr中的default - private ProduceProcessor defaultProcessor; + protected List fileKeys = new ArrayList<>(); protected String absolutePath; @@ -80,44 +71,91 @@ public class RestOperationMeta { public void init(OperationMeta operationMeta) { this.operationMeta = operationMeta; - Swagger swagger = operationMeta.getSchemaMeta().getSwagger(); + OpenAPI swagger = operationMeta.getSchemaMeta().getSwagger(); Operation operation = operationMeta.getSwaggerOperation(); - this.produces = operation.getProduces(); - if (produces == null) { - this.produces = swagger.getProduces(); - } this.downloadFile = checkDownloadFileFlag(); - this.createProduceProcessors(); - - Method method = operationMeta.getMethod(); - Type[] genericParamTypes = method.getGenericParameterTypes(); - if (genericParamTypes.length != operation.getParameters().size()) { - throw new Error("Param count is not equal between swagger and method, path=" + absolutePath - + ";operation=" + operationMeta.getMicroserviceQualifiedName()); + this.serverSendEvents = checkServerSendEvents(); + + if (operation.getParameters() != null) { + for (int swaggerParameterIdx = 0; swaggerParameterIdx < operation.getParameters().size(); swaggerParameterIdx++) { + Parameter parameter = operation.getParameters().get(swaggerParameterIdx); + Type type = operationMeta.getSwaggerProducerOperation() != null ? operationMeta.getSwaggerProducerOperation() + .getSwaggerParameterTypes().get(parameter.getName()) : null; + RestParam param = new RestParam(operationMeta, parameter, type); + addParam(param); + } } - // 初始化所有rest param - for (int idx = 0; idx < genericParamTypes.length; idx++) { - Parameter parameter = operation.getParameters().get(idx); - Type genericParamType = genericParamTypes[idx]; - - if ("formData".equals(parameter.getIn())) { + if (operation.getRequestBody() != null) { + if (isFormParameters(operation)) { formData = true; + Schema formSchema = formSchemas(operation); + if (formSchema != null) { + formSchema.getProperties().forEach((k, v) -> { + addRestParamByName(operationMeta, (String) k, operation); + }); + } + } else { + addRestParamByName(operationMeta, + (String) operation.getRequestBody().getExtensions().get(SwaggerConst.EXT_BODY_NAME), operation); } + } - RestParam param = new RestParam(idx, parameter, genericParamType); - addParam(param); + setAbsolutePath(SwaggerUtils.concatAbsolutePath(swagger, operationMeta.getOperationPath())); + } + + private void addRestParamByName(OperationMeta operationMeta, String name, Operation operation) { + Type type = operationMeta.getSwaggerProducerOperation() != null ? operationMeta.getSwaggerProducerOperation() + .getSwaggerParameterTypes().get(name) : null; + RestParam param = new RestParam(operationMeta, name, operation.getRequestBody(), formData, type); + addParam(param); + } + + private boolean isFormParameters(Operation operation) { + return operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null || + operation.getRequestBody().getContent().get(SwaggerConst.FILE_MEDIA_TYPE) != null; + } + + private Schema formSchemas(Operation operation) { + if (operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + return operation.getRequestBody().getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema(); } + return operation.getRequestBody().getContent().get(SwaggerConst.FILE_MEDIA_TYPE).getSchema(); + } - setAbsolutePath(concatPath(swagger.getBasePath(), operationMeta.getOperationPath())); + public boolean isDownloadFile() { + return downloadFile; + } + + public boolean isServerSendEvents() { + return serverSendEvents; + } + + private boolean checkServerSendEvents() { + ApiResponses responses = operationMeta.getSwaggerOperation().getResponses(); + if (responses == null) { + return false; + } + ApiResponse response = responses.get(SwaggerConst.SUCCESS_KEY); + return response != null && response.getContent() != null + && response.getContent().get(MediaType.SERVER_SENT_EVENTS) != null; } private boolean checkDownloadFileFlag() { - ResponseMeta responseMeta = operationMeta.findResponseMeta(200); - if (responseMeta != null) { - JavaType javaType = responseMeta.getJavaType(); - return javaType.getRawClass().equals(Part.class); + ApiResponses responses = operationMeta.getSwaggerOperation().getResponses(); + if (responses == null) { + return false; + } + ApiResponse response = responses.get(SwaggerConst.SUCCESS_KEY); + if (response != null && response.getContent() != null) { + for (io.swagger.v3.oas.models.media.MediaType mediaType : response.getContent().values()) { + if (mediaType.getSchema() != null + && "string".equals(mediaType.getSchema().getType()) + && "binary".equals(mediaType.getSchema().getFormat())) { + return true; + } + } } return false; } @@ -130,16 +168,6 @@ public void setOperationMeta(OperationMeta operationMeta) { this.operationMeta = operationMeta; } - // 输出b/c/形式的url - private String concatPath(String basePath, String operationPath) { - return ("/" + nonNullify(basePath) + "/" + nonNullify(operationPath) + "/") - .replaceAll("/{2,}", "/"); - } - - private String nonNullify(String path) { - return path == null ? "" : path; - } - public String getAbsolutePath() { return this.absolutePath; } @@ -163,7 +191,7 @@ protected PathRegExp createPathRegExp(String path) { throw new Error("null rest url is not supported"); } try { - return new PathRegExp(path); + return new PathRegExp(OperationLocator.getStandardPath(path)); } catch (Exception e) { LOGGER.error(e.getMessage()); return null; @@ -174,42 +202,10 @@ public RestParam getParamByName(String name) { return paramMap.get(name); } - public RestParam getParamByIndex(int index) { - return paramList.get(index); - } - public OperationMeta getOperationMeta() { return operationMeta; } - // 为operation创建支持的多种produce processor - protected void createProduceProcessors() { - if (null == produces || produces.isEmpty()) { - for (ProduceProcessor processor : ProduceProcessorManager.INSTANCE.values()) { - this.produceProcessorMap.put(processor.getName(), processor); - } - } else { - for (String produce : produces) { - if (produce.contains(";")) { - produce = produce.substring(0, produce.indexOf(";")); - } - ProduceProcessor processor = ProduceProcessorManager.INSTANCE.findValue(produce); - if (processor == null) { - LOGGER.error("produce {} is not supported", produce); - continue; - } - this.produceProcessorMap.put(produce, processor); - } - - if (produceProcessorMap.isEmpty()) { - produceProcessorMap.put(ProduceProcessorManager.DEFAULT_TYPE, ProduceProcessorManager.DEFAULT_PROCESSOR); - } - } - - defaultProcessor = produceProcessorMap.values().stream().findFirst().get(); - produceProcessorMap.putIfAbsent(MediaType.WILDCARD, defaultProcessor); - } - public URLPathBuilder getPathBuilder() { return this.pathBuilder; } @@ -219,46 +215,18 @@ public List getParamList() { } private void addParam(RestParam param) { + if (param.getParamProcessor() instanceof PartProcessor) { + fileKeys.add(param.getParamName()); + } paramList.add(param); paramMap.put(param.getParamName(), param); } - public ProduceProcessor findProduceProcessor(String type) { - return this.produceProcessorMap.get(type); - } - - // 选择与accept匹配的produce processor或者缺省的 - public ProduceProcessor ensureFindProduceProcessor(HttpServletRequestEx requestEx) { - String acceptType = requestEx.getHeader(HttpHeaders.ACCEPT); - return ensureFindProduceProcessor(acceptType); - } - - public ProduceProcessor ensureFindProduceProcessor(String acceptType) { - if (downloadFile) { - //do not check accept type, when the produces of provider is text/plain there will return text/plain processor - //when the produces of provider is application/json there will return the application/json processor - //so do not care what accept type the consumer will set. - return this.produceProcessorMap.get(MediaType.WILDCARD); - } - if (StringUtils.isEmpty(acceptType)) { - return defaultProcessor; - } - List mimeTypes = MimeTypesUtils.getSortedAcceptableMimeTypes(acceptType.toLowerCase(Locale.US)); - for (String mime : mimeTypes) { - ProduceProcessor processor = this.produceProcessorMap.get(mime); - if (null != processor) { - return processor; - } - } - - return null; - } - public String getHttpMethod() { return operationMeta.getHttpMethod(); } - public List getProduces() { - return produces; + public List getFileKeys() { + return fileKeys; } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java index 4a71b0ef6c0..a2b44674c6f 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java @@ -19,16 +19,22 @@ import java.lang.reflect.Type; import java.util.Collection; +import java.util.Map; +import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator; +import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator; import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessor; import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessorCreator; import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessorCreatorManager; +import org.apache.servicecomb.core.definition.OperationMeta; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; +@SuppressWarnings({"rawtypes", "unchecked"}) public class RestParam { private static final JavaType STRING_ARRAY_TYPE = TypeFactory.defaultInstance().constructArrayType(String.class); @@ -36,16 +42,20 @@ public class RestParam { protected String paramName; - // 在args数组中的下标 - protected int paramIndex; - - public RestParam(int paramIndex, Parameter parameter, Type genericParamType) { - this.paramIndex = paramIndex; + public RestParam(OperationMeta operationMeta, Parameter parameter, Type genericParamType) { this.paramName = parameter.getName(); - init(parameter, genericParamType); + init(operationMeta, parameter, genericParamType); } + public RestParam(OperationMeta operationMeta, + String paramName, RequestBody parameter, boolean isForm, Type genericParamType) { + this.paramName = paramName; + + init(operationMeta, parameter, isForm, genericParamType); + } + + public ParamValueProcessor getParamProcessor() { return this.paramProcessor; } @@ -58,26 +68,39 @@ public String getParamName() { return paramName; } - protected void init(Parameter parameter, Type genericParamType) { + protected void init(OperationMeta operationMeta, Parameter parameter, Type genericParamType) { String paramType = parameter.getIn(); - ParamValueProcessorCreator creater = + ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.ensureFindValue(paramType); - this.setParamProcessor(creater.create(parameter, genericParamType)); + this.setParamProcessor(creator.create(operationMeta, parameter.getName(), parameter, genericParamType)); + } + + protected void init(OperationMeta operationMeta, RequestBody parameter, boolean isForm, Type genericParamType) { + ParamValueProcessorCreator creator; + if (isForm) { + creator = + ParamValueProcessorCreatorManager.INSTANCE.ensureFindValue(FormProcessorCreator.PARAMTYPE); + } else { + creator = + ParamValueProcessorCreatorManager.INSTANCE.ensureFindValue(BodyProcessorCreator.PARAM_TYPE); + } + + this.setParamProcessor(creator.create(operationMeta, this.paramName, + parameter, genericParamType)); } - @SuppressWarnings("unchecked") - public T getValue(Object[] args) { - return (T) args[paramIndex]; + public T getValue(Map args) { + return (T) args.get(paramName); } - public String[] getValueAsStrings(Object[] args) { - Object value = args[paramIndex]; + public String[] getValueAsStrings(Map args) { + Object value = args.get(paramName); if (value == null) { return null; } - if (value.getClass().isArray() || Collection.class.isInstance(value)) { + if (value.getClass().isArray() || value instanceof Collection) { return (String[]) paramProcessor.convertValue(value, STRING_ARRAY_TYPE); } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/AbstractUrlParamWriter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/AbstractUrlParamWriter.java index 212d7356f38..d4eca87d86c 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/AbstractUrlParamWriter.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/AbstractUrlParamWriter.java @@ -17,16 +17,23 @@ package org.apache.servicecomb.common.rest.definition.path; +import java.util.Map; + +import com.google.common.annotations.VisibleForTesting; import org.apache.servicecomb.common.rest.definition.RestParam; public abstract class AbstractUrlParamWriter implements UrlParamWriter { protected RestParam param; - public void setParam(RestParam param) { - this.param = param; - } - - protected Object getParamValue(Object[] args) { - return param.getValue(args); + @VisibleForTesting + public Object getParamValue(Map args) { + if (param == null) { + // Wrong server definition + // @GetMapping(path = "/getLocalDateTime/{paramX}") + // public LocalDateTime getLocalDateTimePath(@PathParam("paramY") LocalDateTime date) { + throw new IllegalArgumentException("Path parameter name not valid in provider. Check if provider " + + "path pattern has the parameter name."); + } + return args.get(param.getParamName()); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java index a9950731325..4cd96411fad 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java @@ -17,6 +17,9 @@ package org.apache.servicecomb.common.rest.definition.path; +import java.util.Map; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.common.rest.definition.RestParam; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; import org.apache.servicecomb.foundation.common.http.HttpUtils; @@ -30,9 +33,16 @@ public PathVarParamWriter(RestParam param) { } @Override - public void write(URLPathStringBuilder builder, Object[] args) throws Exception { - String paramValue = getParamValue(args).toString(); - String encodedPathParam = HttpUtils.encodePathParam(paramValue); + public void write(URLPathStringBuilder builder, Map args) throws Exception { + if (getParamValue(args) == null) { + throw new IllegalArgumentException("path parameter can not be null."); + } + String encodedPathParam = encodeNotNullValue(getParamValue(args)); builder.appendPath(encodedPathParam); } + + private String encodeNotNullValue(Object value) throws Exception { + String strValue = RestObjectMapperFactory.getRestObjectMapper().convertToString(value); + return HttpUtils.encodePathParam(strValue); + } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriter.java index db14dfcc4d6..699bc07d66b 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriter.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriter.java @@ -17,96 +17,24 @@ package org.apache.servicecomb.common.rest.definition.path; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; +import java.util.Map; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.common.rest.codec.query.QueryCodec; import org.apache.servicecomb.common.rest.definition.RestParam; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; -import org.apache.servicecomb.swagger.converter.property.SwaggerParamCollectionFormat; public class QueryVarParamWriter extends AbstractUrlParamWriter { - - private SwaggerParamCollectionFormat collectionFormat; + private final QueryCodec queryCodec; public QueryVarParamWriter(RestParam param) { this.param = param; - this.collectionFormat = ((QueryProcessor) param.getParamProcessor()).getCollectionFormat(); + this.queryCodec = ((QueryProcessor) param.getParamProcessor()).getQueryCodec(); } @Override - public void write(URLPathStringBuilder builder, Object[] args) throws Exception { + public void write(URLPathStringBuilder builder, Map args) throws Exception { Object value = getParamValue(args); - if (value == null) { - // do not write query key to express "null" - return; - } - - if (value.getClass().isArray()) { - writeArray(builder, value); - return; - } - - if (Collection.class.isInstance(value)) { - writeCollection(builder, value); - return; - } - - builder.appendQuery(param.getParamName(), encodeNotNullValue(value)); - } - - @SuppressWarnings("unchecked") - private void writeCollection(URLPathStringBuilder builder, Object value) throws Exception { - if (shouldJoinParams()) { - writeJoinedParams(builder, (Collection) value); - return; - } - - for (Object item : (Collection) value) { - writeItem(builder, item); - } - } - - private void writeArray(URLPathStringBuilder builder, Object value) throws Exception { - if (shouldJoinParams()) { - writeJoinedParams(builder, Arrays.asList(((Object[]) value))); - return; - } - - for (Object item : (Object[]) value) { - writeItem(builder, item); - } - } - - private void writeJoinedParams(URLPathStringBuilder builder, Collection value) throws Exception { - String joinedParam = collectionFormat.joinParam(value); - if (null == joinedParam) { - return; - } - builder.appendQuery(param.getParamName(), encodeNotNullValue(joinedParam)); - } - - /** - * Whether to join params with separator. - * For collection format csv/ssv/tsv/pipes - */ - private boolean shouldJoinParams() { - return null != collectionFormat && SwaggerParamCollectionFormat.MULTI != collectionFormat; - } - - private void writeItem(URLPathStringBuilder builder, Object item) throws Exception { - if (null == item) { - return; - } - - builder.appendQuery(param.getParamName(), encodeNotNullValue(item)); - } - - private String encodeNotNullValue(Object value) throws Exception { - String strValue = RestObjectMapperFactory.getRestObjectMapper().convertToString(value); - return URLEncoder.encode(strValue, StandardCharsets.UTF_8.name()); + queryCodec.encode(builder, param.getParamName(), value); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/StaticUrlParamWriter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/StaticUrlParamWriter.java index 315a6778e94..ff9e9658f7b 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/StaticUrlParamWriter.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/StaticUrlParamWriter.java @@ -17,18 +17,20 @@ package org.apache.servicecomb.common.rest.definition.path; +import java.util.Map; + import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; public class StaticUrlParamWriter implements UrlParamWriter { - private String staticPath; + private final String staticPath; public StaticUrlParamWriter(String staticPath) { this.staticPath = staticPath; } @Override - public void write(URLPathStringBuilder builder, Object[] args) { + public void write(URLPathStringBuilder builder, Map args) { builder.appendPath(staticPath); } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilder.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilder.java index 8a948f5584f..a59c904ff41 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilder.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilder.java @@ -29,9 +29,9 @@ */ public class URLPathBuilder { - private List pathParamWriterList = new ArrayList<>(); + private final List pathParamWriterList = new ArrayList<>(); - private List queryParamWriterList = new ArrayList<>(); + private final List queryParamWriterList = new ArrayList<>(); private static final String SLASH = "/"; @@ -42,7 +42,6 @@ public URLPathBuilder(String rawPath, Map paramMap) { private void initQueryWriterList(Map paramMap) { for (RestParam param : paramMap.values()) { - if (!QueryProcessorCreator.PARAMTYPE.equals(param.getParamProcessor().getProcessorType())) { continue; } @@ -53,10 +52,6 @@ private void initQueryWriterList(Map paramMap) { } private void initPathWriterList(String rawPath, Map paramMap) { - // 去掉末尾'/' - if (rawPath.endsWith(SLASH)) { - rawPath = rawPath.substring(0, rawPath.length() - 1); - } // 首部加上'/' if (!rawPath.startsWith(SLASH)) { rawPath = SLASH + rawPath; @@ -71,11 +66,17 @@ private void initPathWriterList(String rawPath, Map paramMap) tmpPath.setLength(0); } } else if (currentChar == '}') { - if (tmpPath.length() != 0) { - RestParam param = paramMap.get(tmpPath.toString()); - this.pathParamWriterList.add(new PathVarParamWriter(param)); - tmpPath.setLength(0); + if (tmpPath.length() == 0) { + continue; + } + String tmpPathStr = tmpPath.toString(); + String pathParamName = tmpPathStr; + if (tmpPathStr.contains(":")) { + pathParamName = tmpPathStr.split(":", 2)[0].trim(); } + RestParam param = paramMap.get(pathParamName); + this.pathParamWriterList.add(new PathVarParamWriter(param)); + tmpPath.setLength(0); } else { tmpPath.append(currentChar); } @@ -85,7 +86,7 @@ private void initPathWriterList(String rawPath, Map paramMap) } } - public String createRequestPath(Object[] args) throws Exception { + public String createRequestPath(Map args) throws Exception { URLPathStringBuilder builder = new URLPathStringBuilder(); genPathString(builder, args); @@ -94,26 +95,26 @@ public String createRequestPath(Object[] args) throws Exception { return builder.build(); } - public String createPathString(Object[] args) throws Exception { + public String createPathString(Map args) throws Exception { URLPathStringBuilder builder = new URLPathStringBuilder(); genPathString(builder, args); return builder.build(); } - private void genPathString(URLPathStringBuilder builder, Object[] args) throws Exception { + private void genPathString(URLPathStringBuilder builder, Map args) throws Exception { for (UrlParamWriter writer : this.pathParamWriterList) { writer.write(builder, args); } } - private void genQueryString(URLPathStringBuilder builder, Object[] args) throws Exception { + private void genQueryString(URLPathStringBuilder builder, Map args) throws Exception { for (UrlParamWriter writer : queryParamWriterList) { writer.write(builder, args); } } public static class URLPathStringBuilder { - private StringBuilder stringBuilder = new StringBuilder(); + private final StringBuilder stringBuilder = new StringBuilder(); private boolean queryPrefixNotWrite = true; @@ -122,7 +123,7 @@ public URLPathStringBuilder appendPath(String s) { return this; } - public URLPathStringBuilder appendQuery(String key, String value) { + public URLPathStringBuilder appendQuery(String name, String encodedValue) { if (queryPrefixNotWrite) { stringBuilder.append('?'); queryPrefixNotWrite = false; @@ -130,7 +131,7 @@ public URLPathStringBuilder appendQuery(String key, String value) { stringBuilder.append('&'); } - stringBuilder.append(key).append("=").append(value); + stringBuilder.append(name).append("=").append(encodedValue); return this; } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/UrlParamWriter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/UrlParamWriter.java index a1a5fa6b32e..21ed73a7340 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/UrlParamWriter.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/UrlParamWriter.java @@ -17,8 +17,10 @@ package org.apache.servicecomb.common.rest.definition.path; +import java.util.Map; + import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; public interface UrlParamWriter { - void write(URLPathStringBuilder builder, Object[] args) throws Exception; + void write(URLPathStringBuilder builder, Map args) throws Exception; } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java deleted file mode 100644 index a139712c14c..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpClientFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.filter; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; - -public interface HttpClientFilter { - default boolean enabled() { - return true; - } - - int getOrder(); - - void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx); - - // if finished, then return a none null response - // if return a null response, then sdk will call next filter.afterReceive - Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx); -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java deleted file mode 100644 index b809660a48a..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.filter; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; - -public interface HttpServerFilter { - int getOrder(); - - default boolean enabled() { - return true; - } - - default boolean needCacheRequest(OperationMeta operationMeta) { - return false; - } - - /** - * @return if finished, then return a none null response
- * if return a null response, then sdk will call next filter.afterReceiveRequest - */ - Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx); - - /** - * @param invocation maybe null - */ - default CompletableFuture beforeSendResponseAsync(Invocation invocation, HttpServletResponseEx responseEx) { - CompletableFuture future = new CompletableFuture<>(); - try { - beforeSendResponse(invocation, responseEx); - future.complete(null); - } catch (Throwable e) { - future.completeExceptionally(e); - } - return future; - } - - /** - * @param invocation maybe null - */ - default void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBeforeSendResponseExecutor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBeforeSendResponseExecutor.java deleted file mode 100644 index 2c6e1f43114..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBeforeSendResponseExecutor.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.filter; - -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; - -public class HttpServerFilterBeforeSendResponseExecutor { - private List httpServerFilters; - - private Invocation invocation; - - private HttpServletResponseEx responseEx; - - private int currentIndex; - - private CompletableFuture future = new CompletableFuture(); - - public HttpServerFilterBeforeSendResponseExecutor(List httpServerFilters, Invocation invocation, - HttpServletResponseEx responseEx) { - this.httpServerFilters = httpServerFilters; - this.invocation = invocation; - this.responseEx = responseEx; - } - - public CompletableFuture run() { - doRun(); - - return future; - } - - protected CompletableFuture safeInvoke(HttpServerFilter httpServerFilter) { - try { - if (httpServerFilter.enabled()) { - return httpServerFilter.beforeSendResponseAsync(invocation, responseEx); - } else { - CompletableFuture eFuture = new CompletableFuture(); - eFuture.complete(null); - return eFuture; - } - } catch (Throwable e) { - CompletableFuture eFuture = new CompletableFuture(); - eFuture.completeExceptionally(e); - return eFuture; - } - } - - protected void doRun() { - if (currentIndex == httpServerFilters.size()) { - future.complete(null); - return; - } - - HttpServerFilter httpServerFilter = httpServerFilters.get(currentIndex); - currentIndex++; - - CompletableFuture stepFuture = safeInvoke(httpServerFilter); - stepFuture.whenComplete((v, e) -> { - if (e == null) { - doRun(); - return; - } - - future.completeExceptionally(e); - }); - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java deleted file mode 100644 index d3a61958793..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ClientRestArgsFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.filter.inner; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.codec.RestCodec; -import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; - -public class ClientRestArgsFilter implements HttpClientFilter { - - @Override - public int getOrder() { - return -100; - } - - @Override - public void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx) { - RestClientRequestImpl restClientRequest = (RestClientRequestImpl) invocation.getHandlerContext() - .get(RestConst.INVOCATION_HANDLER_REQUESTCLIENT); - OperationMeta operationMeta = invocation.getOperationMeta(); - RestOperationMeta swaggerRestOperation = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - try { - RestCodec.argsToRest(invocation.getArgs(), swaggerRestOperation, restClientRequest); - requestEx.setBodyBuffer(restClientRequest.getBodyBuffer()); - } catch (Throwable e) { - throw ExceptionFactory.convertConsumerException(e); - } - } - - @Override - public Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx) { - return null; - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java new file mode 100644 index 00000000000..1d21e9c8bbd --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.filter.inner; + +import static com.google.common.net.HttpHeaders.CONTENT_LENGTH; +import static com.google.common.net.HttpHeaders.TRANSFER_ENCODING; +import static org.apache.servicecomb.core.exception.Exceptions.toProducerResponse; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.common.rest.HttpTransportContext; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.codec.RestCodec; +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.foundation.common.utils.PartUtils; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.context.TransportContext; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; + +public class RestServerCodecFilter extends AbstractFilter implements ProviderFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(RestServerCodecFilter.class); + + public static final String NAME = "rest-server-codec"; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + // almost time, should be the first filter. + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 2000; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.RESTFUL.equals(transport); + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + return CompletableFuture.completedFuture(invocation) + .thenAccept(this::decodeRequest) + .thenCompose(v -> invokeNext(invocation, nextNode)) + .exceptionally(exception -> toProducerResponse(invocation, exception)) + .thenCompose(response -> encodeResponse(invocation, response)); + } + + protected CompletableFuture invokeNext(Invocation invocation, FilterNode nextNode) { + if (invocation.isEdge()) { + TransportContext transportContext = invocation.getTransportContext(); + return nextNode.onFilter(invocation).whenComplete((r, e) -> invocation.setTransportContext(transportContext)); + } + return nextNode.onFilter(invocation); + } + + protected void decodeRequest(Invocation invocation) { + invocation.getInvocationStageTrace().startProviderDecodeRequest(); + HttpServletRequestEx requestEx = invocation.getRequestEx(); + + OperationMeta operationMeta = invocation.getOperationMeta(); + RestOperationMeta restOperationMeta = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); + Map swaggerArguments = RestCodec.restToArgs(requestEx, restOperationMeta); + invocation.setSwaggerArguments(swaggerArguments); + invocation.getInvocationStageTrace().finishProviderDecodeRequest(); + } + + protected CompletableFuture encodeResponse(Invocation invocation, Response response) { + invocation.onEncodeResponseStart(response); + HttpTransportContext transportContext = invocation.getTransportContext(); + HttpServletResponseEx responseEx = transportContext.getResponseEx(); + // TODO: response support JsonView + ProduceProcessor produceProcessor = ProduceProcessorManager.INSTANCE + .createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(), + invocation.getRequestEx().getHeader(HttpHeaders.ACCEPT), null); + + return encodeResponse(invocation, response, produceProcessor, responseEx) + .whenComplete((r, e) -> invocation.onEncodeResponseFinish()); + } + + private static boolean isFailedResponse(Response response) { + return response.getResult() instanceof InvocationException; + } + + private static CompletableFuture writePart( + HttpServletResponseEx responseEx, Object data, Response response) { + CompletableFuture result = new CompletableFuture<>(); + responseEx.sendPart(PartUtils.getSinglePart(null, data)) + .whenComplete((r, e) -> { + if (e != null) { + result.completeExceptionally(e); + return; + } + result.complete(response); + }); + return result; + } + + private static CompletableFuture writeResponse( + HttpServletResponseEx responseEx, ProduceProcessor produceProcessor, Object data, Response response, + boolean commit) { + try (BufferOutputStream output = new BufferOutputStream(Buffer.buffer())) { + produceProcessor.encodeResponse(output, data); + + CompletableFuture result = new CompletableFuture<>(); + responseEx.setBodyBuffer(output.getBuffer()); // For extensions usage + if (commit) { + responseEx.setContentLength(output.getBuffer().length()); + } + responseEx.sendBuffer(output.getBuffer()).whenComplete((v, e) -> { + if (e != null) { + result.completeExceptionally(e); + return; + } + if (!commit) { + try { + responseEx.flushBuffer(); + } catch (IOException ex) { + LOGGER.warn("Failed to flush buffer for Server Send Events", ex); + } + } + result.complete(response); + }); + return result; + } catch (Throwable e) { + LOGGER.error("internal service error must be fixed.", e); + responseEx.setStatus(500); + return CompletableFuture.failedFuture(e); + } + } + + public static CompletableFuture encodeResponse(Invocation invocation, Response response, + ProduceProcessor produceProcessor, HttpServletResponseEx responseEx) { + responseEx.setStatus(response.getStatusCode()); + copyHeadersToHttpResponse(invocation, response.getHeaders(), responseEx); + + if (isFailedResponse(response)) { + responseEx.setContentType(produceProcessor.getName()); + return writeResponse(responseEx, produceProcessor, ((InvocationException) response.getResult()).getErrorData(), + response, true); + } + + if (isDownloadFileResponseType(invocation, response)) { + return writePart(responseEx, response.getResult(), response); + } + + if (isServerSendEvent(response)) { + responseEx.setContentType(produceProcessor.getName()); + return writeServerSendEvent(response, produceProcessor, responseEx); + } + + responseEx.setContentType(produceProcessor.getName()); + return writeResponse(responseEx, produceProcessor, response.getResult(), response, true); + } + + private static CompletableFuture writeServerSendEvent(Response response, ProduceProcessor produceProcessor, + HttpServletResponseEx responseEx) { + responseEx.setChunked(true); + CompletableFuture result = new CompletableFuture<>(); + Publisher publisher = response.getResult(); + publisher.subscribe(new Subscriber() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + s.request(1); + subscription = s; + } + + @Override + public void onNext(Object o) { + writeResponse(responseEx, produceProcessor, o, response, false).whenComplete((r, e) -> { + if (e != null) { + subscription.cancel(); + result.completeExceptionally(e); + return; + } + subscription.request(1); + }); + } + + @Override + public void onError(Throwable t) { + result.completeExceptionally(t); + } + + @Override + public void onComplete() { + result.complete(response); + } + }); + return result; + } + + /** + * Check whether this response is a downloaded file response, + * according to the schema recorded in {@link org.apache.servicecomb.swagger.invocation.response.ResponsesMeta} + * and response status code. + * @return true if this response is a downloaded file, otherwise false. + */ + public static boolean isDownloadFileResponseType(Invocation invocation, Response response) { + return Part.class.isAssignableFrom( + invocation.findResponseType(response.getStatusCode()).getRawClass()); + } + + public static boolean isServerSendEvent(Response response) { + return response.getResult() instanceof Publisher; + } + + public static void copyHeadersToHttpResponse(Invocation invocation, MultiMap headers, + HttpServletResponseEx responseEx) { + if (headers != null) { + headers.remove(CONTENT_LENGTH); + headers.remove(TRANSFER_ENCODING); + for (Entry entry : headers.entries()) { + responseEx.addHeader(entry.getKey(), entry.getValue()); + } + } + + if (invocation != null && responseEx.getHeader(CoreConst.TRACE_ID_NAME) == null) { + responseEx.addHeader(CoreConst.TRACE_ID_NAME, invocation.getTraceId()); + } + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ServerRestArgsFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ServerRestArgsFilter.java deleted file mode 100644 index 6416d7afc17..00000000000 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/ServerRestArgsFilter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.filter.inner; - -import java.util.concurrent.CompletableFuture; - -import javax.servlet.http.Part; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.codec.RestCodec; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -import com.netflix.config.DynamicPropertyFactory; - -import io.netty.buffer.Unpooled; - -public class ServerRestArgsFilter implements HttpServerFilter { - private static final boolean enabled = DynamicPropertyFactory.getInstance().getBooleanProperty - ("servicecomb.http.filter.server.serverRestArgs.enabled", true).get(); - - @Override - public int getOrder() { - return -100; - } - - @Override - public boolean enabled() { - return enabled; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - OperationMeta operationMeta = invocation.getOperationMeta(); - RestOperationMeta restOperationMeta = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - Object[] args = RestCodec.restToArgs(requestEx, restOperationMeta); - invocation.setSwaggerArguments(args); - return null; - } - - @Override - public CompletableFuture beforeSendResponseAsync(Invocation invocation, HttpServletResponseEx responseEx) { - Response response = (Response) responseEx.getAttribute(RestConst.INVOCATION_HANDLER_RESPONSE); - ProduceProcessor produceProcessor = - (ProduceProcessor) responseEx.getAttribute(RestConst.INVOCATION_HANDLER_PROCESSOR); - Object body = response.getResult(); - if (response.isFailed()) { - body = ((InvocationException) body).getErrorData(); - } - - if (Part.class.isInstance(body)) { - return responseEx.sendPart((Part) body); - } - - responseEx.setContentType(produceProcessor.getName() + "; charset=utf-8"); - - CompletableFuture future = new CompletableFuture<>(); - try (BufferOutputStream output = new BufferOutputStream(Unpooled.compositeBuffer())) { - produceProcessor.encodeResponse(output, body); - - responseEx.setBodyBuffer(output.getBuffer()); - future.complete(null); - } catch (Throwable e) { - future.completeExceptionally(ExceptionFactory.convertProducerException(e)); - } - return future; - } -} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/WebSocketServerCodecFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/WebSocketServerCodecFilter.java new file mode 100644 index 00000000000..79e7368520b --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/WebSocketServerCodecFilter.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.filter.inner; + +import static org.apache.servicecomb.core.exception.Exceptions.toProducerResponse; + +import java.util.HashMap; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.common.rest.WebSocketTransportContext; +import org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.context.TransportContext; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.ServerWebSocket; + +public class WebSocketServerCodecFilter extends AbstractFilter implements ProviderFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServerCodecFilter.class); + + public static final String NAME = "websocket-codec"; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + // almost time, should be the first filter. + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 2000; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.WEBSOCKET.equals(transport); + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + return CompletableFuture.completedFuture(invocation) + .thenCompose(this::decodeRequest) + .thenCompose(v -> invokeNext(invocation, nextNode)) + .exceptionally(exception -> toProducerResponse(invocation, exception)) + .thenCompose(response -> encodeResponse(invocation, response)); + } + + protected CompletableFuture invokeNext(Invocation invocation, FilterNode nextNode) { + if (invocation.isEdge()) { + TransportContext transportContext = invocation.getTransportContext(); + return nextNode.onFilter(invocation).whenComplete((r, e) -> invocation.setTransportContext(transportContext)); + } + return nextNode.onFilter(invocation); + } + + protected CompletableFuture decodeRequest(Invocation invocation) { + invocation.getInvocationStageTrace().startProviderDecodeRequest(); + invocation.setSwaggerArguments(new HashMap<>()); // set context parameters and do nothing else. + invocation.getInvocationStageTrace().finishProviderDecodeRequest(); + return CompletableFuture.completedFuture(null); + } + + protected CompletableFuture encodeResponse(Invocation invocation, Response response) { + invocation.onEncodeResponseStart(response); + WebSocketTransportContext context = invocation.getTransportContext(); + + return encodeResponse(response, context.getServerWebSocket()) + .whenComplete((r, e) -> invocation.onEncodeResponseFinish()); + } + + private static boolean isFailedResponse(Response response) { + return response.getResult() instanceof InvocationException; + } + + private static CompletableFuture writeResponse( + ServerWebSocket webSocket, Object data, Response response) { + try (BufferOutputStream output = new BufferOutputStream(Buffer.buffer())) { + ProduceJsonProcessor produceProcessor = new ProduceJsonProcessor(); + produceProcessor.encodeResponse(output, data); + CompletableFuture result = new CompletableFuture<>(); + webSocket.write(output.getBuffer()).onComplete(v -> + result.complete(response), result::completeExceptionally); + + return result; + } catch (Throwable e) { + LOGGER.error("internal service error must be fixed.", e); + return CompletableFuture.failedFuture(e); + } + } + + public static CompletableFuture encodeResponse(Response response, ServerWebSocket webSocket) { + if (isFailedResponse(response)) { + return writeResponse(webSocket, ((InvocationException) response.getResult()).getErrorData(), + response); + } + return CompletableFuture.completedFuture(response); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/MicroservicePaths.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/MicroservicePaths.java index 3be4b366726..3df5c699403 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/MicroservicePaths.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/MicroservicePaths.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,6 +27,7 @@ import org.apache.servicecomb.common.rest.definition.RestOperationComparator; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,14 +41,9 @@ public class MicroservicePaths { // 运行阶段,以path优先级,从高到低排列的operation列表 protected List dynamicPathOperationsList = new ArrayList<>(); - public void cloneTo(MicroservicePaths other) { - other.staticPathOperations.putAll(staticPathOperations); - other.dynamicPathOperationsList.addAll(dynamicPathOperationsList); - } - public void sortPath() { RestOperationComparator comparator = new RestOperationComparator(); - Collections.sort(this.dynamicPathOperationsList, comparator); + this.dynamicPathOperationsList.sort(comparator); } public void addResource(RestOperationMeta swaggerRestOperation) { @@ -63,7 +58,7 @@ public void addResource(RestOperationMeta swaggerRestOperation) { protected void addStaticPathResource(RestOperationMeta operation) { String httpMethod = operation.getHttpMethod(); - String path = operation.getAbsolutePath(); + String path = OperationLocator.getStandardPath(operation.getAbsolutePath()); OperationGroup group = staticPathOperations.get(path); if (group == null) { group = new OperationGroup(); @@ -100,11 +95,12 @@ public void printPaths() { protected void printPath(Collection operations) { for (RestOperationMeta operation : operations) { - LOGGER.info("Swagger mapped \"{[{}], method=[{}], produces={}}\" onto {}", + SwaggerProducerOperation producerOperation = operation.getOperationMeta().getSwaggerProducerOperation(); + + LOGGER.debug("Swagger mapped \"{[{}], method=[{}]}\" onto {}", operation.getAbsolutePath(), operation.getHttpMethod(), - operation.getProduces(), - operation.getOperationMeta().getMethod()); + producerOperation.getProducerMethod()); } } } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/OperationLocator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/OperationLocator.java index 9a088e70d85..4b94cee9e36 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/OperationLocator.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/OperationLocator.java @@ -21,13 +21,13 @@ import java.util.HashMap; import java.util.Map; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.ws.rs.core.Response.Status; + /** * 从path和http method定位到具体的operation */ @@ -107,9 +107,9 @@ protected boolean checkHttpMethod(RestOperationMeta operation, String httpMethod return operation.getHttpMethod().equals(httpMethod); } - // TODO: almost always change path, this make performance lower. - // Path: /a/b/c -> /a/b/c/ - static String getStandardPath(String path) { + // Make path standard in order to build path mapping and find path operation. + // NOTE: Path: /a/b/c -> /a/b/c/. Almost change path every time, this make performance lower. + public static String getStandardPath(String path) { if (path.length() > 0 && !path.endsWith(SLASH)) { path += SLASH; } diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java index 932a81be805..d59d7019bc9 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/locator/ServicePathManager.java @@ -18,25 +18,21 @@ package org.apache.servicecomb.common.rest.locator; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; + /** * 对静态路径和动态路径的operation进行预先处理,加速operation的查询定位 */ public class ServicePathManager { - private static final Logger LOGGER = LoggerFactory.getLogger(ServicePathManager.class); - private static final String REST_PATH_MANAGER = "RestServicePathManager"; protected MicroserviceMeta microserviceMeta; @@ -49,62 +45,34 @@ public class ServicePathManager { // only valid for microservice of this process protected MicroservicePaths producerPaths; - // 已经有哪些schemaId的path信息加进来了 - // 在producer场景中,业务before producer provider事件中将契约注册进来,此时会触发事件,携带注册范围的信息 - // 启动流程的最后阶段,同样会触发一次事件,此时是全量的信息 - // 所以,可能会重复 - protected Set schemaIdSet = new HashSet<>(); - public static ServicePathManager getServicePathManager(MicroserviceMeta microserviceMeta) { return microserviceMeta.getExtData(REST_PATH_MANAGER); } - public void saveToMicroserviceMeta() { - microserviceMeta.putExtData(REST_PATH_MANAGER, this); - } - public ServicePathManager(MicroserviceMeta microserviceMeta) { this.microserviceMeta = microserviceMeta; - } - public MicroserviceMeta getMicroserviceMeta() { - return microserviceMeta; - } + for (SchemaMeta schemaMeta : microserviceMeta.getSchemaMetas().values()) { + addSchema(schemaMeta); + } + sortPath(); - public boolean isSchemaExists(String schemaId) { - return schemaIdSet.contains(schemaId); + microserviceMeta.putExtData(REST_PATH_MANAGER, this); } - public void addSchema(SchemaMeta schemaMeta) { - if (isSchemaExists(schemaMeta.getSchemaId())) { - return; - } - - schemaIdSet.add(schemaMeta.getSchemaId()); - for (OperationMeta operationMeta : schemaMeta.getOperations()) { + private void addSchema(SchemaMeta schemaMeta) { + for (OperationMeta operationMeta : schemaMeta.getOperations().values()) { RestOperationMeta restOperationMeta = new RestOperationMeta(); restOperationMeta.init(operationMeta); operationMeta.putExtData(RestConst.SWAGGER_REST_OPERATION, restOperationMeta); addResource(restOperationMeta); } - - LOGGER.info("add schema to service paths. {}:{}:{}.", - schemaMeta.getMicroserviceMeta().getAppId(), - schemaMeta.getMicroserviceName(), - schemaMeta.getSchemaId()); - } - - public ServicePathManager cloneServicePathManager() { - ServicePathManager mgr = new ServicePathManager(microserviceMeta); - swaggerPaths.cloneTo(mgr.swaggerPaths); - mgr.schemaIdSet.addAll(schemaIdSet); - return mgr; } public OperationLocator consumerLocateOperation(String path, String httpMethod) { String standPath = OperationLocator.getStandardPath(path); OperationLocator locator = new OperationLocator(); - locator.locate(microserviceMeta.getName(), standPath, httpMethod, swaggerPaths); + locator.locate(microserviceMeta.getMicroserviceName(), standPath, httpMethod, swaggerPaths); return locator; } @@ -112,7 +80,7 @@ public OperationLocator consumerLocateOperation(String path, String httpMethod) public OperationLocator producerLocateOperation(String path, String httpMethod) { String standPath = OperationLocator.getStandardPath(path); OperationLocator locator = new OperationLocator(); - locator.locate(microserviceMeta.getName(), standPath, httpMethod, producerPaths); + locator.locate(microserviceMeta.getMicroserviceName(), standPath, httpMethod, producerPaths); return locator; } @@ -126,7 +94,7 @@ public void sortPath() { } public void buildProducerPaths() { - String urlPrefix = System.getProperty(Const.URL_PREFIX); + String urlPrefix = ClassLoaderScopeContext.getClassLoaderScopeProperty(DefinitionConst.URL_PREFIX); if (StringUtils.isEmpty(urlPrefix)) { producerPaths = swaggerPaths; producerPaths.printPaths(); diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/ClassPathStaticResourceHandler.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/ClassPathStaticResourceHandler.java new file mode 100644 index 00000000000..3884d85a86c --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/ClassPathStaticResourceHandler.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.resource; + +import java.io.IOException; +import java.net.URL; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.foundation.common.part.InputStreamPart; + +public class ClassPathStaticResourceHandler extends StaticResourceHandler { + protected Part findResource(String path) throws IOException { + URL url = this.getClass().getClassLoader().getResource(path); + if (url == null) { + return null; + } + + return new InputStreamPart(null, url.openStream()).setSubmittedFileName(path); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/StaticResourceHandler.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/StaticResourceHandler.java new file mode 100644 index 00000000000..a01813fbd70 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/resource/StaticResourceHandler.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.resource; + +import java.io.IOException; +import java.net.URI; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// TODO: LRU cache for small resource in jar? +public abstract class StaticResourceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(StaticResourceHandler.class); + + private String webRoot = "webroot/"; + + public void setWebRoot(String webRoot) { + this.webRoot = webRoot; + } + + protected abstract Part findResource(String path) throws IOException; + + public Response handle(String path) { + path = URI.create(webRoot + path).normalize().getPath(); + if (!path.startsWith(webRoot)) { + // maybe request of attack, just return 404 + return Response.failResp(new InvocationException(Status.NOT_FOUND, Status.NOT_FOUND.getReasonPhrase())); + } + + Part part; + try { + part = findResource(path); + } catch (Throwable e) { + LOGGER.error("failed to process static resource, path={}", path, e); + return Response + .failResp(new InvocationException(Status.INTERNAL_SERVER_ERROR, "failed to process static resource.")); + } + + if (part == null) { + return Response.failResp(new InvocationException(Status.NOT_FOUND, Status.NOT_FOUND.getReasonPhrase())); + } + + return handler(part); + } + + public Response handler(Part part) { + // todo: cache control + Response response = Response.ok(part); + response.setHeader(HttpHeaders.CONTENT_TYPE, part.getContentType()); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline"); + return response; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationItem.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationItem.java new file mode 100644 index 00000000000..d884e49e453 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationItem.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.route; + +import java.util.regex.Pattern; + +public class URLMappedConfigurationItem { + private String microserviceName; + + private String versionRule; + + private int prefixSegmentCount; + + private Pattern pattern; + + private String stringPattern; + + public String getMicroserviceName() { + return microserviceName; + } + + public void setMicroserviceName(String microserviceName) { + this.microserviceName = microserviceName; + } + + public String getVersionRule() { + return versionRule; + } + + public void setVersionRule(String versionRule) { + this.versionRule = versionRule; + } + + public int getPrefixSegmentCount() { + return prefixSegmentCount; + } + + public void setPrefixSegmentCount(int prefixSegmentCount) { + this.prefixSegmentCount = prefixSegmentCount; + } + + public Pattern getPattern() { + return pattern; + } + + public void setPattern(Pattern pattern) { + this.pattern = pattern; + } + + public String getStringPattern() { + return stringPattern; + } + + public void setStringPattern(String stringPattern) { + this.stringPattern = stringPattern; + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationLoader.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationLoader.java new file mode 100644 index 00000000000..5c3df2c3355 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/URLMappedConfigurationLoader.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.route; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.ConfigUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; + +public class URLMappedConfigurationLoader { + private static final Logger LOG = LoggerFactory.getLogger(URLMappedConfigurationLoader.class); + + private static final String KEY_MAPPING_PATH = ".path"; + + private static final String KEY_MAPPING_SERVICE_NAME = "%s.%s.microserviceName"; + + private static final String KEY_MAPPING_VERSION_RULE = "%s.%s.versionRule"; + + private static final String KEY_MAPPING_PREFIX_SEGMENT_COUNT = "%s.%s.prefixSegmentCount"; + + public static Map loadConfigurations( + Environment environment, String configPrefix) { + Map configurations = new HashMap<>(); + Set configsItems = ConfigUtil.propertiesWithPrefix((ConfigurableEnvironment) environment, configPrefix); + for (String pathKey : configsItems) { + if (pathKey.endsWith(KEY_MAPPING_PATH)) { + URLMappedConfigurationItem configurationItem = new URLMappedConfigurationItem(); + String pattern = environment.getProperty(pathKey); + if (StringUtils.isEmpty(pattern)) { + continue; + } + configurationItem.setPattern(Pattern.compile(pattern)); + configurationItem.setStringPattern(pattern); + String pathKeyItem = pathKey + .substring(configPrefix.length() + 1, pathKey.length() - KEY_MAPPING_PATH.length()); + configurationItem.setMicroserviceName(environment.getProperty( + String.format(KEY_MAPPING_SERVICE_NAME, configPrefix, pathKeyItem))); + if (StringUtils.isEmpty(configurationItem.getMicroserviceName())) { + continue; + } + configurationItem.setPrefixSegmentCount(environment.getProperty( + String.format(KEY_MAPPING_PREFIX_SEGMENT_COUNT, configPrefix, pathKeyItem), int.class, 0)); + configurationItem.setVersionRule(environment.getProperty( + String.format(KEY_MAPPING_VERSION_RULE, configPrefix, pathKeyItem), "0.0.0+")); + configurations.put(pathKeyItem, configurationItem); + } + } + logConfigurations(configurations); + return configurations; + } + + private static void logConfigurations(Map configurations) { + configurations.forEach((key, item) -> LOG.info("config item: key=" + key + ";pattern=" + item.getStringPattern() + + ";service=" + item.getMicroserviceName() + ";versionRule=" + item.getVersionRule())); + } +} diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/Utils.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/Utils.java new file mode 100644 index 00000000000..0e1f64291c9 --- /dev/null +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/route/Utils.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.route; + +/** + * Commonly used methods in this package. + */ +public final class Utils { + private Utils() { + + } + + /** + * Get the actual path without prefix + * @param path full path + * @param pathIndex the index of / that after prefix + * @return actual path + */ + public static String findActualPath(String path, int pathIndex) { + if (pathIndex <= 0) { + return path; + } + + int fromIndex = 0; + int counter = pathIndex; + char[] chars = path.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '/') { + if (--counter < 0) { + fromIndex = i; + break; + } + } + } + return fromIndex > 0 ? path.substring(fromIndex) : ""; + } +} diff --git a/common/common-rest/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/common/common-rest/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module new file mode 100644 index 00000000000..65a6c38a587 --- /dev/null +++ b/common/common-rest/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.foundation.common.utils.json.PartModule diff --git a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor index 9353b9dce7c..c13dc4dac85 100644 --- a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor +++ b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor @@ -16,4 +16,4 @@ # org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor -org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor \ No newline at end of file +org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor diff --git a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter deleted file mode 100644 index 6fccbe3e684..00000000000 --- a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.common.rest.filter.inner.ClientRestArgsFilter \ No newline at end of file diff --git a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter deleted file mode 100644 index 13ee39be868..00000000000 --- a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.common.rest.filter.inner.ServerRestArgsFilter diff --git a/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider new file mode 100644 index 00000000000..94be435a96b --- /dev/null +++ b/common/common-rest/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.common.rest.filter.RestFilterProvider diff --git a/common/common-rest/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/common-rest/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..8784e8798e8 --- /dev/null +++ b/common/common-rest/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.common.rest.CommonRestConfiguration diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java new file mode 100644 index 00000000000..50b3e8329d5 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest; + +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; +import static org.apache.servicecomb.common.rest.RestConst.DECODE_INVOCATION_CONTEXT; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.common.rest.locator.OperationLocator; +import org.apache.servicecomb.common.rest.locator.ServicePathManager; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.SCBStatus; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import io.vertx.core.json.Json; +import io.vertx.ext.web.RoutingContext; + +public class RestProducerInvocationCreatorTest { + + final RoutingContext routingContext = Mockito.mock(RoutingContext.class); + + final MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + + final ServicePathManager servicePathManager = Mockito.mock(ServicePathManager.class); + + final RestOperationMeta restOperationMeta = Mockito.mock(RestOperationMeta.class); + + final Endpoint endpoint = Mockito.mock(Endpoint.class); + + final HttpServletRequestEx requestEx = Mockito.mock(HttpServletRequestEx.class); + + final HttpServletResponseEx responseEx = Mockito.mock(HttpServletResponseEx.class); + + final OperationLocator locator = Mockito.mock(OperationLocator.class); + + final InvocationRuntimeType invocationRuntimeType = Mockito.mock(InvocationRuntimeType.class); + + final OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + + final SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + + RestProducerInvocationCreator creator; + + static SCBEngine engine; + + static Environment environment; + + @BeforeAll + public static void beforeClass() { + environment = Mockito.mock(Environment.class); + engine = SCBBootstrap.createSCBEngineForTest(environment); + engine.setStatus(SCBStatus.UP); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + engine.setEnvironment(environment); + } + + @AfterAll + public static void afterClass() { + engine.destroy(); + } + + @BeforeEach + public void setUp() { + creator = new RestVertxProducerInvocationCreator(routingContext, microserviceMeta, endpoint, + requestEx, responseEx); + creator = Mockito.spy(creator); + } + + @Test + public void should_failed_when_not_defined_any_schema() { + try (MockedStatic mockedStatic = Mockito.mockStatic(ServicePathManager.class)) { + mockedStatic.when(() -> ServicePathManager.getServicePathManager(null)).thenReturn(servicePathManager); + + InvocationException throwable = (InvocationException) catchThrowable(() -> creator.createAsync().join()); + CommonExceptionData data = (CommonExceptionData) throwable.getErrorData(); + + assertThat(throwable.getStatusCode()).isEqualTo(NOT_FOUND.getStatusCode()); + assertThat(Json.encode(data)).isIn("{\"code\":\"SCB.00000002\",\"message\":\"Not Found\"}", + "{\"message\":\"Not Found\",\"code\":\"SCB.00000002\"}"); + } + } + + @Test + public void should_save_requestEx_in_invocation_context() { + try (MockedStatic mockedStatic = Mockito.mockStatic(ServicePathManager.class)) { + mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)) + .thenReturn(servicePathManager); + Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator); + Mockito.when(locator.getOperation()).thenReturn(restOperationMeta); + Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType); + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + + Invocation invocation = creator.createAsync().join(); + + Object request = invocation.getLocalContext(RestConst.REST_REQUEST); + assertThat(request).isSameAs(requestEx); + } + } + + @Test + public void should_save_path_var_map_in_requestEx() { + try (MockedStatic mockedStatic = Mockito.mockStatic(ServicePathManager.class)) { + mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)) + .thenReturn(servicePathManager); + Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator); + Mockito.when(locator.getOperation()).thenReturn(restOperationMeta); + Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType); + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + + creator.createAsync().join(); + + Mockito.verify(requestEx, Mockito.times(1)).setAttribute(Mockito.eq(RestConst.PATH_PARAMETERS), Mockito.any()); + } + } + + @Test + public void should_merge_invocation_context_from_request() { + Mockito.when(environment.getProperty(DECODE_INVOCATION_CONTEXT, boolean.class, true)) + .thenReturn(true); + try (MockedStatic mockedStatic = Mockito.mockStatic(ServicePathManager.class)) { + mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)) + .thenReturn(servicePathManager); + Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator); + Mockito.when(locator.getOperation()).thenReturn(restOperationMeta); + Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType); + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + Mockito.when(requestEx.getHeader(CoreConst.CSE_CONTEXT)).thenReturn("{\"k\":\"v\"}"); + + Invocation invocation = creator.createAsync().join(); + + assertThat(invocation.getContext("k")).isEqualTo("v"); + } + } + + @Test + public void should_not_merge_invocation_context_from_request() { + Mockito.when(environment.getProperty(DECODE_INVOCATION_CONTEXT, boolean.class, true)) + .thenReturn(false); + try (MockedStatic mockedStatic = Mockito.mockStatic(ServicePathManager.class)) { + mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)) + .thenReturn(servicePathManager); + Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator); + Mockito.when(locator.getOperation()).thenReturn(restOperationMeta); + Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType); + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + Mockito.when(requestEx.getHeader(CoreConst.CSE_CONTEXT)).thenReturn("{\"k\":\"v\"}"); + + Invocation invocation = creator.createAsync().join(); + + assertThat(invocation.getContext("k")).isNull(); + } + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java deleted file mode 100644 index 958fbef7d61..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestAbstractRestInvocation.java +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.filter.HttpServerFilterBaseForTest; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.event.InvocationStartEvent; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; -import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletResponse; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.HttpStatus; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.Headers; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import io.vertx.core.buffer.Buffer; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestAbstractRestInvocation { - @Mocked - HttpServletRequestEx requestEx; - - @Mocked - HttpServletResponseEx responseEx; - - @Mocked - ReferenceConfig endpoint; - - @Mocked - SchemaMeta schemaMeta; - - @Mocked - OperationMeta operationMeta; - - @Mocked - RestOperationMeta restOperation; - - @Mocked - Object[] swaggerArguments; - - Invocation invocation; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - class AbstractHttpServletRequestForTest extends AbstractHttpServletRequest { - @Override - public String getHeader(String name) { - return null; - } - } - - class AbstractRestInvocationForTest extends AbstractRestInvocation { - @Override - protected OperationLocator locateOperation(ServicePathManager servicePathManager) { - return null; - } - - @Override - protected void createInvocation() { - this.invocation = TestAbstractRestInvocation.this.invocation; - } - } - - AbstractRestInvocation restInvocation = new AbstractRestInvocationForTest(); - - static long nanoTime = 123; - - @BeforeClass - public static void classSetup() { - EventManager.eventBus = new EventBus(); - SCBEngine.getInstance().setStatus(SCBStatus.UP); - - new MockUp() { - @Mock - long nanoTime() { - return nanoTime; - } - }; - } - - @AfterClass - public static void classTeardown() { - EventManager.eventBus = new EventBus(); - SCBEngine.getInstance().setStatus(SCBStatus.DOWN); - } - - @Before - public void setup() { - invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - - initRestInvocation(); - List httpServerFilters = SPIServiceUtils.getSortedService(HttpServerFilter.class); - restInvocation.setHttpServerFilters(httpServerFilters); - } - - private void initRestInvocation() { - restInvocation.produceProcessor = ProduceProcessorManager.JSON_PROCESSOR; - restInvocation.requestEx = requestEx; - restInvocation.responseEx = responseEx; - restInvocation.invocation = invocation; - restInvocation.restOperationMeta = restOperation; - } - - @Test - public void setHttpServerFilters(@Mocked List httpServerFilters) { - restInvocation.setHttpServerFilters(httpServerFilters); - - Assert.assertSame(httpServerFilters, restInvocation.httpServerFilters); - } - - @Test - public void initProduceProcessorNull() { - new Expectations() { - { - restOperation.ensureFindProduceProcessor(requestEx); - result = null; - } - }; - - restInvocation = new AbstractRestInvocationForTest() { - @Override - public void sendFailResponse(Throwable throwable) { - } - }; - initRestInvocation(); - - try { - restInvocation.initProduceProcessor(); - Assert.fail("must throw exception"); - } catch (InvocationException e) { - assertEquals(Status.NOT_ACCEPTABLE, e.getStatus()); - assertEquals("Accept null is not supported", ((CommonExceptionData) e.getErrorData()).getMessage()); - } - } - - @Test - public void initProduceProcessorNormal() { - new Expectations() { - { - restOperation.ensureFindProduceProcessor(requestEx); - result = ProduceProcessorManager.JSON_PROCESSOR; - } - }; - - // not throw exception - restInvocation.initProduceProcessor(); - } - - @Test - public void setContextNull() throws Exception { - new Expectations() { - { - requestEx.getHeader(Const.CSE_CONTEXT); - result = null; - } - }; - - Map context = invocation.getContext(); - restInvocation.setContext(); - Assert.assertSame(context, invocation.getContext()); - } - - @Test - public void setContextEmpty() throws Exception { - new Expectations() { - { - requestEx.getHeader(Const.CSE_CONTEXT); - result = ""; - } - }; - - Map context = invocation.getContext(); - restInvocation.setContext(); - Assert.assertSame(context, invocation.getContext()); - } - - @Test - public void setContextNormal() throws Exception { - Map context = new HashMap<>(); - context.put("name", "value"); - new Expectations() { - { - requestEx.getHeader(Const.CSE_CONTEXT); - result = JsonUtils.writeValueAsString(context); - } - }; - - restInvocation.setContext(); - Assert.assertThat(invocation.getContext().size(), Matchers.is(1)); - Assert.assertThat(invocation.getContext(), Matchers.hasEntry("name", "value")); - } - - @Test - public void setContextTraceId() throws Exception { - Map context = new HashMap<>(); - new Expectations() { - { - requestEx.getHeader(Const.CSE_CONTEXT); - result = JsonUtils.writeValueAsString(context); - } - }; - invocation.addContext("X-B3-traceId", "value1"); - //if request has no traceId, use invocation's traceId - restInvocation.setContext(); - Assert.assertThat(invocation.getContext().size(), Matchers.is(1)); - Assert.assertThat(invocation.getContext(), Matchers.hasEntry("X-B3-traceId", "value1")); - - context.put("X-B3-traceId", "value2"); - new Expectations() { - { - requestEx.getHeader(Const.CSE_CONTEXT); - result = JsonUtils.writeValueAsString(context); - } - }; - //if request has traceId, use request's traceId - restInvocation.setContext(); - Assert.assertThat(invocation.getContext().size(), Matchers.is(1)); - Assert.assertThat(invocation.getContext(), Matchers.hasEntry("X-B3-traceId", "value2")); - } - - @Test - public void getContext() { - invocation.addContext("key", "test"); - assertEquals("test", restInvocation.getContext("key")); - } - - @Test - public void getContextNull() { - Assert.assertNull(restInvocation.getContext("key")); - } - - @Test - public void invokeFilterHaveResponse(@Mocked HttpServerFilter filter) { - Response response = Response.ok(""); - new Expectations() { - { - filter.enabled(); - result = true; - filter.afterReceiveRequest(invocation, requestEx); - result = response; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - result.value = Response.ok("not run to here"); - } - - @Override - protected void sendResponseQuietly(Response response) { - result.value = response; - } - }; - initRestInvocation(); - restInvocation.httpServerFilters = Arrays.asList(filter); - - restInvocation.invoke(); - - Assert.assertSame(response, result.value); - } - - @Test - public void invokeFilterNoResponse(@Mocked HttpServerFilter filter) { - new Expectations() { - { - filter.enabled(); - result = true; - filter.afterReceiveRequest(invocation, requestEx); - result = null; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - result.value = true; - } - }; - initRestInvocation(); - restInvocation.httpServerFilters = Arrays.asList(filter); - - restInvocation.invoke(); - - Assert.assertTrue(result.value); - } - - @Test - public void invokeFilterNoResponseDisableFilter(@Mocked HttpServerFilter filter) { - new Expectations() { - { - filter.enabled(); - result = false; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - result.value = true; - } - }; - initRestInvocation(); - restInvocation.httpServerFilters = Arrays.asList(filter); - - restInvocation.invoke(); - - Assert.assertTrue(result.value); - } - - @Test - public void invokeFilterException(@Mocked HttpServerFilter filter) { - Error error = new Error(); - new Expectations() { - { - filter.enabled(); - result = true; - filter.afterReceiveRequest(invocation, requestEx); - result = error; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - public void sendFailResponse(Throwable throwable) { - result.value = throwable; - } - - @Override - protected void doInvoke() { - - } - }; - initRestInvocation(); - restInvocation.httpServerFilters = Arrays.asList(filter); - - restInvocation.invoke(); - - Assert.assertSame(error, result.value); - } - - @Test - public void invokeNormal(@Mocked HttpServerFilter filter) { - new Expectations() { - { - filter.enabled(); - result = true; - filter.afterReceiveRequest(invocation, requestEx); - result = null; - } - }; - - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - } - - @Override - public void sendFailResponse(Throwable throwable) { - Assert.fail("must not fail"); - } - }; - initRestInvocation(); - restInvocation.httpServerFilters = Arrays.asList(filter); - - restInvocation.invoke(); - - assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartServerFiltersRequest()); - } - - @Test - public void sendFailResponseNoProduceProcessor() { - restInvocation.produceProcessor = null; - restInvocation.sendFailResponse(new Error()); - - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, restInvocation.produceProcessor); - } - - @Test - public void sendFailResponseHaveProduceProcessor() { - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - } - - @Override - protected void sendResponseQuietly(Response response) { - result.value = response; - } - }; - initRestInvocation(); - restInvocation.produceProcessor = ProduceProcessorManager.PLAIN_PROCESSOR; - - Throwable e = new InvocationException(Status.BAD_GATEWAY, ""); - restInvocation.sendFailResponse(e); - Assert.assertSame(e, result.value.getResult()); - Assert.assertSame(ProduceProcessorManager.PLAIN_PROCESSOR, restInvocation.produceProcessor); - } - - @Test - public void sendResponseQuietlyNormal(@Mocked Response response) { - Holder eventHolder = new Holder<>(); - Object subscriber = new Object() { - @Subscribe - public void onFinished(InvocationFinishEvent event) { - eventHolder.value = event; - } - }; - EventManager.register(subscriber); - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - } - - @Override - protected void sendResponse(Response response) { - result.value = response; - super.sendResponse(response); - } - }; - initRestInvocation(); - - restInvocation.sendResponseQuietly(response); - - EventManager.unregister(subscriber); - - Assert.assertSame(invocation, eventHolder.value.getInvocation()); - Assert.assertSame(response, result.value); - } - - @Test - public void sendResponseQuietlyException(@Mocked Response response) { - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - } - - @Override - protected void sendResponse(Response response) { - throw new Error(""); - } - }; - initRestInvocation(); - - restInvocation.sendResponseQuietly(response); - - // just log, check nothing - } - - @Test - public void sendResponseQuietlyExceptionOnNullInvocation(@Mocked Response response) { - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void doInvoke() { - } - - @Override - protected void sendResponse(Response response) { - throw new Error(""); - } - }; - initRestInvocation(); - restInvocation.invocation = null; - - restInvocation.sendResponseQuietly(response); - - // just log, check nothing, and should not throw NPE - } - - @Test - public void executeHttpServerFiltersNullInvocation(@Mocked Response response) { - Holder flag = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void onExecuteHttpServerFiltersFinish(Response response, Throwable e) { - super.onExecuteHttpServerFiltersFinish(response, e); - flag.value = true; - } - }; - initRestInvocation(); - restInvocation.invocation = null; - - restInvocation.executeHttpServerFilters(response); - - Assert.assertTrue(flag.value); - } - - @Test - public void sendResponseStatusAndContentTypeAndHeader(@Mocked Response response) { - new Expectations() { - { - response.getStatusCode(); - result = 123; - response.getReasonPhrase(); - result = "reason"; - response.getResult(); - result = "result"; - } - }; - - Map result = new HashMap<>(); - responseEx = new MockUp() { - private Map attributes = new HashMap<>(); - - @Mock - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); - } - - @Mock - public Object getAttribute(String key) { - return this.attributes.get(key); - } - - @Mock - void setStatus(int sc, String sm) { - result.put("statusCode", sc); - result.put("reasonPhrase", sm); - } - - @Mock - void setContentType(String type) { - result.put("contentType", type); - } - }.getMockInstance(); - - Map expected = new HashMap<>(); - expected.put("statusCode", 123); - expected.put("reasonPhrase", "reason"); - expected.put("contentType", "application/json; charset=utf-8"); - - initRestInvocation(); - - restInvocation.sendResponse(response); - assertEquals(expected, result); - } - - @Test - public void testDoSendResponseHeaderNull(@Mocked Response response) { - Headers headers = new Headers(); - - new Expectations() { - { - response.getResult(); - result = new Error("stop"); - response.getHeaders(); - result = headers; - } - }; - - Headers resultHeaders = new Headers(); - responseEx = new MockUp() { - private Map attributes = new HashMap<>(); - - @Mock - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); - } - - @Mock - public Object getAttribute(String key) { - return this.attributes.get(key); - } - - @Mock - void addHeader(String name, String value) { - resultHeaders.addHeader(name, value); - } - }.getMockInstance(); - - initRestInvocation(); - - try { - restInvocation.sendResponse(response); - Assert.fail("must throw exception"); - } catch (Error e) { - Assert.assertNull(resultHeaders.getHeaderMap()); - } - } - - @Test - public void testDoSendResponseHeaderNormal(@Mocked Response response) { - Headers headers = new Headers(); - headers.addHeader("h1", "h1v1"); - headers.addHeader("h1", "h1v2"); - headers.addHeader("h2", "h2v"); - - new Expectations() { - { - response.getResult(); - result = new Error("stop"); - response.getHeaders(); - result = headers; - } - }; - - Headers resultHeaders = new Headers(); - responseEx = new MockUp() { - private Map attributes = new HashMap<>(); - - @Mock - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); - } - - @Mock - public Object getAttribute(String key) { - return this.attributes.get(key); - } - - @Mock - void addHeader(String name, String value) { - resultHeaders.addHeader(name, value); - } - }.getMockInstance(); - initRestInvocation(); - - try { - restInvocation.sendResponse(response); - Assert.fail("must throw exception"); - } catch (Error e) { - assertEquals(headers.getHeaderMap(), resultHeaders.getHeaderMap()); - } - } - - @Test - public void testDoSendResponseResultOK(@Mocked Response response) { - new Expectations() { - { - response.getResult(); - result = "ok"; - } - }; - - Buffer buffer = Buffer.buffer(); - responseEx = new MockUp() { - private Map attributes = new HashMap<>(); - - @Mock - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); - } - - @Mock - public Object getAttribute(String key) { - return this.attributes.get(key); - } - - @Mock - void setBodyBuffer(Buffer bodyBuffer) { - buffer.appendBuffer(bodyBuffer); - } - }.getMockInstance(); - initRestInvocation(); - - restInvocation.sendResponse(response); - assertEquals("\"ok\"", buffer.toString()); - assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishServerFiltersResponse()); - } - - @Test - public void testDoSendResponseResultOKFilter(@Mocked Response response) { - Headers headers = new Headers(); - headers.addHeader("Content-Type", "application/json"); - new Expectations() { - { - response.getHeaders(); - result = headers; - response.getStatusCode(); - result = 123; - response.getReasonPhrase(); - result = "reason"; - response.getResult(); - result = "ok"; - } - }; - - Buffer buffer = Buffer.buffer(); - responseEx = new MockUp() { - private Map attributes = new HashMap<>(); - - @Mock - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); - } - - @Mock - public Object getAttribute(String key) { - return this.attributes.get(key); - } - - @Mock - void setBodyBuffer(Buffer bodyBuffer) { - buffer.appendBuffer(bodyBuffer); - } - }.getMockInstance(); - - HttpServerFilter filter = new HttpServerFilterBaseForTest() { - @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - buffer.appendString("-filter"); - } - }; - - initRestInvocation(); - List httpServerFilters = SPIServiceUtils.loadSortedService(HttpServerFilter.class); - httpServerFilters.add(filter); - restInvocation.setHttpServerFilters(httpServerFilters); - - restInvocation.sendResponse(response); - assertEquals("\"ok\"-filter", buffer.toString()); - } - - @Test - public void findRestOperationServicePathManagerNull(@Mocked MicroserviceMeta microserviceMeta) { - new Expectations(ServicePathManager.class) { - { - requestEx.getHeader(Const.TARGET_MICROSERVICE); - result = "ms"; - ServicePathManager.getServicePathManager(microserviceMeta); - result = null; - } - }; - - expectedException.expect(InvocationException.class); - expectedException.expectMessage("CommonExceptionData [message=Not Found]"); - restInvocation.findRestOperation(microserviceMeta); - } - - @Test - public void findRestOperationNormal(@Mocked MicroserviceMeta microserviceMeta, - @Mocked ServicePathManager servicePathManager, @Mocked OperationLocator locator) { - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected OperationLocator locateOperation(ServicePathManager servicePathManager) { - return locator; - } - }; - - requestEx = new AbstractHttpServletRequest() { - }; - restInvocation.requestEx = requestEx; - Map pathVars = new HashMap<>(); - new Expectations(ServicePathManager.class) { - { - ServicePathManager.getServicePathManager(microserviceMeta); - result = servicePathManager; - locator.getPathVarMap(); - result = pathVars; - locator.getOperation(); - result = restOperation; - } - }; - - restInvocation.findRestOperation(microserviceMeta); - Assert.assertSame(restOperation, restInvocation.restOperationMeta); - Assert.assertSame(pathVars, requestEx.getAttribute(RestConst.PATH_PARAMETERS)); - } - - @Test - public void scheduleInvocationException(@Mocked OperationMeta operationMeta) { - Executor executor = new ReactiveExecutor(); - requestEx = new AbstractHttpServletRequestForTest(); - requestEx.setAttribute(RestConst.REST_REQUEST, requestEx); - new Expectations() { - { - restOperation.getOperationMeta(); - result = operationMeta; - operationMeta.getExecutor(); - result = executor; - } - }; - - Holder result = new Holder<>(); - Error error = new Error("run on executor"); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void runOnExecutor() { - throw error; - } - - @Override - public void sendFailResponse(Throwable throwable) { - result.value = throwable; - } - }; - restInvocation.requestEx = requestEx; - restInvocation.restOperationMeta = restOperation; - - restInvocation.scheduleInvocation(); - - Assert.assertSame(error, result.value); - } - - @Test - public void scheduleInvocationTimeout(@Mocked OperationMeta operationMeta) { - Executor executor = Runnable::run; - - new Expectations() { - { - restOperation.getOperationMeta(); - result = operationMeta; - operationMeta.getExecutor(); - result = executor; - operationMeta.getMicroserviceQualifiedName(); - result = "sayHi"; - } - }; - - requestEx = new AbstractHttpServletRequestForTest(); - - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void runOnExecutor() { - throw new Error("run on executor"); - } - - @Override - public void sendFailResponse(Throwable throwable) { - throw (Error) throwable; - } - }; - restInvocation.requestEx = requestEx; - restInvocation.restOperationMeta = restOperation; - - // will not throw exception - restInvocation.scheduleInvocation(); - } - - @Test - public void scheduleInvocationNormal(@Mocked OperationMeta operationMeta) { - Holder eventHolder = new Holder<>(); - Object subscriber = new Object() { - @Subscribe - public void onStart(InvocationStartEvent event) { - eventHolder.value = event; - } - }; - EventManager.register(subscriber); - - Executor executor = new ReactiveExecutor(); - requestEx = new AbstractHttpServletRequestForTest(); - requestEx.setAttribute(RestConst.REST_REQUEST, requestEx); - new Expectations(requestEx) { - { - restOperation.getOperationMeta(); - result = operationMeta; - operationMeta.getExecutor(); - result = executor; - requestEx.getHeader(Const.TRACE_ID_NAME); - result = "tid"; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void runOnExecutor() { - result.value = true; - } - }; - restInvocation.requestEx = requestEx; - restInvocation.restOperationMeta = restOperation; - - restInvocation.scheduleInvocation(); - EventManager.unregister(subscriber); - - Assert.assertTrue(result.value); - assertEquals(nanoTime, invocation.getInvocationStageTrace().getStart()); - assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartSchedule()); - Assert.assertSame(invocation, eventHolder.value.getInvocation()); - assertEquals("tid", invocation.getTraceId()); - } - - @Test - public void runOnExecutor() { - long time = 123; - new MockUp() { - @Mock - long nanoTime() { - return time; - } - }; - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - public void invoke() { - result.value = true; - } - }; - restInvocation.createInvocation(); - restInvocation.requestEx = requestEx; - restInvocation.restOperationMeta = restOperation; - - restInvocation.runOnExecutor(); - - Assert.assertTrue(result.value); - Assert.assertSame(invocation, restInvocation.invocation); - assertEquals(time, invocation.getInvocationStageTrace().getStartExecution()); - } - - @Test - public void doInvoke(@Mocked Endpoint endpoint, @Mocked OperationMeta operationMeta, - @Mocked Object[] swaggerArguments, @Mocked SchemaMeta schemaMeta) throws Throwable { - Response response = Response.ok("ok"); - Handler handler = (invocation, asyncResp) -> asyncResp.complete(response); - List handlerChain = Arrays.asList(handler); - Deencapsulation.setField(invocation, "handlerList", handlerChain); - - Holder result = new Holder<>(); - restInvocation = new AbstractRestInvocationForTest() { - @Override - protected void sendResponse(Response response) { - result.value = response; - } - }; - restInvocation.invocation = invocation; - - restInvocation.doInvoke(); - - Assert.assertSame(response, result.value); - assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartHandlersRequest()); - assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishHandlersResponse()); - } - - @Test - public void scheduleInvocation_invocationContextDeserializeError() { - requestEx = new AbstractHttpServletRequest() { - @Override - public String getHeader(String name) { - return "{\"x-cse-src-microservice\":'source\"}"; - } - }; - Holder status = new Holder<>(); - Holder reasonPhrase = new Holder<>(); - Holder endCount = new Holder<>(0); - responseEx = new AbstractHttpServletResponse() { - @SuppressWarnings("deprecation") - @Override - public void setStatus(int sc, String sm) { - status.value = sc; - reasonPhrase.value = sm; - } - - @Override - public void flushBuffer() { - endCount.value = endCount.value + 1; - } - - @Override - public void setContentType(String type) { - assertEquals("application/json; charset=utf-8", type); - } - }; - restInvocation.requestEx = requestEx; - restInvocation.responseEx = responseEx; - - restInvocation.scheduleInvocation(); - - assertEquals(Integer.valueOf(590), status.value); - assertEquals("Cse Internal Server Error", reasonPhrase.value); - assertEquals(Integer.valueOf(1), endCount.value); - } - - @SuppressWarnings("deprecation") - @Test - public void scheduleInvocation_flowControlReject() { - new Expectations() { - { - operationMeta.getProviderQpsFlowControlHandler(); - result = (Handler) (invocation, asyncResp) -> asyncResp.producerFail(new InvocationException( - new HttpStatus(429, "Too Many Requests"), - new CommonExceptionData("rejected by qps flowcontrol"))); - } - }; - Holder status = new Holder<>(); - Holder reasonPhrase = new Holder<>(); - Holder endCount = new Holder<>(0); - Holder responseBody = new Holder<>(); - responseEx = new AbstractHttpServletResponse() { - @SuppressWarnings("deprecation") - @Override - public void setStatus(int sc, String sm) { - status.value = sc; - reasonPhrase.value = sm; - } - - @Override - public void flushBuffer() { - endCount.value = endCount.value + 1; - } - - @Override - public void setContentType(String type) { - assertEquals("application/json; charset=utf-8", type); - } - - @Override - public void setBodyBuffer(Buffer bodyBuffer) { - responseBody.value = bodyBuffer.toString(); - } - }; - setup(); - - restInvocation.scheduleInvocation(); - - assertEquals(Integer.valueOf(429), status.value); - assertEquals("Too Many Requests", reasonPhrase.value); - assertEquals("{\"message\":\"rejected by qps flowcontrol\"}", responseBody.value); - assertEquals(Integer.valueOf(1), endCount.value); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestCommonRestConfig.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestCommonRestConfig.java deleted file mode 100644 index d3bb2a27682..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestCommonRestConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -public class TestCommonRestConfig { - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testTimeoutConfig() { - Assert.assertEquals(CommonRestConfig.getRequestWaitInPoolTimeout(), 30000); - ArchaiusUtils.setProperty(CommonRestConfig.KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT, 50000); - Assert.assertEquals(CommonRestConfig.getRequestWaitInPoolTimeout(), 50000); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestDefPath.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestDefPath.java index a288db17c95..e6b1f4bcf76 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestDefPath.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestDefPath.java @@ -18,21 +18,21 @@ package org.apache.servicecomb.common.rest; import org.apache.servicecomb.common.rest.definition.path.PathRegExp; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestDefPath { @Test public void testPathRegExp() throws Exception { PathRegExp oPathRegExp = new PathRegExp("//{test}//"); - Assert.assertEquals(1, oPathRegExp.getGroupCount()); - Assert.assertEquals(0, oPathRegExp.getGroupWithRegExpCount()); + Assertions.assertEquals(1, oPathRegExp.getGroupCount()); + Assertions.assertEquals(0, oPathRegExp.getGroupWithRegExpCount()); PathRegExp oSecondPathRegExp = new PathRegExp("{[^/:]+?}"); - Assert.assertEquals(1, oSecondPathRegExp.getGroupCount()); - Assert.assertEquals(1, oSecondPathRegExp.getGroupWithRegExpCount()); - Assert.assertEquals("test/", PathRegExp.ensureEndWithSlash("test/")); - Assert.assertEquals("test/", PathRegExp.ensureEndWithSlash("test")); - Assert.assertEquals(null, oSecondPathRegExp.match("{test/test}", null)); + Assertions.assertEquals(1, oSecondPathRegExp.getGroupCount()); + Assertions.assertEquals(1, oSecondPathRegExp.getGroupWithRegExpCount()); + Assertions.assertEquals("test/", PathRegExp.ensureEndWithSlash("test/")); + Assertions.assertEquals("test/", PathRegExp.ensureEndWithSlash("test")); + Assertions.assertNull(oSecondPathRegExp.match("{test/test}", null)); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestEngineSchemaListener.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestEngineSchemaListener.java index 37ba052b041..fa619acb725 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestEngineSchemaListener.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestEngineSchemaListener.java @@ -17,56 +17,109 @@ package org.apache.servicecomb.common.rest; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + import java.util.ArrayList; import java.util.List; +import org.apache.servicecomb.common.rest.locator.OperationLocator; import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.common.rest.locator.TestPathSchema; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.springframework.context.ApplicationContext; - -import io.swagger.models.Swagger; +import org.springframework.core.env.Environment; public class TestRestEngineSchemaListener { - private final SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); + static SCBEngine scbEngine; + + static ServicePathManager spm; + + @BeforeAll + public static void setup() { + Environment environment = Mockito.mock(Environment.class); + scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + scbEngine.setTransportManager(transportManager); + scbEngine.setExecutorManager(executorManager); + scbEngine.setEnvironment(environment); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_NAME); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); - private static class TestRestEngineSchemaListenerSchemaImpl { - @SuppressWarnings("unused") - public int add(int x, int y) { - return 0; - } + List listeners = new ArrayList<>(); + listeners.add(new RestEngineSchemaListener()); + scbEngine.setBootListeners(listeners); + scbEngine.addProducerMeta("sid1", new TestPathSchema()) + .run(); + spm = ServicePathManager.getServicePathManager(scbEngine.getProducerMicroserviceMeta()); + } + + @AfterAll + public static void teardown() { + scbEngine.destroy(); } @Test - public void test() { - BeanUtils.setContext(Mockito.mock(ApplicationContext.class)); + public void testLocateNotFound() { + InvocationException exception = Assertions.assertThrows(InvocationException.class, + () -> spm.producerLocateOperation("/notExist", "GET")); + Assertions.assertEquals("InvocationException: code=404;msg=CommonExceptionData [message=Not Found]", + exception.getMessage()); + } - MicroserviceMeta mm = new MicroserviceMeta("app:ms"); - List smList = new ArrayList<>(); + @Test + public void testLocateNotFoundDynamicRemained() { + InvocationException exception = Assertions.assertThrows(InvocationException.class, + () -> spm.producerLocateOperation("/dynamic/1/2", "GET")); + Assertions.assertEquals("InvocationException: code=404;msg=CommonExceptionData [message=Not Found]", + exception.getMessage()); + } - SwaggerGenerator generator = new SwaggerGenerator(context, TestRestEngineSchemaListenerSchemaImpl.class); - Swagger swagger = generator.generate(); - swagger.setBasePath(""); - SchemaMeta sm1 = new SchemaMeta(swagger, mm, "sid1"); - smList.add(sm1); + @Test + public void testLocateStaticMethodNotAllowed() { + InvocationException exception = Assertions.assertThrows(InvocationException.class, + () -> spm.producerLocateOperation("/staticEx", "POST")); + Assertions.assertEquals("InvocationException: code=405;msg=CommonExceptionData [message=Method Not Allowed]", + exception.getMessage()); + } - RestEngineSchemaListener listener = new RestEngineSchemaListener(); - SchemaMeta[] smArr = smList.toArray(new SchemaMeta[smList.size()]); - listener.onSchemaLoaded(smArr); - // 重复调用,不应该出异常 - listener.onSchemaLoaded(smArr); + @Test + public void testLocateDynamicMethodNotAllowed() { + InvocationException exception = Assertions.assertThrows(InvocationException.class, + () -> spm.producerLocateOperation("/dynamic/1", "POST")); + Assertions.assertEquals("InvocationException: code=405;msg=CommonExceptionData [message=Method Not Allowed]", + exception.getMessage()); + } - ServicePathManager spm = ServicePathManager.getServicePathManager(mm); - Assert.assertEquals(mm, spm.getMicroserviceMeta()); + @Test + public void testLocateStaticFound() { + Assertions.assertNotNull(spm.producerLocateOperation("/staticEx", "GET")); + } - Assert.assertSame(sm1, - spm.consumerLocateOperation("/add/", "POST").getOperation().getOperationMeta().getSchemaMeta()); + @Test + public void testLocateDynamicFound() { + OperationLocator locator = spm.producerLocateOperation("/dynamic/1", "GET"); + Assertions.assertEquals("1", locator.getPathVarMap().get("id")); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestProducerInvocation.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestProducerInvocation.java deleted file mode 100644 index 671106b3c77..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestRestProducerInvocation.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRestProducerInvocation { - @Mocked - Transport transport; - - @Mocked - HttpServletRequestEx requestEx; - - @Mocked - HttpServletResponseEx responseEx; - - @Mocked - RestOperationMeta restOperationMeta; - - @Mocked - MicroserviceMeta microserviceMeta; - - List httpServerFilters = Collections.emptyList(); - - RestProducerInvocation restProducerInvocation; - - Throwable throwableOfSendFailResponse; - - boolean scheduleInvocation; - - boolean runOnExecutor; - - boolean invokeNoParam; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private void initRestProducerInvocation() { - restProducerInvocation.transport = transport; - restProducerInvocation.requestEx = requestEx; - restProducerInvocation.responseEx = responseEx; - restProducerInvocation.restOperationMeta = restOperationMeta; - restProducerInvocation.httpServerFilters = httpServerFilters; - } - - @Before - public void setup() { - SCBEngine.getInstance().setProducerMicroserviceMeta(microserviceMeta); - } - - @After - public void teardown() { - SCBEngine.getInstance().setProducerMicroserviceMeta(null); - } - - @Test - public void invokeSendFail(@Mocked InvocationException expected) { - restProducerInvocation = new MockUp() { - @Mock - void sendFailResponse(Throwable throwable) { - throwableOfSendFailResponse = throwable; - } - - @Mock - void findRestOperation() { - throw expected; - } - - @Mock - void scheduleInvocation() { - throw new IllegalStateException("must not invoke scheduleInvocation"); - } - }.getMockInstance(); - - restProducerInvocation.invoke(transport, requestEx, responseEx, httpServerFilters); - - Assert.assertSame(expected, throwableOfSendFailResponse); - } - - @Test - public void invokeNormal() { - restProducerInvocation = new MockUp() { - @Mock - void findRestOperation() { - restProducerInvocation.restOperationMeta = restOperationMeta; - } - - @Mock - void scheduleInvocation() { - scheduleInvocation = true; - } - }.getMockInstance(); - - requestEx = new AbstractHttpServletRequest() { - }; - restProducerInvocation.invoke(transport, requestEx, responseEx, httpServerFilters); - - Assert.assertTrue(scheduleInvocation); - Assert.assertSame(requestEx, requestEx.getAttribute(RestConst.REST_REQUEST)); - } - - @Test - public void findRestOperationNameFromRegistry() { - Microservice microservice = new Microservice(); - microservice.setServiceName("ms"); - - new Expectations(RegistryUtils.class) { - { - requestEx.getHeader(Const.TARGET_MICROSERVICE); - result = null; - RegistryUtils.getMicroservice(); - result = microservice; - } - }; - new Expectations(ServicePathManager.class) { - { - //just make the method throw Exception - ServicePathManager.getServicePathManager(microserviceMeta); - result = null; - } - }; - restProducerInvocation = new RestProducerInvocation(); - initRestProducerInvocation(); - - expectedException.expect(Exception.class); - expectedException.expectMessage("[message=Not Found]"); - restProducerInvocation.findRestOperation(); - } - - @Test - public void findRestOperationNormal(@Mocked ServicePathManager servicePathManager, - @Mocked OperationLocator locator) { - requestEx = new AbstractHttpServletRequest() { - @Override - public String getRequestURI() { - return "/path"; - } - - @Override - public String getMethod() { - return "GET"; - } - - @Override - public String getHeader(String name) { - return "ms"; - } - }; - Map pathVars = new HashMap<>(); - new Expectations(ServicePathManager.class) { - { - ServicePathManager.getServicePathManager(microserviceMeta); - result = servicePathManager; - servicePathManager.producerLocateOperation(anyString, anyString); - result = locator; - locator.getPathVarMap(); - result = pathVars; - locator.getOperation(); - result = restOperationMeta; - } - }; - restProducerInvocation = new RestProducerInvocation(); - initRestProducerInvocation(); - - restProducerInvocation.findRestOperation(); - Assert.assertSame(restOperationMeta, restProducerInvocation.restOperationMeta); - Assert.assertSame(pathVars, requestEx.getAttribute(RestConst.PATH_PARAMETERS)); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestUploadConfig.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestUploadConfig.java deleted file mode 100644 index 00d6f746138..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/TestUploadConfig.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest; - -import javax.servlet.MultipartConfigElement; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestUploadConfig { - @Before - public void setUp() { - ArchaiusUtils.resetConfig(); - } - - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void getMultipartConfig_notSupport() { - UploadConfig uploadConfig = new UploadConfig(); - - Assert.assertNull(uploadConfig.toMultipartConfigElement()); - Assert.assertEquals(-1L, uploadConfig.getMaxFileSize()); - Assert.assertEquals(-1L, uploadConfig.getMaxSize()); - Assert.assertEquals(0, uploadConfig.getFileSizeThreshold()); - } - - @Test - public void getMultipartConfig_default() { - ArchaiusUtils.setProperty(RestConst.UPLOAD_DIR, "upload"); - - UploadConfig uploadConfig = new UploadConfig(); - MultipartConfigElement multipartConfigElement = uploadConfig.toMultipartConfigElement(); - - Assert.assertEquals("upload", uploadConfig.getLocation()); - Assert.assertEquals(-1L, uploadConfig.getMaxFileSize()); - Assert.assertEquals(-1L, uploadConfig.getMaxSize()); - Assert.assertEquals(0, uploadConfig.getFileSizeThreshold()); - - Assert.assertEquals("upload", multipartConfigElement.getLocation()); - Assert.assertEquals(-1L, multipartConfigElement.getMaxFileSize()); - Assert.assertEquals(-1L, multipartConfigElement.getMaxRequestSize()); - Assert.assertEquals(0, multipartConfigElement.getFileSizeThreshold()); - } - - @Test - public void getMultipartConfig_config() { - ArchaiusUtils.setProperty(RestConst.UPLOAD_DIR, "upload"); - ArchaiusUtils.setProperty(RestConst.UPLOAD_MAX_FILE_SIZE, 1); - ArchaiusUtils.setProperty(RestConst.UPLOAD_MAX_SIZE, 2); - ArchaiusUtils.setProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, 3); - - UploadConfig uploadConfig = new UploadConfig(); - MultipartConfigElement multipartConfigElement = uploadConfig.toMultipartConfigElement(); - - Assert.assertEquals("upload", uploadConfig.getLocation()); - Assert.assertEquals(1, uploadConfig.getMaxFileSize()); - Assert.assertEquals(2, uploadConfig.getMaxSize()); - Assert.assertEquals(3, uploadConfig.getFileSizeThreshold()); - - Assert.assertEquals("upload", multipartConfigElement.getLocation()); - Assert.assertEquals(1, multipartConfigElement.getMaxFileSize()); - Assert.assertEquals(2, multipartConfigElement.getMaxRequestSize()); - Assert.assertEquals(3, multipartConfigElement.getFileSizeThreshold()); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/VertxRestInvocationTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/VertxRestInvocationTest.java deleted file mode 100644 index 28ab24b89a2..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/VertxRestInvocationTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class VertxRestInvocationTest { - @Test - public void testCreateInvocation() { - new MockUp() { - /** - * Mock this method to avoid error - */ - @Mock - void createInvocation() { - } - }; - - VertxRestInvocation vertxRestInvocation = new VertxRestInvocation(); - VertxServerRequestToHttpServletRequest requestEx = Mockito.mock(VertxServerRequestToHttpServletRequest.class); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Invocation invocation = Mockito.mock(Invocation.class); - - Deencapsulation.setField( - vertxRestInvocation, "requestEx", requestEx); - Deencapsulation.setField( - vertxRestInvocation, "invocation", invocation); - Mockito.when(requestEx.getContext()).thenReturn(routingContext); - - Deencapsulation.invoke(vertxRestInvocation, "createInvocation"); - - Mockito.verify(routingContext, Mockito.times(1)).put(RestConst.REST_INVOCATION_CONTEXT, invocation); - } -} \ No newline at end of file diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java index 90245d7a3a2..c134cb46558 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java @@ -17,154 +17,144 @@ package org.apache.servicecomb.common.rest.codec; -import static org.mockito.Mockito.when; - import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessor; -import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.common.rest.definition.RestParam; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.Parameter; -import mockit.Expectations; -import mockit.Mocked; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.Response.Status; public class TestRestCodec { private static RestOperationMeta restOperation; - private static Map header = new HashMap<>(); - - private static RestClientRequest clientRequest = new RestClientRequestImpl(null, null, null) { - public void putHeader(String name, String value) { - header.put(name, value); - } - }; - private static List paramList = null; - @BeforeClass + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll public static void beforeClass() { - restOperation = Mockito.mock(RestOperationMeta.class); - // clientRequest = Mockito.mock(RestClientRequest.class); - paramList = new ArrayList<>(); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.header.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); Parameter hp = new HeaderParameter(); hp.setName("header"); - paramList.add(new RestParam(0, hp, int.class)); - when(restOperation.getParamList()).thenReturn(paramList); + hp.setSchema(new Schema<>()); + RestParam restParam = new RestParam(null, hp, int.class); + + restOperation = Mockito.mock(RestOperationMeta.class); + paramList = new ArrayList<>(); + + paramList.add(restParam); + Mockito.when(restOperation.getParamList()).thenReturn(paramList); + Mockito.when(restOperation.getParamByName("test")).thenReturn(restParam); } - @AfterClass + @AfterAll public static void afterClass() { restOperation = null; - clientRequest = null; paramList.clear(); } @Test - public void testArgsToRest() { - try { - RestCodec.argsToRest(new String[] {"abc"}, restOperation, clientRequest); - Assert.assertEquals("abc", header.get("header")); - } catch (Exception e) { - Assert.assertTrue(false); - } - } - - @Test - public void testRestToArgs(@Mocked HttpServletRequest request, - @Mocked RestOperationMeta restOperation, @Mocked RestParam restParam, - @Mocked ParamValueProcessor processer) throws Exception { + public void testRestToArgs() throws Exception { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + RestOperationMeta restOperation = Mockito.mock(RestOperationMeta.class); + RestParam restParam = Mockito.mock(RestParam.class); + ParamValueProcessor processor = Mockito.mock(ParamValueProcessor.class); List params = new ArrayList<>(); params.add(restParam); String s = "my"; + Mockito.when(restOperation.getParamList()).thenReturn(params); + Mockito.when(restParam.getParamProcessor()).thenReturn(processor); + Mockito.when(processor.getValue(request)).thenReturn(s); + Mockito.when(restParam.getParamName()).thenReturn("test"); - new Expectations() { - { - restOperation.getParamList(); - result = params; - restParam.getParamProcessor(); - result = processer; - processer.getValue(request); - result = s; - } - }; - - Object[] xx = RestCodec.restToArgs(request, restOperation); - Assert.assertEquals(xx[0], s); + Map xx = RestCodec.restToArgs(request, restOperation); + Assertions.assertEquals(xx.get("test"), s); } @Test - public void testRestToArgsExcetpion(@Mocked HttpServletRequest request, - @Mocked RestOperationMeta restOperation, @Mocked RestParam restParam, - @Mocked ParamValueProcessor processer) throws Exception { + public void testRestToArgsException() throws Exception { + ParamValueProcessor processor = Mockito.mock(ParamValueProcessor.class); + Mockito.when(processor.getValue(Mockito.any())).thenThrow(new Exception("bad request parame")); + + RestOperationMeta restOperation = Mockito.mock(RestOperationMeta.class); + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(restParam.getParamProcessor()).thenReturn(processor); + List params = new ArrayList<>(); params.add(restParam); + Mockito.when(restOperation.getParamList()).thenReturn(params); - new Expectations() { - { - restOperation.getParamList(); - result = params; - restParam.getParamProcessor(); - result = processer; - processer.getValue(request); - result = new Exception("bad request parame"); - } - }; + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(restOperation.getOperationMeta()).thenReturn(operationMeta); boolean success = false; try { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); RestCodec.restToArgs(request, restOperation); success = true; } catch (InvocationException e) { - Assert.assertEquals(400, e.getStatusCode()); - Assert.assertEquals("Parameter is not valid.", ((CommonExceptionData) e.getErrorData()).getMessage()); + Assertions.assertEquals(400, e.getStatusCode()); + Assertions.assertTrue(e.getMessage().contains("Parameter is not valid")); } - Assert.assertEquals(success, false); + Assertions.assertFalse(success); } @Test - public void testRestToArgsInstanceExcetpion(@Mocked HttpServletRequest request, - @Mocked RestOperationMeta restOperation, @Mocked RestParam restParam, - @Mocked ParamValueProcessor processer) throws Exception { + public void testRestToArgsInstanceException() throws Exception { + InvocationException exception = new InvocationException(Status.BAD_REQUEST, "Parameter is not valid."); + ParamValueProcessor processor = Mockito.mock(ParamValueProcessor.class); + Mockito.when(processor.getValue(Mockito.any())).thenThrow(exception); + + RestOperationMeta restOperation = Mockito.mock(RestOperationMeta.class); + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(restParam.getParamProcessor()).thenReturn(processor); + List params = new ArrayList<>(); params.add(restParam); - InvocationException exception = new InvocationException(Status.BAD_REQUEST, "Parameter is not valid."); + Mockito.when(restOperation.getParamList()).thenReturn(params); - new Expectations() { - { - restOperation.getParamList(); - result = params; - restParam.getParamProcessor(); - result = processer; - processer.getValue(request); - result = exception; - } - }; + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(restOperation.getOperationMeta()).thenReturn(operationMeta); boolean success = false; try { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); RestCodec.restToArgs(request, restOperation); success = true; } catch (InvocationException e) { - Assert.assertEquals(e.getStatusCode(), Status.BAD_REQUEST.getStatusCode()); + Assertions.assertEquals(e.getStatusCode(), Status.BAD_REQUEST.getStatusCode()); + Assertions.assertTrue(((CommonExceptionData) e.getErrorData()).getMessage() + .contains("Parameter is not valid for operation")); } - Assert.assertEquals(success, false); + Assertions.assertFalse(success); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestObjectMapper.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestObjectMapper.java index af840e1241f..57da9440e4f 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestObjectMapper.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestObjectMapper.java @@ -19,30 +19,54 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.util.Date; -import org.junit.Assert; -import org.junit.Test; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.exc.StreamConstraintsException; +import com.google.common.base.Strings; +import org.apache.servicecomb.foundation.common.utils.RestObjectMapper; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.core.JsonParser.Feature; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.type.TypeFactory; import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.Test; public class TestRestObjectMapper { + @Test + public void testFormatDate() throws Exception { + RestObjectMapper mapper = new RestObjectMapper(); + // must read/write ISO 8061 dates + Date date = mapper.readValue("\"2017-07-21T17:32:28Z\"".getBytes(), Date.class); + String dateStr = mapper.writeValueAsString(date); + Assertions.assertEquals(dateStr, "\"2017-07-21T17:32:28.000+00:00\""); + + date = mapper.readValue("\"2017-07-21T17:32:28.320+0100\"".getBytes(), Date.class); + dateStr = mapper.writeValueAsString(date); + Assertions.assertEquals(dateStr, "\"2017-07-21T16:32:28.320+00:00\""); // one hour later + } + @Test public void testAutoCloseSource() { - Assert.assertFalse(RestObjectMapperFactory.getRestObjectMapper().getFactory().isEnabled(Feature.AUTO_CLOSE_SOURCE)); + Assertions.assertFalse(RestObjectMapperFactory.getRestObjectMapper().getFactory().isEnabled(Feature.AUTO_CLOSE_SOURCE)); } @Test public void testDeserializationFeature() { - Assert.assertFalse( + Assertions.assertFalse( RestObjectMapperFactory.getRestObjectMapper().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)); } + @Test + public void testDefaultViewInclusionFeature() { + Assertions.assertFalse(RestObjectMapperFactory.getRestObjectMapper().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)); + } + @Test public void testJsonObjectWork() { JsonObject obj = new JsonObject(); @@ -50,23 +74,37 @@ public void testJsonObjectWork() { obj.put("desc", "b"); PojoModel model = RestObjectMapperFactory.getRestObjectMapper() .convertValue(obj, TypeFactory.defaultInstance().constructType(PojoModel.class)); - Assert.assertEquals("a", model.getName()); - Assert.assertEquals("b", model.getDesc()); + Assertions.assertEquals("a", model.getName()); + Assertions.assertEquals("b", model.getDesc()); RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapper()); model = RestObjectMapperFactory.getRestObjectMapper() .convertValue(obj, TypeFactory.defaultInstance().constructType(PojoModel.class)); - Assert.assertEquals("a", model.getName()); - Assert.assertEquals("b", model.getDesc()); + Assertions.assertEquals("a", model.getName()); + Assertions.assertEquals("b", model.getDesc()); InputStream inputStream = new ByteArrayInputStream(new byte[0]); try { RestObjectMapperFactory.getRestObjectMapper().readValue(inputStream, PojoModel.class); - Assert.fail(); + Assertions.fail(); } catch (MismatchedInputException e) { // right place, nothing to do. } catch (Exception e) { - Assert.fail(); + Assertions.fail(); } } + + @Test + public void testReadValue() { + String content = "{\"desc\":" + Strings.repeat("9", 1001) + "}"; + try { + RestObjectMapperFactory.getRestObjectMapper().readValue(content, PojoModel.class); + Assertions.fail(); + } catch (StreamConstraintsException e) { + // right place, nothing to do. + } catch (JsonProcessingException ex) { + Assertions.fail(); + } + } + } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/fix/TestDoSFix.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/fix/TestDoSFix.java index 2692cb33192..361a3844d4c 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/fix/TestDoSFix.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/fix/TestDoSFix.java @@ -21,28 +21,27 @@ import java.lang.reflect.Field; import java.util.concurrent.Callable; -import org.apache.servicecomb.common.rest.codec.RestObjectMapper; +import org.apache.servicecomb.foundation.common.utils.RestObjectMapper; import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; -import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.exc.InputCoercionException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidFormatException; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.google.common.base.Strings; +import org.junit.jupiter.api.Test; public class TestDoSFix { - static ObjectMapper mapper = new RestObjectMapper(); + static final ObjectMapper mapper = new RestObjectMapper(); - static String invalidNum = Strings.repeat("9", 100_0000); + static final String invalidNum = Strings.repeat("9", 1000); - static String invalidStr = "\"" + invalidNum + "\""; + static final String invalidStr = "\"" + invalidNum + "\""; - static String invalidArrNum = "[" + invalidNum + "]"; + static final String invalidArrNum = "[" + invalidNum + "]"; - static String invalidArrStr = "[\"" + invalidNum + "\"]"; + static final String invalidArrStr = "[\"" + invalidNum + "\"]"; public static class Model { public Color color; @@ -80,18 +79,18 @@ void fastFail(Callable callable, Class eCls) { long start = System.currentTimeMillis(); try { Object ret = callable.call(); - Assert.fail("expect failed, but succes to be " + ret); + Assertions.fail("expect failed, but success to be " + ret); } catch (AssertionError e) { throw e; } catch (Throwable e) { if (eCls != e.getClass()) { e.printStackTrace(); } - Assert.assertEquals(eCls, e.getClass()); + Assertions.assertEquals(eCls, e.getClass()); } long time = System.currentTimeMillis() - start; - Assert.assertTrue("did not fix DoS problem, time:" + time, time < 1000); + Assertions.assertTrue(time < 1000, "did not fix DoS problem, time:" + time); } void fastFail(String input, Class cls, Class eCls) { @@ -108,7 +107,7 @@ void batFastFail(Class cls, Class e1, Class e2) { } void batFastFail(Class cls) { - batFastFail(cls, JsonParseException.class, InvalidFormatException.class); + batFastFail(cls, InputCoercionException.class, InvalidFormatException.class); } void batFastFail(String fieldName, Class e1, Class e2) { @@ -130,11 +129,11 @@ public void testEnum() { @Test public void testChar() { - batFastFail(char.class, JsonParseException.class, MismatchedInputException.class); - batFastFail(Character.class, JsonParseException.class, MismatchedInputException.class); + batFastFail(char.class, InputCoercionException.class, InvalidFormatException.class); + batFastFail(Character.class, InputCoercionException.class, InvalidFormatException.class); - batFastFail("cValue", JsonMappingException.class, MismatchedInputException.class); - batFastFail("cObjValue", JsonMappingException.class, MismatchedInputException.class); + batFastFail("cValue", JsonMappingException.class, InvalidFormatException.class); + batFastFail("cObjValue", JsonMappingException.class, InvalidFormatException.class); } @Test @@ -177,7 +176,7 @@ Object fastSucc(Callable callable) { long start = System.currentTimeMillis(); try { Object ret = callable.call(); - Assert.assertTrue(System.currentTimeMillis() - start < 1000); + Assertions.assertTrue(System.currentTimeMillis() - start < 1000); return ret; } catch (Throwable e) { throw new IllegalStateException(e); @@ -196,24 +195,24 @@ Object fastSucc(InputStream input, Class cls) { } void batFastSucc(Class cls, Object expected) { - Assert.assertEquals(expected, fastSucc(invalidNum, cls)); - Assert.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidNum.getBytes()), cls)); + Assertions.assertEquals(expected, fastSucc(invalidNum, cls)); + Assertions.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidNum.getBytes()), cls)); - Assert.assertEquals(expected, fastSucc(invalidStr, cls)); - Assert.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidStr.getBytes()), cls)); + Assertions.assertEquals(expected, fastSucc(invalidStr, cls)); + Assertions.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidStr.getBytes()), cls)); - Assert.assertEquals(expected, fastSucc(invalidArrNum, cls)); - Assert.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidArrNum.getBytes()), cls)); + Assertions.assertEquals(expected, fastSucc(invalidArrNum, cls)); + Assertions.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidArrNum.getBytes()), cls)); - Assert.assertEquals(expected, fastSucc(invalidArrStr, cls)); - Assert.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidArrStr.getBytes()), cls)); + Assertions.assertEquals(expected, fastSucc(invalidArrStr, cls)); + Assertions.assertEquals(expected, fastSucc(new ByteArrayInputStream(invalidArrStr.getBytes()), cls)); } void checkField(Model model, String fieldName, Object expected) { try { Field field = Model.class.getField(fieldName); Object value = field.get(model); - Assert.assertEquals(expected, value); + Assertions.assertEquals(expected, value); } catch (Throwable e) { throw new IllegalStateException(e); } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java index a7afaa5800c..ab71e3a9e99 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java @@ -17,57 +17,76 @@ package org.apache.servicecomb.common.rest.codec.param; -import static org.junit.Assert.fail; - import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; +import java.util.Set; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.BodyProcessor; import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.RawJsonBodyProcessor; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.parameters.RequestBody; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.impl.headers.VertxHttpHeaders; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import io.vertx.core.buffer.impl.BufferImpl; +import io.vertx.core.http.impl.headers.HeadersMultiMap; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; + public class TestBodyProcessor { - @Mocked - HttpServletRequest request; + Environment environment = Mockito.mock(Environment.class); + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); MultiMap headers; - RestClientRequest clientRequest; + final RestClientRequest clientRequest = Mockito.mock(RestClientRequest.class); ParamValueProcessor processor; - ByteBuf inputBodyByteBuf = Unpooled.buffer(); + final Buffer inputBodyByteBuf = Buffer.buffer(); - BufferInputStream inputStream = new BufferInputStream(inputBodyByteBuf); + final BufferInputStream inputStream = new BufferInputStream(inputBodyByteBuf); Buffer outputBodyBuffer; + String value; + private void createProcessor(Class type) { - processor = new BodyProcessor(TypeFactory.defaultInstance().constructType(type), true); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + OpenAPI openAPI = Mockito.mock(OpenAPI.class); + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getSwagger()).thenReturn(openAPI); + RequestBody requestBody = Mockito.mock(RequestBody.class); + Content content = Mockito.mock(Content.class); + Mockito.when(requestBody.getContent()).thenReturn(content); + Mockito.when(requestBody.getRequired()).thenReturn(true); + Set supported = new HashSet<>(); + supported.add(MediaType.APPLICATION_JSON); + supported.add(MediaType.TEXT_PLAIN); + Mockito.when(content.keySet()).thenReturn(supported); + processor = new BodyProcessor(operationMeta, TypeFactory.defaultInstance().constructType(type), requestBody); } private void createRawJsonProcessor() { @@ -75,31 +94,16 @@ private void createRawJsonProcessor() { } private void createClientRequest() { - clientRequest = new MockUp() { - @Mock - void putHeader(String name, String value) { - headers.add(name, value); - } - - @Mock - void write(Buffer bodyBuffer) { - outputBodyBuffer = bodyBuffer; - } - - @Mock - MultiMap getHeaders() { - return headers; - } - }.getMockInstance(); + Mockito.doAnswer(invocation -> { + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + return null; + }).when(clientRequest).putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + + Mockito.when(clientRequest.getHeaders()).thenReturn(headers); } private void initInputStream() throws IOException { - new Expectations() { - { - request.getInputStream(); - result = inputStream; - } - }; + Mockito.when(request.getInputStream()).thenReturn(inputStream); } private void setupGetValue(Class type) throws IOException { @@ -107,76 +111,58 @@ private void setupGetValue(Class type) throws IOException { initInputStream(); } - @Before + @BeforeEach public void before() { - headers = new VertxHttpHeaders(); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + headers = HeadersMultiMap.httpHeaders(); + value = "value"; } @Test public void testGetValueHaveAttr() throws Exception { int body = 10; createProcessor(String.class); - new Expectations() { - { - request.getAttribute(RestConst.BODY_PARAMETER); - result = body; - } - }; + Mockito.when(request.getAttribute(RestConst.BODY_PARAMETER)).thenReturn(body); Object result = processor.getValue(request); - Assert.assertEquals("10", result); + Assertions.assertEquals("10", result); } @Test public void testGetValueNoAttrNoStream() throws Exception { createProcessor(String.class); - new Expectations() { - { - request.getInputStream(); - result = null; - } - }; - - Object result = processor.getValue(request); - Assert.assertNull(result); + Mockito.when(request.getInputStream()).thenReturn(null); + Assertions.assertThrows(InvocationException.class, () -> processor.getValue(request)); } @Test public void testGetValueTextPlain() throws Exception { setupGetValue(String.class); - inputBodyByteBuf.writeCharSequence("abc", StandardCharsets.UTF_8); + inputBodyByteBuf.appendString("abc", StandardCharsets.UTF_8.toString()); - new Expectations() { - { - request.getContentType(); - result = MediaType.TEXT_PLAIN; - } - }; + Mockito.when(request.getContentType()).thenReturn(MediaType.TEXT_PLAIN); - Assert.assertEquals("abc", processor.getValue(request)); + Assertions.assertEquals("abc", processor.getValue(request)); } @Test public void testGetValueContextTypeJson() throws Exception { setupGetValue(Integer.class); - inputBodyByteBuf.writeCharSequence("\"1\"", StandardCharsets.UTF_8); + inputBodyByteBuf.appendString("\"1\"", StandardCharsets.UTF_8.toString()); - new Expectations() { - { - request.getContentType(); - result = MediaType.APPLICATION_JSON; - } - }; + Mockito.when(request.getContentType()).thenReturn(MediaType.APPLICATION_JSON); - Assert.assertEquals(1, processor.getValue(request)); + Assertions.assertEquals(1, processor.getValue(request)); } @Test public void testGetValueDefaultJson() throws Exception { setupGetValue(Integer.class); - inputBodyByteBuf.writeCharSequence("\"1\"", StandardCharsets.UTF_8); + inputBodyByteBuf.appendString("\"1\"", StandardCharsets.UTF_8.toString()); - Assert.assertEquals(1, processor.getValue(request)); + Assertions.assertEquals(1, processor.getValue(request)); } @Test @@ -184,9 +170,17 @@ public void testSetValue() throws Exception { createClientRequest(); createProcessor(String.class); - processor.setValue(clientRequest, "value"); - Assert.assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.CONTENT_TYPE)); - Assert.assertEquals("\"value\"", outputBodyBuffer.toString()); + Mockito.when(clientRequest.getHeaders()).thenReturn(headers); + ParamValueProcessor spy = Mockito.spy(processor); + Mockito.doAnswer(invocation -> { + outputBodyBuffer = new BufferImpl().appendBytes((value).getBytes(StandardCharsets.UTF_8)); + return null; + }).when(spy).setValue(clientRequest, value); + + spy.setValue(clientRequest, value); + processor.setValue(clientRequest, value); + Assertions.assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.CONTENT_TYPE)); + Assertions.assertEquals(value, outputBodyBuffer.toString()); } @Test @@ -195,74 +189,57 @@ public void testSetValueTextPlain() throws Exception { createProcessor(String.class); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN); - processor.setValue(clientRequest, "value"); - Assert.assertEquals(MediaType.TEXT_PLAIN, headers.get(HttpHeaders.CONTENT_TYPE)); - Assert.assertEquals("value", outputBodyBuffer.toString()); - } + ParamValueProcessor spy = Mockito.spy(processor); + Mockito.doAnswer(invocation -> { + outputBodyBuffer = new BufferImpl().appendBytes((value).getBytes(StandardCharsets.UTF_8)); + return null; + }).when(spy).setValue(clientRequest, value); - @Test - public void testSetValueTextPlainTypeMismatch() { - createClientRequest(); - createProcessor(String.class); - headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN); - - try { - processor.setValue(clientRequest, new Date()); - fail("an exception is expected!"); - } catch (Exception e) { - Assert.assertEquals(IllegalArgumentException.class, e.getClass()); - Assert.assertEquals("Content-Type is text/plain while arg type is not String", e.getMessage()); - } + spy.setValue(clientRequest, value); + processor.setValue(clientRequest, value); + Assertions.assertEquals(MediaType.TEXT_PLAIN, headers.get(HttpHeaders.CONTENT_TYPE)); + Assertions.assertEquals(value, outputBodyBuffer.toString()); } + @Test public void testGetParameterPath() { createProcessor(String.class); - Assert.assertEquals("", processor.getParameterPath()); + Assertions.assertEquals("", processor.getParameterPath()); } @Test public void testGetProcessorType() { createProcessor(String.class); - Assert.assertEquals("body", processor.getProcessorType()); + Assertions.assertEquals("body", processor.getProcessorType()); } @Test public void testGetValueRawJson() throws Exception { createRawJsonProcessor(); initInputStream(); - inputBodyByteBuf.writeCharSequence("\"1\"", StandardCharsets.UTF_8); + inputBodyByteBuf.appendString("\"1\"", StandardCharsets.UTF_8.toString()); - Assert.assertEquals("\"1\"", processor.getValue(request)); + Assertions.assertEquals("\"1\"", processor.getValue(request)); } @Test public void testGetValueRawJsonHaveAttr() throws Exception { int body = 10; createRawJsonProcessor(); - new Expectations() { - { - request.getAttribute(RestConst.BODY_PARAMETER); - result = body; - } - }; + Mockito.when(request.getAttribute(RestConst.BODY_PARAMETER)).thenReturn(body); Object result = processor.getValue(request); - Assert.assertEquals("10", result); + Assertions.assertEquals("10", result); } @Test public void testGetValueRawJsonNoAttrNoStream() throws Exception { createRawJsonProcessor(); - new Expectations() { - { - request.getInputStream(); - result = null; - } - }; + Mockito.when(request.getInputStream()).thenReturn(null); Object result = processor.getValue(request); - Assert.assertNull(result); + Assertions.assertNull(result); } @Test @@ -270,9 +247,15 @@ public void testSetValueRawJson() throws Exception { createClientRequest(); createRawJsonProcessor(); - processor.setValue(clientRequest, "value"); - Assert.assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.CONTENT_TYPE)); - Assert.assertEquals("value", outputBodyBuffer.toString()); + ParamValueProcessor spy = Mockito.spy(processor); + Mockito.doAnswer(invocation -> { + outputBodyBuffer = new BufferImpl().appendBytes((value).getBytes(StandardCharsets.UTF_8)); + return null; + }).when(spy).setValue(clientRequest, value); + spy.setValue(clientRequest, value); + processor.setValue(clientRequest, value); + Assertions.assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.CONTENT_TYPE)); + Assertions.assertEquals("value", outputBodyBuffer.toString()); } static class BodyModel { @@ -287,18 +270,12 @@ public void convertFromFormData() throws Exception { Map parameterMap = new HashMap<>(); parameterMap.put("name", new String[] {"n"}); parameterMap.put("age", new String[] {"10"}); - new Expectations() { - { - request.getParameterMap(); - result = parameterMap; - request.getContentType(); - result = MediaType.MULTIPART_FORM_DATA + ";utf-8"; - } - }; + Mockito.when(request.getParameterMap()).thenReturn(parameterMap); + Mockito.when(request.getContentType()).thenReturn(MediaType.MULTIPART_FORM_DATA + ";utf-8"); BodyModel bm = (BodyModel) processor.getValue(request); - Assert.assertEquals("n", bm.name); - Assert.assertEquals(10, bm.age); + Assertions.assertEquals("n", bm.name); + Assertions.assertEquals(10, bm.age); } @Test @@ -307,17 +284,11 @@ public void convertFromUrlencoded() throws Exception { Map parameterMap = new HashMap<>(); parameterMap.put("name", new String[] {"n"}); parameterMap.put("age", new String[] {"10"}); - new Expectations() { - { - request.getParameterMap(); - result = parameterMap; - request.getContentType(); - result = MediaType.APPLICATION_FORM_URLENCODED + ";utf-8"; - } - }; + Mockito.when(request.getParameterMap()).thenReturn(parameterMap); + Mockito.when(request.getContentType()).thenReturn(MediaType.APPLICATION_FORM_URLENCODED + ";utf-8"); BodyModel bm = (BodyModel) processor.getValue(request); - Assert.assertEquals("n", bm.name); - Assert.assertEquals(10, bm.age); + Assertions.assertEquals("n", bm.name); + Assertions.assertEquals(10, bm.age); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java index 104a115c08d..22d7e8d39db 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java @@ -17,48 +17,61 @@ package org.apache.servicecomb.common.rest.codec.param; +import java.util.HashMap; + import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.BodyProcessor; import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.RawJsonBodyProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.BodyParameter; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +@SuppressWarnings({"rawtypes", "unchecked"}) public class TestBodyProcessorCreator { - @Test - public void testCreateNormal() { - ParamValueProcessorCreator creator = - ParamValueProcessorCreatorManager.INSTANCE.findValue(BodyProcessorCreator.PARAMTYPE); - BodyParameter param = new BodyParameter(); + Environment environment = Mockito.mock(Environment.class); - ParamValueProcessor processor = creator.create(param, String.class); - - Assert.assertEquals(BodyProcessor.class, processor.getClass()); + @BeforeEach + public void before() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); } @Test - public void testCreateRawJson() { + public void testCreateNormal() { ParamValueProcessorCreator creator = - ParamValueProcessorCreatorManager.INSTANCE.findValue(BodyProcessorCreator.PARAMTYPE); - BodyParameter param = new BodyParameter(); - param.setVendorExtension(SwaggerConst.EXT_RAW_JSON_TYPE, true); + ParamValueProcessorCreatorManager.INSTANCE.findValue(BodyProcessorCreator.PARAM_TYPE); + RequestBody param = new RequestBody(); + param.setContent(new Content()); + param.getContent().addMediaType(SwaggerConst.DEFAULT_MEDIA_TYPE, new MediaType()); + param.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE).setSchema(new Schema()); + param.setExtensions(new HashMap<>()); - ParamValueProcessor processor = creator.create(param, String.class); + ParamValueProcessor processor = creator.create(null, null, param, String.class); - Assert.assertEquals(RawJsonBodyProcessor.class, processor.getClass()); + Assertions.assertEquals(BodyProcessor.class, processor.getClass()); } - // now, we ignore rawJson flag @Test - public void testCreateInvalidRawJson() { + public void testCreateRawJson() { ParamValueProcessorCreator creator = - ParamValueProcessorCreatorManager.INSTANCE.findValue(BodyProcessorCreator.PARAMTYPE); - BodyParameter param = new BodyParameter(); - param.setVendorExtension(SwaggerConst.EXT_RAW_JSON_TYPE, true); + ParamValueProcessorCreatorManager.INSTANCE.findValue(BodyProcessorCreator.PARAM_TYPE); + RequestBody param = new RequestBody(); + param.setContent(new Content()); + param.getContent().addMediaType(SwaggerConst.DEFAULT_MEDIA_TYPE, new MediaType()); + param.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE).setSchema(new Schema()); + param.addExtension(SwaggerConst.EXT_RAW_JSON_TYPE, true); - ParamValueProcessor processor = creator.create(param, Integer.class); + ParamValueProcessor processor = creator.create(null, null, param, String.class); - Assert.assertEquals(BodyProcessor.class, processor.getClass()); + Assertions.assertEquals(RawJsonBodyProcessor.class, processor.getClass()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java index 63364c482ab..10cad81b4f4 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java @@ -21,28 +21,29 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.common.rest.codec.param.CookieProcessorCreator.CookieProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.databind.type.TypeFactory; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import com.fasterxml.jackson.databind.util.StdDateFormat; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestCookieProcessor { - @Mocked - HttpServletRequest request; + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + + final Map cookies = new HashMap<>(); - Map cookies = new HashMap<>(); + final RestClientRequest clientRequest = Mockito.mock(RestClientRequest.class); - RestClientRequest clientRequest; + final String cookieName = "v1"; + + final String cookieValue = "c1v"; private CookieProcessor createProcessor(String name, Class type) { return new CookieProcessor(name, TypeFactory.defaultInstance().constructType(type), null, true); @@ -53,108 +54,76 @@ private CookieProcessor createProcessor(String name, Class type, String defau } private void createClientRequest() { - clientRequest = new MockUp() { - @Mock - void addCookie(String name, String value) { - cookies.put(name, value); - } - }.getMockInstance(); + Mockito.doAnswer(invocation -> { + cookies.put(cookieName, cookieValue); + return null; + }).when(clientRequest).addCookie(cookieName, cookieValue); } @Test public void testGetValueNoCookies() throws Exception { - new Expectations() { - { - request.getCookies(); - result = null; - } - }; - - CookieProcessor processor = createProcessor("c1", String.class, null, false); + Mockito.when(request.getCookies()).thenReturn(null); + + CookieProcessor processor = createProcessor(cookieName, String.class, null, false); Object value = processor.getValue(request); - Assert.assertNull(value); + Assertions.assertNull(value); } @Test public void testNoCookieAndRequired() throws Exception { - new Expectations() { - { - request.getCookies(); - result = null; - } - }; - - CookieProcessor processor = createProcessor("c1", String.class, null, true); + Mockito.when(request.getCookies()).thenReturn(null); + + CookieProcessor processor = createProcessor(cookieName, String.class, null, true); try { processor.getValue(request); - Assert.assertEquals("required is true, throw exception", "not throw exception"); + Assertions.assertEquals("required is true, throw exception", "not throw exception"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("Parameter is required.")); + Assertions.assertTrue(e.getMessage().contains("Parameter is required.")); } } @Test public void testGetValueCookiesNotFound() throws Exception { - Cookie[] cookies = new Cookie[] {new Cookie("c1", "c1v")}; - new Expectations() { - { - request.getCookies(); - result = cookies; - } - }; + Cookie[] cookies = new Cookie[] {new Cookie(cookieName, cookieValue)}; + Mockito.when(request.getCookies()).thenReturn(cookies); CookieProcessor processor = createProcessor("c2", String.class, null, false); Object value = processor.getValue(request); - Assert.assertNull(value); + Assertions.assertNull(value); } @Test public void testGetValueCookiesFound() throws Exception { - Cookie[] cookies = new Cookie[] {new Cookie("c1", "c1v")}; - new Expectations() { - { - request.getCookies(); - result = cookies; - } - }; - - CookieProcessor processor = createProcessor("c1", String.class); + Cookie[] cookies = new Cookie[] {new Cookie(cookieName, cookieValue)}; + Mockito.when(request.getCookies()).thenReturn(cookies); + + CookieProcessor processor = createProcessor(cookieName, String.class); Object value = processor.getValue(request); - Assert.assertEquals("c1v", value); + Assertions.assertEquals(cookieValue, value); } @Test public void testGetValueRequiredTrue() throws Exception { - Cookie[] cookies = new Cookie[] {new Cookie("c1", null)}; - new Expectations() { - { - request.getCookies(); - result = cookies; - } - }; - - CookieProcessor processor = createProcessor("c1", String.class, null, true); + Cookie[] cookies = new Cookie[] {new Cookie(cookieName, null)}; + Mockito.when(request.getCookies()).thenReturn(cookies); + + CookieProcessor processor = createProcessor(cookieName, String.class, null, true); try { processor.getValue(request); - Assert.assertEquals("required is true, throw exception", "not throw exception"); + Assertions.assertEquals("required is true, throw exception", "not throw exception"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("Parameter is required.")); + Assertions.assertTrue(e.getMessage().contains("Parameter is required.")); } } @Test public void testGetValueRequiredFalse() throws Exception { - Cookie[] cookies = new Cookie[] {new Cookie("c1", null)}; - new Expectations() { - { - request.getCookies(); - result = cookies; - } - }; - - CookieProcessor processor = createProcessor("c1", String.class, "test", false); + Cookie[] cookies = new Cookie[] {new Cookie(cookieName, null)}; + Mockito.when(request.getCookies()).thenReturn(cookies); + + CookieProcessor processor = createProcessor(cookieName, String.class, "test", false); Object result = processor.getValue(request); - Assert.assertEquals("test", result); + Assertions.assertEquals("test", result); } @SuppressWarnings("deprecation") @@ -162,44 +131,57 @@ public void testGetValueRequiredFalse() throws Exception { public void testGetValueCookiesDate() throws Exception { Date date = new Date(); String strDate = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date); - Cookie[] cookies = new Cookie[] {new Cookie("c1", strDate)}; - new Expectations() { - { - request.getCookies(); - result = cookies; - } - }; - - CookieProcessor processor = createProcessor("c1", Date.class); + Cookie[] cookies = new Cookie[] {new Cookie(cookieName, strDate)}; + Mockito.when(request.getCookies()).thenReturn(cookies); + + CookieProcessor processor = createProcessor(cookieName, Date.class); Object value = processor.getValue(request); - Assert.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); + Assertions.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); } @Test public void testSetValue() throws Exception { createClientRequest(); - CookieProcessor processor = createProcessor("c1", String.class); - processor.setValue(clientRequest, "c1v"); - Assert.assertEquals("c1v", cookies.get("c1")); + CookieProcessor processor = createProcessor(cookieName, String.class); + processor.setValue(clientRequest, cookieValue); + Assertions.assertEquals(cookieValue, cookies.get(cookieName)); + } + + @Test + public void testSetValueDateFixed() throws Exception { + Date date = new Date(1586957400199L); + String strDate = "2020-04-15T13:30:00.199+00:00"; + + String cookieValue = RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date); + Mockito.doAnswer(invocation -> { + cookies.put("h1", cookieValue); + return null; + }).when(clientRequest).addCookie("h1", cookieValue); + CookieProcessor processor = createProcessor("h1", Date.class); + processor.setValue(clientRequest, date); + Assertions.assertEquals(strDate, cookies.get("h1")); } @Test public void testSetValueDate() throws Exception { Date date = new Date(); - @SuppressWarnings("deprecation") - String strDate = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date, true); - createClientRequest(); + String strDate = new StdDateFormat().format(date); + String cookieValue = RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date); + Mockito.doAnswer(invocation -> { + cookies.put("h1", cookieValue); + return null; + }).when(clientRequest).addCookie("h1", cookieValue); CookieProcessor processor = createProcessor("h1", Date.class); processor.setValue(clientRequest, date); - Assert.assertEquals(strDate, cookies.get("h1")); + Assertions.assertEquals(strDate, cookies.get("h1")); } @Test public void testGetProcessorType() { - CookieProcessor processor = createProcessor("c1", String.class); - Assert.assertEquals("cookie", processor.getProcessorType()); + CookieProcessor processor = createProcessor(cookieName, String.class); + Assertions.assertEquals("cookie", processor.getProcessorType()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java index 1d23d900999..d3769dcb2c5 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java @@ -18,21 +18,33 @@ package org.apache.servicecomb.common.rest.codec.param; import org.apache.servicecomb.common.rest.codec.param.CookieProcessorCreator.CookieProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.CookieParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.CookieParameter; public class TestCookieProcessorCreator { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + } + @Test public void testCreate() { ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.findValue(CookieProcessorCreator.PARAMTYPE); CookieParameter p = new CookieParameter(); p.setName("p1"); + p.setSchema(new Schema()); + ParamValueProcessor processor = creator.create(null, p.getName(), p, String.class); - ParamValueProcessor processor = creator.create(p, String.class); - - Assert.assertEquals(CookieProcessor.class, processor.getClass()); + Assertions.assertEquals(CookieProcessor.class, processor.getClass()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java index c14403e6e4f..42aa5343bef 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java @@ -17,204 +17,186 @@ package org.apache.servicecomb.common.rest.codec.param; +import java.lang.reflect.Type; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator.FormProcessor; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.MediaType; public class TestFormProcessor { - @Mocked - HttpServletRequest request; + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - Map forms = new HashMap<>(); + final Map forms = new HashMap<>(); - RestClientRequest clientRequest; + final RestClientRequest clientRequest = Mockito.mock(RestClientRequest.class); - private FormProcessor createProcessor(String name, Class type) { - return new FormProcessor(name, TypeFactory.defaultInstance().constructType(type), null, true); + private FormProcessor createProcessor(String name, Type type) { + return createProcessor(name, type, null, true); } - private FormProcessor createProcessor(String name, Class type, String defaultValue, boolean required) { - return new FormProcessor(name, TypeFactory.defaultInstance().constructType(type), defaultValue, required); - } + private FormProcessor createProcessor(String name, Type type, String defaultValue, boolean required) { + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + + RequestBody formParameter = new RequestBody(); + Content content = new Content(); + MapSchema schema = new MapSchema(); + io.swagger.v3.oas.models.media.MediaType mediaType = new io.swagger.v3.oas.models.media.MediaType(); + + if (javaType.isContainerType()) { + Schema propertySchema = new ArraySchema(); + schema.addProperty(name, propertySchema); + mediaType.schema(schema); + } else { + Schema propertySchema = new Schema(); + propertySchema.setDefault(defaultValue); + schema.addProperty(name, propertySchema); + mediaType.schema(schema); + } + + content.addMediaType(MediaType.APPLICATION_FORM_URLENCODED, + mediaType); + formParameter.content(content) + .required(required); - private void createClientRequest() { - clientRequest = new MockUp() { - @Mock - void addForm(String name, Object value) { - forms.put(name, value); - } - }.getMockInstance(); + return new FormProcessor(name, formParameter, MediaType.APPLICATION_FORM_URLENCODED, javaType); } @Test public void testGetValueWithAttr() throws Exception { Map forms = new HashMap<>(); forms.put("name", "value"); - new Expectations() { - { - request.getAttribute(RestConst.FORM_PARAMETERS); - result = forms; - } - }; + Mockito.when(request.getAttribute(RestConst.BODY_PARAMETER)).thenReturn(forms); ParamValueProcessor processor = createProcessor("name", String.class); Object value = processor.getValue(request); - Assert.assertEquals("value", value); + Assertions.assertEquals("value", value); } @Test public void testGetValueNormal() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = "value"; - } - }; + Mockito.when(request.getParameter("name")).thenReturn("value"); ParamValueProcessor processor = createProcessor("name", String.class); Object value = processor.getValue(request); - Assert.assertEquals("value", value); + Assertions.assertEquals("value", value); } - @SuppressWarnings("deprecation") @Test public void testGetValueNormalDate() throws Exception { Date date = new Date(); String strDate = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date); - new Expectations() { - { - request.getParameter("name"); - result = strDate; - } - }; + Mockito.when(request.getParameter("name")).thenReturn(strDate); ParamValueProcessor processor = createProcessor("name", Date.class); Object value = processor.getValue(request); - Assert.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); + Assertions.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); } @Test public void testGetValueContainerTypeNull() throws Exception { - new Expectations() { - { - request.getParameterValues("name"); - result = null; - } - }; + Mockito.when(request.getParameterValues("name")).thenReturn(null); ParamValueProcessor processor = createProcessor("name", String[].class, null, false); String[] value = (String[]) processor.getValue(request); - Assert.assertNull(value); + Assertions.assertNull(value); } @Test public void testGetValueNull() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = null; - } - }; + Mockito.when(request.getParameter("name")).thenReturn(null); ParamValueProcessor processor = createProcessor("name", String.class, null, true); try { processor.getValue(request); - Assert.assertEquals("required is true, throw exception", "not throw exception"); + Assertions.assertEquals("required is true, throw exception", "not throw exception"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("Parameter is required.")); + Assertions.assertTrue(e.getMessage().contains("Parameter is required.")); } } @Test public void testGetValueArray() throws Exception { - new Expectations() { - { - request.getParameterValues("name"); - result = new String[] {"value"}; - } - }; + Mockito.when(request.getParameterValues("name")).thenReturn(new String[] {"value"}); ParamValueProcessor processor = createProcessor("name", String[].class); String[] value = (String[]) processor.getValue(request); - Assert.assertThat(value, Matchers.arrayContaining("value")); + MatcherAssert.assertThat(value, Matchers.arrayContaining("value")); } @SuppressWarnings("unchecked") @Test public void testGetValueList() throws Exception { - new Expectations() { - { - request.getParameterValues("name"); - result = new String[] {"value"}; - } - }; - - ParamValueProcessor processor = - new FormProcessor("name", TypeFactory.defaultInstance().constructCollectionType(List.class, String.class), - null, true); + Mockito.when(request.getParameterValues("name")).thenReturn(new String[] {"value"}); + + ParamValueProcessor processor = createProcessor("name", + TypeFactory.defaultInstance().constructCollectionType(List.class, String.class), + null, true); Object value = processor.getValue(request); - Assert.assertThat((List) value, Matchers.contains("value")); + MatcherAssert.assertThat((List) value, Matchers.contains("value")); } @SuppressWarnings("unchecked") @Test public void testGetValueSet() throws Exception { - new Expectations() { - { - request.getParameterValues("name"); - result = new String[] {"value"}; - } - }; - - ParamValueProcessor processor = - new FormProcessor("name", TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), null, - true); + Mockito.when(request.getParameterValues("name")).thenReturn(new String[] {"value"}); + + ParamValueProcessor processor = createProcessor("name", + TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), null, + true); Object value = processor.getValue(request); - Assert.assertThat((Set) value, Matchers.contains("value")); + MatcherAssert.assertThat((Set) value, Matchers.contains("value")); } @Test public void testSetValue() throws Exception { - createClientRequest(); + Mockito.doAnswer(invocation -> { + forms.put("name", "value"); + return null; + }).when(clientRequest).addForm("name", "value"); ParamValueProcessor processor = createProcessor("name", String.class); processor.setValue(clientRequest, "value"); - Assert.assertEquals("value", forms.get("name")); + Assertions.assertEquals("value", forms.get("name")); } @Test public void testSetValueDate() throws Exception { Date date = new Date(); - createClientRequest(); - + Mockito.doAnswer(invocation -> { + forms.put("name", date); + return null; + }).when(clientRequest).addForm("name", date); ParamValueProcessor processor = createProcessor("name", Date.class); processor.setValue(clientRequest, date); - Assert.assertSame(date, forms.get("name")); + Assertions.assertSame(date, forms.get("name")); } @Test public void testGetProcessorType() { ParamValueProcessor processor = createProcessor("name", String.class); - Assert.assertEquals("formData", processor.getProcessorType()); + Assertions.assertEquals("formData", processor.getProcessorType()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java index 4551f6a1366..f2b7b9c393e 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java @@ -17,22 +17,32 @@ package org.apache.servicecomb.common.rest.codec.param; +import java.util.HashMap; + import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator.FormProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import io.swagger.models.parameters.FormParameter; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +@SuppressWarnings({"rawtypes", "unchecked"}) public class TestFormProcessorCreator { @Test public void testCreate() { ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.findValue(FormProcessorCreator.PARAMTYPE); - FormParameter p = new FormParameter(); - p.setName("p1"); + RequestBody p = new RequestBody(); + p.setContent(new Content()); + p.getContent().addMediaType(SwaggerConst.FORM_MEDIA_TYPE, new MediaType()); + p.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).setSchema(new Schema()); + p.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().setProperties(new HashMap<>()); - ParamValueProcessor processor = creator.create(p, String.class); + ParamValueProcessor processor = creator.create(null, "p1", p, String.class); - Assert.assertEquals(FormProcessor.class, processor.getClass()); + Assertions.assertEquals(FormProcessor.class, processor.getClass()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java index a205336605d..39bed2e809b 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.common.rest.codec.param; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -25,205 +26,202 @@ import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.codec.RestClientRequest; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.databind.util.StdDateFormat; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import jakarta.servlet.http.HttpServletRequest; public class TestHeaderProcessor { - @Mocked - HttpServletRequest request; + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - Map headers = new HashMap<>(); + final Map headers = new HashMap<>(); - RestClientRequest clientRequest; + final RestClientRequest clientRequest = Mockito.mock(RestClientRequest.class); - private HeaderProcessor createProcessor(String name, Class type) { - return new HeaderProcessor(name, TypeFactory.defaultInstance().constructType(type), null, true); + private HeaderProcessor createProcessor(String name, Type type) { + return createProcessor(name, type, null, true); } - private HeaderProcessor createProcessor(String name, Class type, String defaultValue, boolean required) { - return new HeaderProcessor(name, TypeFactory.defaultInstance().constructType(type), defaultValue, required); + private HeaderProcessor createProcessor(String name, Type type, String defaultValue, boolean required) { + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + + HeaderParameter headerParameter = new HeaderParameter(); + headerParameter.setSchema(new Schema()); + headerParameter.name(name) + .required(required); + headerParameter.getSchema().setDefault(defaultValue); + + if (javaType.isContainerType()) { + headerParameter.schema(new ArraySchema()); + } + return new HeaderProcessor(headerParameter, javaType); } - private void createClientRequest() { - clientRequest = new MockUp() { - @Mock - void putHeader(String name, String value) { - headers.put(name, value); - } - }.getMockInstance(); + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + void setUp() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.header.ignoreRequiredCheck" + , boolean.class, false)).thenReturn(false); } @Test public void testGetValueNormal() throws Exception { - new Expectations() { - { - request.getHeader("h1"); - result = "h1v"; - } - }; + Mockito.when(request.getHeader("h1")).thenReturn("h1v"); HeaderProcessor processor = createProcessor("h1", String.class); Object value = processor.getValue(request); - Assert.assertEquals("h1v", value); + Assertions.assertEquals("h1v", value); } - @SuppressWarnings("deprecation") @Test public void testGetValueNormalDate() throws Exception { Date date = new Date(); String strDate = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date); - new Expectations() { - { - request.getHeader("h1"); - result = strDate; - } - }; + Mockito.when(request.getHeader("h1")).thenReturn(strDate); HeaderProcessor processor = createProcessor("h1", Date.class); Object value = processor.getValue(request); - Assert.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); + Assertions.assertEquals(strDate, com.fasterxml.jackson.databind.util.ISO8601Utils.format((Date) value)); } @Test public void testGetValueContainerTypeNull() throws Exception { - new Expectations() { - { - request.getHeaders("h1"); - result = null; - } - }; + Mockito.when(request.getHeader("h1")).thenReturn(null); HeaderProcessor processor = createProcessor("h1", String[].class, null, false); String[] value = (String[]) processor.getValue(request); - Assert.assertNull(value); + Assertions.assertNull(value); } @Test public void testGetValueRequiredTrue() throws Exception { - new Expectations() { - { - request.getHeader("h1"); - result = null; - } - }; + Mockito.when(request.getHeader("h1")).thenReturn(null); HeaderProcessor processor = createProcessor("h1", String.class); try { processor.getValue(request); - Assert.assertEquals("required is true, throw exception", "not throw exception"); + Assertions.assertEquals("required is true, throw exception", "not throw exception"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("Parameter is required.")); + Assertions.assertTrue(e.getMessage().contains("Parameter is required.")); } } @Test public void testGetValueRequiredFalse() throws Exception { - new Expectations() { - { - request.getHeader("h1"); - result = null; - } - }; + Mockito.when(request.getHeader("h1")).thenReturn(null); HeaderProcessor processor = createProcessor("h1", String.class, "test", false); Object value = processor.getValue(request); - Assert.assertEquals("test", value); + Assertions.assertEquals("test", value); } @Test public void testGetValueArray() throws Exception { - new Expectations() { - { - request.getHeaders("h1"); - result = Collections.enumeration(Arrays.asList("h1v")); - } - }; + Mockito.when(request.getHeaders("h1")).thenReturn(Collections.enumeration(Arrays.asList("h1v"))); HeaderProcessor processor = createProcessor("h1", String[].class); String[] value = (String[]) processor.getValue(request); - Assert.assertThat(value, Matchers.arrayContaining("h1v")); + MatcherAssert.assertThat(value, Matchers.arrayContaining("h1v")); } @SuppressWarnings("unchecked") @Test public void testGetValueList() throws Exception { - new Expectations() { - { - request.getHeaders("h1"); - result = Collections.enumeration(Arrays.asList("h1v")); - } - }; - - HeaderProcessor processor = - new HeaderProcessor("h1", TypeFactory.defaultInstance().constructCollectionType(List.class, String.class), - null, true); + Mockito.when(request.getHeaders("h1")).thenReturn(Collections.enumeration(Arrays.asList("h1v"))); + + HeaderProcessor processor = createProcessor("h1", + TypeFactory.defaultInstance().constructCollectionType(List.class, String.class), + null, true); Object value = processor.getValue(request); - Assert.assertThat((List) value, Matchers.contains("h1v")); + MatcherAssert.assertThat((List) value, Matchers.contains("h1v")); } @SuppressWarnings("unchecked") @Test public void testGetValueSet() throws Exception { - new Expectations() { - { - request.getHeaders("h1"); - result = Collections.enumeration(Arrays.asList("h1v")); - } - }; - - HeaderProcessor processor = - new HeaderProcessor("h1", TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), null, - true); + Mockito.when(request.getHeaders("h1")).thenReturn(Collections.enumeration(Arrays.asList("h1v"))); + + HeaderProcessor processor = createProcessor("h1", + TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), + null, true); Object value = processor.getValue(request); - Assert.assertThat((Set) value, Matchers.contains("h1v")); + MatcherAssert.assertThat((Set) value, Matchers.contains("h1v")); } @Test public void testSetValue() throws Exception { - createClientRequest(); + Mockito.doAnswer(invocation -> { + headers.put("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString("h1v")); + return null; + }).when(clientRequest).putHeader("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString("h1v")); HeaderProcessor processor = createProcessor("h1", String.class); processor.setValue(clientRequest, "h1v"); - Assert.assertEquals("h1v", headers.get("h1")); + Assertions.assertEquals("h1v", headers.get("h1")); } @Test public void testSetValueNull() throws Exception { - createClientRequest(); + Mockito.doAnswer(invocation -> { + headers.put("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(null)); + return null; + }).when(clientRequest).putHeader("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(null)); HeaderProcessor processor = createProcessor("h1", String.class); processor.setValue(clientRequest, null); - Assert.assertEquals(0, headers.size()); + Assertions.assertEquals(0, headers.size()); + } + + @Test + public void testSetValueDateFixed() throws Exception { + Date date = new Date(1586957400199L); + String strDate = "2020-04-15T13:30:00.199+00:00"; + + Mockito.doAnswer(invocation -> { + headers.put("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date)); + return null; + }).when(clientRequest).putHeader("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date)); + + HeaderProcessor processor = createProcessor("h1", Date.class); + processor.setValue(clientRequest, date); + Assertions.assertEquals(strDate, headers.get("h1")); } @Test public void testSetValueDate() throws Exception { Date date = new Date(); - @SuppressWarnings("deprecation") - String strDate = com.fasterxml.jackson.databind.util.ISO8601Utils.format(date, true); - - createClientRequest(); + String strDate = new StdDateFormat().format(date); + Mockito.doAnswer(invocation -> { + headers.put("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date)); + return null; + }).when(clientRequest).putHeader("h1", RestObjectMapperFactory.getConsumerWriterMapper().convertToString(date)); HeaderProcessor processor = createProcessor("h1", Date.class); processor.setValue(clientRequest, date); - Assert.assertEquals(strDate, headers.get("h1")); + Assertions.assertEquals(strDate, headers.get("h1")); } @Test public void testGetProcessorType() { HeaderProcessor processor = createProcessor("h1", String.class); - Assert.assertEquals("header", processor.getProcessorType()); + Assertions.assertEquals("header", processor.getProcessorType()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java index 8e8e9f4ef68..d275b16b62e 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java @@ -18,21 +18,36 @@ package org.apache.servicecomb.common.rest.codec.param; import org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.HeaderParameter; public class TestHeaderProcessorCreator { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.header.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + @Test public void testCreate() { ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.findValue(HeaderProcessorCreator.PARAMTYPE); HeaderParameter hp = new HeaderParameter(); hp.setName("h1"); + hp.setSchema(new Schema()); - ParamValueProcessor processor = creator.create(hp, String.class); + ParamValueProcessor processor = creator.create(null, hp.getName(), hp, String.class); - Assert.assertEquals(HeaderProcessor.class, processor.getClass()); + Assertions.assertEquals(HeaderProcessor.class, processor.getClass()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java index 19cca94bb55..ff8218768cf 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java @@ -20,23 +20,20 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.param.PathProcessorCreator.PathProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.databind.type.TypeFactory; - -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestPathProcessor { - @Mocked - HttpServletRequest request; + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - Map pathVars = new HashMap<>(); + final Map pathVars = new HashMap<>(); ParamValueProcessor processor; @@ -46,26 +43,21 @@ private void createProcessor(String name, Class type) { private void prepareGetValue(String name, Class type) { createProcessor(name, type); - new Expectations() { - { - request.getAttribute(RestConst.PATH_PARAMETERS); - result = pathVars; - } - }; + Mockito.when(request.getAttribute(RestConst.PATH_PARAMETERS)).thenReturn(pathVars); } @Test public void testGetValueNoPathVars() throws Exception { createProcessor("name", String.class); - Assert.assertEquals(null, processor.getValue(request)); + Assertions.assertNull(processor.getValue(request)); } @Test public void testGetValuePathNotFound() throws Exception { prepareGetValue("name", String.class); - Assert.assertEquals(null, processor.getValue(request)); + Assertions.assertNull(processor.getValue(request)); } @Test @@ -73,7 +65,7 @@ public void testGetValuePathNormal() throws Exception { prepareGetValue("name", String.class); pathVars.put("name", "value"); - Assert.assertEquals("value", processor.getValue(request)); + Assertions.assertEquals("value", processor.getValue(request)); } @Test @@ -81,7 +73,7 @@ public void testGetSpaceEncoded() throws Exception { prepareGetValue("name", String.class); pathVars.put("name", "a%20b"); - Assert.assertEquals("a b", processor.getValue(request)); + Assertions.assertEquals("a b", processor.getValue(request)); } @Test @@ -89,7 +81,7 @@ public void testGetPlus() throws Exception { prepareGetValue("name", String.class); pathVars.put("name", "a+b"); - Assert.assertEquals("a+b", processor.getValue(request)); + Assertions.assertEquals("a+b", processor.getValue(request)); } @Test @@ -97,12 +89,19 @@ public void testGetPercentage() throws Exception { prepareGetValue("name", String.class); pathVars.put("name", "%25%25"); - Assert.assertEquals("%%", processor.getValue(request)); + Assertions.assertEquals("%%", processor.getValue(request)); + } + + @Test + public void testGetColon() throws Exception { + prepareGetValue("name", String.class); + pathVars.put("name", "aa:bb"); + Assertions.assertEquals("aa:bb", processor.getValue(request)); } @Test public void testGetProcessorType() { createProcessor("name", String.class); - Assert.assertEquals("path", processor.getProcessorType()); + Assertions.assertEquals("path", processor.getProcessorType()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java index b6a99327851..0f40291c82b 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java @@ -18,11 +18,12 @@ package org.apache.servicecomb.common.rest.codec.param; import org.apache.servicecomb.common.rest.codec.param.PathProcessorCreator.PathProcessor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; public class TestPathProcessorCreator { @Test @@ -31,9 +32,10 @@ public void testCreate() { ParamValueProcessorCreatorManager.INSTANCE.findValue(PathProcessorCreator.PARAMTYPE); Parameter parameter = new PathParameter(); parameter.setName("path"); + parameter.setSchema(new Schema()); - ParamValueProcessor processor = creator.create(parameter, String.class); + ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class); - Assert.assertEquals(PathProcessor.class, processor.getClass()); + Assertions.assertEquals(PathProcessor.class, processor.getClass()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java index 4a3e6d70a60..be18fb8378b 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java @@ -17,109 +17,117 @@ package org.apache.servicecomb.common.rest.codec.param; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import mockit.Expectations; -import mockit.Mocked; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; +import io.swagger.v3.oas.models.parameters.QueryParameter; +import jakarta.servlet.http.HttpServletRequest; public class TestQueryProcessor { - @Mocked - HttpServletRequest request; + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + + final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - private ParamValueProcessor createProcessor(String name, Class type, String collectionFormat) { - return new QueryProcessor(name, TypeFactory.defaultInstance().constructType(type), null, true, collectionFormat); + private ParamValueProcessor createProcessor(String name, Class type, + Parameter.StyleEnum style, boolean explode) { + return createProcessor(name, type, null, true, style, explode); } private ParamValueProcessor createProcessor(String name, Class type, String defaultValue, boolean required, - String collectionFormat) { - return new QueryProcessor(name, TypeFactory.defaultInstance().constructType(type), defaultValue, required, - collectionFormat); + Parameter.StyleEnum style, boolean explode) { + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + + QueryParameter queryParameter = new QueryParameter(); + queryParameter.name(name) + .required(required) + .setSchema(new StringSchema()); + queryParameter.getSchema().setDefault(defaultValue); + + if (javaType.isContainerType()) { + queryParameter.setSchema(new ArraySchema()); + queryParameter.setExplode(explode); + queryParameter.setStyle(style); + } + return new QueryProcessor(queryParameter, javaType); } @Test public void testGetValueNormal() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = "value"; - } - }; - - ParamValueProcessor processor = createProcessor("name", String.class, "multi"); + Mockito.when(request.getParameter("name")).thenReturn("value"); + + ParamValueProcessor processor = createProcessor("name", String.class, StyleEnum.FORM, true); Object value = processor.getValue(request); - Assert.assertEquals("value", value); + Assertions.assertEquals("value", value); } @Test public void testGetValueContainerType() throws Exception { - new Expectations() { - { - request.getParameterValues("name"); - result = new String[] {"value", "value2"}; - } - }; - - ParamValueProcessor processor = createProcessor("name", String[].class, "multi"); + Mockito.when(request.getParameterValues("name")).thenReturn(new String[] {"value", "value2"}); + + ParamValueProcessor processor = createProcessor("name", String[].class, StyleEnum.FORM, true); String[] value = (String[]) processor.getValue(request); - Assert.assertThat(value, Matchers.arrayContaining("value", "value2")); + MatcherAssert.assertThat(value, Matchers.arrayContaining("value", "value2")); } @Test public void testGetValueOnCollectionFormatIsCsv() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = "value2,value3"; - } - }; - - ParamValueProcessor processor = createProcessor("name", String[].class, "csv"); + Mockito.when(request.getParameter("name")).thenReturn("value2,value3"); + + ParamValueProcessor processor = createProcessor("name", String[].class, StyleEnum.FORM, false); String[] value = (String[]) processor.getValue(request); - Assert.assertThat(value, Matchers.arrayContaining("value2", "value3")); + MatcherAssert.assertThat(value, Matchers.arrayContaining("value2", "value3")); } @Test public void testGetProcessorType() { - ParamValueProcessor processor = createProcessor("name", String.class, "multi"); - Assert.assertEquals("query", processor.getProcessorType()); + ParamValueProcessor processor = createProcessor("name", String.class, StyleEnum.FORM, true); + Assertions.assertEquals("query", processor.getProcessorType()); } @Test public void testGetValueRequiredTrue() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = null; - } - }; - - ParamValueProcessor processor = createProcessor("name", String.class, "multi"); + Mockito.when(request.getParameter("name")).thenReturn(null); + + ParamValueProcessor processor = createProcessor("name", String.class, StyleEnum.FORM, true); try { processor.getValue(request); - Assert.assertEquals("required is true, throw exception", "not throw exception"); + Assertions.assertEquals("required is true, throw exception", "not throw exception"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("Parameter is required.")); + Assertions.assertTrue(e.getMessage().contains("Parameter name is required.")); } } @Test public void testGetValueRequiredFalse() throws Exception { - new Expectations() { - { - request.getParameter("name"); - result = null; - } - }; - - ParamValueProcessor processor = createProcessor("name", String.class, "test", false, "multi"); + Mockito.when(request.getParameter("name")).thenReturn(null); + + ParamValueProcessor processor = createProcessor("name", String.class, "test", false, StyleEnum.FORM, true); Object result = processor.getValue(request); - Assert.assertEquals("test", result); + Assertions.assertEquals("test", result); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java index f5b0e77e7e6..a75e1df2b2f 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java @@ -17,66 +17,83 @@ package org.apache.servicecomb.common.rest.codec.param; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.springframework.core.env.Environment; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; +import jakarta.servlet.http.HttpServletRequest; public class TestQueryProcessorCreator { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + @Test public void testCreate() { ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.findValue(QueryProcessorCreator.PARAMTYPE); Parameter parameter = new QueryParameter(); parameter.setName("query"); + parameter.setSchema(new Schema()); + ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class); - ParamValueProcessor processor = creator.create(parameter, String.class); - - Assert.assertEquals(QueryProcessor.class, processor.getClass()); + Assertions.assertEquals(QueryProcessor.class, processor.getClass()); String result = (String) processor.convertValue("Hello", TypeFactory.defaultInstance().constructType(String.class)); - Assert.assertEquals("Hello", result); + Assertions.assertEquals("Hello", result); result = (String) processor.convertValue("", TypeFactory.defaultInstance().constructType(String.class)); - Assert.assertEquals("", result); + Assertions.assertEquals("", result); result = (String) processor.convertValue(null, TypeFactory.defaultInstance().constructType(String.class)); - Assert.assertEquals(null, result); + Assertions.assertNull(result); } @SuppressWarnings("UnusedAssignment") @Test public void testCreateNullAsEmpty() throws Exception { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - ArchaiusUtils.setProperty("servicecomb.rest.parameter.query.emptyAsNull", "true"); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(true); ParamValueProcessorCreator creator = ParamValueProcessorCreatorManager.INSTANCE.findValue(QueryProcessorCreator.PARAMTYPE); Parameter parameter = new QueryParameter(); parameter.setName("query"); + parameter.setSchema(new Schema()); - ParamValueProcessor processor = creator.create(parameter, String.class); + ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class); - Assert.assertEquals(QueryProcessor.class, processor.getClass()); + Assertions.assertEquals(QueryProcessor.class, processor.getClass()); Mockito.when(request.getParameter("query")).thenReturn("Hello"); String result = (String) processor.getValue(request); - Assert.assertEquals("Hello", result); + Assertions.assertEquals("Hello", result); Mockito.when(request.getParameter("query")).thenReturn(""); result = (String) processor.getValue(request); - Assert.assertEquals(null, result); + Assertions.assertNull(result); Mockito.when(request.getParameter("query")).thenReturn(null); result = (String) processor.convertValue(null, TypeFactory.defaultInstance().constructType(String.class)); result = (String) processor.getValue(request); - Assert.assertEquals(null, result); + Assertions.assertNull(result); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java deleted file mode 100644 index 137063fd440..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.codec.param; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import javax.servlet.http.Part; -import javax.ws.rs.core.MediaType; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.CaseInsensitiveHeaders; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpHeaders; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRestClientRequestImpl { - @Mocked - private HttpClientRequest request; - - @Test - public void testForm() throws Exception { - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - restClientRequest.addForm("abc", "Hello"); - restClientRequest.addForm("def", "world"); - restClientRequest.addForm("ghi", null); - Buffer buffer = restClientRequest.getBodyBuffer(); - Assert.assertEquals("abc=Hello&def=world&", buffer.toString()); - } - - @Test - public void testCookie() throws Exception { - HttpClientRequest request = new MockUp() { - - MultiMap map = new CaseInsensitiveHeaders(); - - @Mock - public HttpClientRequest putHeader(CharSequence key, CharSequence val) { - map.add(key, val); - return null; - } - - @Mock - public MultiMap headers() { - return map; - } - }.getMockInstance(); - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - restClientRequest.addCookie("sessionid", "abcdefghijklmnopqrstuvwxyz"); - restClientRequest.addCookie("region", "china-north"); - restClientRequest.write(Buffer.buffer("I love servicecomb")); - restClientRequest.end(); - Buffer buffer = restClientRequest.getBodyBuffer(); - Assert.assertEquals("I love servicecomb", buffer.toString()); - Assert.assertEquals("sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ", - restClientRequest.request.headers().get(HttpHeaders.COOKIE)); - } - - @Test - public void fileBoundaryInfo_nullSubmittedFileName(@Mocked Part part) { - new Expectations() { - { - part.getSubmittedFileName(); - result = null; - part.getContentType(); - result = "abc"; - } - }; - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - Buffer buffer = restClientRequest.fileBoundaryInfo("boundary", "name", part); - Assert.assertEquals("\r\n" + - "--boundary\r\n" + - "Content-Disposition: form-data; name=\"name\"; filename=\"null\"\r\n" + - "Content-Type: abc\r\n" + - "Content-Transfer-Encoding: binary\r\n" + - "\r\n", buffer.toString()); - } - - @Test - public void fileBoundaryInfo_validSubmittedFileName(@Mocked Part part) { - new Expectations() { - { - part.getSubmittedFileName(); - result = "a.txt"; - part.getContentType(); - result = MediaType.TEXT_PLAIN; - } - }; - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - Buffer buffer = restClientRequest.fileBoundaryInfo("boundary", "name", part); - Assert.assertEquals("\r\n" + - "--boundary\r\n" + - "Content-Disposition: form-data; name=\"name\"; filename=\"a.txt\"\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Transfer-Encoding: binary\r\n" + - "\r\n", buffer.toString()); - } - - @Test - public void testAttach() { - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - Part part = Mockito.mock(Part.class); - String fileName = "fileName"; - - restClientRequest.attach(fileName, part); - - Map uploads = Deencapsulation.getField(restClientRequest, "uploads"); - Assert.assertEquals(1, uploads.size()); - Assert.assertThat(uploads, Matchers.hasEntry(fileName, part)); - } - - @Test - public void testAttachOnPartIsNull() { - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - - restClientRequest.attach("fileName", null); - - Map uploads = Deencapsulation.getField(restClientRequest, "uploads"); - Assert.assertTrue(uploads.isEmpty()); - } - - @Test - public void doEndWithUpload() { - Map headers = new HashMap<>(); - new MockUp(request) { - @Mock - HttpClientRequest putHeader(String name, String value) { - headers.put(name, value); - return request; - } - }; - - UUID uuid = new UUID(0, 0); - new Expectations(UUID.class) { - { - UUID.randomUUID(); - result = uuid; - } - }; - RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, null, null); - restClientRequest.doEndWithUpload(); - - Assert.assertEquals("multipart/form-data; charset=UTF-8; boundary=boundary00000000-0000-0000-0000-000000000000", - headers.get(HttpHeaders.CONTENT_TYPE.toString())); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceJsonProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceJsonProcessor.java index 98a83d953a9..db8e71cd5a9 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceJsonProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceJsonProcessor.java @@ -17,58 +17,59 @@ package org.apache.servicecomb.common.rest.codec.produce; +import static org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager.DEFAULT_SERIAL_CLASS; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.type.TypeFactory; import io.vertx.core.buffer.Buffer; +import org.junit.jupiter.api.Test; public class TestProduceJsonProcessor { - ProduceProcessor pp = ProduceProcessorManager.JSON_PROCESSOR; + final ProduceProcessor pp = ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(); - JavaType stringType = TypeFactory.defaultInstance().constructType(String.class); + final JavaType stringType = TypeFactory.defaultInstance().constructType(String.class); @Test public void testEncodeResponseNull() throws Exception { Buffer buffer = pp.encodeResponse(null); - Assert.assertNull(buffer); + Assertions.assertNull(buffer); ByteArrayOutputStream os = new ByteArrayOutputStream(); pp.encodeResponse(os, null); - Assert.assertEquals(0, os.size()); + Assertions.assertEquals(0, os.size()); } @Test - public void testdecodeResponseNull() throws Exception { + public void testDecodeResponseNull() throws Exception { JavaType resultType = TypeFactory.unknownType(); Object result = pp.decodeResponse(Buffer.buffer(), resultType); - Assert.assertNull(result); + Assertions.assertNull(result); ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {}); try { pp.decodeResponse(is, resultType); - Assert.fail(); + Assertions.fail(); } catch (Exception e) { - Assert.assertTrue(e instanceof MismatchedInputException); + Assertions.assertTrue(e instanceof MismatchedInputException); } - } @Test public void testBufferNormal() throws Exception { String value = "abc"; Buffer buffer = pp.encodeResponse(value); - Assert.assertEquals("\"abc\"", buffer.toString(StandardCharsets.UTF_8)); + Assertions.assertEquals("\"abc\"", buffer.toString(StandardCharsets.UTF_8)); Object result = pp.decodeResponse(buffer, stringType); - Assert.assertEquals(value, result); + Assertions.assertEquals(value, result); } @Test @@ -77,13 +78,24 @@ public void testStreamNormal() throws Exception { ByteArrayOutputStream os = new ByteArrayOutputStream(); pp.encodeResponse(os, value); - Assert.assertEquals("\"abc\"", os.toString(StandardCharsets.UTF_8.name())); + Assertions.assertEquals("\"abc\"", os.toString(StandardCharsets.UTF_8.name())); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); Object result = pp.decodeResponse(is, stringType); - Assert.assertEquals(value, result); + Assertions.assertEquals(value, result); os.close(); is.close(); } + + @Test + public void testSetSerializationView() { + Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView()); + + pp.setSerializationView(null); + Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView()); + + pp.setSerializationView(Object.class); + Assertions.assertEquals(Object.class.getCanonicalName(), pp.getSerializationView()); + } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceProcessorManager.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceProcessorManager.java index 5310a7ac4df..58dd3e6d856 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceProcessorManager.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceProcessorManager.java @@ -17,12 +17,13 @@ package org.apache.servicecomb.common.rest.codec.produce; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestProduceProcessorManager { @Test public void testDefault() { - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, ProduceProcessorManager.DEFAULT_PROCESSOR); + Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(), + ProduceProcessorManager.INSTANCE.findDefaultProcessor()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java index 905f70f155c..d717072a27c 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java @@ -17,52 +17,54 @@ package org.apache.servicecomb.common.rest.codec.produce; +import static org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager.DEFAULT_SERIAL_CLASS; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; import io.vertx.core.buffer.Buffer; +import org.junit.jupiter.api.Test; public class TestProduceTextPlainProcessor { - ProduceProcessor pp = ProduceProcessorManager.PLAIN_PROCESSOR; + final ProduceProcessor pp = ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(); - JavaType stringType = TypeFactory.defaultInstance().constructType(String.class); + final JavaType stringType = TypeFactory.defaultInstance().constructType(String.class); @Test public void testEncodeResponseNull() throws Exception { Buffer buffer = pp.encodeResponse(null); - Assert.assertNull(buffer); + Assertions.assertNull(buffer); ByteArrayOutputStream os = new ByteArrayOutputStream(); pp.encodeResponse(os, null); - Assert.assertEquals(0, os.size()); + Assertions.assertEquals(0, os.size()); } @Test public void testdecodeResponseNull() throws Exception { JavaType resultType = TypeFactory.unknownType(); Object result = pp.decodeResponse(Buffer.buffer(), resultType); - Assert.assertNull(result); + Assertions.assertNull(result); - ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {}); + ByteArrayInputStream is = new ByteArrayInputStream("\"\"".getBytes(StandardCharsets.UTF_8)); result = pp.decodeResponse(is, resultType); - Assert.assertEquals(result, ""); + Assertions.assertEquals(result, ""); } @Test public void testBufferNormal() throws Exception { String value = "abc"; Buffer buffer = pp.encodeResponse(value); - Assert.assertEquals(value, buffer.toString(StandardCharsets.UTF_8)); + Assertions.assertEquals(value, buffer.toString(StandardCharsets.UTF_8)); Object result = pp.decodeResponse(buffer, stringType); - Assert.assertEquals(value, result); + Assertions.assertEquals(value, result); } @Test @@ -71,13 +73,24 @@ public void testStreamNormal() throws Exception { ByteArrayOutputStream os = new ByteArrayOutputStream(); pp.encodeResponse(os, value); - Assert.assertEquals(value, os.toString(StandardCharsets.UTF_8.name())); + Assertions.assertEquals(value, os.toString(StandardCharsets.UTF_8.name())); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); Object result = pp.decodeResponse(is, stringType); - Assert.assertEquals(value, result); + Assertions.assertEquals(value, result); os.close(); is.close(); } + + @Test + public void testSetSerializationView() { + Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView()); + + pp.setSerializationView(null); + Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView()); + + pp.setSerializationView(Object.class); + Assertions.assertEquals("java.lang.Object", pp.getSerializationView()); + } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsvTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsvTest.java new file mode 100644 index 00000000000..890075cbe7a --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecCsvTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Date; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +class QueryCodecCsvTest extends QueryCodecTestBase { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + + @BeforeEach + void setUp() { + codec = new QueryCodecCsv(); + } + + @Nested + class Encode { + @Test + void should_encode_date() throws Exception { + should_encode("?q=1970-01-01T00%3A00%3A00.000%2B00%3A00", new Date(0)); + } + + @Test + void should_encode_single_value() throws Exception { + should_encode("?q=v1", "v1"); + } + + @Test + void should_encode_empty_string() throws Exception { + should_encode("?q=", ""); + } + + @Test + void should_encode_common_string() throws Exception { + should_encode("?q=v1%2Cv2", "v1", "v2"); + } + + @Test + void should_encode_common_numbers() throws Exception { + should_encode("?q=1%2C2", 1, 2); + } + + @Test + void should_encode_chinese_values() throws Exception { + should_encode("?q=%E4%B8%AD%E6%96%87%2Cv2", "中文", "v2"); + } + + @Test + void should_encode_ignore_null() throws Exception { + should_encode("?q=v1%2Cv2", "v1", null, "v2"); + } + + @Test + void should_encode_when_values_is_empty_after_ignore_null() throws Exception { + should_encode("", new Object[] {null}); + } + } + + @Nested + class Decode { + @Test + void should_decode_single_value_to_array() { + should_decode("1", new int[] {1}); + } + + @Test + void should_decode_common_values_to_array() { + should_decode("1,2", new int[] {1, 2}); + } + + @Test + void should_decode_null_to_array() { + should_decode((String) null, new int[] {}); + } + + @Test + void should_decode_empty_string_to_number() { + should_decode("", new int[] {0}); + } + + @Test + void should_decode_empty_string_to_string() { + should_decode("", new String[] {""}); + } + + @Test + void should_decode_common_values_with_empty_string_to_array() { + should_decode("1,,2", new int[] {1, 0, 2}); + } + + @Test + void should_decode_values_end_with_delimiter() { + should_decode("1,,", new int[] {1, 0, 0}); + } + + @Test + void should_decode_values_start_with_delimiter() { + should_decode(",,1", new int[] {0, 0, 1}); + } + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMultiTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMultiTest.java new file mode 100644 index 00000000000..3c56d1b1ce6 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecMultiTest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Date; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +class QueryCodecMultiTest extends QueryCodecTestBase { + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + void setUp() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + codec = new QueryCodecMulti(); + } + + @Nested + class Encode { + @Test + void should_encode_date() throws Exception { + should_encode("?q=1970-01-01T00%3A00%3A00.000%2B00%3A00", new Date(0)); + } + + @Test + void should_encode_single_value() throws Exception { + should_encode("?q=v1", "v1"); + } + + @Test + void should_encode_empty_string() throws Exception { + should_encode("?q=", ""); + } + + @Test + void should_encode_common_string() throws Exception { + should_encode("?q=v1&q=v2", "v1", "v2"); + } + + @Test + void should_encode_common_numbers() throws Exception { + should_encode("?q=1&q=2", 1, 2); + } + + @Test + void should_encode_chinese_values() throws Exception { + should_encode("?q=%E4%B8%AD%E6%96%87&q=v2", "中文", "v2"); + } + + @Test + void should_encode_ignore_null() throws Exception { + should_encode("?q=v1&q=v2", "v1", null, "v2"); + } + + @Test + void should_encode_when_values_is_empty_after_ignore_null() throws Exception { + should_encode("", new Object[] {null}); + } + } + + @Nested + class Decode { + @Test + void should_decode_single_value_to_array() { + should_decode(new String[] {"1"}, new int[] {1}); + } + + @Test + void should_decode_common_values_to_array() { + should_decode(new String[] {"1", "2"}, new int[] {1, 2}); + } + + @Test + void should_decode_empty_string_to_array() { + should_decode(new String[] {""}, new int[] {0}); + } + + @Test + void should_decode_common_values_with_empty_string_to_array() { + should_decode(new String[] {"1", "", "2"}, new int[] {1, 0, 2}); + } + + @Test + void should_decode_single_value_to_single() { + should_decode("1", 1); + } + + @Test + void should_decode_null_to_single() { + should_decode((String) null, null); + } + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipesTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipesTest.java new file mode 100644 index 00000000000..83f2b80062c --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecPipesTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Date; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +class QueryCodecPipesTest extends QueryCodecTestBase { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + + @BeforeEach + void setUp() { + codec = new QueryCodecPipes(); + } + + @Nested + class Encode { + @Test + void should_encode_date() throws Exception { + should_encode("?q=1970-01-01T00%3A00%3A00.000%2B00%3A00", new Date(0)); + } + + @Test + void should_encode_single_value() throws Exception { + should_encode("?q=v1", "v1"); + } + + @Test + void should_encode_empty_string() throws Exception { + should_encode("?q=", ""); + } + + @Test + void should_encode_common_string() throws Exception { + should_encode("?q=v1%7Cv2", "v1", "v2"); + } + + @Test + void should_encode_common_numbers() throws Exception { + should_encode("?q=1%7C2", 1, 2); + } + + @Test + void should_encode_chinese_values() throws Exception { + should_encode("?q=%E4%B8%AD%E6%96%87%7Cv2", "中文", "v2"); + } + + @Test + void should_encode_ignore_null() throws Exception { + should_encode("?q=v1%7Cv2", "v1", null, "v2"); + } + + @Test + void should_encode_when_values_is_empty_after_ignore_null() throws Exception { + should_encode("", new Object[] {null}); + } + } + + @Nested + class Decode { + @Test + void should_decode_single_value_to_array() { + should_decode("1", new int[] {1}); + } + + @Test + void should_decode_common_values_to_array() { + should_decode("1|2", new int[] {1, 2}); + } + + @Test + void should_decode_null_to_array() { + should_decode((String) null, new int[] {}); + } + + @Test + void should_decode_empty_string_to_number() { + should_decode("", new int[] {0}); + } + + @Test + void should_decode_empty_string_to_string() { + should_decode("", new String[] {""}); + } + + @Test + void should_decode_common_values_with_empty_string_to_array() { + should_decode("1||2", new int[] {1, 0, 2}); + } + + @Test + void should_decode_values_end_with_delimiter() { + should_decode("1||", new int[] {1, 0, 0}); + } + + @Test + void should_decode_values_start_with_delimiter() { + should_decode("||1", new int[] {0, 0, 1}); + } + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsvTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsvTest.java new file mode 100644 index 00000000000..c6e521f6718 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecSsvTest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.query; + +import java.util.Date; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class QueryCodecSsvTest extends QueryCodecTestBase { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + + @BeforeEach + void setUp() { + codec = new QueryCodecSsv(); + } + + @Nested + class Encode { + @Test + void should_encode_date() throws Exception { + should_encode("?q=1970-01-01T00%3A00%3A00.000%2B00%3A00", new Date(0)); + } + + @Test + void should_encode_single_value() throws Exception { + should_encode("?q=v1", "v1"); + } + + @Test + void should_encode_empty_string() throws Exception { + should_encode("?q=", ""); + } + + @Test + void should_encode_common_string() throws Exception { + should_encode("?q=v1+v2", "v1", "v2"); + } + + @Test + void should_encode_common_numbers() throws Exception { + should_encode("?q=1+2", 1, 2); + } + + @Test + void should_encode_chinese_values() throws Exception { + should_encode("?q=%E4%B8%AD%E6%96%87+v2", "中文", "v2"); + } + + @Test + void should_encode_ignore_null() throws Exception { + should_encode("?q=v1+v2", "v1", null, "v2"); + } + + @Test + void should_encode_when_values_is_empty_after_ignore_null() throws Exception { + should_encode("", new Object[] {null}); + } + } + + @Nested + class Decode { + @Test + void should_decode_single_value_to_array() { + should_decode("1", new int[] {1}); + } + + @Test + void should_decode_common_values_to_array() { + should_decode("1 2", new int[] {1, 2}); + } + + @Test + void should_decode_null_to_array() { + should_decode((String) null, new int[] {}); + } + + @Test + void should_decode_empty_string_to_number() { + should_decode("", new int[] {0}); + } + + @Test + void should_decode_empty_string_to_string() { + should_decode("", new String[] {""}); + } + + @Test + void should_decode_common_values_with_empty_string_to_array() { + should_decode("1 2", new int[] {1, 0, 2}); + } + + @Test + void should_decode_values_end_with_delimiter() { + should_decode("1 ", new int[] {1, 0, 0}); + } + + @Test + void should_decode_values_start_with_delimiter() { + should_decode(" 1", new int[] {0, 0, 1}); + } + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecTestBase.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecTestBase.java new file mode 100644 index 00000000000..03347607b36 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecTestBase.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.codec.query; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.servicecomb.common.rest.codec.param.QueryProcessorCreator.QueryProcessor; +import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; +import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; + +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.QueryParameter; + +public class QueryCodecTestBase { + QueryCodec codec; + + final String queryName = "q"; + + void should_encode(String encodedValue, Object... values) throws Exception { + URLPathStringBuilder builder = new URLPathStringBuilder(); + codec.encode(builder, queryName, values); + + assertThat(builder.build()).isEqualTo(encodedValue); + } + + void should_decode(String value, Object decodedValue) { + HttpServletRequest request = new AbstractHttpServletRequest() { + @Override + public String getParameter(String name) { + return value; + } + }; + + should_decode(request, decodedValue); + } + + void should_decode(String[] value, Object decodedValue) { + HttpServletRequest request = new AbstractHttpServletRequest() { + @Override + public String[] getParameterValues(String name) { + return value; + } + }; + + should_decode(request, decodedValue); + } + + private void should_decode(HttpServletRequest request, Object decodedValue) { + Class targetType = decodedValue == null ? Object.class : decodedValue.getClass(); + + QueryParameter queryParameter = new QueryParameter(); + queryParameter.setSchema(new Schema()); + queryParameter.getSchema().setFormat(codec.getCodecName()); + if (targetType.isArray()) { + queryParameter.setSchema(new ArraySchema()); + } + + QueryProcessor queryProcessor = new QueryProcessor(queryParameter, + TypeFactory.defaultInstance().constructType(targetType)); + + Object values = codec.decode(queryProcessor, request); + + assertThat(values).isEqualTo(decodedValue); + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsTest.java new file mode 100644 index 00000000000..7ccdbb2b38b --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/query/QueryCodecsTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.codec.query; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class QueryCodecsTest { + static class MyQueryCodecCsv extends QueryCodecCsv { + @Override + public int getOrder() { + return 0; + } + } + + @Test + void can_override_by_customize_implement() { + QueryCodecs queryCodecs = QueryCodecs.createForTest(); + assertThat(queryCodecs.find(QueryCodecCsv.CODEC_NAME).getClass()) + .isEqualTo(QueryCodecCsv.class); + + queryCodecs = new QueryCodecs(singletonList(new MyQueryCodecCsv())); + assertThat(queryCodecs.find(QueryCodecCsv.CODEC_NAME).getClass()) + .isEqualTo(MyQueryCodecCsv.class); + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java index bfac3fa9960..db0b09f83fe 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java @@ -17,8 +17,6 @@ package org.apache.servicecomb.common.rest.definition; -import static org.junit.Assert.fail; - import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -27,72 +25,87 @@ import org.apache.servicecomb.common.rest.definition.path.QueryVarParamWriter; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import mockit.Mock; -import mockit.MockUp; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; public class TestPath { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } - @Before + @BeforeEach public void setUp() { } - @After + @AfterEach public void tearDown() { } @Test public void testPathRegExp() throws Exception { PathRegExp oPathRegExp = new PathRegExp("//{test}//"); - Assert.assertEquals(1, oPathRegExp.getGroupCount()); - Assert.assertEquals(0, oPathRegExp.getGroupWithRegExpCount()); + Assertions.assertEquals(1, oPathRegExp.getGroupCount()); + Assertions.assertEquals(0, oPathRegExp.getGroupWithRegExpCount()); PathRegExp oSecondPathRegExp = new PathRegExp("{[^/:]+?}"); - Assert.assertEquals(1, oSecondPathRegExp.getGroupCount()); - Assert.assertEquals(1, oSecondPathRegExp.getGroupWithRegExpCount()); - Assert.assertEquals("test/", PathRegExp.ensureEndWithSlash("test/")); - Assert.assertEquals("test/", PathRegExp.ensureEndWithSlash("test")); - Assert.assertEquals(null, oSecondPathRegExp.match("{test/test}", null)); - Assert.assertEquals("(]+?)/(.*)", (oSecondPathRegExp.toString())); - Assert.assertEquals(false, oSecondPathRegExp.isStaticPath()); - Assert.assertEquals(0, oSecondPathRegExp.getStaticCharCount()); - Assert.assertNotEquals(null, (oPathRegExp.match("//{test}//", new HashMap<>()))); + Assertions.assertEquals(1, oSecondPathRegExp.getGroupCount()); + Assertions.assertEquals(1, oSecondPathRegExp.getGroupWithRegExpCount()); + Assertions.assertEquals("test/", PathRegExp.ensureEndWithSlash("test/")); + Assertions.assertEquals("test/", PathRegExp.ensureEndWithSlash("test")); + Assertions.assertNull(oSecondPathRegExp.match("{test/test}", null)); + Assertions.assertEquals("(]+?)/(.*)", (oSecondPathRegExp.toString())); + Assertions.assertFalse(oSecondPathRegExp.isStaticPath()); + Assertions.assertEquals(0, oSecondPathRegExp.getStaticCharCount()); + Assertions.assertNotEquals(null, (oPathRegExp.match("//{test}//", new HashMap<>()))); // Error Scenarios new PathRegExp("//{test \t}//"); // Error Scenarios for double {{ try { new PathRegExp("//{test{"); - fail("an exception is expected!"); + Assertions.fail("an exception is expected!"); } catch (Exception e) { - Assert.assertEquals(true, e.getMessage().contains("A variable must not contain an extra")); + Assertions.assertTrue(e.getMessage().contains("A variable must not contain an extra")); } // Error Scenarios for illegal }} try { new PathRegExp("//}"); - fail("an exception is expected!"); + Assertions.fail("an exception is expected!"); } catch (Exception e) { - Assert.assertEquals(true, e.getMessage().contains("is only allowed as")); + Assertions.assertTrue(e.getMessage().contains("is only allowed as")); } // Error Scenarios for illegal ; try { new PathRegExp("//;"); - fail("an exception is expected!"); + Assertions.fail("an exception is expected!"); } catch (Exception e) { - Assert.assertEquals(true, e.getMessage().contains("matrix parameters are not allowed in")); + Assertions.assertTrue(e.getMessage().contains("matrix parameters are not allowed in")); } // Error Scenarios for NO } ; try { new PathRegExp("//{test"); - fail("an exception is expected!"); + Assertions.fail("an exception is expected!"); } catch (Exception e) { - Assert.assertEquals(true, e.getMessage().contains("No '}' found after")); + Assertions.assertTrue(e.getMessage().contains("No '}' found after")); } } @@ -102,57 +115,61 @@ public void testUrlPathBuilder() throws Exception { Parameter pathParameter = new PathParameter(); pathParameter.setName("id"); - RestParam oRestParam = new RestParam(0, pathParameter, int.class); + pathParameter.setSchema(new Schema<>()); + RestParam oRestParam = new RestParam(null, pathParameter, int.class); paramMap.put(oRestParam.getParamName(), oRestParam); Parameter queryParameter = new QueryParameter(); queryParameter.setName("q"); - oRestParam = new RestParam(1, queryParameter, String.class); + queryParameter.setSchema(new Schema<>()); + oRestParam = new RestParam(null, queryParameter, String.class); paramMap.put(oRestParam.getParamName(), oRestParam); URLPathBuilder oURLPathBuilder = new URLPathBuilder("/root/{id}", paramMap); - Object[] args = new Object[] {100, "query"}; - Assert.assertEquals("/root/100?q=query", oURLPathBuilder.createRequestPath(args)); - Assert.assertEquals("/root/100", oURLPathBuilder.createPathString(args)); + Map parameters = new HashMap<>(); + parameters.put("id", 100); + parameters.put("q", "query"); + Assertions.assertEquals("/root/100?q=query", oURLPathBuilder.createRequestPath(parameters)); + Assertions.assertEquals("/root/100", oURLPathBuilder.createPathString(parameters)); } @Test public void testQueryVarParamWriter() { boolean status = true; - new MockUp() { - @Mock - public String getParamName() { - return "queryVar"; - } - }; - new MockUp() { - @Mock - protected Object getParamValue(Object[] args) { - return args[0]; - } - }; Parameter parameter = new QueryParameter(); - QueryVarParamWriter writer = new QueryVarParamWriter(new RestParam(0, parameter, String.class)); + parameter.setSchema(new Schema<>()); + RestParam restParam = new RestParam(null, parameter, String.class); + RestParam spy = Mockito.spy(restParam); + Mockito.when(spy.getParamName()).thenReturn("queryVar"); + QueryVarParamWriter writer = new QueryVarParamWriter(spy); try { - verify(writer, "T", "&queryVar=T"); - verify(writer, null, "&"); - verify(writer, new String[] {"a", "b"}, "&queryVar=a&queryVar=b"); - verify(writer, new String[] {"a", null, "b"}, "&queryVar=a&queryVar=&queryVar=b"); - verify(writer, Arrays.asList("Lars", "Simon"), "&queryVar=Lars&queryVar=Simon"); - verify(writer, "测试", "&queryVar=%E6%B5%8B%E8%AF%95"); - verify(writer, "a b", "&queryVar=a+b"); - verify(writer, "a+b", "&queryVar=a%2Bb"); + Map parameters = new HashMap<>(); + parameters.put("queryVar", "T"); + verify(writer, parameters, "?queryVar=T"); + parameters.put("queryVar", null); + verify(writer, parameters, ""); + parameters.put("queryVar", new String[] {"a", "b"}); + verify(writer, parameters, "?queryVar=a&queryVar=b"); + parameters.put("queryVar", new String[] {"a", null, "b"}); + verify(writer, parameters, "?queryVar=a&queryVar=b"); + parameters.put("queryVar", Arrays.asList("Lars", "Simon")); + verify(writer, parameters, "?queryVar=Lars&queryVar=Simon"); + parameters.put("queryVar", "测试"); + verify(writer, parameters, "?queryVar=%E6%B5%8B%E8%AF%95"); + parameters.put("queryVar", "a b"); + verify(writer, parameters, "?queryVar=a+b"); + parameters.put("queryVar", "a+b"); + verify(writer, parameters, "?queryVar=a%2Bb"); } catch (Exception e) { status = false; } - Assert.assertTrue(status); + Assertions.assertTrue(status); } - // TODO expect not used? - private void verify(QueryVarParamWriter writer, Object arg, String expect) throws Exception { + private void verify(QueryVarParamWriter writer, Map args, String expect) throws Exception { URLPathStringBuilder sb = new URLPathStringBuilder(); - Object[] args = new Object[] {arg}; writer.write(sb, args); + Assertions.assertEquals(expect, sb.build()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationComparator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationComparator.java index cc4970eadee..66a4a5bad54 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationComparator.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationComparator.java @@ -18,8 +18,8 @@ package org.apache.servicecomb.common.rest.definition; import org.apache.servicecomb.common.rest.locator.MicroservicePaths; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestRestOperationComparator { @Test @@ -35,8 +35,8 @@ public void testStaticCharCount() { paths.addResource(more); paths.sortPath(); - Assert.assertSame(more, paths.getDynamicPathOperationList().get(0)); - Assert.assertSame(less, paths.getDynamicPathOperationList().get(1)); + Assertions.assertSame(more, paths.getDynamicPathOperationList().get(0)); + Assertions.assertSame(less, paths.getDynamicPathOperationList().get(1)); } @Test @@ -52,8 +52,8 @@ public void testVarGroupCount() { paths.addResource(more); paths.sortPath(); - Assert.assertSame(more, paths.getDynamicPathOperationList().get(0)); - Assert.assertSame(less, paths.getDynamicPathOperationList().get(1)); + Assertions.assertSame(more, paths.getDynamicPathOperationList().get(0)); + Assertions.assertSame(less, paths.getDynamicPathOperationList().get(1)); } @Test @@ -69,7 +69,7 @@ public void testGroupWithRegExpCount() { paths.addResource(more); paths.sortPath(); - Assert.assertSame(more, paths.getDynamicPathOperationList().get(0)); - Assert.assertSame(less, paths.getDynamicPathOperationList().get(1)); + Assertions.assertSame(more, paths.getDynamicPathOperationList().get(0)); + Assertions.assertSame(less, paths.getDynamicPathOperationList().get(1)); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java index fa466511398..df8ebe47a75 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java @@ -17,285 +17,265 @@ package org.apache.servicecomb.common.rest.definition; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; +import org.apache.servicecomb.common.rest.RestEngineSchemaListener; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.transport.TransportManager; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.models.Operation; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; -import mockit.Expectations; -import mockit.Mocked; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.servers.Server; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; public class TestRestOperationMeta { + @Path("/") + static class RestOperationMetaSchema { + @Path("/emptyProduces") + @GET + @Produces(value = MediaType.APPLICATION_JSON) + public String emptyProduces() { + return null; + } - private final Swagger swagger = Mockito.mock(Swagger.class); + @Path("/emptyProducesWithView") + @GET + @Produces(value = MediaType.APPLICATION_JSON) + @JsonView(Object.class) + public String emptyProducesWithView() { + return null; + } - private final SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + @Path("/notSupport") + @GET + @Produces(value = MediaType.APPLICATION_JSON) + public void notSupport() { - private final Operation operation = Mockito.mock(Operation.class); + } - private final OperationMeta meta = mock(OperationMeta.class); + @Path("/notSupportWithView") + @GET + @Produces(value = MediaType.APPLICATION_JSON) + @JsonView(Object.class) + public void notSupportWithView() { - @Before - public void setUp() throws Exception { - when(meta.getSchemaMeta()).thenReturn(schemaMeta); - when(meta.getSwaggerOperation()).thenReturn(operation); - when(meta.getMethod()).thenReturn(SomeRestController.class.getMethod("sayHi")); + } - when(schemaMeta.getSwagger()).thenReturn(swagger); - } + @Path("/textPlain") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String textPlain() { + return null; + } - @Test - public void testCreateProduceProcessorsNull() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor((String) null)); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, operationMeta.ensureFindProduceProcessor("*/*")); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE)); - for (String produce : ProduceProcessorManager.INSTANCE.keys()) { - ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findValue(produce); - Assert.assertSame(expected, operationMeta.findProduceProcessor(produce)); + @Path("/textPlainWithView") + @GET + @Produces(MediaType.TEXT_PLAIN) + @JsonView(Object.class) + public String textPlainWithView() { + return null; } - } - @Test - public void testCreateProduceProcessorsEmpty() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(); - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor((String) null)); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, operationMeta.ensureFindProduceProcessor("*/*")); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE)); - for (String produce : ProduceProcessorManager.INSTANCE.keys()) { - ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findValue(produce); - Assert.assertSame(expected, operationMeta.findProduceProcessor(produce)); + @Path("/json") + @GET + @Produces(MediaType.APPLICATION_JSON) + public String json() { + return null; } - } - @Test - public void testCreateProduceProcessorsNormal() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(MediaType.APPLICATION_JSON); - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor((String) null)); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, operationMeta.ensureFindProduceProcessor("*/*")); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE)); - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, - operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON)); - Assert.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN)); - } + @Path("/jsonWithView") + @GET + @Produces(MediaType.APPLICATION_JSON) + @JsonView(Object.class) + public String jsonWithView() { + return null; + } - @Test - public void testCreateProduceProcessorsNotSupported() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList("notSupport"); - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor((String) null)); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, operationMeta.ensureFindProduceProcessor("*/*")); - Assert.assertSame(ProduceProcessorManager.DEFAULT_PROCESSOR, - operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE)); - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, - operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON)); - Assert.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN)); - } + @Path("/textCharJsonChar") + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) + public void textCharJsonChar() { - @Test - public void testCreateProduceProcessorsTextAndWildcard() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(MediaType.TEXT_PLAIN); - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.PLAIN_PROCESSOR, - operationMeta.ensureFindProduceProcessor(MediaType.WILDCARD)); - Assert.assertSame(ProduceProcessorManager.PLAIN_PROCESSOR, - operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN)); - Assert.assertNull(operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON)); - Assert.assertSame(ProduceProcessorManager.PLAIN_PROCESSOR, - operationMeta.ensureFindProduceProcessor( - MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML + "," + MediaType.WILDCARD)); - } + } - @Test - public void testCreateProduceProcessorsWithSemicolon() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays - .asList(MediaType.TEXT_PLAIN + ";charset=UTF-8", MediaType.APPLICATION_JSON + ";charset=UTF-8"); - operationMeta.createProduceProcessors(); - Assert.assertSame(ProduceProcessorManager.PLAIN_PROCESSOR, - operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN)); - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, - operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON)); - } + @Path("/textCharJsonCharWithView") + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) + @JsonView(Object.class) + public void textCharJsonCharWithView() { - @Test - public void testEnsureFindProduceProcessorRequest(@Mocked HttpServletRequestEx requestEx) { - RestOperationMeta operationMeta = new RestOperationMeta(); - new Expectations() { - { - requestEx.getHeader(HttpHeaders.ACCEPT); - result = null; - } - }; - operationMeta.createProduceProcessors(); - - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, operationMeta.ensureFindProduceProcessor(requestEx)); - } + } - @Test - public void testEnsureFindProduceProcessorAcceptFound() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN); - operationMeta.createProduceProcessors(); + @Path("/download") + @GET + @Produces(MediaType.APPLICATION_JSON) + public File download() { + return null; + } - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, - operationMeta.ensureFindProduceProcessor("text/plain;q=0.7;charset=utf-8,application/json;q=0.8")); - } + @Path("/downloadWithView") + @GET + @Produces(MediaType.APPLICATION_JSON) + @JsonView(Object.class) + public File downloadWithView() { + return null; + } - @Test - public void testEnsureFindProduceProcessorWithDownload() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(MediaType.APPLICATION_JSON); - operationMeta.downloadFile = true; - operationMeta.createProduceProcessors(); + @Path("/form") + @POST + public void form(@FormParam("form") String form) { + } - Assert.assertSame(ProduceProcessorManager.JSON_PROCESSOR, - operationMeta.ensureFindProduceProcessor("text/plain")); + @Path("/formWithView") + @POST + public void formWithView(@FormParam("form") String form) { + } + } - operationMeta.downloadFile = false; - Assert.assertNull(operationMeta.ensureFindProduceProcessor("text/plain")); + SCBEngine scbEngine; + + OpenAPI swagger; + + OperationMeta meta; + + RestOperationMeta operationMeta; + + @BeforeEach + public void setUp() { + Environment environment = Mockito.mock(Environment.class); + scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + scbEngine.setTransportManager(transportManager); + scbEngine.setExecutorManager(executorManager); + + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn("test"); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); + + List listeners = new ArrayList<>(); + listeners.add(new RestEngineSchemaListener()); + scbEngine.setBootListeners(listeners); + scbEngine + .addProducerMeta("sid1", new RestOperationMetaSchema()) + .run(); + swagger = Mockito.spy(scbEngine.getProducerMicroserviceMeta().ensureFindSchemaMeta("sid1").getSwagger()); } - @Test - public void testEnsureFindProduceProcessorAcceptNotFound() { - RestOperationMeta operationMeta = new RestOperationMeta(); - operationMeta.produces = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN); - operationMeta.createProduceProcessors(); + @AfterEach + public void teardown() { + scbEngine.destroy(); + } - Assert.assertNull(operationMeta.ensureFindProduceProcessor("notSupport")); + private void findOperation(String operationId) { + meta = Mockito.spy(scbEngine.getProducerMicroserviceMeta().operationMetas().get("test.sid1." + operationId)); + operationMeta = Mockito.spy(RestMetaUtils.getRestOperationMeta(meta)); + SchemaMeta schemaMeta = Mockito.spy(meta.getSchemaMeta()); + Mockito.when(meta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getSwagger()).thenReturn(swagger); } @Test public void generatesAbsolutePathWithRootBasePath() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(swagger.getBasePath()).thenReturn("/"); - when(meta.getOperationPath()).thenReturn("/sayHi/"); - - operationMeta.init(meta); + findOperation("textCharJsonChar"); - assertThat(operationMeta.getAbsolutePath(), is("/sayHi/")); + MatcherAssert.assertThat(operationMeta.getAbsolutePath(), is("/textCharJsonChar")); } @Test public void generatesAbsolutePathWithNonRootBasePath() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(swagger.getBasePath()).thenReturn("/rest"); - when(meta.getOperationPath()).thenReturn("/sayHi"); - - operationMeta.init(meta); - - assertThat(operationMeta.getAbsolutePath(), is("/rest/sayHi/")); + findOperation("textCharJsonChar"); + Server server = Mockito.mock(Server.class); + Mockito.when(server.getUrl()).thenReturn("/rest"); + Mockito.when(swagger.getServers()).thenReturn(Arrays.asList(server)); + RestOperationMeta restOperationMeta = new RestOperationMeta(); + restOperationMeta.init(meta); + + MatcherAssert.assertThat(restOperationMeta.getAbsolutePath(), is("/rest/textCharJsonChar")); } @Test public void generatesAbsolutePathWithNullPath() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(swagger.getBasePath()).thenReturn(null); - when(meta.getOperationPath()).thenReturn(null); - - operationMeta.init(meta); - - assertThat(operationMeta.getAbsolutePath(), is("/")); + findOperation("textCharJsonChar"); + Server server = Mockito.mock(Server.class); + Mockito.when(server.getUrl()).thenReturn(null); + Mockito.when(swagger.getServers()).thenReturn(Arrays.asList(server)); + Mockito.when(meta.getOperationPath()).thenReturn(null); + RestOperationMeta restOperationMeta = new RestOperationMeta(); + restOperationMeta.init(meta); + + MatcherAssert.assertThat(restOperationMeta.getAbsolutePath(), is("/")); } @Test public void generatesAbsolutePathWithEmptyPath() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(swagger.getBasePath()).thenReturn(""); - when(meta.getOperationPath()).thenReturn(""); - - operationMeta.init(meta); - - assertThat(operationMeta.getAbsolutePath(), is("/")); + findOperation("textCharJsonChar"); + Server server = Mockito.mock(Server.class); + Mockito.when(server.getUrl()).thenReturn(""); + Mockito.when(swagger.getServers()).thenReturn(Arrays.asList(server)); + Mockito.when(meta.getOperationPath()).thenReturn(""); + RestOperationMeta restOperationMeta = new RestOperationMeta(); + restOperationMeta.init(meta); + + MatcherAssert.assertThat(restOperationMeta.getAbsolutePath(), is("/")); } @Test public void consecutiveSlashesAreRemoved() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(swagger.getBasePath()).thenReturn("//rest//"); - when(meta.getOperationPath()).thenReturn("//sayHi//"); - - operationMeta.init(meta); - - assertThat(operationMeta.getAbsolutePath(), is("/rest/sayHi/")); + findOperation("textCharJsonChar"); + Server server = Mockito.mock(Server.class); + Mockito.when(server.getUrl()).thenReturn("//rest//"); + Mockito.when(swagger.getServers()).thenReturn(Arrays.asList(server)); + Mockito.when(meta.getOperationPath()).thenReturn("//sayHi//"); + RestOperationMeta restOperationMeta = new RestOperationMeta(); + restOperationMeta.init(meta); + + MatcherAssert.assertThat(restOperationMeta.getAbsolutePath(), is("/rest/sayHi/")); } @Test public void testFormDataFlagTrue() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(meta.getMethod()).thenReturn(ReflectUtils.findMethod(SomeRestController.class, "form")); - when(meta.getSwaggerOperation()).thenReturn(operation); - List params = Arrays.asList(new FormParameter()); - when(operation.getParameters()).thenReturn(params); - - operationMeta.init(meta); + findOperation("form"); - assertThat(operationMeta.isFormData(), is(true)); + MatcherAssert.assertThat(operationMeta.isFormData(), is(true)); } @Test public void testFormDataFlagFalse() { - RestOperationMeta operationMeta = new RestOperationMeta(); - when(meta.getMethod()).thenReturn(ReflectUtils.findMethod(SomeRestController.class, "form")); - when(meta.getSwaggerOperation()).thenReturn(operation); - List params = Arrays.asList(new QueryParameter()); - when(operation.getParameters()).thenReturn(params); + findOperation("json"); - operationMeta.init(meta); - - assertThat(operationMeta.isFormData(), is(false)); - } - - private static class SomeRestController { - @SuppressWarnings("unused") - public String sayHi() { - return "Hi"; - } - - @SuppressWarnings("unused") - public String form(String param) { - return ""; - } + MatcherAssert.assertThat(operationMeta.isFormData(), is(false)); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/UnitTestRestUtils.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/UnitTestRestUtils.java deleted file mode 100644 index 00cf068c4fb..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/UnitTestRestUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.definition; - -import java.util.Arrays; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.core.definition.OperationMeta; - -import mockit.Deencapsulation; - -public class UnitTestRestUtils { - public static RestOperationMeta createRestOperationMeta(String httpMethod, String path) { - OperationMeta om = new OperationMeta(); - om.setHttpMethod(httpMethod); - - RestOperationMeta rom = new RestOperationMeta(); - rom.setOperationMeta(om); - rom.setAbsolutePath(path); - Deencapsulation.setField(rom, "produces", Arrays.asList(MediaType.APPLICATION_JSON)); - return rom; - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java index fd24009847c..99ef928b48d 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java @@ -17,13 +17,14 @@ package org.apache.servicecomb.common.rest.definition.path; +import java.util.HashMap; +import java.util.Map; + import org.apache.servicecomb.common.rest.definition.RestParam; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mock; -import mockit.MockUp; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class PathVarParamWriterTest { @@ -32,8 +33,10 @@ public void writePlainPath() throws Exception { PathVarParamWriter pathVarParamWriter = createPathVarParamWriter(); URLPathStringBuilder pathBuilder = new URLPathStringBuilder(); - pathVarParamWriter.write(pathBuilder, new Object[] {"abc"}); - Assert.assertEquals("abc", pathBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", "abc"); + pathVarParamWriter.write(pathBuilder, parameters); + Assertions.assertEquals("abc", pathBuilder.build()); } @Test @@ -41,8 +44,10 @@ public void writePathWithSpace() throws Exception { PathVarParamWriter pathVarParamWriter = createPathVarParamWriter(); URLPathStringBuilder pathBuilder = new URLPathStringBuilder(); - pathVarParamWriter.write(pathBuilder, new String[] {"a 20bc"}); - Assert.assertEquals("a%2020bc", pathBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", "a 20bc"); + pathVarParamWriter.write(pathBuilder, parameters); + Assertions.assertEquals("a%2020bc", pathBuilder.build()); } @Test @@ -50,8 +55,10 @@ public void writePathWithPercentage() throws Exception { PathVarParamWriter pathVarParamWriter = createPathVarParamWriter(); URLPathStringBuilder pathBuilder = new URLPathStringBuilder(); pathBuilder.appendPath("/api/"); - pathVarParamWriter.write(pathBuilder, new String[] {"a%%bc"}); - Assert.assertEquals("/api/a%25%25bc", pathBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", "a%%bc"); + pathVarParamWriter.write(pathBuilder, parameters); + Assertions.assertEquals("/api/a%25%25bc", pathBuilder.build()); } @Test @@ -59,25 +66,25 @@ public void writePathParamWithSlash() throws Exception { PathVarParamWriter pathVarParamWriter = createPathVarParamWriter(); URLPathStringBuilder pathBuilder = new URLPathStringBuilder(); pathBuilder.appendPath("/api/"); - pathVarParamWriter.write(pathBuilder, new String[] {"a/bc"}); - Assert.assertEquals("/api/a%2Fbc", pathBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", "a/bc"); + pathVarParamWriter.write(pathBuilder, parameters); + Assertions.assertEquals("/api/a%2Fbc", pathBuilder.build()); } @Test public void writeIntegerParam() throws Exception { PathVarParamWriter pathVarParamWriter = createPathVarParamWriter(); URLPathStringBuilder pathBuilder = new URLPathStringBuilder(); - pathVarParamWriter.write(pathBuilder, new Integer[] {12}); - Assert.assertEquals("12", pathBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", 12); + pathVarParamWriter.write(pathBuilder, parameters); + Assertions.assertEquals("12", pathBuilder.build()); } private PathVarParamWriter createPathVarParamWriter() { - RestParam restParam = new MockUp() { - @Mock - Object getValue(Object[] args) { - return args[0]; - } - }.getMockInstance(); + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(restParam.getParamName()).thenReturn("test"); return new PathVarParamWriter(restParam); } -} \ No newline at end of file +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java index 33648a61819..1aafc89fbb3 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java @@ -20,212 +20,239 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.servicecomb.common.rest.definition.RestParam; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.QueryParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; +import io.swagger.v3.oas.models.parameters.QueryParameter; public class QueryVarParamWriterTest { - private static QueryVarParamWriter queryVarParamWriterCsv; private static QueryVarParamWriter queryVarParamWriterMulti; private static QueryVarParamWriter queryVarParamWriterDefault; - @BeforeClass + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + QueryParameter parameter = new QueryParameter(); parameter.setName("q"); - parameter.setCollectionFormat("csv"); + parameter.setSchema(new Schema()); + parameter.setStyle(StyleEnum.FORM); + parameter.setExplode(false); queryVarParamWriterCsv = new QueryVarParamWriter( - new RestParam(0, parameter, String[].class)); + new RestParam(null, parameter, String[].class)); parameter = new QueryParameter(); parameter.setName("q"); - parameter.setCollectionFormat("multi"); + parameter.setSchema(new Schema()); + parameter.setStyle(StyleEnum.FORM); + parameter.setExplode(true); queryVarParamWriterMulti = new QueryVarParamWriter( - new RestParam(0, parameter, String[].class)); + new RestParam(null, parameter, String[].class)); parameter = new QueryParameter(); parameter.setName("q"); + parameter.setSchema(new Schema()); queryVarParamWriterDefault = new QueryVarParamWriter( - new RestParam(0, parameter, String[].class)); + new RestParam(null, parameter, String[].class)); } @Test public void write() throws Exception { URLPathStringBuilder stringBuilder = new URLPathStringBuilder(); - Object[] args = {"a"}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=a", stringBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("q", "a"); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=a", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=a", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a", stringBuilder.build()); } @Test public void writeNull() throws Exception { URLPathStringBuilder stringBuilder = new URLPathStringBuilder(); - Object[] args = {null}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("test", null); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); } @Test public void writeArray() throws Exception { URLPathStringBuilder stringBuilder = new URLPathStringBuilder(); - Object[] args = new Object[] {new String[] {"ab", "cd", "ef"}}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=ab%2Ccd%2Cef", stringBuilder.build()); + Map parameters = new HashMap<>(); + parameters.put("q", new String[] {"ab", "cd", "ef"}); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab%2Ccd%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); // encode space char stringBuilder = new URLPathStringBuilder(); - args[0] = new String[] {"a b", " ", "", "ef"}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=a+b%2C+%2C%2Cef", stringBuilder.build()); + parameters.put("q", new String[] {"a b", " ", "", "ef"}); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b%2C+%2C%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); // pass blank string stringBuilder = new URLPathStringBuilder(); - args[0] = new String[] {""}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + parameters.put("q", new String[] {""}); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); // pass empty stringBuilder = new URLPathStringBuilder(); - args[0] = new String[] {}; - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + parameters.put("q", new String[] {}); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); // pass null - args[0] = new String[] {null}; + parameters.put("q", new String[] {null}); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); - args[0] = new String[] {null, "ab", null, "cd", null, null, "", null, "ef", null}; + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); + + parameters.put("q", new String[] {null, "ab", null, "cd", null, null, "", null, "ef", null}); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=ab%2Ccd%2C%2Cef", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab%2Ccd%2C%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); } @Test public void writeList() throws Exception { List queryList = Arrays.asList("ab", "cd", "ef"); - Object[] args = {queryList}; + Map parameters = new HashMap<>(); + parameters.put("q", queryList); URLPathStringBuilder stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=ab%2Ccd%2Cef", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab%2Ccd%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=ef", stringBuilder.build()); // encode space char - args[0] = Arrays.asList("a b", " ", "", "ef"); + parameters.put("q", Arrays.asList("a b", " ", "", "ef")); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=a+b%2C+%2C%2Cef", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b%2C+%2C%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=a+b&q=+&q=&q=ef", stringBuilder.build()); // pass blank string stringBuilder = new URLPathStringBuilder(); - args[0] = Collections.singletonList(""); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + parameters.put("q", Collections.singletonList("")); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=", stringBuilder.build()); // pass empty stringBuilder = new URLPathStringBuilder(); - args[0] = new ArrayList<>(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + parameters.put("q", new ArrayList<>()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); // pass null - args[0] = Collections.singletonList(null); + parameters.put("q", Collections.singletonList(null)); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("", stringBuilder.build()); - args[0] = Arrays.asList(null, "ab", null, "cd", null, null, "", null, "ef", null); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("", stringBuilder.build()); + + parameters.put("q", Arrays.asList(null, "ab", null, "cd", null, null, "", null, "ef", null)); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterCsv.write(stringBuilder, args); - Assert.assertEquals("?q=ab%2Ccd%2C%2Cef", stringBuilder.build()); + queryVarParamWriterCsv.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab%2Ccd%2C%2Cef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterMulti.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); + queryVarParamWriterMulti.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); stringBuilder = new URLPathStringBuilder(); - queryVarParamWriterDefault.write(stringBuilder, args); - Assert.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); + queryVarParamWriterDefault.write(stringBuilder, parameters); + Assertions.assertEquals("?q=ab&q=cd&q=&q=ef", stringBuilder.build()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java index 75af1872093..bcff2ff1523 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java @@ -18,18 +18,37 @@ package org.apache.servicecomb.common.rest.definition.path; import java.lang.reflect.Type; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.servicecomb.common.rest.definition.RestParam; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; public class URLPathBuilderTest { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void beforeClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.emptyAsNull", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreDefaultValue", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.query.ignoreRequiredCheck", boolean.class, false)) + .thenReturn(false); + } + @Test public void testNormal() throws Exception { Map paramMap = new LinkedHashMap<>(); @@ -39,11 +58,15 @@ public void testNormal() throws Exception { addParam("q1", String.class, QueryParameter::new, paramMap); URLPathBuilder urlPathBuilder = new URLPathBuilder("/path/{p0}/and/{p1}", paramMap); - Object[] args = {10, "abcPath", 11, "queryABC"}; - Assert.assertEquals("/path/10/and/abcPath?q0=11&q1=queryABC", - urlPathBuilder.createRequestPath(args)); - Assert.assertEquals("/path/10/and/abcPath", - urlPathBuilder.createPathString(args)); + Map parameters = new HashMap<>(); + parameters.put("p0", 10); + parameters.put("p1", "abcPath"); + parameters.put("q0", 11); + parameters.put("q1", "queryABC"); + Assertions.assertEquals("/path/10/and/abcPath?q0=11&q1=queryABC", + urlPathBuilder.createRequestPath(parameters)); + Assertions.assertEquals("/path/10/and/abcPath", + urlPathBuilder.createPathString(parameters)); } @Test @@ -53,11 +76,13 @@ public void testEncode() throws Exception { addParam("q", String.class, QueryParameter::new, paramMap); URLPathBuilder urlPathBuilder = new URLPathBuilder("/path/{p}", paramMap); - Object[] args = {"ab%% %cd%", "ab%% %cd%"}; - Assert.assertEquals("/path/ab%25%25%20%25cd%25?q=ab%25%25+%25cd%25", - urlPathBuilder.createRequestPath(args)); - Assert.assertEquals("/path/ab%25%25%20%25cd%25", - urlPathBuilder.createPathString(args)); + Map parameters = new HashMap<>(); + parameters.put("p", "ab%% %cd%"); + parameters.put("q", "ab%% %cd%"); + Assertions.assertEquals("/path/ab%25%25%20%25cd%25?q=ab%25%25+%25cd%25", + urlPathBuilder.createRequestPath(parameters)); + Assertions.assertEquals("/path/ab%25%25%20%25cd%25", + urlPathBuilder.createPathString(parameters)); } @Test @@ -67,40 +92,54 @@ public void testMultiQuery() throws Exception { addParam("intArr", int[].class, QueryParameter::new, paramMap); URLPathBuilder urlPathBuilder = new URLPathBuilder("/path", paramMap); - Object[] args = new Object[] { - new Object[] {"a", "b", "c"}, - new Object[] {1, 2, 3} - }; - Assert.assertEquals("/path?strArr=a&strArr=b&strArr=c&intArr=1&intArr=2&intArr=3", - urlPathBuilder.createRequestPath(args)); - args = new Object[] { - new Object[] {}, - new Object[] {1, 2, 3} - }; - Assert.assertEquals("/path?intArr=1&intArr=2&intArr=3", - urlPathBuilder.createRequestPath(args)); - args = new Object[] { - new Object[] {"a", "b", "c"}, - new Object[] {} - }; - Assert.assertEquals("/path?strArr=a&strArr=b&strArr=c", - urlPathBuilder.createRequestPath(args)); - args = new Object[] { - new Object[] {}, - new Object[] {} - }; - Assert.assertEquals("/path", - urlPathBuilder.createRequestPath(args)); + Map parameters = new HashMap<>(); + parameters.put("strArr", new Object[] {"a", "b", "c"}); + parameters.put("intArr", new Object[] {1, 2, 3}); + Assertions.assertEquals("/path?strArr=a&strArr=b&strArr=c&intArr=1&intArr=2&intArr=3", + urlPathBuilder.createRequestPath(parameters)); + parameters.put("strArr", new Object[] {}); + parameters.put("intArr", new Object[] {1, 2, 3}); + Assertions.assertEquals("/path?intArr=1&intArr=2&intArr=3", + urlPathBuilder.createRequestPath(parameters)); + parameters.put("strArr", new Object[] {"a", "b", "c"}); + parameters.put("intArr", new Object[] {}); + Assertions.assertEquals("/path?strArr=a&strArr=b&strArr=c", + urlPathBuilder.createRequestPath(parameters)); + parameters.put("strArr", new Object[] {}); + parameters.put("intArr", new Object[] {}); + Assertions.assertEquals("/path", + urlPathBuilder.createRequestPath(parameters)); + } + + @Test + public void testRegexPathParam() throws Exception { + Map paramMap = new LinkedHashMap<>(); + addParam("p0", int.class, PathParameter::new, paramMap); + addParam("p1", String.class, PathParameter::new, paramMap); + addParam("q0", int.class, QueryParameter::new, paramMap); + addParam("q1", String.class, QueryParameter::new, paramMap); + + URLPathBuilder urlPathBuilder = new URLPathBuilder("/path/{p0 : .*}/and/{p1:.*}", paramMap); + Map parameters = new HashMap<>(); + parameters.put("p0", 10); + parameters.put("p1", "abcPath"); + parameters.put("q0", 11); + parameters.put("q1", "queryABC"); + Assertions.assertEquals("/path/10/and/abcPath?q0=11&q1=queryABC", + urlPathBuilder.createRequestPath(parameters)); + Assertions.assertEquals("/path/10/and/abcPath", + urlPathBuilder.createPathString(parameters)); } private void addParam(String paramName, Type paramType, ParameterConstructor constructor, Map paramMap) { Parameter parameter = constructor.construct(); parameter.setName(paramName); - paramMap.put(paramName, new RestParam(paramMap.size(), parameter, paramType)); + parameter.setSchema(new Schema()); + paramMap.put(paramName, new RestParam(null, parameter, paramType)); } - static interface ParameterConstructor { + interface ParameterConstructor { Parameter construct(); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathStringBuilderTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathStringBuilderTest.java index 2fc9a55aad5..5ccb4a7eff2 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathStringBuilderTest.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathStringBuilderTest.java @@ -17,10 +17,9 @@ package org.apache.servicecomb.common.rest.definition.path; -import static org.junit.Assert.assertEquals; - import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder.URLPathStringBuilder; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class URLPathStringBuilderTest { @Test @@ -28,27 +27,27 @@ public void testNormal() { URLPathStringBuilder builder = new URLPathStringBuilder(); builder.appendPath("/path"); builder.appendQuery("q", "abc"); - assertEquals("/path?q=abc", builder.build()); + Assertions.assertEquals("/path?q=abc", builder.build()); } @Test public void appendPath() { URLPathStringBuilder builder = new URLPathStringBuilder(); builder.appendPath("/abc"); - assertEquals("/abc", builder.build()); + Assertions.assertEquals("/abc", builder.build()); builder.appendPath("/de fg"); - assertEquals("/abc/de fg", builder.build()); + Assertions.assertEquals("/abc/de fg", builder.build()); } @Test public void appendQuery() { URLPathStringBuilder builder = new URLPathStringBuilder(); - assertEquals("", builder.build()); + Assertions.assertEquals("", builder.build()); builder.appendQuery("ab", "cd"); - assertEquals("?ab=cd", builder.build()); + Assertions.assertEquals("?ab=cd", builder.build()); builder.appendQuery("ef", ""); - assertEquals("?ab=cd&ef=", builder.build()); + Assertions.assertEquals("?ab=cd&ef=", builder.build()); builder.appendQuery("gh", "jk"); - assertEquals("?ab=cd&ef=&gh=jk", builder.build()); + Assertions.assertEquals("?ab=cd&ef=&gh=jk", builder.build()); } -} \ No newline at end of file +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBaseForTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBaseForTest.java deleted file mode 100644 index 24ccd95a81d..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/HttpServerFilterBaseForTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.filter; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.swagger.invocation.Response; - -public class HttpServerFilterBaseForTest implements HttpServerFilter { - @Override - public int getOrder() { - return 0; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - return null; - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java deleted file mode 100644 index 38c1f97c75a..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.filter; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class TestHttpServerFilter { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void asyncSucc() throws InterruptedException, ExecutionException { - HttpServerFilter filter = new HttpServerFilterBaseForTest(); - - CompletableFuture future = filter.beforeSendResponseAsync(null, null); - Assert.assertNull(future.get()); - } - - @Test - public void asyncFailed() throws InterruptedException, ExecutionException { - HttpServerFilter filter = new HttpServerFilterBaseForTest() { - @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - throw new Error(""); - } - }; - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.instanceOf(Error.class)); - - CompletableFuture future = filter.beforeSendResponseAsync(null, null); - future.get(); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilterBeforeSendResponseExecutor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilterBeforeSendResponseExecutor.java deleted file mode 100644 index 0708f8fd189..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/TestHttpServerFilterBeforeSendResponseExecutor.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.filter; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import mockit.Mocked; - -public class TestHttpServerFilterBeforeSendResponseExecutor { - @Mocked - Invocation invocation; - - @Mocked - HttpServletResponseEx responseEx; - - List httpServerFilters = new ArrayList<>(); - - HttpServerFilterBeforeSendResponseExecutor executor = - new HttpServerFilterBeforeSendResponseExecutor(httpServerFilters, invocation, responseEx); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setup() { - httpServerFilters.add(new HttpServerFilterBaseForTest()); - } - - @Test - public void runSucc() throws InterruptedException, ExecutionException { - CompletableFuture result = executor.run(); - - Assert.assertNull(result.get()); - } - - @Test - public void runFail() throws InterruptedException, ExecutionException { - httpServerFilters.add(new HttpServerFilterBaseForTest() { - @Override - public CompletableFuture beforeSendResponseAsync(Invocation invocation, HttpServletResponseEx responseEx) { - throw new Error(""); - } - }); - - CompletableFuture result = executor.run(); - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.instanceOf(Error.class)); - - result.get(); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java new file mode 100644 index 00000000000..0decec28bd9 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.common.rest.filter.inner; + +import static com.google.common.net.HttpHeaders.CONTENT_LENGTH; +import static com.google.common.net.HttpHeaders.TRANSFER_ENCODING; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + +import java.io.ByteArrayInputStream; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.servicecomb.common.rest.HttpTransportContext; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.SCBStatus; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.foundation.common.part.InputStreamPart; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import io.vertx.core.MultiMap; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.MediaType; + +public class RestServerCodecFilterTest { + final RestServerCodecFilter codecFilter = new RestServerCodecFilter(); + + Invocation invocation; + + final Endpoint endpoint = Mockito.mock(Endpoint.class); + + final OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + + final SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + + final MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + + final InvocationRuntimeType invocationRuntimeType = Mockito.mock(InvocationRuntimeType.class); + + final RestOperationMeta restOperationMeta = Mockito.mock(RestOperationMeta.class); + + final HttpTransportContext transportContext = Mockito.mock(HttpTransportContext.class); + + final HttpServletResponseEx responseEx = Mockito.mock(HttpServletResponseEx.class); + + final MultiMap headers = MultiMap.caseInsensitiveMultiMap(); + + final Part part = new InputStreamPart("ok", new ByteArrayInputStream(new byte[] {1, 2})); + + final FilterNode nextNode = new FilterNode(new AbstractFilter() { + @Override + public String getName() { + return "f2"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + Response response = Response.ok(part); + response.setHeaders(headers); + return CompletableFuture.completedFuture(response); + } + }); + + static SCBEngine engine; + + @BeforeAll + public static void beforeClass() { + Environment environment = Mockito.mock(Environment.class); + engine = SCBBootstrap.createSCBEngineForTest(environment); + engine.setEnvironment(environment); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + engine.setStatus(SCBStatus.UP); + } + + @AfterAll + public static void afterClass() { + engine.destroy(); + } + + @BeforeEach + public void setUp() { + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType); + invocation = Mockito.spy(InvocationFactory.forProvider(endpoint, operationMeta, null)); + Mockito.when(responseEx.sendPart(part)).thenReturn(CompletableFuture.completedFuture(null)); + } + + private void mockDecodeRequestFail() { + Mockito.when(invocation.getTransportContext()).thenReturn(transportContext); + Mockito.when(transportContext.getResponseEx()).thenReturn(responseEx); + Mockito.when(invocation.getRequestEx()) + .thenThrow(new RuntimeExceptionWithoutStackTrace("mock encode request failed")); + } + + @Test + public void should_not_invoke_filter_when_decode_request_failed() { + FilterNode nextNode = Mockito.mock(FilterNode.class); + mockDecodeRequestFail(); + + codecFilter.onFilter(invocation, nextNode); + + Mockito.verify(nextNode, Mockito.times(0)).onFilter(invocation); + } + + @Test + public void should_convert_exception_to_response_when_decode_request_failed() + throws ExecutionException, InterruptedException { + mockDecodeRequestFail(); + Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode())) + .thenReturn(TypeFactory.defaultInstance().constructType(String.class)); + + Assertions.assertThrows(ExecutionException.class, + () -> codecFilter.onFilter(invocation, nextNode).get()); + } + + private void success_invocation() throws InterruptedException, ExecutionException { + Mockito.when(invocation.getTransportContext()).thenReturn(transportContext); + HttpServletRequestEx requestExt = Mockito.mock(HttpServletRequestEx.class); + Mockito.when(invocation.getRequestEx()).thenReturn(requestExt); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Operation swaggerOperation = Mockito.mock(Operation.class); + Mockito.when(operationMeta.getSwaggerOperation()).thenReturn(swaggerOperation); + ApiResponses apiResponses = Mockito.mock(ApiResponses.class); + Mockito.when(swaggerOperation.getResponses()).thenReturn(apiResponses); + ApiResponse apiResponse = Mockito.mock(ApiResponse.class); + Mockito.when(apiResponses.get("200")).thenReturn(apiResponse); + Content content = new Content(); + content.addMediaType(MediaType.APPLICATION_JSON, new io.swagger.v3.oas.models.media.MediaType()); + content.get(MediaType.APPLICATION_JSON).setSchema(new StringSchema()); + Mockito.when(apiResponse.getContent()).thenReturn(content); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta); + Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode())) + .thenReturn(TypeFactory.defaultInstance().constructType(String.class)); + JavaType javaType = Mockito.mock(JavaType.class); + Mockito.when(invocationRuntimeType.findResponseType(200)).thenReturn(javaType); + Mockito.when(javaType.getRawClass()).thenAnswer(invocationOnMock -> Part.class); + Mockito.when(invocation.getTransportContext()).thenReturn(transportContext); + Mockito.when(transportContext.getResponseEx()).thenReturn(responseEx); + + codecFilter.onFilter(invocation, nextNode).get(); + } + + @Test + public void should_encode_response_header() throws ExecutionException, InterruptedException { + headers.add("h1", "v1"); + success_invocation(); + + Mockito.verify(responseEx).addHeader("h1", "v1"); + } + + @Test + public void should_not_encode_content_length_header() throws ExecutionException, InterruptedException { + headers.add("h1", "v1") + .add("h2", "v2") + .add(CONTENT_LENGTH, "10"); + success_invocation(); + + Mockito.verify(responseEx, Mockito.times(1)).addHeader("h1", "v1"); + Mockito.verify(responseEx, Mockito.times(1)).addHeader("h2", "v2"); + } + + @Test + public void should_not_encode_transfer_encoding_header() throws ExecutionException, InterruptedException { + headers.add("h1", "v1") + .add("h2", "v2") + .add(TRANSFER_ENCODING, "test"); + success_invocation(); + + Mockito.verify(responseEx, Mockito.times(1)).addHeader("h1", "v1"); + Mockito.verify(responseEx, Mockito.times(1)).addHeader("h2", "v2"); + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/TestServerRestArgsFilter.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/TestServerRestArgsFilter.java deleted file mode 100644 index 8a322e07d84..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/TestServerRestArgsFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.common.rest.filter.inner; - -import java.util.concurrent.CompletableFuture; - -import javax.servlet.http.Part; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestServerRestArgsFilter { - @Mocked - Invocation invocation; - - @Mocked - HttpServletResponseEx responseEx; - - @Mocked - Response response; - - @Mocked - Part part; - - boolean invokedSendPart; - - ServerRestArgsFilter filter = new ServerRestArgsFilter(); - - @Test - public void asyncBeforeSendResponse_part() { - new Expectations() { - { - responseEx.getAttribute(RestConst.INVOCATION_HANDLER_RESPONSE); - result = response; - response.getResult(); - result = part; - } - }; - new MockUp(responseEx) { - @Mock - CompletableFuture sendPart(Part body) { - invokedSendPart = true; - return null; - } - }; - - Assert.assertNull(filter.beforeSendResponseAsync(invocation, responseEx)); - Assert.assertTrue(invokedSendPart); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestMicroservicePaths.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestMicroservicePaths.java index 70ab207f074..d99fb3b04f1 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestMicroservicePaths.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestMicroservicePaths.java @@ -17,123 +17,93 @@ package org.apache.servicecomb.common.rest.locator; -import java.io.StringWriter; -import java.io.Writer; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; -import org.apache.log4j.Logger; -import org.apache.log4j.SimpleLayout; -import org.apache.log4j.WriterAppender; +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.common.rest.RestEngineSchemaListener; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.definition.UnitTestRestUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.transport.TransportManager; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestMicroservicePaths { - @Test - public void testAddResourceStaticNewGroup() { - RestOperationMeta staticRes = UnitTestRestUtils.createRestOperationMeta("POST", "/static"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(staticRes); - - Assert.assertSame(staticRes, paths.getStaticPathOperationMap().get("/static").findValue("POST")); - } - - @Test - public void testAddResourceStaticAddToGroup() { - RestOperationMeta staticResPost = UnitTestRestUtils.createRestOperationMeta("POST", "/static"); - RestOperationMeta staticResGet = UnitTestRestUtils.createRestOperationMeta("GET", "/static"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(staticResPost); - paths.addResource(staticResGet); - - Assert.assertSame(staticResPost, paths.getStaticPathOperationMap().get("/static").findValue("POST")); - Assert.assertSame(staticResGet, paths.getStaticPathOperationMap().get("/static").findValue("GET")); - } - - @Test - public void testAddResourceStaticDuplicatedHttpMethod() { - RestOperationMeta staticResPost = UnitTestRestUtils.createRestOperationMeta("POST", "/static"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(staticResPost); - - try { - paths.addResource(staticResPost); - Assert.fail("must throw exception"); - } catch (ServiceCombException e) { - Assert.assertEquals("operation with url /static, method POST is duplicated.", e.getMessage()); - } + SCBEngine scbEngine; + + MicroservicePaths paths; + + @BeforeEach + public void setup() { + Environment environment = Mockito.mock(Environment.class); + scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_NAME); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + List listeners = new ArrayList<>(); + listeners.add(new RestEngineSchemaListener()); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + scbEngine.setTransportManager(transportManager); + scbEngine.setExecutorManager(executorManager); + scbEngine.setBootListeners(listeners); + scbEngine.addProducerMeta("sid1", new TestPathSchema()) + .run(); + + ServicePathManager spm = ServicePathManager.getServicePathManager(scbEngine.getProducerMicroserviceMeta()); + paths = spm.producerPaths; } - @Test - public void testAddResourceDynamic() { - RestOperationMeta dynamicRes = UnitTestRestUtils.createRestOperationMeta("POST", "/dynamic/{id}"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(dynamicRes); - - Assert.assertSame(dynamicRes, paths.getDynamicPathOperationList().get(0)); + @AfterEach + public void teardown() { + scbEngine.destroy(); } @Test - public void testCloneTo() { - RestOperationMeta staticRes = UnitTestRestUtils.createRestOperationMeta("POST", "/static"); - RestOperationMeta dynamicRes = UnitTestRestUtils.createRestOperationMeta("POST", "/dynamic/{id}"); + public void staticGroup() { + RestOperationMeta meta = paths.getStaticPathOperationMap().get("/static/").findValue("POST"); + Assertions.assertSame("postStatic", meta.getOperationMeta().getOperationId()); - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(staticRes); - paths.addResource(dynamicRes); - - MicroservicePaths other = new MicroservicePaths(); - paths.cloneTo(other); - - Assert.assertEquals(paths.getStaticPathOperationMap(), other.getStaticPathOperationMap()); - Assert.assertEquals(paths.getDynamicPathOperationList(), other.getDynamicPathOperationList()); + meta = paths.getStaticPathOperationMap().get("/static/").findValue("GET"); + Assertions.assertSame("getStatic", meta.getOperationMeta().getOperationId()); } @Test - public void testSortPath() { - // only test base rule - // completely rule test by TestRestOperationComparator - RestOperationMeta dynamicResLessStatic = UnitTestRestUtils.createRestOperationMeta("POST", "/a/{id}"); - RestOperationMeta dynamicResMoreStatic = UnitTestRestUtils.createRestOperationMeta("POST", "/abc/{id}"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(dynamicResLessStatic); - paths.addResource(dynamicResMoreStatic); - paths.sortPath(); - - Assert.assertSame(dynamicResMoreStatic, paths.getDynamicPathOperationList().get(0)); - Assert.assertSame(dynamicResLessStatic, paths.getDynamicPathOperationList().get(1)); + public void testAddResourceStaticDuplicatedHttpMethod() { + RestOperationMeta staticResPost = Mockito.mock(RestOperationMeta.class); + Mockito.when(staticResPost.getHttpMethod()).thenReturn("POST"); + Mockito.when(staticResPost.getAbsolutePath()).thenReturn("/static/"); + Mockito.when(staticResPost.isAbsoluteStaticPath()).thenReturn(true); + + ServiceCombException exception = Assertions.assertThrows(ServiceCombException.class, + () -> paths.addResource(staticResPost)); + Assertions.assertEquals("operation with url /static/, method POST is duplicated.", exception.getMessage()); } @Test - public void testPrintPaths() { - RestOperationMeta staticRes = UnitTestRestUtils.createRestOperationMeta("POST", "/static"); - RestOperationMeta dynamicRes = UnitTestRestUtils.createRestOperationMeta("POST", "/dynamic/{id}"); - - MicroservicePaths paths = new MicroservicePaths(); - paths.addResource(staticRes); - paths.addResource(dynamicRes); - - WriterAppender appender = new WriterAppender(); - Writer writer = new StringWriter(); - appender.setWriter(writer); - appender.setLayout(new SimpleLayout()); - Logger.getRootLogger().addAppender(appender); - - paths.printPaths(); - - String[] lines = writer.toString().split("\n"); - Assert.assertEquals("INFO - Swagger mapped \"{[/static], method=[POST], produces=[application/json]}\" onto null", - lines[0].trim()); - Assert.assertEquals( - "INFO - Swagger mapped \"{[/dynamic/{id}], method=[POST], produces=[application/json]}\" onto null", - lines[1].trim()); - - Logger.getRootLogger().removeAppender(appender); + public void dynamicPath() { + Assertions.assertEquals("dynamicExId", + paths.getDynamicPathOperationList().get(0).getOperationMeta().getOperationId()); + Assertions.assertEquals("dynamicId", + paths.getDynamicPathOperationList().get(1).getOperationMeta().getOperationId()); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestOperationLocator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestOperationLocator.java deleted file mode 100644 index c865843443f..00000000000 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestOperationLocator.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.common.rest.locator; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.definition.UnitTestRestUtils; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; - -public class TestOperationLocator { - MicroservicePaths paths = new MicroservicePaths(); - - OperationLocator locator = new OperationLocator(); - - private RestOperationMeta addRestOperationMeta(String httpMethod, String path) { - RestOperationMeta rom = UnitTestRestUtils.createRestOperationMeta(httpMethod, path); - paths.addResource(rom); - return rom; - } - - @Test - public void testLocateNotFound() { - try { - locator.locate("ms", "/notExist", "GET", paths); - Assert.fail("must throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(Status.NOT_FOUND, e.getStatus()); - } - } - - @Test - public void testLocateNotFoundDynamicRemained() { - addRestOperationMeta("GET", "/dynamic/{id}"); - try { - locator.locate("ms", "/dynamic/1/2", "GET", paths); - Assert.fail("must throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(Status.NOT_FOUND, e.getStatus()); - } - } - - @Test - public void testLocateStaticMethodNotAllowed() { - addRestOperationMeta("GET", "/static"); - - try { - locator.locate("ms", "/static", "POST", paths); - Assert.fail("must throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(Status.METHOD_NOT_ALLOWED, e.getStatus()); - } - } - - @Test - public void testLocateDynamicMethodNotAllowed() { - addRestOperationMeta("GET", "/dynamic/{id}"); - try { - locator.locate("ms", "/dynamic/1/", "POST", paths); - Assert.fail("must throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(Status.METHOD_NOT_ALLOWED, e.getStatus()); - } - } - - @Test - public void testLocateStaticFound() { - RestOperationMeta rom = addRestOperationMeta("GET", "/static"); - locator.locate("ms", "/static", "GET", paths); - - Assert.assertSame(rom, locator.getOperation()); - } - - @Test - public void testLocateDynamicFound() { - RestOperationMeta rom = addRestOperationMeta("GET", "/dynamic/{id}"); - locator.locate("ms", "/dynamic/1/", "GET", paths); - - Assert.assertSame(rom, locator.getOperation()); - Assert.assertEquals("1", locator.getPathVarMap().get("id")); - } -} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestPathSchema.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestPathSchema.java new file mode 100644 index 00000000000..b0de6caf78b --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestPathSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.locator; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +@Path("/") +public class TestPathSchema { + @Path("/static") + @GET + public void getStatic() { + + } + + @Path("/static") + @POST + public void postStatic() { + + } + + @Path("/staticEx") + @GET + public void getStaticEx() { + + } + + @Path("/dynamic/{id}") + @GET + public void dynamicId(@PathParam("id") String id) { + + } + + @Path("/dynamicEx/{id}") + @GET + public void dynamicExId(@PathParam("id") String id) { + + } +} diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java index 529b6302271..84ae22015ae 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/locator/TestServicePathManager.java @@ -17,97 +17,103 @@ package org.apache.servicecomb.common.rest.locator; -import java.util.Map; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.context.ApplicationContext; - -import io.swagger.models.Path; -import io.swagger.models.Swagger; -import mockit.Mocked; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.common.rest.RestEngineSchemaListener; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestServicePathManager { - private static class TestServicePathManagerSchemaImpl { - @SuppressWarnings("unused") - public void static1() { - } - - @SuppressWarnings("unused") - public void static2() { - } - - @SuppressWarnings("unused") - public void dynamic1() { - } - - @SuppressWarnings("unused") - public void dynamic2() { - } + SCBEngine scbEngine; + + Environment environment; + + @BeforeEach + public void setUp() { + environment = Mockito.mock(Environment.class); + scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.parameter.decodeAsObject", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_NAME); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); } - private ServicePathManager spm; - - @Mocked - ApplicationContext applicationContext; - - @Before - public void setup() { - BeanUtils.setContext(applicationContext); - - MicroserviceMeta mm = new MicroserviceMeta("app:ms"); - Swagger swagger = UnitTestSwaggerUtils.generateSwagger(TestServicePathManagerSchemaImpl.class).getSwagger(); - Map paths = swagger.getPaths(); - - swagger.setBasePath(""); - Path path = paths.remove("/static1"); - paths.put("/root/rest/static1", path); - - path = paths.remove("/dynamic1"); - paths.put("/dynamic1/{id}", path); - - path = paths.remove("/dynamic2"); - paths.put("/dynamic2/{id}", path); - - SchemaMeta schemaMeta = new SchemaMeta(swagger, mm, "sid"); - - spm = new ServicePathManager(mm); - spm.addSchema(schemaMeta); - spm.sortPath(); - } - - @After - public void teardown() { - BeanUtils.setContext(null); + @AfterEach + public void tearDown() { + scbEngine.destroy(); + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); } @Test public void testBuildProducerPathsNoPrefix() { - System.clearProperty(Const.URL_PREFIX); + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + scbEngine.setTransportManager(transportManager); + scbEngine.setExecutorManager(executorManager); + List listeners = new ArrayList<>(); + listeners.add(new RestEngineSchemaListener()); + scbEngine.setBootListeners(listeners); + scbEngine.addProducerMeta("sid1", new TestPathSchema()) + .run(); + + ServicePathManager spm = ServicePathManager.getServicePathManager(scbEngine.getProducerMicroserviceMeta()); - spm.buildProducerPaths(); - Assert.assertSame(spm.producerPaths, spm.swaggerPaths); + Assertions.assertSame(spm.producerPaths, spm.swaggerPaths); + + scbEngine.destroy(); } @Test public void testBuildProducerPathsHasPrefix() { - System.setProperty(Const.URL_PREFIX, "/root/rest"); + ClassLoaderScopeContext.setClassLoaderScopeProperty(DefinitionConst.URL_PREFIX, "/root/rest"); + + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty(DefinitionConst.REGISTER_URL_PREFIX, boolean.class, false)).thenReturn(false); + + ExecutorManager executorManager = Mockito.mock(ExecutorManager.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + scbEngine.setTransportManager(transportManager); + scbEngine.setExecutorManager(executorManager); + List listeners = new ArrayList<>(); + listeners.add(new RestEngineSchemaListener()); + scbEngine.setBootListeners(listeners); + scbEngine.addProducerMeta("sid1", new TestPathSchema()) + .run(); - spm.buildProducerPaths(); + ServicePathManager spm = ServicePathManager.getServicePathManager(scbEngine.getProducerMicroserviceMeta()); // all locate should be success - spm.producerLocateOperation("/root/rest/static1/", "POST"); - spm.producerLocateOperation("/root/rest/static2/", "POST"); - spm.producerLocateOperation("/root/rest/dynamic1/1/", "POST"); - spm.producerLocateOperation("/root/rest/dynamic2/1/", "POST"); + spm.producerLocateOperation("/root/rest/static/", "GET"); + spm.producerLocateOperation("/root/rest/static/", "POST"); + spm.producerLocateOperation("/root/rest/dynamic/1/", "GET"); + spm.producerLocateOperation("/root/rest/dynamicEx/1/", "GET"); - System.clearProperty(Const.URL_PREFIX); + scbEngine.destroy(); } } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/resource/TestClassPathStaticResourceHandler.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/resource/TestClassPathStaticResourceHandler.java new file mode 100644 index 00000000000..f95468f4f38 --- /dev/null +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/resource/TestClassPathStaticResourceHandler.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.common.rest.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response.Status; + +public class TestClassPathStaticResourceHandler { + static ClassPathStaticResourceHandler handler = new ClassPathStaticResourceHandler(); + + @BeforeAll + public static void setup() { + handler.setWebRoot("web-root/"); + } + + @Test + public void normal() throws IOException { + Response response = handler.handle("index.html"); + Part part = response.getResult(); + + try (InputStream is = part.getInputStream()) { + Assertions.assertTrue(IOUtils.toString(is, StandardCharsets.UTF_8).trim().endsWith("")); + } + Assertions.assertEquals("text/html", part.getContentType()); + Assertions.assertEquals("text/html", response.getHeader(HttpHeaders.CONTENT_TYPE)); + Assertions.assertEquals("inline", response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); + } + + @Test + public void notExist() { + Response response = handler.handle("notExist.html"); + + InvocationException invocationException = response.getResult(); + Assertions.assertEquals(Status.NOT_FOUND, invocationException.getStatus()); + Assertions.assertEquals(Status.NOT_FOUND.getReasonPhrase(), + ((CommonExceptionData) invocationException.getErrorData()).getMessage()); + Assertions.assertEquals(404, response.getStatusCode()); + Assertions.assertEquals("Not Found", response.getReasonPhrase()); + } + + @Test + public void attack() { + Response response = handler.handle("../microservice.yaml"); + + InvocationException invocationException = response.getResult(); + Assertions.assertEquals(Status.NOT_FOUND, invocationException.getStatus()); + Assertions.assertEquals(Status.NOT_FOUND.getReasonPhrase(), + ((CommonExceptionData) invocationException.getErrorData()).getMessage()); + Assertions.assertEquals(404, response.getStatusCode()); + Assertions.assertEquals("Not Found", response.getReasonPhrase()); + } + + @Test + public void readContentFailed() throws IOException { + handler = Mockito.spy(TestClassPathStaticResourceHandler.handler); + Mockito.when(handler.findResource("web-root/index.html")) + .thenThrow(new RuntimeExceptionWithoutStackTrace("read content failed.")); + + try (LogCollector logCollector = new LogCollector()) { + Response response = handler.handle("index.html"); + + Assertions.assertEquals("failed to process static resource, path=web-root/index.html", + logCollector.getLastEvents().getMessage().getFormattedMessage()); + + InvocationException invocationException = response.getResult(); + Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR, invocationException.getStatus()); + Assertions.assertEquals("failed to process static resource.", + ((CommonExceptionData) invocationException.getErrorData()).getMessage()); + Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode()); + Assertions.assertEquals(Status.INTERNAL_SERVER_ERROR.getReasonPhrase(), response.getReasonPhrase()); + } + } +} diff --git a/common/common-rest/src/test/resources/config/test.properties b/common/common-rest/src/test/resources/config/test.properties deleted file mode 100644 index 88992190bfa..00000000000 --- a/common/common-rest/src/test/resources/config/test.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -1=0 -1.1=0 -1.2=0 diff --git a/common/common-rest/src/test/resources/log4j.properties b/common/common-rest/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/common/common-rest/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/common/common-rest/src/test/resources/log4j2.xml b/common/common-rest/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/common/common-rest/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/common/common-rest/src/test/resources/microservice.yaml b/common/common-rest/src/test/resources/microservice.yaml index b47bdef7360..90fd8d97c8e 100644 --- a/common/common-rest/src/test/resources/microservice.yaml +++ b/common/common-rest/src/test/resources/microservice.yaml @@ -27,9 +27,3 @@ servicecomb: address: 0.0.0.0:8080 highway: address: 0.0.0.0:7070 - #executors: - #default: test - #Provider: - #server: test - #server.wrapParam: test - diff --git a/common/common-rest/src/test/resources/web-root/index.html b/common/common-rest/src/test/resources/web-root/index.html new file mode 100644 index 00000000000..8fe33dc3cfa --- /dev/null +++ b/common/common-rest/src/test/resources/web-root/index.html @@ -0,0 +1,17 @@ + + diff --git a/common/pom.xml b/common/pom.xml index 540adb836f5..c39c89ff4ce 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -21,15 +21,15 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default common Java Chassis::Common pom - common-javassist common-protobuf common-rest + common-access-log diff --git a/core/pom.xml b/core/pom.xml index 0ce9ad50b15..af73c36dff9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,8 +21,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default java-chassis-core Java Chassis::Core @@ -30,49 +30,61 @@ org.apache.servicecomb - service-registry + foundation-vertx + + + org.apache.servicecomb + foundation-registry org.apache.servicecomb swagger-invocation-core + + org.apache.servicecomb + swagger-generator-core + io.zipkin.brave brave - org.jmockit - jmockit - provided + org.hibernate.validator + hibernate-validator - org.mockito - mockito-core - provided + org.apache.servicecomb + servicecomb-governance + + + org.springframework.boot + spring-boot-autoconfigure - junit - junit + io.vertx + vertx-codegen provided + - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + foundation-test-scaffolding test - log4j - log4j + org.apache.logging.log4j + log4j-slf4j-impl test - org.apache.servicecomb - foundation-test-scaffolding + org.apache.logging.log4j + log4j-core + test - io.vertx - vertx-codegen - provided + org.jmockit + jmockit + test diff --git a/core/src/main/java/org/apache/servicecomb/core/BootListener.java b/core/src/main/java/org/apache/servicecomb/core/BootListener.java index b273467db25..ea8314e2e1d 100644 --- a/core/src/main/java/org/apache/servicecomb/core/BootListener.java +++ b/core/src/main/java/org/apache/servicecomb/core/BootListener.java @@ -17,10 +17,12 @@ package org.apache.servicecomb.core; -public interface BootListener { +import org.springframework.core.Ordered; + +public interface BootListener extends Ordered { enum EventType { - BEFORE_HANDLER, - AFTER_HANDLER, + BEFORE_FILTER, + AFTER_FILTER, BEFORE_PRODUCER_PROVIDER, AFTER_PRODUCER_PROVIDER, BEFORE_CONSUMER_PROVIDER, @@ -38,26 +40,126 @@ class BootEvent { private EventType eventType; + public BootEvent() { + } + + public BootEvent(SCBEngine scbEngine, EventType eventType) { + this.scbEngine = scbEngine; + this.eventType = eventType; + } + public SCBEngine getScbEngine() { return scbEngine; } - public void setScbEngine(SCBEngine scbEngine) { + public BootEvent setScbEngine(SCBEngine scbEngine) { this.scbEngine = scbEngine; + return this; } public EventType getEventType() { return eventType; } - public void setEventType(EventType eventType) { + public BootEvent setEventType(EventType eventType) { this.eventType = eventType; + return this; } } + @Override default int getOrder() { return 0; } - void onBootEvent(BootEvent event); + default void onBootEvent(BootEvent event) { + switch (event.eventType) { + case BEFORE_FILTER: + onBeforeFilter(event); + return; + case AFTER_FILTER: + onAfterFilter(event); + return; + case BEFORE_PRODUCER_PROVIDER: + onBeforeProducerProvider(event); + return; + case AFTER_PRODUCER_PROVIDER: + onAfterProducerProvider(event); + return; + case BEFORE_CONSUMER_PROVIDER: + onBeforeConsumerProvider(event); + return; + case AFTER_CONSUMER_PROVIDER: + onAfterConsumerProvider(event); + return; + case BEFORE_TRANSPORT: + onBeforeTransport(event); + return; + case AFTER_TRANSPORT: + onAfterTransport(event); + return; + case BEFORE_REGISTRY: + onBeforeRegistry(event); + return; + case AFTER_REGISTRY: + onAfterRegistry(event); + return; + case BEFORE_CLOSE: + onBeforeClose(event); + return; + case AFTER_CLOSE: + onAfterClose(event); + return; + default: + throw new IllegalStateException("unknown boot event type: " + event.eventType); + } + } + + default void onBeforeFilter(BootEvent event) { + + } + + default void onAfterFilter(BootEvent event) { + + } + + default void onBeforeProducerProvider(BootEvent event) { + + } + + default void onAfterProducerProvider(BootEvent event) { + + } + + default void onBeforeConsumerProvider(BootEvent event) { + + } + + default void onAfterConsumerProvider(BootEvent event) { + + } + + default void onBeforeTransport(BootEvent event) { + + } + + default void onAfterTransport(BootEvent event) { + + } + + default void onBeforeRegistry(BootEvent event) { + + } + + default void onAfterRegistry(BootEvent event) { + + } + + default void onBeforeClose(BootEvent event) { + + } + + default void onAfterClose(BootEvent event) { + + } } diff --git a/core/src/main/java/org/apache/servicecomb/core/Const.java b/core/src/main/java/org/apache/servicecomb/core/Const.java deleted file mode 100644 index e46cc820aab..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/Const.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; - -public final class Const { - private Const() { - } - - public static final String CSE_CONTEXT = "x-cse-context"; - - public static final String RESTFUL = "rest"; - - public static final String HIGHWAY = "highway"; - - public static final String ANY_TRANSPORT = ""; - - public static final String VERSION_RULE_LATEST = DefinitionConst.VERSION_RULE_LATEST; - - public static final String DEFAULT_VERSION_RULE = DefinitionConst.VERSION_RULE_ALL; - - public static final String PRODUCER_OPERATION = "producer-operation"; - - public static final String SRC_MICROSERVICE = "x-cse-src-microservice"; - - public static final String TARGET_MICROSERVICE = "x-cse-target-microservice"; - - public static final String REMOTE_ADDRESS = "x-cse-remote-address"; - - public static final String AUTH_TOKEN = "x-cse-auth-rsatoken"; - - public static final String TRACE_ID_NAME = "X-B3-TraceId"; -} diff --git a/core/src/main/java/org/apache/servicecomb/core/ConsumerProvider.java b/core/src/main/java/org/apache/servicecomb/core/ConsumerProvider.java deleted file mode 100644 index 528c57c2135..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/ConsumerProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -/** - * consumer端对业务的接口,不同场景是完全不同的 - * 所以这里只定义consumer对core的接口 - */ -public interface ConsumerProvider { - String getName(); - - void init() throws Exception; -} diff --git a/core/src/main/java/org/apache/servicecomb/core/CoreConst.java b/core/src/main/java/org/apache/servicecomb/core/CoreConst.java new file mode 100644 index 00000000000..37c34b9c96d --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/CoreConst.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core; + +import org.apache.servicecomb.registry.definition.DefinitionConst; + +public final class CoreConst { + private CoreConst() { + } + + public static final String CSE_CONTEXT = "x-cse-context"; + + public static final String TRANSPORT_NAME = "x-transport-name"; + + public static final String RESTFUL = "rest"; + + public static final String HIGHWAY = "highway"; + + public static final String WEBSOCKET = "websocket"; + + public static final String ANY_TRANSPORT = ""; + + public static final String VERSION_RULE_LATEST = DefinitionConst.VERSION_RULE_LATEST; + + public static final String DEFAULT_VERSION_RULE = DefinitionConst.VERSION_RULE_ALL; + + public static final String PRODUCER_OPERATION = "producer-operation"; + + public static final String CONSUMER_OPERATION = "consumer-operation"; + + public static final String SRC_MICROSERVICE = "x-cse-src-microservice"; + + public static final String SRC_SERVICE_ID = "x-src-serviceId"; + + public static final String SRC_INSTANCE_ID = "x-src-instanceId"; + + public static final String TARGET_MICROSERVICE = "x-cse-target-microservice"; + + public static final String REMOTE_ADDRESS = "x-cse-remote-address"; + + public static final String AUTH_TOKEN = "x-cse-auth-rsatoken"; + + public static final String TRACE_ID_NAME = "X-B3-TraceId"; + + // controlling whether to print stack information with sensitive errors + public static final String PRINT_SENSITIVE_ERROR_MESSAGE = "servicecomb.error.printSensitiveErrorMessage"; + + public static final String SWAGGER_EXPORT_ENABLED = "servicecomb.swagger.export.enabled"; + + public static final String SWAGGER_DIRECTORY = "servicecomb.swagger.export.directory"; +} diff --git a/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java b/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java deleted file mode 100644 index 5ed1759c103..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/CseApplicationListener.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.schema.StaticSchemaFactory; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.producer.ProducerProviderManager; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextClosedEvent; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.support.AbstractApplicationContext; -import org.springframework.core.Ordered; - -public class CseApplicationListener - implements ApplicationListener, Ordered, ApplicationContextAware { - private Class initEventClass = ContextRefreshedEvent.class; - - private ApplicationContext applicationContext; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - BeanUtils.setContext(applicationContext); - RegistryUtils.init(); - } - - public void setInitEventClass(Class initEventClass) { - this.initEventClass = initEventClass; - } - - @Override - public int getOrder() { - // should run before default listener, eg: ZuulConfiguration - return -1000; - } - - @Override - public void onApplicationEvent(ApplicationEvent event) { - if (initEventClass.isInstance(event)) { - if (applicationContext instanceof AbstractApplicationContext) { - ((AbstractApplicationContext) applicationContext).registerShutdownHook(); - } - - if (SCBEngine.getInstance().getBootListenerList() == null) { - //SCBEngine init first, hence we do not need worry that when other beans need use the - //producer microserviceMeta, the SCBEngine is not inited. - String serviceName = RegistryUtils.getMicroservice().getServiceName(); - SCBEngine.getInstance().setProducerMicroserviceMeta(new MicroserviceMeta(serviceName)); - SCBEngine.getInstance().setProducerProviderManager(applicationContext.getBean(ProducerProviderManager.class)); - SCBEngine.getInstance().setConsumerProviderManager(applicationContext.getBean(ConsumerProviderManager.class)); - SCBEngine.getInstance().setTransportManager(applicationContext.getBean(TransportManager.class)); - SCBEngine.getInstance().setSchemaListenerManager(applicationContext.getBean(SchemaListenerManager.class)); - SCBEngine.getInstance().setBootListenerList(applicationContext.getBeansOfType(BootListener.class).values()); - SCBEngine.getInstance().setStaticSchemaFactory(applicationContext.getBean(StaticSchemaFactory.class)); - } - - SCBEngine.getInstance().init(); - } else if (event instanceof ContextClosedEvent) { - SCBEngine.getInstance().destroy(); - } - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/CseContext.java b/core/src/main/java/org/apache/servicecomb/core/CseContext.java deleted file mode 100644 index 45b84157024..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/CseContext.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import javax.inject.Inject; - -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.producer.ProducerProviderManager; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; - -public class CseContext { - private static final CseContext INSTANCE = new CseContext(); - - public static CseContext getInstance() { - return INSTANCE; - } - - private SchemaListenerManager schemaListenerManager; - - private SchemaLoader schemaLoader; - - private ConsumerSchemaFactory consumerSchemaFactory; - - private ConsumerProviderManager consumerProviderManager; - - private ProducerProviderManager producerProviderManager; - - private TransportManager transportManager; - - private SwaggerEnvironment swaggerEnvironment; - - public SchemaListenerManager getSchemaListenerManager() { - return schemaListenerManager; - } - - public SchemaLoader getSchemaLoader() { - return schemaLoader; - } - - public ConsumerSchemaFactory getConsumerSchemaFactory() { - return consumerSchemaFactory; - } - - public ConsumerProviderManager getConsumerProviderManager() { - return consumerProviderManager; - } - - public ProducerProviderManager getProducerProviderManager() { - return producerProviderManager; - } - - public TransportManager getTransportManager() { - return transportManager; - } - - public SwaggerEnvironment getSwaggerEnvironment() { - return swaggerEnvironment; - } - - @Inject - public void setSwaggerEnvironment(SwaggerEnvironment swaggerEnvironment) { - this.swaggerEnvironment = swaggerEnvironment; - } - - @Inject - public void setSchemaLoader(SchemaLoader schemaLoader) { - this.schemaLoader = schemaLoader; - } - - @Inject - public void setConsumerSchemaFactory(ConsumerSchemaFactory consumerSchemaFactory) { - this.consumerSchemaFactory = consumerSchemaFactory; - } - - @Inject - public void setConsumerProviderManager(ConsumerProviderManager consumerProviderManager) { - this.consumerProviderManager = consumerProviderManager; - } - - @Inject - public void setProducerProviderManager(ProducerProviderManager producerProviderManager) { - this.producerProviderManager = producerProviderManager; - } - - @Inject - public void setSchemaListenerManager(SchemaListenerManager schemaListenerManager) { - this.schemaListenerManager = schemaListenerManager; - } - - @Inject - public void setTransportManager(TransportManager transportManager) { - this.transportManager = transportManager; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/Endpoint.java b/core/src/main/java/org/apache/servicecomb/core/Endpoint.java index 9852aef6efd..01f6f1129d5 100644 --- a/core/src/main/java/org/apache/servicecomb/core/Endpoint.java +++ b/core/src/main/java/org/apache/servicecomb/core/Endpoint.java @@ -17,39 +17,47 @@ package org.apache.servicecomb.core; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; /** - * Endpoint : 表示一个Endpoint。Transport识别其内部格式. + * Internal representation for microservice instance address. */ public class Endpoint { - // 格式:rest://192.168.1.1:8080 + // Registry address: http://192.168.1.1:8080 // see: http://www.ietf.org/rfc/rfc2396.txt private final String endpoint; private final Transport transport; - private final MicroserviceInstance instance; + private final DiscoveryInstance instance; - // 内部格式, 只有Transport能够认识 + // Internal address format recognized by Transport private final Object address; public Endpoint(Transport transport, String endpoint) { this(transport, endpoint, null); } - public Endpoint(Transport transport, String endpoint, MicroserviceInstance instance) { + public Endpoint(Transport transport, String endpoint, DiscoveryInstance instance) { this.transport = transport; this.endpoint = endpoint; this.instance = instance; this.address = transport.parseAddress(this.endpoint); } + public Endpoint(Transport transport, String endpoint, StatefulDiscoveryInstance instance, Object address) { + this.transport = transport; + this.endpoint = endpoint; + this.instance = instance; + this.address = address; + } + public String getEndpoint() { return endpoint; } - public MicroserviceInstance getMicroserviceInstance() { + public DiscoveryInstance getMicroserviceInstance() { return instance; } @@ -65,4 +73,17 @@ public Object getAddress() { public String toString() { return endpoint; } + + @Override + public boolean equals(Object o) { + if (o instanceof Endpoint) { + return this.endpoint.equals(((Endpoint) o).getEndpoint()); + } + return false; + } + + @Override + public int hashCode() { + return this.endpoint.hashCode(); + } } diff --git a/core/src/main/java/org/apache/servicecomb/core/Handler.java b/core/src/main/java/org/apache/servicecomb/core/Handler.java deleted file mode 100644 index b966963c25c..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/Handler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.InvocationType; - -// 每个微服务 + invocationType,都对应一个handler实例 -public interface Handler { - default void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) { - } - - void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception; -} diff --git a/core/src/main/java/org/apache/servicecomb/core/Invocation.java b/core/src/main/java/org/apache/servicecomb/core/Invocation.java index 46c3c4a2ccc..067fe6558f4 100644 --- a/core/src/main/java/org/apache/servicecomb/core/Invocation.java +++ b/core/src/main/java/org/apache/servicecomb/core/Invocation.java @@ -17,37 +17,55 @@ package org.apache.servicecomb.core; +import java.lang.reflect.Method; import java.util.Collection; -import java.util.List; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.event.InvocationBusinessMethodFinishEvent; +import org.apache.servicecomb.core.event.InvocationBusinessFinishEvent; import org.apache.servicecomb.core.event.InvocationBusinessMethodStartEvent; +import org.apache.servicecomb.core.event.InvocationEncodeResponseStartEvent; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.event.InvocationStartEvent; +import org.apache.servicecomb.core.event.InvocationStartSendRequestEvent; +import org.apache.servicecomb.core.event.InvocationTimeoutCheckEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; import org.apache.servicecomb.core.tracing.TraceIdGenerator; +import org.apache.servicecomb.core.tracing.TraceIdLogger; import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import com.fasterxml.jackson.databind.JavaType; public class Invocation extends SwaggerInvocation { private static final Collection TRACE_ID_GENERATORS = loadTraceIdGenerators(); + protected static final AtomicLong INVOCATION_ID = new AtomicLong(); + static Collection loadTraceIdGenerators() { - return SPIServiceUtils.getPriorityHighestServices(generator -> generator.getName(), TraceIdGenerator.class); + return SPIServiceUtils.getPriorityHighestServices(TraceIdGenerator::getName, TraceIdGenerator.class); } - private ReferenceConfig referenceConfig; + protected ReferenceConfig referenceConfig; + + private InvocationRuntimeType invocationRuntimeType; // 本次调用对应的schemaMeta private SchemaMeta schemaMeta; @@ -60,77 +78,64 @@ static Collection loadTraceIdGenerators() { private Endpoint endpoint; // 只用于handler之间传递数据,是本地数据 - private Map handlerContext = localContext; - - // handler链,是arrayList,可以高效地通过index访问 - private List handlerList; - - private int handlerIndex; + private final Map handlerContext = localContext; // 应答的处理器 // 同步模式:避免应答在网络线程中处理解码等等业务级逻辑 private Executor responseExecutor; - private boolean sync = true; + private volatile boolean sync = true; - private InvocationStageTrace invocationStageTrace = new InvocationStageTrace(this); + private final InvocationStageTrace invocationStageTrace = new InvocationStageTrace(this); private HttpServletRequestEx requestEx; - private boolean finished; - - // not extend InvocationType - // because isEdge() only affect to apm/metrics output, no need to change so many logic - private boolean edge; - - public HttpServletRequestEx getRequestEx() { - return requestEx; - } + private volatile boolean finished; - public InvocationStageTrace getInvocationStageTrace() { - return invocationStageTrace; - } + private volatile long invocationId; - public String getTraceId() { - return getContext(Const.TRACE_ID_NAME); - } + private TraceIdLogger traceIdLogger; - public String getTraceId(String traceIdName) { - return getContext(traceIdName); - } + private Map invocationArguments = Collections.emptyMap(); - @Deprecated - public long getStartTime() { - return invocationStageTrace.getStart(); - } + private Object[] producerArguments; - @Deprecated - public long getStartExecutionTime() { - return invocationStageTrace.getStartExecution(); - } + private Map swaggerArguments = Collections.emptyMap(); public Invocation() { // An empty invocation, used to mock or some other scenario do not need operation information. + traceIdLogger = new TraceIdLogger(this); } - public Invocation(ReferenceConfig referenceConfig, OperationMeta operationMeta, Object[] swaggerArguments) { + public Invocation(ReferenceConfig referenceConfig, OperationMeta operationMeta, + InvocationRuntimeType invocationRuntimeType, + Map swaggerArguments) { this.invocationType = InvocationType.CONSUMER; this.referenceConfig = referenceConfig; + this.invocationRuntimeType = invocationRuntimeType; init(operationMeta, swaggerArguments); } - public Invocation(Endpoint endpoint, OperationMeta operationMeta, Object[] swaggerArguments) { - this.invocationType = InvocationType.PRODUCER; + public Invocation(Endpoint endpoint, OperationMeta operationMeta, Map swaggerArguments) { + this.invocationType = InvocationType.PROVIDER; + this.invocationRuntimeType = operationMeta.buildBaseProviderRuntimeType(); this.endpoint = endpoint; init(operationMeta, swaggerArguments); } - private void init(OperationMeta operationMeta, Object[] swaggerArguments) { + private void init(OperationMeta operationMeta, Map swaggerArguments) { + this.invocationId = INVOCATION_ID.getAndIncrement(); this.schemaMeta = operationMeta.getSchemaMeta(); this.operationMeta = operationMeta; - this.swaggerArguments = swaggerArguments; - this.handlerList = getHandlerChain(); - handlerIndex = 0; + this.setSwaggerArguments(swaggerArguments); + traceIdLogger = new TraceIdLogger(this); + } + + public String getTransportName() { + if (endpoint == null || endpoint.getTransport() == null) { + return null; + } + return endpoint.getTransport().getName(); } public Transport getTransport() { @@ -141,11 +146,6 @@ public Transport getTransport() { return endpoint.getTransport(); } - public List getHandlerChain() { - return (InvocationType.CONSUMER.equals(invocationType)) ? schemaMeta.getConsumerHandlerChain() - : schemaMeta.getProviderHandlerChain(); - } - public Executor getResponseExecutor() { return responseExecutor; } @@ -162,35 +162,87 @@ public OperationMeta getOperationMeta() { return operationMeta; } - public Object[] getArgs() { - return swaggerArguments; + public Map getInvocationArguments() { + return this.invocationArguments; } - public Endpoint getEndpoint() { - return endpoint; + public Map getSwaggerArguments() { + return this.swaggerArguments; } - public void setEndpoint(Endpoint endpoint) { - this.endpoint = endpoint; + public Object getInvocationArgument(String name) { + return this.invocationArguments.get(name); } - public Map getHandlerContext() { - return handlerContext; + public Object getSwaggerArgument(String name) { + return this.swaggerArguments.get(name); + } + + public void setInvocationArguments(Map invocationArguments) { + if (invocationArguments == null) { + // Empty arguments + this.invocationArguments = new HashMap<>(0); + return; + } + this.invocationArguments = invocationArguments; + + buildSwaggerArguments(); } - public int getHandlerIndex() { - return handlerIndex; + private void buildSwaggerArguments() { + if (!this.invocationRuntimeType.isRawConsumer()) { + this.swaggerArguments = this.invocationRuntimeType.getArgumentsMapper() + .invocationArgumentToSwaggerArguments(this, + this.invocationArguments); + } else { + this.swaggerArguments = invocationArguments; + } + } + + public void setSwaggerArguments(Map swaggerArguments) { + if (swaggerArguments == null) { + // Empty arguments + this.swaggerArguments = new HashMap<>(0); + return; + } + this.swaggerArguments = swaggerArguments; + + buildInvocationArguments(); + } + + private void buildInvocationArguments() { + if (operationMeta.getSwaggerProducerOperation() != null && !isEdge()) { + this.invocationArguments = operationMeta.getSwaggerProducerOperation().getArgumentsMapper() + .swaggerArgumentToInvocationArguments(this, + swaggerArguments); + } else { + this.invocationArguments = swaggerArguments; + } + } + + public Object[] toProducerArguments() { + if (producerArguments != null) { + return producerArguments; + } + + Method method = operationMeta.getSwaggerProducerOperation().getProducerMethod(); + Object[] args = new Object[method.getParameterCount()]; + for (int i = 0; i < method.getParameterCount(); i++) { + args[i] = this.invocationArguments.get(method.getParameters()[i].getName()); + } + return producerArguments = args; + } + + public Endpoint getEndpoint() { + return endpoint; } - public void setHandlerIndex(int handlerIndex) { - this.handlerIndex = handlerIndex; + public void setEndpoint(Endpoint endpoint) { + this.endpoint = endpoint; } - public void next(AsyncResponse asyncResp) throws Exception { - // 不必判断有效性,因为整个流程都是内部控制的 - int runIndex = handlerIndex; - handlerIndex++; - handlerList.get(runIndex).handle(this, asyncResp); + public Map getHandlerContext() { + return handlerContext; } public String getSchemaId() { @@ -201,9 +253,21 @@ public String getOperationName() { return operationMeta.getOperationId(); } + public String getProviderTransportName() { + if (operationMeta.getSwaggerOperation().getExtensions() != null && + operationMeta.getSwaggerOperation().getExtensions().get(CoreConst.TRANSPORT_NAME) != null) { + return (String) operationMeta.getSwaggerOperation().getExtensions().get(CoreConst.TRANSPORT_NAME); + } + if (schemaMeta.getSwagger().getExtensions() != null && + schemaMeta.getSwagger().getExtensions().get(CoreConst.TRANSPORT_NAME) != null) { + return (String) schemaMeta.getSwagger().getExtensions().get(CoreConst.TRANSPORT_NAME); + } + return null; + } + public String getConfigTransportName() { - if (operationMeta.getTransport() != null) { - return operationMeta.getTransport(); + if (getProviderTransportName() != null) { + return getProviderTransportName(); } return referenceConfig.getTransport(); } @@ -220,10 +284,23 @@ public String getAppId() { return schemaMeta.getMicroserviceMeta().getAppId(); } - public String getMicroserviceVersionRule() { - return referenceConfig.getVersionRule(); + public MicroserviceMeta getMicroserviceMeta() { + return schemaMeta.getMicroserviceMeta(); + } + + public InvocationRuntimeType getInvocationRuntimeType() { + return this.invocationRuntimeType; + } + + public JavaType findResponseType(int statusCode) { + return this.invocationRuntimeType.findResponseType(statusCode); + } + + public void setSuccessResponseType(JavaType javaType) { + this.invocationRuntimeType.setSuccessResponseType(javaType); } + @Override public String getInvocationQualifiedName() { return invocationType.name() + " " + getRealTransportName() + " " + getOperationMeta().getMicroserviceQualifiedName(); @@ -262,35 +339,38 @@ protected void initTraceId(TraceIdGenerator traceIdGenerator) { addContext(traceIdGenerator.getTraceIdKeyName(), traceIdGenerator.generate()); } - public void onStart(long start) { - invocationStageTrace.start(start); + public void onStart() { initTraceId(); EventManager.post(new InvocationStartEvent(this)); } - public void onStart(HttpServletRequestEx requestEx, long start) { + public void onStart(HttpServletRequestEx requestEx) { this.requestEx = requestEx; - onStart(start); + + onStart(); } - public void onExecuteStart() { - invocationStageTrace.startExecution(); + public void onStartSendRequest() { + EventManager.post(new InvocationStartSendRequestEvent(this)); } - @Override public void onBusinessMethodStart() { - invocationStageTrace.startBusinessMethod(); + invocationStageTrace.startBusinessExecute(); EventManager.post(new InvocationBusinessMethodStartEvent(this)); } - @Override - public void onBusinessMethodFinish() { - EventManager.post(new InvocationBusinessMethodFinishEvent(this)); + public void onEncodeResponseStart(Response response) { + invocationStageTrace.startProviderEncodeResponse(); + EventManager.post(new InvocationEncodeResponseStartEvent(this, response)); + } + + public void onEncodeResponseFinish() { + invocationStageTrace.finishProviderEncodeResponse(); } - @Override public void onBusinessFinish() { - invocationStageTrace.finishBusiness(); + invocationStageTrace.finishBusinessExecute(); + EventManager.post(new InvocationBusinessFinishEvent(this)); } public void onFinish(Response response) { @@ -299,9 +379,14 @@ public void onFinish(Response response) { return; } + finished = true; invocationStageTrace.finish(); EventManager.post(new InvocationFinishEvent(this, response)); - finished = true; + } + + // for retry, reset invocation and try it again + public void reset() { + finished = false; } public boolean isFinished() { @@ -320,11 +405,76 @@ public boolean isConsumer() { return InvocationType.CONSUMER.equals(invocationType); } + public boolean isProducer() { + return InvocationType.PROVIDER.equals(invocationType); + } + public boolean isEdge() { - return edge; + return InvocationType.EDGE.equals(invocationType); } - public void setEdge(boolean edge) { - this.edge = edge; + public void setEdge() { + this.invocationType = InvocationType.EDGE; + } + + public long getInvocationId() { + return invocationId; + } + + public TraceIdLogger getTraceIdLogger() { + return this.traceIdLogger; + } + + public HttpServletRequestEx getRequestEx() { + return requestEx; + } + + public InvocationStageTrace getInvocationStageTrace() { + return invocationStageTrace; + } + + public String getTraceId() { + return getContext(CoreConst.TRACE_ID_NAME); + } + + public String getTraceId(String traceIdName) { + return getContext(traceIdName); + } + + // ensure sync consumer invocation response flow not run in eventLoop + public CompletableFuture optimizeSyncConsumerThread(CompletableFuture future) { + if (sync && !InvokerUtils.isInEventLoop()) { + return AsyncUtils.tryCatchSupplier(() -> InvokerUtils.toSync(future, getWaitTime())); + } + + return future; + } + + public long getWaitTime() { + if (getOperationMeta().getConfig().getMsInvocationTimeout() > 0) { + // if invocation timeout configured, use it. + return getOperationMeta().getConfig().getMsInvocationTimeout(); + } + + // In invocation handlers, may call other microservices, invocation + // timeout may be much longer than request timeout. + // But this is quite rare, for simplicity, default two times of request timeout. + // If users need longer timeout, can configure invocation timeout. + return getOperationMeta().getConfig().getMsRequestTimeout() * 2; + } + + /** + * Check if invocation is timeout. + * + * NOTICE: this method only trigger event to ask the target checker to do the real check. So this method + * will only take effect when timeout checker is enabled. + * + * e.g. InvocationTimeoutBootListener.ENABLE_TIMEOUT_CHECK is enabled. + * + * @throws InvocationException if timeout, throw an exception. Will not throw exception twice if this method called + * after timeout. + */ + public void ensureInvocationNotTimeout() throws InvocationException { + EventManager.post(new InvocationTimeoutCheckEvent(this)); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/NonSwaggerInvocation.java b/core/src/main/java/org/apache/servicecomb/core/NonSwaggerInvocation.java index 785c90c93b3..e7f903e7552 100644 --- a/core/src/main/java/org/apache/servicecomb/core/NonSwaggerInvocation.java +++ b/core/src/main/java/org/apache/servicecomb/core/NonSwaggerInvocation.java @@ -17,32 +17,24 @@ package org.apache.servicecomb.core; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; - public class NonSwaggerInvocation extends Invocation { - private String appId; - - private String microserviceName; - - private String versionRule; + private final String appId; - private Handler nextHandler; + private final String microserviceName; - public NonSwaggerInvocation(String appId, String microserviceName, String versionRule, Handler nextHandler) { + public NonSwaggerInvocation(String appId, String microserviceName) { this.appId = appId; this.microserviceName = microserviceName; - this.versionRule = versionRule; - this.nextHandler = nextHandler; } @Override public String getSchemaId() { - throw new UnsupportedOperationException(); + return "third-schema"; } @Override public String getOperationName() { - throw new UnsupportedOperationException(); + return "third-operation"; } @Override @@ -52,7 +44,7 @@ public String getInvocationQualifiedName() { @Override public String getConfigTransportName() { - return Const.RESTFUL; + return CoreConst.RESTFUL; } @Override @@ -64,14 +56,4 @@ public String getMicroserviceName() { public String getAppId() { return appId; } - - @Override - public String getMicroserviceVersionRule() { - return versionRule; - } - - @Override - public void next(AsyncResponse asyncResp) throws Exception { - nextHandler.handle(this, asyncResp); - } } diff --git a/core/src/main/java/org/apache/servicecomb/core/ProducerProvider.java b/core/src/main/java/org/apache/servicecomb/core/ProducerProvider.java index e50d1551f5b..4fbbe799b03 100644 --- a/core/src/main/java/org/apache/servicecomb/core/ProducerProvider.java +++ b/core/src/main/java/org/apache/servicecomb/core/ProducerProvider.java @@ -17,8 +17,12 @@ package org.apache.servicecomb.core; +import java.util.List; + +import org.apache.servicecomb.core.provider.producer.ProducerMeta; + public interface ProducerProvider { - void init() throws Exception; + List init(); String getName(); } diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBApplicationListener.java b/core/src/main/java/org/apache/servicecomb/core/SCBApplicationListener.java new file mode 100644 index 00000000000..3bd5bd5d8f7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/SCBApplicationListener.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core; + +import org.apache.servicecomb.config.priority.PriorityPropertyManager; +import org.apache.servicecomb.core.filter.FilterChainsManager; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; + +public class SCBApplicationListener + implements ApplicationListener, Ordered, ApplicationContextAware, EnvironmentAware { + private Class initEventClass = ContextRefreshedEvent.class; + + private ApplicationContext applicationContext; + + private final SCBEngine scbEngine; + + public SCBApplicationListener(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (this.applicationContext == applicationContext) { + // same object. avoid initialize many times. + return; + } + this.applicationContext = applicationContext; + BeanUtils.setContext(applicationContext); + HttpClients.load(); + } + + @Override + public void setEnvironment(Environment environment) { + scbEngine.init(); + } + + public void setInitEventClass(Class initEventClass) { + this.initEventClass = initEventClass; + } + + @Override + public int getOrder() { + // should run before default listener, eg: ZuulConfiguration + return -1000; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (initEventClass.isInstance(event)) { + if (applicationContext instanceof AbstractApplicationContext) { + ((AbstractApplicationContext) applicationContext).registerShutdownHook(); + } + + scbEngine.setPriorityPropertyManager(applicationContext.getBean(PriorityPropertyManager.class)); + scbEngine.setFilterChainsManager(applicationContext.getBean(FilterChainsManager.class)); + scbEngine.getProducerProviderManager().getProducerProviderList() + .addAll(applicationContext.getBeansOfType(ProducerProvider.class).values()); + + scbEngine.run(); + } else if (event instanceof ContextClosedEvent) { + if (SCBEngine.getInstance() != null) { + SCBEngine.getInstance().destroy(); + } + } + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java index 7cdb51e7b81..c69521698af 100644 --- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java +++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java @@ -16,52 +16,63 @@ */ package org.apache.servicecomb.core; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.config.ConfigUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.priority.PriorityPropertyManager; import org.apache.servicecomb.core.BootListener.BootEvent; import org.apache.servicecomb.core.BootListener.EventType; +import org.apache.servicecomb.core.bootup.BootUpInformationCollector; import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.schema.StaticSchemaFactory; -import org.apache.servicecomb.core.endpoint.AbstractEndpointsCache; +import org.apache.servicecomb.core.definition.MicroserviceVersionsMeta; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.event.InvocationStartEvent; -import org.apache.servicecomb.core.handler.HandlerConfigUtils; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.filter.FilterChainsManager; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager; import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfigManager; import org.apache.servicecomb.core.provider.producer.ProducerProviderManager; import org.apache.servicecomb.core.transport.TransportManager; import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceRegisterTask; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import com.netflix.config.DynamicPropertyFactory; -// TODO: should not depend on spring, that will make integration more flexible +import jakarta.ws.rs.core.Response.Status; + public class SCBEngine { private static final Logger LOGGER = LoggerFactory.getLogger(SCBEngine.class); - static final String CFG_KEY_WAIT_UP_TIMEOUT = "servicecomb.boot.waitUp.timeoutInMilliseconds"; + public static final String CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC = "servicecomb.boot.turnDown.waitInSeconds"; + + public static final long DEFAULT_TURN_DOWN_STATUS_WAIT_SEC = 0; + + // TODO: will remove in future. Too many codes need refactor. + private static volatile SCBEngine INSTANCE; + + private ApplicationContext applicationContext; - static final long DEFAULT_WAIT_UP_TIMEOUT = 10_000; + private FilterChainsManager filterChainsManager; private ProducerProviderManager producerProviderManager; @@ -71,9 +82,7 @@ public class SCBEngine { private TransportManager transportManager; - private SchemaListenerManager schemaListenerManager; - - private Collection bootListenerList; + private List bootListeners; private final AtomicLong invocationStartedCounter = new AtomicLong(); @@ -81,11 +90,116 @@ public class SCBEngine { private volatile SCBStatus status = SCBStatus.DOWN; - private EventBus eventBus = EventManager.getEventBus(); + private final EventBus eventBus; + + private ExecutorManager executorManager; + + private PriorityPropertyManager priorityPropertyManager; + + private List bootUpInformationCollectors; + + private final SwaggerEnvironment swaggerEnvironment = new SwaggerEnvironment(); + + private OpenAPIRegistryManager openAPIRegistryManager; + + private RegistrationManager registrationManager; + + private DiscoveryManager discoveryManager; + + private Environment environment; + + private ReferenceConfigManager referenceConfigManager; + + public SCBEngine() { + eventBus = EventManager.getEventBus(); + + eventBus.register(this); + + INSTANCE = this; + + producerProviderManager = new ProducerProviderManager(this); + } + + public static SCBEngine getInstance() { + if (INSTANCE == null) { + throw new InvocationException(Status.SERVICE_UNAVAILABLE, + new CommonExceptionData("SCBEngine is not initialized yet.")); + } + return INSTANCE; + } + + @Autowired + public void setReferenceConfigManager(ReferenceConfigManager referenceConfigManager) { + this.referenceConfigManager = referenceConfigManager; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + public Environment getEnvironment() { + return this.environment; + } + + @Autowired + @SuppressWarnings("unused") + public void setBootUpInformationCollectors(List bootUpInformationCollectors) { + this.bootUpInformationCollectors = bootUpInformationCollectors; + } - private StaticSchemaFactory staticSchemaFactory; + @Autowired + @SuppressWarnings("unused") + public void setBootListeners(List listeners) { + this.bootListeners = listeners; + } - private static final SCBEngine INSTANCE = new SCBEngine(); + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Autowired + public void setOpenAPIRegistryManager(OpenAPIRegistryManager openAPIRegistryManager) { + this.openAPIRegistryManager = openAPIRegistryManager; + } + + @Autowired + public void setConsumerProviderManager(ConsumerProviderManager consumerProviderManager) { + this.consumerProviderManager = consumerProviderManager; + } + + @Autowired + public void setExecutorManager(ExecutorManager executorManager) { + this.executorManager = executorManager; + } + + @Autowired + public void setTransportManager(TransportManager transportManager) { + this.transportManager = transportManager; + } + + public RegistrationManager getRegistrationManager() { + return this.registrationManager; + } + + public ApplicationContext getApplicationContext() { + return applicationContext; + } + + public String getAppId() { + return BootStrapProperties.readApplication(environment); + } public void setStatus(SCBStatus status) { this.status = status; @@ -95,48 +209,59 @@ public SCBStatus getStatus() { return status; } - public static SCBEngine getInstance() { - return INSTANCE; + public OpenAPIRegistryManager getOpenAPIRegistryManager() { + return this.openAPIRegistryManager; + } + + public FilterChainsManager getFilterChainsManager() { + return filterChainsManager; + } + + public SCBEngine setFilterChainsManager(FilterChainsManager filterChainsManager) { + this.filterChainsManager = filterChainsManager; + return this; + } + + public PriorityPropertyManager getPriorityPropertyManager() { + return priorityPropertyManager; + } + + public SCBEngine setPriorityPropertyManager(PriorityPropertyManager priorityPropertyManager) { + this.priorityPropertyManager = priorityPropertyManager; + return this; } public EventBus getEventBus() { return eventBus; } - public void setProducerProviderManager( - ProducerProviderManager producerProviderManager) { - this.producerProviderManager = producerProviderManager; + public ExecutorManager getExecutorManager() { + return executorManager; } - public void setConsumerProviderManager( - ConsumerProviderManager consumerProviderManager) { - this.consumerProviderManager = consumerProviderManager; + public ProducerProviderManager getProducerProviderManager() { + return producerProviderManager; } - public TransportManager getTransportManager() { - return transportManager; + public void setProducerProviderManager(ProducerProviderManager producerProviderManager) { + this.producerProviderManager = producerProviderManager; } - public void setTransportManager(TransportManager transportManager) { - this.transportManager = transportManager; + public ConsumerProviderManager getConsumerProviderManager() { + return consumerProviderManager; } - public void setSchemaListenerManager( - SchemaListenerManager schemaListenerManager) { - this.schemaListenerManager = schemaListenerManager; + public TransportManager getTransportManager() { + return transportManager; } - public Collection getBootListenerList() { - return bootListenerList; + public SwaggerEnvironment getSwaggerEnvironment() { + return swaggerEnvironment; } - public void setBootListenerList(Collection bootListenerList) { - List tmp = new ArrayList<>(); - tmp.addAll(bootListenerList); - tmp.addAll(SPIServiceUtils.getOrLoadSortedService(BootListener.class)); - tmp.sort(Comparator.comparingInt(BootListener::getOrder)); - - this.bootListenerList = tmp; + public SCBEngine addProducerMeta(String schemaId, Object instance) { + getProducerProviderManager().addProducerMeta(schemaId, instance); + return this; } protected void triggerEvent(EventType eventType) { @@ -144,7 +269,7 @@ protected void triggerEvent(EventType eventType) { event.setScbEngine(this); event.setEventType(eventType); - for (BootListener listener : bootListenerList) { + for (BootListener listener : bootListeners) { listener.onBootEvent(event); } } @@ -154,7 +279,7 @@ protected void safeTriggerEvent(EventType eventType) { event.setScbEngine(this); event.setEventType(eventType); - for (BootListener listener : bootListenerList) { + for (BootListener listener : bootListeners) { try { listener.onBootEvent(event); LOGGER.info("BootListener {} succeed to process {}.", listener.getClass().getName(), eventType); @@ -164,53 +289,33 @@ protected void safeTriggerEvent(EventType eventType) { } } - /** - *

As the process of instance registry is asynchronous, the {@code AFTER_REGISTRY} - * event should not be sent immediately after {@link RegistryUtils#run()} is invoked. - * When the instance registry succeeds, {@link MicroserviceInstanceRegisterTask} will be posted in {@link EventManager}, - * register a subscriber to watch this event and send {@code AFTER_REGISTRY}.

- * - *

This method should be called before {@link RegistryUtils#run()} to avoid that the registry process is too quick - * that the event is not watched by this subscriber.

- * - *

Check if {@code InstanceId} is null to judge whether the instance registry has succeeded.

- */ - private void triggerAfterRegistryEvent() { - EventManager.register(new Object() { - @Subscribe - public void afterRegistryInstance(MicroserviceInstanceRegisterTask microserviceInstanceRegisterTask) { - LOGGER.info("receive MicroserviceInstanceRegisterTask event, check instance Id..."); - if (!StringUtils.isEmpty(RegistryUtils.getMicroserviceInstance().getInstanceId())) { - LOGGER.info("instance registry succeeds for the first time, will send AFTER_REGISTRY event."); - status = SCBStatus.UP; - triggerEvent(EventType.AFTER_REGISTRY); - EventManager.unregister(this); - LOGGER.info("ServiceComb is ready."); - } - } - }); - } - @AllowConcurrentEvents @Subscribe + @SuppressWarnings("unused") public void onInvocationStart(InvocationStartEvent event) { invocationStartedCounter.incrementAndGet(); } @AllowConcurrentEvents @Subscribe + @SuppressWarnings("unused") public void onInvocationFinish(InvocationFinishEvent event) { invocationFinishedCounter.incrementAndGet(); } - public synchronized void init() { + public synchronized SCBEngine init() { + this.discoveryManager.init(); + this.registrationManager.init(); + return this; + } + + public synchronized SCBEngine run() { if (SCBStatus.DOWN.equals(status)) { try { - doInit(); - waitStatusUp(); - } catch (TimeoutException e) { - LOGGER.warn("{}", e.getMessage()); + doRun(); + printServiceInfo(); } catch (Throwable e) { + LOGGER.error("Failed to start ServiceComb due to errors and close", e); try { destroy(); } catch (Exception exception) { @@ -220,19 +325,35 @@ public synchronized void init() { throw new IllegalStateException("ServiceComb init failed.", e); } } + + return this; } - private void doInit() throws Exception { - status = SCBStatus.STARTING; + private void printServiceInfo() { + StringBuilder serviceInfo = new StringBuilder(); + serviceInfo.append("Service information is shown below:\n"); + for (BootUpInformationCollector bootUpInformationCollector : bootUpInformationCollectors) { + String info = bootUpInformationCollector.collect(this); + if (StringUtils.isEmpty(info)) { + continue; + } - eventBus.register(this); + serviceInfo.append(info); + if (!info.endsWith("\n")) { + serviceInfo.append('\n'); + } + } + LOGGER.info(serviceInfo.toString()); + } + + private void doRun() throws Exception { + status = SCBStatus.STARTING; - consumerProviderManager.setAppManager(RegistryUtils.getServiceRegistry().getAppManager()); - AbstractEndpointsCache.init(RegistryUtils.getInstanceCacheManager(), transportManager); + triggerEvent(EventType.BEFORE_FILTER); + filterChainsManager.init(); + triggerEvent(EventType.AFTER_FILTER); - triggerEvent(EventType.BEFORE_HANDLER); - HandlerConfigUtils.init(); - triggerEvent(EventType.AFTER_HANDLER); + createProducerMicroserviceMeta(); triggerEvent(EventType.BEFORE_PRODUCER_PROVIDER); producerProviderManager.init(); @@ -243,18 +364,26 @@ private void doInit() throws Exception { triggerEvent(EventType.AFTER_CONSUMER_PROVIDER); triggerEvent(EventType.BEFORE_TRANSPORT); - transportManager.init(); + transportManager.init(this); triggerEvent(EventType.AFTER_TRANSPORT); - schemaListenerManager.notifySchemaListener(); - triggerEvent(EventType.BEFORE_REGISTRY); + registrationManager.run(); + discoveryManager.run(); + status = SCBStatus.UP; + triggerEvent(EventType.AFTER_REGISTRY); - triggerAfterRegistryEvent(); - - RegistryUtils.run(); + // Keep this message for tests cases work. + LOGGER.warn("ServiceComb is ready."); + } - Runtime.getRuntime().addShutdownHook(new Thread(this::destroy)); + private void createProducerMicroserviceMeta() { + String microserviceName = BootStrapProperties.readServiceName(environment); + producerMicroserviceMeta = new MicroserviceMeta(this, + BootStrapProperties.readApplication(environment), microserviceName, false); + producerMicroserviceMeta.setProviderFilterChain(filterChainsManager.findProducerChain( + BootStrapProperties.readApplication(environment), microserviceName)); + producerMicroserviceMeta.setMicroserviceVersionsMeta(new MicroserviceVersionsMeta(this)); } /** @@ -271,6 +400,11 @@ public synchronized void destroy() { } private void doDestroy() { + //Step 0: turn down the status of this instance in service center, + // so that the consumers can remove this instance record in advance + turnDownInstanceStatus(); + blockShutDownOperationForConsumerRefresh(); + //Step 1: notify all component stop invoke via BEFORE_CLOSE Event safeTriggerEvent(EventType.BEFORE_CLOSE); @@ -279,8 +413,8 @@ private void doDestroy() { //Step 3: Unregister microservice instance from Service Center and close vertx // Forbidden other consumers find me - RegistryUtils.destroy(); - VertxUtils.blockCloseVertxByName("registry"); + registrationManager.destroy(); + discoveryManager.destroy(); //Step 4: wait all invocation finished try { @@ -289,20 +423,53 @@ private void doDestroy() { LOGGER.error("wait all invocation finished interrupted", e); } - //Step 5: Stop vertx to prevent blocking exit - VertxUtils.blockCloseVertxByName("config-center"); + //Step 5: destroy config source + // only be null for some test cases + if (priorityPropertyManager != null) { + priorityPropertyManager.close(); + } + + //Step 6: Stop vertx to prevent blocking exit + // delete the following one line when every refactor is done. VertxUtils.blockCloseVertxByName("transport"); - //Step 6: destroy config center source - ConfigUtil.destroyConfigCenterConfigurationSource(); + HttpClients.destroy(); //Step 7: notify all component do clean works via AFTER_CLOSE Event safeTriggerEvent(EventType.AFTER_CLOSE); } + private void turnDownInstanceStatus() { + try { + registrationManager.updateMicroserviceInstanceStatus(MicroserviceInstanceStatus.DOWN); + } catch (Throwable e) { + LOGGER.warn("turn down instance status fail: {}", e.getMessage()); + } + } + + private void blockShutDownOperationForConsumerRefresh() { + try { + long turnDownWaitSeconds = environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + if (turnDownWaitSeconds <= 0) { + return; + } + Thread.sleep(TimeUnit.SECONDS.toMillis(turnDownWaitSeconds)); + } catch (InterruptedException e) { + LOGGER.warn("failed to block the shutdown procedure", e); + } + } + private void validAllInvocationFinished() throws InterruptedException { + long start = System.currentTimeMillis(); while (true) { - if (invocationFinishedCounter.get() == invocationStartedCounter.get()) { + long remaining = invocationStartedCounter.get() - invocationFinishedCounter.get(); + if (remaining <= 0) { + return; + } + + if (System.currentTimeMillis() - start > TimeUnit.SECONDS.toMillis(30)) { + LOGGER.error("wait for all requests timeout, abandon waiting, remaining requests: {}.", remaining); return; } TimeUnit.SECONDS.sleep(1); @@ -314,21 +481,19 @@ public void ensureStatusUp() { if (!SCBStatus.UP.equals(currentStatus)) { String message = "The request is rejected. Cannot process the request due to STATUS = " + currentStatus; - LOGGER.warn(message); - throw new InvocationException(Status.SERVICE_UNAVAILABLE, message); + throw new InvocationException(Status.SERVICE_UNAVAILABLE, new CommonExceptionData(message)); } } - public ReferenceConfig createReferenceConfigForInvoke(String microserviceName, String versionRule, String transport) { - ensureStatusUp(); - - return consumerProviderManager.createReferenceConfig(microserviceName, versionRule, transport); + public CompletableFuture getOrCreateReferenceConfigAsync( + String microserviceName) { + return referenceConfigManager.getOrCreateReferenceConfigAsync(this, microserviceName); } - public ReferenceConfig getReferenceConfigForInvoke(String microserviceName) { + public MicroserviceReferenceConfig getOrCreateReferenceConfig( + String microserviceName) { ensureStatusUp(); - - return consumerProviderManager.getReferenceConfig(microserviceName); + return referenceConfigManager.getOrCreateReferenceConfig(this, microserviceName); } public MicroserviceMeta getProducerMicroserviceMeta() { @@ -339,54 +504,16 @@ public void setProducerMicroserviceMeta(MicroserviceMeta producerMicroserviceMet this.producerMicroserviceMeta = producerMicroserviceMeta; } - /** - * better to subscribe EventType.AFTER_REGISTRY by BootListener
- * but in some simple scenes, just block and wait is enough. - */ - public void waitStatusUp() throws InterruptedException, TimeoutException { - long msWait = DynamicPropertyFactory.getInstance().getLongProperty(CFG_KEY_WAIT_UP_TIMEOUT, DEFAULT_WAIT_UP_TIMEOUT) - .get(); - waitStatusUp(msWait); - } - - /** - * better to subscribe EventType.AFTER_REGISTRY by BootListener
- * but in some simple scenes, just block and wait is enough. - */ - public void waitStatusUp(long msWait) throws InterruptedException, TimeoutException { - if (msWait <= 0) { - LOGGER.info("Give up waiting for status up, wait timeout milliseconds={}.", msWait); - return; - } - LOGGER.info("Waiting for status up. timeout: {}ms", msWait); - long start = System.currentTimeMillis(); - for (; ; ) { - SCBStatus currentStatus = getStatus(); - switch (currentStatus) { - case DOWN: - case FAILED: - throw new IllegalStateException("Failed to wait status up, real status: " + currentStatus); - case UP: - LOGGER.info("Status already changed to up."); - return; - default: - break; - } + public static class CreateMicroserviceMetaEvent { + private final MicroserviceMeta microserviceMeta; - TimeUnit.MILLISECONDS.sleep(100); - if (System.currentTimeMillis() - start > msWait) { - throw new TimeoutException( - String.format("Timeout to wait status up, timeout: %dms, last status: %s", msWait, currentStatus)); - } + public CreateMicroserviceMetaEvent(MicroserviceMeta microserviceMeta) { + this.microserviceMeta = microserviceMeta; } - } - - public StaticSchemaFactory getStaticSchemaFactory() { - return staticSchemaFactory; - } - public void setStaticSchemaFactory(StaticSchemaFactory staticSchemaFactory) { - this.staticSchemaFactory = staticSchemaFactory; + public MicroserviceMeta getMicroserviceMeta() { + return this.microserviceMeta; + } } } diff --git a/core/src/main/java/org/apache/servicecomb/core/ServiceCombCoreConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/ServiceCombCoreConfiguration.java new file mode 100644 index 00000000000..8abaceef9b5 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/ServiceCombCoreConfiguration.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core; + +import org.apache.servicecomb.core.bootup.ConfigurationProblemsCollector; +import org.apache.servicecomb.core.bootup.FilterChainCollector; +import org.apache.servicecomb.core.bootup.ServiceInformationCollector; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.executor.GroupExecutor; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager; +import org.apache.servicecomb.core.provider.RegistryOpenAPIRegistry; +import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfigManager; +import org.apache.servicecomb.core.provider.producer.ProducerBootListener; +import org.apache.servicecomb.core.transport.TransportManager; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@SuppressWarnings("unused") +public class ServiceCombCoreConfiguration { + @Bean + public SCBApplicationListener scbApplicationListener(SCBEngine scbEngine) { + SCBApplicationListener scbApplicationListener = new SCBApplicationListener(scbEngine); + scbApplicationListener.setInitEventClass(ApplicationReadyEvent.class); + return scbApplicationListener; + } + + @Bean + public SCBEngine scbEngine() { + return new SCBEngine(); + } + + @Bean + public ConsumerProviderManager scbConsumerProviderManager(Environment environment, + OpenAPIRegistryManager openAPIRegistryManager) { + return new ConsumerProviderManager(environment, openAPIRegistryManager); + } + + @Bean + public ReferenceConfigManager scbReferenceConfigManager() { + return new ReferenceConfigManager(); + } + + @Bean + public OpenAPIRegistryManager scbOpenAPIRegistryManager() { + return new OpenAPIRegistryManager(); + } + + @Bean + public LocalOpenAPIRegistry scbLocalOpenAPIRegistry(Environment environment) { + return new LocalOpenAPIRegistry(environment); + } + + @Bean + public RegistryOpenAPIRegistry scbRegistryOpenAPIRegistry() { + return new RegistryOpenAPIRegistry(); + } + + @Bean + public ProducerBootListener scbProducerBootListener() { + return new ProducerBootListener(); + } + + @Bean + public FilterChainCollector scbFilterChainCollector() { + return new FilterChainCollector(); + } + + @Bean + public ConfigurationProblemsCollector scbConfigurationProblemsCollector() { + return new ConfigurationProblemsCollector(); + } + + @Bean + public ServiceInformationCollector scbServiceInformationCollector() { + return new ServiceInformationCollector(); + } + + @Bean + public ExecutorManager scbExecutorManager() { + return new ExecutorManager(); + } + + @Bean(value = {"cse.executor.groupThreadPool", "cse.executor.default", "servicecomb.executor.groupThreadPool"}) + public GroupExecutor scbGroupExecutor(Environment environment) { + GroupExecutor groupExecutor = new GroupExecutor(environment); + groupExecutor.init(); + return groupExecutor; + } + + @Bean + public TransportManager scbTransportManager() { + return new TransportManager(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/Transport.java b/core/src/main/java/org/apache/servicecomb/core/Transport.java index ed9ade43e88..1c40303fce8 100644 --- a/core/src/main/java/org/apache/servicecomb/core/Transport.java +++ b/core/src/main/java/org/apache/servicecomb/core/Transport.java @@ -17,9 +17,8 @@ package org.apache.servicecomb.core; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; +import org.springframework.core.env.Environment; -// TODO:感觉要拆成显式的client、server才好些 public interface Transport { String getName(); @@ -33,6 +32,8 @@ default boolean canInit() { boolean init() throws Exception; + void setEnvironment(Environment environment); + /* * endpoint的格式为 URI,比如rest://192.168.1.1:8080 */ @@ -47,6 +48,4 @@ default boolean canInit() { * 用于上报到服务中心,要求是其他节点可访问的地址 */ Endpoint getPublishEndpoint() throws Exception; - - void send(Invocation invocation, AsyncResponse asyncResp) throws Exception; } diff --git a/core/src/main/java/org/apache/servicecomb/core/annotation/Transport.java b/core/src/main/java/org/apache/servicecomb/core/annotation/Transport.java new file mode 100644 index 00000000000..c81055c7b46 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/annotation/Transport.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.annotation; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +@Inherited +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD, ANNOTATION_TYPE}) +@Component +public @interface Transport { + /** + * Transport name. e.g. rest, highway. + */ + String name(); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBBootstrap.java b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBBootstrap.java new file mode 100644 index 00000000000..21040a3410f --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBBootstrap.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.bootstrap; + +import java.util.Collections; +import java.util.List; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager; +import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.registry.discovery.TelnetInstancePing; +import org.springframework.core.env.Environment; + +public class SCBBootstrap { + public static SCBEngine createSCBEngineForTest(Environment environment) { + LegacyPropertyFactory.setEnvironment(environment); + RegistrationManager registrationManager = new RegistrationManager(Collections.emptyList()); + DiscoveryManager discoveryManager = new DiscoveryManager(Collections.emptyList(), + List.of(new TelnetInstancePing())); + registrationManager.init(); + discoveryManager.init(); + SCBEngine result = new SCBEngineForTest(environment); + result.setDiscoveryManager(discoveryManager); + result.setRegistrationManager(registrationManager); + result.setBootListeners(Collections.emptyList()); + result.setBootUpInformationCollectors(Collections.emptyList()); + result.setExecutorManager(new ExecutorManager()); + result.setTransportManager(new TransportManager()); + result.setEnvironment(environment); + OpenAPIRegistryManager openAPIRegistryManager = new OpenAPIRegistryManager(); + openAPIRegistryManager.setOpenAPIRegistries(List.of(new LocalOpenAPIRegistry(environment))); + result.setConsumerProviderManager(new ConsumerProviderManager(environment, openAPIRegistryManager)); + result.setOpenAPIRegistryManager(openAPIRegistryManager); + return result; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java new file mode 100644 index 00000000000..46ccd954155 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootstrap/SCBEngineForTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.bootstrap; + +import java.util.List; + +import org.apache.servicecomb.config.priority.ConfigObjectFactory; +import org.apache.servicecomb.config.priority.PriorityPropertyFactory; +import org.apache.servicecomb.config.priority.PriorityPropertyManager; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.filter.FilterChainsManager; +import org.apache.servicecomb.core.filter.impl.EmptyFilter; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.event.SimpleEventBus; +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; +import org.springframework.core.env.Environment; + +/** + * not depend on remote service registry and spring context + */ +public class SCBEngineForTest extends SCBEngine { + public SCBEngineForTest(Environment environment) { + EmptyFilter emptyFilter = new EmptyFilter(); + emptyFilter.setEnvironment(environment); + setFilterChainsManager(new FilterChainsManager() + .setProviderFilters(List.of(emptyFilter)) + .setConsumerFilters(List.of(emptyFilter)) + .setEdgeFilters(List.of(emptyFilter))); + + PriorityPropertyFactory propertyFactory = new PriorityPropertyFactory(environment); + ConfigObjectFactory configObjectFactory = new ConfigObjectFactory(propertyFactory); + setPriorityPropertyManager(new PriorityPropertyManager(configObjectFactory)); + setEnvironment(environment); + } + + @Override + public synchronized void destroy() { + super.destroy(); + + ReflectUtils.setField(SCBEngine.class, null, "INSTANCE", null); + + EventManager.eventBus = new SimpleEventBus(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootup/BootUpInformationCollector.java b/core/src/main/java/org/apache/servicecomb/core/bootup/BootUpInformationCollector.java new file mode 100644 index 00000000000..4ebae5180f4 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootup/BootUpInformationCollector.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.bootup; + +import org.apache.servicecomb.core.SCBEngine; +import org.springframework.core.Ordered; + +public interface BootUpInformationCollector extends Ordered { + default String collect(SCBEngine engine) { + return collect(); + } + + String collect(); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsAlarmEvent.java b/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsAlarmEvent.java new file mode 100644 index 00000000000..631cc361235 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsAlarmEvent.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.bootup; + +import org.apache.servicecomb.foundation.common.event.AlarmEvent; + +public class ConfigurationProblemsAlarmEvent extends AlarmEvent { + private final String problems; + + public ConfigurationProblemsAlarmEvent(Type type, String problems) { + super(type); + this.problems = problems; + } + + public String getProblems() { + return problems; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsCollector.java b/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsCollector.java new file mode 100644 index 00000000000..415516f6fea --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootup/ConfigurationProblemsCollector.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.bootup; + +import java.util.Arrays; +import java.util.Set; +import java.util.regex.Pattern; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.springframework.core.env.Environment; + +/** + * Detect deprecated and wrong usages of configurations + * and print warning messages + * and sending ConfigurationProblemsAlarmEvent. + */ +public class ConfigurationProblemsCollector implements BootUpInformationCollector { + private static final String SERVICE_NAME_PATTERN_STRING = "([A-Za-z])|([A-Za-z][A-Za-z0-9_\\-.]*[A-Za-z0-9])"; + + private static final Pattern SERVICE_NAME_PATTERN = Pattern.compile(SERVICE_NAME_PATTERN_STRING); + + @Override + public String collect(SCBEngine engine) { + StringBuilder result = new StringBuilder(); + collectCsePrefix(engine.getEnvironment(), result); + collectServiceDefinition(engine.getEnvironment(), result); + collectServiceDefinitionValidation(engine.getEnvironment(), result); + collectTimeoutConfiguration(engine.getEnvironment(), result); + collectIsolationConfiguration(engine.getEnvironment(), result); + if (result.isEmpty()) { + return null; + } + String warnings = "[WARN]Configurations warnings:\n" + result; + EventManager.post(new ConfigurationProblemsAlarmEvent(Type.OPEN, warnings)); + return warnings; + } + + private void collectServiceDefinitionValidation(Environment environment, StringBuilder result) { + String application = BootStrapProperties.readApplication(environment); + if (!SERVICE_NAME_PATTERN.matcher(application).matches()) { + result.append("application does not match pattern ").append(SERVICE_NAME_PATTERN_STRING).append("."); + } + String serviceName = BootStrapProperties.readServiceName(environment); + if (!SERVICE_NAME_PATTERN.matcher(serviceName).matches()) { + result.append("service name does not match pattern ").append(SERVICE_NAME_PATTERN_STRING).append("."); + } + } + + private void collectIsolationConfiguration(Environment environment, StringBuilder result) { + int percentage = environment.getProperty( + "servicecomb.loadbalance.isolation.errorThresholdPercentage", int.class, -1); + int continuous = environment.getProperty( + "servicecomb.loadbalance.isolation.continuousFailureThreshold", int.class, -1); + if (percentage == -1 && continuous == -1) { + return; + } + result.append("Configuration `servicecomb.loadbalance.isolation.*` is removed, use governance instead. " + + "See https://servicecomb.apache.org/references/java-chassis/" + + "zh_CN/references-handlers/governance-best-practise.html"); + } + + private void collectTimeoutConfiguration(Environment environment, StringBuilder result) { + int keepAliveTimeoutInSeconds = environment.getProperty( + "servicecomb.rest.client.connection.keepAliveTimeoutInSeconds", int.class, 60); + int idleTimeoutInSeconds = environment.getProperty( + "servicecomb.rest.client.connection.idleTimeoutInSeconds", int.class, 150); + if (keepAliveTimeoutInSeconds >= idleTimeoutInSeconds) { + result.append("Configuration `servicecomb.rest.client.connection.keepAliveTimeoutInSeconds` is longer than " + + "servicecomb.rest.client.connection.idleTimeoutInSeconds."); + result.append("[").append(keepAliveTimeoutInSeconds).append(",").append(idleTimeoutInSeconds).append("]\n"); + } + keepAliveTimeoutInSeconds = environment.getProperty( + "servicecomb.rest.client.http2.connection.keepAliveTimeoutInSeconds", int.class, 60); + idleTimeoutInSeconds = environment.getProperty( + "servicecomb.rest.client.http2.connection.idleTimeoutInSeconds", int.class, 150); + if (keepAliveTimeoutInSeconds >= idleTimeoutInSeconds) { + result.append("Configuration `servicecomb.rest.client.http2.connection.keepAliveTimeoutInSeconds` is longer than " + + "servicecomb.rest.client.http2.connection.idleTimeoutInSeconds."); + result.append("[").append(keepAliveTimeoutInSeconds).append(",").append(idleTimeoutInSeconds).append("]\n"); + } + } + + private void collectServiceDefinition(Environment environment, StringBuilder result) { + if (environment.getProperty("APPLICATION_ID") != null) { + result.append("Configurations `APPLICATION_ID` is deprecated, " + + "use `servicecomb.service.application` instead.\n"); + } + Set names = ConfigUtil.propertiesWithPrefix(environment, "service_description."); + if (!names.isEmpty()) { + result.append("Configurations with prefix `service_description` is deprecated, " + + "use `servicecomb.service` instead. Find keys "); + result.append(Arrays.toString(names.toArray())); + result.append("\n"); + } + } + + private void collectCsePrefix(Environment environment, StringBuilder result) { + Set names = ConfigUtil.propertiesWithPrefix(environment, "cse."); + if (!names.isEmpty()) { + result.append("Configurations with prefix `cse` is deprecated, use `servicecomb` instead. Find keys "); + result.append(Arrays.toString(names.toArray())); + result.append("\n"); + } + } + + @Override + public String collect() { + return null; + } + + @Override + public int getOrder() { + return 1000; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootup/FilterChainCollector.java b/core/src/main/java/org/apache/servicecomb/core/bootup/FilterChainCollector.java new file mode 100644 index 00000000000..80289d22ce3 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootup/FilterChainCollector.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.bootup; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.filter.FilterChainsManager; + +public class FilterChainCollector implements BootUpInformationCollector { + @Override + public String collect(SCBEngine engine) { + FilterChainsManager mgr = engine.getFilterChainsManager(); + return mgr.collectResolvedChains(); + } + + @Override + public String collect() { + return null; + } + + @Override + public int getOrder() { + return 300; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/bootup/ServiceInformationCollector.java b/core/src/main/java/org/apache/servicecomb/core/bootup/ServiceInformationCollector.java new file mode 100644 index 00000000000..fb13033ec99 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/bootup/ServiceInformationCollector.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.bootup; + +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.RegistrationManager; +import org.springframework.beans.factory.annotation.Autowired; + +public class ServiceInformationCollector implements BootUpInformationCollector { + private RegistrationManager registrationManager; + + private DiscoveryManager discoveryManager; + + public ServiceInformationCollector() { + } + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Override + public String collect() { + return registrationManager.info() + "\n" + discoveryManager.info(); + } + + @Override + public int getOrder() { + return 200; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/config/ConfigurationSpringInitializer.java b/core/src/main/java/org/apache/servicecomb/core/config/ConfigurationSpringInitializer.java deleted file mode 100644 index 7f792e9c893..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/config/ConfigurationSpringInitializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.config; - -import org.apache.servicecomb.foundation.common.config.PaaSPropertyPlaceholderConfigurer; - -public class ConfigurationSpringInitializer extends PaaSPropertyPlaceholderConfigurer { - - public ConfigurationSpringInitializer() { - setIgnoreUnresolvablePlaceholders(true); - setOrder(Integer.MAX_VALUE - 1); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/CommonService.java b/core/src/main/java/org/apache/servicecomb/core/definition/CommonService.java deleted file mode 100644 index 251cbda86b1..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/CommonService.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import java.util.Collection; - -import org.apache.servicecomb.foundation.common.RegisterManager; - -public class CommonService { - protected String name; - - protected RegisterManager operationMgr; - - public void createOperationMgr(String operationMgrName) { - operationMgr = new RegisterManager<>(operationMgrName); - } - - public void regOperation(String operationName, OPERATION operation) { - operationMgr.register(operationName, operation); - } - - public OPERATION findOperation(String operation) { - return operationMgr.findValue(operation); - } - - public OPERATION ensureFindOperation(String operation) { - return operationMgr.ensureFindValue(operation); - } - - public Collection getOperations() { - return operationMgr.values(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/ConsumerMicroserviceVersionsMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/ConsumerMicroserviceVersionsMeta.java new file mode 100644 index 00000000000..78f24e67f78 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/definition/ConsumerMicroserviceVersionsMeta.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.definition; + +import org.apache.servicecomb.core.SCBEngine; + +public class ConsumerMicroserviceVersionsMeta extends MicroserviceVersionsMeta { + public ConsumerMicroserviceVersionsMeta(SCBEngine scbEngine) { + super(scbEngine); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/CoreMetaUtils.java b/core/src/main/java/org/apache/servicecomb/core/definition/CoreMetaUtils.java new file mode 100644 index 00000000000..9b164223af7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/definition/CoreMetaUtils.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.definition; + +public final class CoreMetaUtils { + + public static final String SWAGGER_PRODUCER = "scb_swagger-producer"; + + private CoreMetaUtils() { + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/InvocationRuntimeType.java b/core/src/main/java/org/apache/servicecomb/core/definition/InvocationRuntimeType.java new file mode 100644 index 00000000000..356201b70d7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/definition/InvocationRuntimeType.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.definition; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.response.ResponsesMeta; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * An InvocationRuntimeType indicates the associated java type information of this invocation. + * + * For producer, java type information NOT be changed for each invocation. + * + * For Consumer, java type information depend on method signature, or not available when in edge or + * invoked by raw type way like RestTemplate or InvokerUtils. + */ +public class InvocationRuntimeType { + private Class associatedClass; + + private Method associatedMethod; + + private final ResponsesMeta responsesMeta; + + private ArgumentsMapper argumentsMapper; + + public InvocationRuntimeType(Class associatedClass, Method associatedMethod, ResponsesMeta responsesMeta, + ArgumentsMapper argumentsMapper) { + this.associatedClass = associatedClass; + this.associatedMethod = associatedMethod; + this.argumentsMapper = argumentsMapper; + this.responsesMeta = responsesMeta; + } + + public InvocationRuntimeType(ResponsesMeta responsesMeta) { + this.responsesMeta = responsesMeta; + } + + public Class getAssociatedClass() { + return this.associatedClass; + } + + public Method getAssociatedMethod() { + return this.associatedMethod; + } + + public ArgumentsMapper getArgumentsMapper() { + return this.argumentsMapper; + } + + public JavaType findResponseType(int statusCode) { + return responsesMeta.findResponseType(statusCode); + } + + public void setSuccessResponseType(JavaType javaType) { + if (javaType != null) { + // when javaType is null , using swagger type, do not override + responsesMeta.setResponseType(Status.OK.getStatusCode(), javaType); + } + } + + public void setSuccessResponseType(Type type) { + if (type != null) { + // when javaType is null , using swagger type, do not override + responsesMeta.setResponseType(Status.OK.getStatusCode(), TypeFactory.defaultInstance().constructType(type)); + } + } + + public void setAssociatedClass(Class associatedClass) { + this.associatedClass = associatedClass; + } + + public void setAssociatedMethod(Method associatedMethod) { + this.associatedMethod = associatedMethod; + } + + public void setArgumentsMapper(ArgumentsMapper argumentsMapper) { + this.argumentsMapper = argumentsMapper; + } + + public boolean isRawConsumer() { + return this.associatedClass == null; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceMeta.java index 7101094b9f2..9476a34229b 100644 --- a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceMeta.java +++ b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceMeta.java @@ -14,147 +14,146 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.servicecomb.core.definition; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.servicecomb.foundation.common.RegisterManager; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.VendorExtensions; -/** - * 微服务名为microserviceName(app内部)或者appId:microserviceName(跨app) - * operation的查询key为operation的qualifiedName - */ -public class MicroserviceMeta extends CommonService { - private String appId; +import io.swagger.v3.oas.models.OpenAPI; + +public class MicroserviceMeta { + private final SCBEngine scbEngine; + + private MicroserviceVersionsMeta microserviceVersionsMeta; + + private final String appId; - // 不包括appId的名字 - private String shortName; + private final String microserviceName; - // 如果要生成class,在这个loader中创建 - private ClassLoader classLoader; + // key is schemaId, this is all schemas + private final Map schemaMetas = new HashMap<>(); - // key为schema id - private RegisterManager idSchemaMetaMgr; + // key is OperationMeta.getMicroserviceQualifiedName() + private final Map operationMetas = new HashMap<>(); - // key为schema interface - // 只有一个interface对应一个schemaMeta时,才允许根据接口查询schema - // 否则直接抛异常,只能显式地指定schemaId来使用 - private Map, List> intfSchemaMetaMgr = new ConcurrentHashMap<>(); + // Used to indicate configuration items type. EDGE & CONSUMER chain are all consumer. + private final boolean consumer; - private final Object intfSchemaLock = new Object(); + private FilterNode consumerFilterChain = FilterNode.EMPTY; - private Map extData = new ConcurrentHashMap<>(); + private FilterNode providerFilterChain = FilterNode.EMPTY; - public MicroserviceMeta(String microserviceName) { - classLoader = JvmUtils.findClassLoader(); - parseMicroserviceName(microserviceName); - createOperationMgr("Operation meta mgr for microservice " + microserviceName); - idSchemaMetaMgr = new RegisterManager<>("Schema meta id mgr for microservice " + microserviceName); + private FilterNode edgeFilterChain = FilterNode.EMPTY; + + private final VendorExtensions vendorExtensions = new VendorExtensions(); + + public MicroserviceMeta(SCBEngine scbEngine, String application, String serviceName, boolean consumer) { + this.scbEngine = scbEngine; + this.appId = application; + this.microserviceName = serviceName; + this.consumer = consumer; } - public void regSchemaMeta(SchemaMeta schemaMeta) { - idSchemaMetaMgr.register(schemaMeta.getSchemaId(), schemaMeta); - regSchemaAndInterface(schemaMeta); + public MicroserviceVersionsMeta getMicroserviceVersionsMeta() { + return microserviceVersionsMeta; + } - for (OperationMeta operationMeta : schemaMeta.getOperations()) { - regOperation(operationMeta.getSchemaQualifiedName(), operationMeta); - } + public void setMicroserviceVersionsMeta(MicroserviceVersionsMeta microserviceVersionsMeta) { + this.microserviceVersionsMeta = microserviceVersionsMeta; } - private void regSchemaAndInterface(SchemaMeta schemaMeta) { - Class intf = schemaMeta.getSwaggerIntf(); - synchronized (intfSchemaLock) { - List schemaList = intfSchemaMetaMgr.computeIfAbsent(intf, k -> new ArrayList<>()); + public SCBEngine getScbEngine() { + return scbEngine; + } - schemaList.add(schemaMeta); - } + public boolean isConsumer() { + return consumer; } - public SchemaMeta ensureFindSchemaMeta(String schemaId) { - return idSchemaMetaMgr.ensureFindValue(schemaId); + public String getMicroserviceName() { + return microserviceName; } - public SchemaMeta findSchemaMeta(String schemaId) { - return idSchemaMetaMgr.findValue(schemaId); + public String getAppId() { + return appId; } - public SchemaMeta ensureFindSchemaMeta(Class schemaIntf) { - SchemaMeta schemaMeta = findSchemaMeta(schemaIntf); - if (schemaMeta == null) { - String msg = - String.format("No schema interface is %s.", schemaIntf.getName()); - throw new Error(msg); + public SchemaMeta registerSchemaMeta(String schemaId, OpenAPI swagger) { + SchemaMeta schemaMeta = new SchemaMeta(this, schemaId, swagger); + + if (schemaMetas.putIfAbsent(schemaMeta.getSchemaId(), schemaMeta) != null) { + throw new IllegalStateException(String.format( + "failed to register SchemaMeta caused by duplicated schemaId, appId=%s, microserviceName=%s, schemaId=%s.", + appId, microserviceName, schemaMeta.getSchemaId())); } + schemaMeta.getOperations().values() + .forEach(operationMeta -> operationMetas.put(operationMeta.getMicroserviceQualifiedName(), operationMeta)); + return schemaMeta; } - public SchemaMeta findSchemaMeta(Class schemaIntf) { - List schemaList = intfSchemaMetaMgr.get(schemaIntf); - if (schemaList == null) { - return null; - } + public Map operationMetas() { + return operationMetas; + } - if (schemaList.size() > 1) { - String msg = - String.format("More than one schema interface is %s, please use schemaId to choose a schema.", - schemaIntf.getName()); - throw new Error(msg); - } + public Collection getOperations() { + return operationMetas.values(); + } - synchronized (intfSchemaLock) { - return schemaList.get(0); + public SchemaMeta ensureFindSchemaMeta(String schemaId) { + SchemaMeta schemaMeta = schemaMetas.get(schemaId); + if (schemaMeta == null) { + throw new IllegalStateException(String.format( + "failed to find SchemaMeta by schemaId, appId=%s, microserviceName=%s, schemaId=%s.", + appId, microserviceName, schemaId)); } + + return schemaMeta; + } + + public SchemaMeta findSchemaMeta(String schemaId) { + return schemaMetas.get(schemaId); } - public Collection getSchemaMetas() { - return idSchemaMetaMgr.values(); + public Map getSchemaMetas() { + return schemaMetas; } public void putExtData(String key, Object data) { - extData.put(key, data); + vendorExtensions.put(key, data); } - @SuppressWarnings("unchecked") public T getExtData(String key) { - return (T) extData.get(key); + return vendorExtensions.get(key); } - public String getAppId() { - return appId; + public FilterNode getConsumerFilterChain() { + return consumerFilterChain; } - public String getShortName() { - return shortName; + public void setConsumerFilterChain(FilterNode consumerFilterChain) { + this.consumerFilterChain = consumerFilterChain; } - public ClassLoader getClassLoader() { - return classLoader; + public FilterNode getProviderFilterChain() { + return providerFilterChain; } - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; + public void setProviderFilterChain(FilterNode providerFilterChain) { + this.providerFilterChain = providerFilterChain; } - protected void parseMicroserviceName(String microserviceName) { - int idxAt = microserviceName.indexOf(Const.APP_SERVICE_SEPARATOR); - if (idxAt == -1) { - appId = RegistryUtils.getAppId(); - name = microserviceName; - shortName = name; - return; - } + public FilterNode getEdgeFilterChain() { + return edgeFilterChain; + } - appId = microserviceName.substring(0, idxAt); - name = microserviceName; - shortName = microserviceName.substring(idxAt + 1); + public void setEdgeFilterChain(FilterNode edgeFilterChain) { + this.edgeFilterChain = edgeFilterChain; } } diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMeta.java deleted file mode 100644 index e4e27632bc2..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMeta.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoaderFactory; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; - -public class MicroserviceVersionMeta extends MicroserviceVersion { - MicroserviceMeta microserviceMeta; - - MicroserviceVersionMeta(Microservice microservice) { - super(microservice); - } - - public MicroserviceVersionMeta(String microserviceName, String microserviceId, - MicroserviceClassLoaderFactory classLoaderFactory) { - super(microserviceId); - - this.microserviceMeta = new MicroserviceMeta(microserviceName); - this.microserviceMeta.setClassLoader( - classLoaderFactory.create(microservice.getAppId(), microserviceName, microservice.getVersion())); - if (Const.REGISTRY_APP_ID.equals(microservice.getAppId()) && Const.REGISTRY_SERVICE_NAME.equals(microserviceName)) { - // do not load service center schemas - return; - } - - CseContext.getInstance().getConsumerSchemaFactory().createConsumerSchema(microserviceMeta, microservice); - CseContext.getInstance().getSchemaListenerManager().notifySchemaListener(microserviceMeta); - } - - public MicroserviceMeta getMicroserviceMeta() { - return microserviceMeta; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMetaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMetaFactory.java deleted file mode 100644 index 85734ddb73f..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionMetaFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.definition.classloader.DefaultMicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoaderFactory; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionFactory; - -public class MicroserviceVersionMetaFactory implements MicroserviceVersionFactory { - private final MicroserviceClassLoaderFactory classLoaderFactory; - - public MicroserviceVersionMetaFactory() { - classLoaderFactory = DefaultMicroserviceClassLoaderFactory.INSTANCE; - } - - public MicroserviceVersionMetaFactory(MicroserviceClassLoaderFactory classLoaderFactory) { - this.classLoaderFactory = classLoaderFactory; - } - - @Override - public MicroserviceVersion create(String microserviceName, String microserviceId) { - return new MicroserviceVersionMeta(microserviceName, microserviceId, classLoaderFactory); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionsMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionsMeta.java new file mode 100644 index 00000000000..9e98bc2db51 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/definition/MicroserviceVersionsMeta.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.definition; + +import java.util.Map; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; + +public class MicroserviceVersionsMeta { + protected final SCBEngine scbEngine; + + // key is operationMeta.getMicroserviceQualifiedName() + private final Map configs = new ConcurrentHashMapEx<>(); + + public MicroserviceVersionsMeta(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + public OperationConfig getOrCreateOperationConfig(OperationMeta operationMeta) { + return configs.computeIfAbsent(operationMeta.getMicroserviceQualifiedName(), + name -> createOperationConfig(operationMeta)); + } + + private OperationConfig createOperationConfig(OperationMeta operationMeta) { + boolean consumer = operationMeta.getMicroserviceMeta().isConsumer(); + return scbEngine.getPriorityPropertyManager().createConfigObject( + OperationConfig.class, + "op-any-priority", consumer ? + OperationConfig.CONSUMER_OP_ANY_PRIORITY : OperationConfig.PRODUCER_OP_ANY_PRIORITY, + "consumer-op-any_priority", OperationConfig.CONSUMER_OP_ANY_PRIORITY, + "producer-op-any_priority", OperationConfig.PRODUCER_OP_ANY_PRIORITY, + + "op-priority", consumer ? + OperationConfig.CONSUMER_OP_PRIORITY : OperationConfig.PRODUCER_OP_PRIORITY, + "consumer-op-priority", OperationConfig.CONSUMER_OP_PRIORITY, + "producer-op-priority", OperationConfig.PRODUCER_OP_PRIORITY, + + "consumer-producer", consumer ? "Consumer" : "Provider", + "consumer-provider", consumer ? "Consumer" : "Provider", + + "service", operationMeta.getMicroserviceName(), + "schema", operationMeta.getSchemaId(), + "operation", operationMeta.getOperationId()); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/OperationConfig.java b/core/src/main/java/org/apache/servicecomb/core/definition/OperationConfig.java new file mode 100644 index 00000000000..bc289521a31 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/definition/OperationConfig.java @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.definition; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.config.inject.InjectProperties; +import org.apache.servicecomb.config.inject.InjectProperty; +import org.apache.servicecomb.core.CoreConst; + +@InjectProperties(prefix = "servicecomb") +public class OperationConfig { + public static final List CONSUMER_OP_ANY_PRIORITY = Arrays.asList( + "${service}.${schema}.${operation}", + "${service}.${schema}", + "${service}"); + + public static final List PRODUCER_OP_ANY_PRIORITY = Arrays.asList( + "${schema}.${operation}", + "${schema}"); + + public static final List CONSUMER_OP_PRIORITY = Arrays.asList( + ".${service}.${schema}.${operation}", + ".${service}.${schema}", + ".${service}", + ""); + + public static final List PRODUCER_OP_PRIORITY = Arrays.asList( + ".${schema}.${operation}", + ".${schema}", + ""); + + @InjectProperty(keys = {"metrics.${consumer-producer}.invocation.slow.enabled${op-priority}", + "${consumer-producer}.invocation.slow.enabled${op-priority}"}, defaultValue = "false") + private boolean slowInvocationEnabled; + + @InjectProperty(keys = {"metrics.${consumer-producer}.invocation.slow.msTime${op-priority}", + "${consumer-producer}.invocation.slow.msTime${op-priority}"}, defaultValue = "1000") + private long msSlowInvocation; + + private long nanoSlowInvocation; + + /** + * consumer request timeout + */ + @InjectProperty(keys = {"request.${op-any-priority}.timeout", "request.timeout"}, defaultValue = "30000") + private long msRequestTimeout; + + /** + * Invocation timeout. + */ + @InjectProperty(keys = {"invocation.${op-any-priority}.timeout", "invocation.timeout"}, defaultValue = "-1") + private long msInvocationTimeout; + + private long nanoInvocationTimeout; + + /** + * whether to remove certain headers from the 3rd party invocations + */ + @InjectProperty(keys = {"request.clientRequestHeaderFilterEnabled${consumer-op-priority}"}, defaultValue = "false") + private boolean clientRequestHeaderFilterEnabled = false; + + /** + * producer wait in thread pool timeout + */ + private final Map nanoRequestWaitInPoolTimeoutByTransport = new HashMap<>(); + + @InjectProperty(keys = "Provider.requestWaitInPoolTimeout${op-priority}", defaultValue = "30000") + private long msDefaultRequestWaitInPoolTimeout; + + private long nanoDefaultRequestWaitInPoolTimeout; + + @InjectProperty(keys = { + "Provider.requestWaitInPoolTimeout${op-priority}", + "highway.server.requestWaitInPoolTimeout"}, defaultValue = "30000") + private long msHighwayRequestWaitInPoolTimeout; + + private long nanoHighwayRequestWaitInPoolTimeout; + + @InjectProperty(keys = { + "Provider.requestWaitInPoolTimeout${op-priority}", + "rest.server.requestWaitInPoolTimeout"}, defaultValue = "30000") + private long msRestRequestWaitInPoolTimeout; + + private long nanoRestRequestWaitInPoolTimeout; + + @InjectProperty(keys = { + "operation${op-priority}.transport", // Deprecated + "references.transport${op-priority}" + }) + private String transport; + + @InjectProperty(keys = {"governance.${op-any-priority}.matchType", "governance.matchType"}, defaultValue = "rest") + private String governanceMatchType; + + public boolean isSlowInvocationEnabled() { + return slowInvocationEnabled; + } + + public void setSlowInvocationEnabled(boolean slowInvocationEnabled) { + this.slowInvocationEnabled = slowInvocationEnabled; + } + + public long getMsSlowInvocation() { + return msSlowInvocation; + } + + public void setMsSlowInvocation(long msSlowInvocation) { + this.msSlowInvocation = msSlowInvocation; + this.nanoSlowInvocation = TimeUnit.MILLISECONDS.toNanos(msSlowInvocation); + } + + public long getNanoSlowInvocation() { + return nanoSlowInvocation; + } + + public long getMsRequestTimeout() { + return msRequestTimeout; + } + + public void setMsRequestTimeout(long msRequestTimeout) { + this.msRequestTimeout = msRequestTimeout; + } + + public long getNanoRequestWaitInPoolTimeout(String transport) { + return nanoRequestWaitInPoolTimeoutByTransport.getOrDefault(transport, nanoDefaultRequestWaitInPoolTimeout); + } + + public void registerRequestWaitInPoolTimeout(String transport, long msTimeout) { + nanoRequestWaitInPoolTimeoutByTransport.put(transport, TimeUnit.MILLISECONDS.toNanos(msTimeout)); + } + + public long getMsDefaultRequestWaitInPoolTimeout() { + return msDefaultRequestWaitInPoolTimeout; + } + + public void setMsDefaultRequestWaitInPoolTimeout(long msDefaultRequestWaitInPoolTimeout) { + this.msDefaultRequestWaitInPoolTimeout = msDefaultRequestWaitInPoolTimeout; + this.nanoDefaultRequestWaitInPoolTimeout = TimeUnit.MILLISECONDS.toNanos(msDefaultRequestWaitInPoolTimeout); + } + + public long getNanoDefaultRequestWaitInPoolTimeout() { + return nanoDefaultRequestWaitInPoolTimeout; + } + + public long getMsHighwayRequestWaitInPoolTimeout() { + return msHighwayRequestWaitInPoolTimeout; + } + + public void setMsHighwayRequestWaitInPoolTimeout(long msHighwayRequestWaitInPoolTimeout) { + this.msHighwayRequestWaitInPoolTimeout = msHighwayRequestWaitInPoolTimeout; + this.nanoHighwayRequestWaitInPoolTimeout = TimeUnit.MILLISECONDS.toNanos(msHighwayRequestWaitInPoolTimeout); + registerRequestWaitInPoolTimeout(CoreConst.HIGHWAY, msHighwayRequestWaitInPoolTimeout); + } + + public long getNanoHighwayRequestWaitInPoolTimeout() { + return nanoHighwayRequestWaitInPoolTimeout; + } + + public long getMsRestRequestWaitInPoolTimeout() { + return msRestRequestWaitInPoolTimeout; + } + + public void setMsRestRequestWaitInPoolTimeout(long msRestRequestWaitInPoolTimeout) { + this.msRestRequestWaitInPoolTimeout = msRestRequestWaitInPoolTimeout; + this.nanoRestRequestWaitInPoolTimeout = TimeUnit.MILLISECONDS.toNanos(msRestRequestWaitInPoolTimeout); + registerRequestWaitInPoolTimeout(CoreConst.RESTFUL, msRestRequestWaitInPoolTimeout); + } + + public long getNanoRestRequestWaitInPoolTimeout() { + return nanoRestRequestWaitInPoolTimeout; + } + + public long getMsInvocationTimeout() { + return msInvocationTimeout; + } + + public void setMsInvocationTimeout(long msInvocationTimeout) { + this.msInvocationTimeout = msInvocationTimeout; + this.nanoInvocationTimeout = TimeUnit.MILLISECONDS.toNanos(msInvocationTimeout); + } + + public String getGovernanceMatchType() { + return governanceMatchType; + } + + public void setGovernanceMatchType(String governanceMatchType) { + this.governanceMatchType = governanceMatchType; + } + + public long getNanoInvocationTimeout() { + return this.nanoInvocationTimeout; + } + + public boolean isClientRequestHeaderFilterEnabled() { + return clientRequestHeaderFilterEnabled; + } + + public void setClientRequestHeaderFilterEnabled(boolean clientRequestHeaderFilterEnabled) { + this.clientRequestHeaderFilterEnabled = clientRequestHeaderFilterEnabled; + } + + public String getTransport() { + return transport; + } + + public void setTransport(String transport) { + if (transport == null) { + transport = CoreConst.ANY_TRANSPORT; + } + this.transport = transport; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/OperationMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/OperationMeta.java index cf908256df4..003daaffab1 100644 --- a/core/src/main/java/org/apache/servicecomb/core/definition/OperationMeta.java +++ b/core/src/main/java/org/apache/servicecomb/core/definition/OperationMeta.java @@ -14,93 +14,71 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.servicecomb.core.definition; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.executor.ExecutorManager; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.foundation.common.VendorExtensions; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; import org.apache.servicecomb.swagger.invocation.response.ResponsesMeta; -import com.netflix.config.DynamicPropertyFactory; +import io.swagger.v3.oas.models.Operation; -import io.swagger.models.Operation; public class OperationMeta { private SchemaMeta schemaMeta; - // schemaId:operation + // schemaId.operation private String schemaQualifiedName; - // microserviceName:schemaId:operation + // microserviceName.schemaId.operation private String microserviceQualifiedName; - // 契约对应的method,与consumer、producer的method没有必然关系 - private Method method; - private String httpMethod; private String operationPath; private Operation swaggerOperation; - // 在哪个executor上执行 + // run in this executor private Executor executor; - private ResponsesMeta responsesMeta = new ResponsesMeta(); - - // transport、provider、consumer端都可能需要扩展数据 - // 为避免每个地方都做复杂的层次管理,直接在这里保存扩展数据 - private Map extData = new ConcurrentHashMap<>(); - - // providerQpsFlowControlHandler is a temporary filed, only for internal usage - private Handler providerQpsFlowControlHandler; - - // providerQpsFlowControlHandlerSearched is a temporary filed, only for internal usage - private boolean providerQpsFlowControlHandlerSearched; + private final ResponsesMeta responsesMeta = new ResponsesMeta(); - private String transport = null; + private final VendorExtensions vendorExtensions = new VendorExtensions(); - public void init(SchemaMeta schemaMeta, Method method, String operationPath, String httpMethod, - Operation swaggerOperation) { + public OperationMeta init(SchemaMeta schemaMeta, SwaggerOperation swaggerOperation) { this.schemaMeta = schemaMeta; - schemaQualifiedName = schemaMeta.getSchemaId() + "." + method.getName(); - microserviceQualifiedName = schemaMeta.getMicroserviceName() + "." + schemaQualifiedName; - this.operationPath = operationPath; - this.method = method; - this.httpMethod = httpMethod.toUpperCase(Locale.US); - this.swaggerOperation = swaggerOperation; + this.schemaQualifiedName = schemaMeta.getSchemaId() + "." + swaggerOperation.getOperationId(); + this.microserviceQualifiedName = + schemaMeta.getMicroserviceQualifiedName() + "." + swaggerOperation.getOperationId(); + this.httpMethod = swaggerOperation.getHttpMethod().name(); + this.operationPath = swaggerOperation.getPath(); + this.swaggerOperation = swaggerOperation.getOperation(); + this.executor = schemaMeta.getMicroserviceMeta().getScbEngine().getExecutorManager().findExecutor(this); + this.responsesMeta.init(schemaMeta.getSwagger(), swaggerOperation.getOperation()); - executor = ExecutorManager.findExecutor(this); + return this; + } - responsesMeta.init(schemaMeta.getSwaggerToClassGenerator(), - swaggerOperation, - method.getGenericReturnType()); + public void setSwaggerProducerOperation(SwaggerProducerOperation swaggerProducerOperation) { + this.putExtData(CoreConst.PRODUCER_OPERATION, swaggerProducerOperation); + } - transport = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.operation." - + microserviceQualifiedName + ".transport", null).get(); + public SwaggerProducerOperation getSwaggerProducerOperation() { + return (SwaggerProducerOperation) this.getExtData(CoreConst.PRODUCER_OPERATION); } - public String getTransport() { - return transport; + public OperationConfig getConfig() { + return schemaMeta.getMicroserviceMeta().getMicroserviceVersionsMeta().getOrCreateOperationConfig(this); } public String getHttpMethod() { return httpMethod; } - public void setHttpMethod(String httpMethod) { - this.httpMethod = httpMethod; - } - public String getOperationPath() { return operationPath; } @@ -109,8 +87,27 @@ public Operation getSwaggerOperation() { return swaggerOperation; } - public ResponseMeta findResponseMeta(int statusCode) { - return responsesMeta.findResponseMeta(statusCode); + public ResponsesMeta getResponsesMeta() { + // TODO : this method now called by highway, and highway always use swagger type + // in the future improvement , highway can use runtime type and this method can be removed + return responsesMeta; + } + + public int parameterCount() { + int result = 0; + if (swaggerOperation.getRequestBody() != null) { + result++; + } + if (swaggerOperation.getParameters() != null) { + result += swaggerOperation.getParameters().size(); + } + return result; + } + + private ResponsesMeta cloneResponseMeta() { + ResponsesMeta result = new ResponsesMeta(); + this.responsesMeta.cloneTo(result); + return result; } public MicroserviceMeta getMicroserviceMeta() { @@ -133,26 +130,29 @@ public String getMicroserviceName() { return schemaMeta.getMicroserviceName(); } - public Method getMethod() { - return method; + public String getSchemaId() { + return schemaMeta.getSchemaId(); } public String getOperationId() { return swaggerOperation.getOperationId(); } - // 调用者保证参数正确性 + // invoker make sure idx is valid public String getParamName(int idx) { return swaggerOperation.getParameters().get(idx).getName(); } public void putExtData(String key, Object data) { - extData.put(key, data); + vendorExtensions.put(key, data); } - @SuppressWarnings("unchecked") public T getExtData(String key) { - return (T) extData.get(key); + return vendorExtensions.get(key); + } + + public VendorExtensions getVendorExtensions() { + return vendorExtensions; } public Executor getExecutor() { @@ -163,28 +163,14 @@ public void setExecutor(Executor executor) { this.executor = executor; } - public int getParamSize() { - return swaggerOperation.getParameters().size(); + public InvocationRuntimeType buildBaseProviderRuntimeType() { + SwaggerProducerOperation swaggerProducerOperation = this.getSwaggerProducerOperation(); + return new InvocationRuntimeType(swaggerProducerOperation.getProducerClass(), + swaggerProducerOperation.getProducerMethod(), this.cloneResponseMeta(), + swaggerProducerOperation.getArgumentsMapper()); } - /** - * Only for JavaChassis internal usage. - */ - @Deprecated - public Handler getProviderQpsFlowControlHandler() { - if (providerQpsFlowControlHandlerSearched) { - return providerQpsFlowControlHandler; - } - - final List providerHandlerChain = getSchemaMeta().getProviderHandlerChain(); - for (Handler handler : providerHandlerChain) { - // matching by class name is more or less better than importing an extra maven dependency - if ("org.apache.servicecomb.qps.ProviderQpsFlowControlHandler".equals(handler.getClass().getName())) { - providerQpsFlowControlHandler = handler; - break; - } - } - providerQpsFlowControlHandlerSearched = true; - return providerQpsFlowControlHandler; + public InvocationRuntimeType buildBaseConsumerRuntimeType() { + return new InvocationRuntimeType(this.cloneResponseMeta()); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/PrivateMicroserviceVersionMetaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/PrivateMicroserviceVersionMetaFactory.java deleted file mode 100644 index 63ebc5833e4..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/PrivateMicroserviceVersionMetaFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.definition.classloader.PrivateMicroserviceClassLoaderFactory; - -public class PrivateMicroserviceVersionMetaFactory extends MicroserviceVersionMetaFactory { - public PrivateMicroserviceVersionMetaFactory() { - super(PrivateMicroserviceClassLoaderFactory.INSTANCE); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/SchemaMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/SchemaMeta.java index 84143f0f2a9..623ec695b0c 100644 --- a/core/src/main/java/org/apache/servicecomb/core/definition/SchemaMeta.java +++ b/core/src/main/java/org/apache/servicecomb/core/definition/SchemaMeta.java @@ -14,161 +14,105 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.servicecomb.core.definition; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map.Entry; +import java.util.HashMap; +import java.util.Map; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.exception.ExceptionUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import org.apache.servicecomb.foundation.common.VendorExtensions; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; +import io.swagger.v3.oas.models.OpenAPI; -public class SchemaMeta extends CommonService { +public class SchemaMeta { private static final Logger LOGGER = LoggerFactory.getLogger(SchemaMeta.class); - // 如果要生成class,使用这个package - private String packageName; - - private Swagger swagger; + private final MicroserviceMeta microserviceMeta; - private MicroserviceMeta microserviceMeta; + private final OpenAPI swagger; - // microserviceName:schemaId - private String microserviceQualifiedName; + private final String schemaId; - // 契约对应的接口 - private Class swaggerIntf; + // microserviceName.schemaId + private final String microserviceQualifiedName; - // handlerChain是microservice级别的 - private List consumerHandlerChain; + private final Map operations = new HashMap<>(); - private List providerHandlerChain; + private final VendorExtensions vendorExtensions = new VendorExtensions(); - private SwaggerToClassGenerator swaggerToClassGenerator; + public SchemaMeta(MicroserviceMeta microserviceMeta, String schemaId, OpenAPI swagger) { + this.microserviceMeta = microserviceMeta; + this.schemaId = schemaId; + this.swagger = swagger; + this.microserviceQualifiedName = microserviceMeta.getMicroserviceName() + "." + schemaId; - public SchemaMeta(Swagger swagger, MicroserviceMeta microserviceMeta, String schemaId) { try { - this.packageName = SchemaUtils.generatePackageName(microserviceMeta, schemaId); - - this.swagger = swagger; - this.name = schemaId; - - this.microserviceMeta = microserviceMeta; - this.microserviceQualifiedName = microserviceMeta.getName() + "." + schemaId; - - swaggerToClassGenerator = new SwaggerToClassGenerator(microserviceMeta.getClassLoader(), swagger, packageName); - swaggerIntf = swaggerToClassGenerator.convert(); - - createOperationMgr("schemaMeta " + schemaId + " operation mgr"); - operationMgr.setRegisterErrorFmt("Operation name repeat, schema=%s, operation=%s"); - - initOperations(); + initOperationMetas(); } catch (Throwable e) { - LOGGER.error("Unhandled exception to service " + microserviceMeta.getName() + " schema " + schemaId); + LOGGER.error("Unhandled exception to {}.", microserviceQualifiedName, e); throw e; } } - public SwaggerToClassGenerator getSwaggerToClassGenerator() { - return swaggerToClassGenerator; + private SchemaMeta initOperationMetas() { + SwaggerOperations swaggerOperations = new SwaggerOperations(swagger); + for (SwaggerOperation swaggerOperation : swaggerOperations.getOperations().values()) { + operations.put(swaggerOperation.getOperationId(), new OperationMeta().init(this, swaggerOperation)); + } + return this; } - public String getPackageName() { - return packageName; + public MicroserviceMeta getMicroserviceMeta() { + return microserviceMeta; } - private void initOperations() { - if (swagger.getPaths() == null) { - LOGGER.warn(swagger.getInfo().getTitle() + " with path " + swagger.getBasePath() - + " is an empty interface, please delete it or fill with one method!"); - return; - } + public OpenAPI getSwagger() { + return swagger; + } - for (Entry entry : swagger.getPaths().entrySet()) { - String strPath = entry.getKey(); - Path path = entry.getValue(); - for (Entry operationEntry : path.getOperationMap().entrySet()) { - Operation operation = operationEntry.getValue(); - if (operation.getOperationId() == null) { - throw ExceptionUtils.operationIdInvalid(getSchemaId(), strPath); - } - - // org.apache.servicecomb.swagger.engine.SwaggerEnvironment.createConsumer(Class, Class) - // org.apache.servicecomb.swagger.engine.SwaggerEnvironment.createProducer(Object, Swagger) - // had make sure that consumer/swagger or producer/swagger can work - // - // in this place, do not throw exception when method not exists - // eg: - // swagger interface is a.b.c, and consumer interface is a.b.c too. - // version 1, they are the same - // version 2, producer add a new operation, that means swagger have more operation than consumer interface a.b.c - // interface a.b.c in consumer process is the old interface - // so for swagger, can not do any valid check here - // only need to save found method, that's enough. - Method method = ReflectUtils.findMethod(swaggerIntf, operation.getOperationId()); - if (method == null) { - LOGGER.warn("method {} not found in swagger interface {}, schemaId={}", - operation.getOperationId(), - swaggerIntf.getName(), - getSchemaId()); - continue; - } - - String httpMethod = operationEntry.getKey().name(); - OperationMeta operationMeta = new OperationMeta(); - operationMeta.init(this, method, strPath, httpMethod, operation); - operationMgr.register(method.getName(), operationMeta); - } - } + public String getAppId() { + return microserviceMeta.getAppId(); } - public Swagger getSwagger() { - return swagger; + public String getMicroserviceName() { + return microserviceMeta.getMicroserviceName(); } public String getSchemaId() { - return name; + return schemaId; } public String getMicroserviceQualifiedName() { return microserviceQualifiedName; } - public String getMicroserviceName() { - return microserviceMeta.getName(); + public Map getOperations() { + return operations; } - public MicroserviceMeta getMicroserviceMeta() { - return microserviceMeta; - } - - public Class getSwaggerIntf() { - return swaggerIntf; + public void putExtData(String key, Object data) { + vendorExtensions.put(key, data); } - public List getConsumerHandlerChain() { - return consumerHandlerChain; + public T getExtData(String key) { + return vendorExtensions.get(key); } - public void setConsumerHandlerChain(List consumerHandlerChain) { - this.consumerHandlerChain = consumerHandlerChain; + public OperationMeta findOperation(String operationId) { + return operations.get(operationId); } - public List getProviderHandlerChain() { - return providerHandlerChain; - } + public OperationMeta ensureFindOperation(String operationId) { + OperationMeta value = operations.get(operationId); + if (value == null) { + throw new IllegalStateException(String + .format("Can not find OperationMeta, microserviceName=%s, schemaId=%s, operationId=%s.", + getMicroserviceName(), getSchemaId(), operationId)); + } - public void setProviderHandlerChain(List providerHandlerChain) { - this.providerHandlerChain = providerHandlerChain; + return value; } } diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/SchemaUtils.java b/core/src/main/java/org/apache/servicecomb/core/definition/SchemaUtils.java deleted file mode 100644 index 3346a240e5e..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/SchemaUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import java.net.URL; - -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; - -import io.swagger.models.Swagger; - -public final class SchemaUtils { - - private SchemaUtils() { - } - - public static String generatePackageName(MicroserviceMeta microserviceMeta, String schemaId) { - String name = "cse.gen." + microserviceMeta.getAppId() + "." + microserviceMeta.getShortName() + "." - + schemaId; - - return ClassUtils.correctClassName(name); - } - - public static String swaggerToString(Swagger swagger) { - return SwaggerUtils.swaggerToString(swagger); - } - - public static Swagger parseSwagger(URL url) { - return SwaggerUtils.parseSwagger(url); - } - - public static Swagger parseSwagger(String swaggerContent) { - Swagger swagger = SwaggerUtils.parseSwagger(swaggerContent); - SwaggerUtils.validateSwagger(swagger); - return swagger; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMeta.java b/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMeta.java deleted file mode 100644 index 0fd866bc076..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMeta.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoaderFactory; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; - -public class StaticMicroserviceVersionMeta extends MicroserviceVersionMeta { - - public StaticMicroserviceVersionMeta(StaticMicroservice microservice, - MicroserviceClassLoaderFactory classLoaderFactory) { - super(microservice); - - this.microserviceMeta = new MicroserviceMeta(microservice.getServiceName()); - this.microserviceMeta.setClassLoader( - classLoaderFactory.create(microservice.getAppId(), microservice.getServiceName(), microservice.getVersion())); - if (Const.REGISTRY_APP_ID.equals(microservice.getAppId()) - && Const.REGISTRY_SERVICE_NAME.equals(microservice.getServiceName())) { - // do not load service center schemas - return; - } - - SCBEngine.getInstance().getStaticSchemaFactory().loadSchema(microserviceMeta, microservice); - CseContext.getInstance().getSchemaListenerManager().notifySchemaListener(microserviceMeta); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaFactory.java deleted file mode 100644 index e10dc9b2e2d..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.classloader.PrivateMicroserviceClassLoaderFactory; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersionFactory; - -public class StaticMicroserviceVersionMetaFactory implements StaticMicroserviceVersionFactory { - private final MicroserviceClassLoaderFactory classLoaderFactory = PrivateMicroserviceClassLoaderFactory.INSTANCE; - - @Override - public MicroserviceVersion create(StaticMicroservice microservice) { - return new StaticMicroserviceVersionMeta(microservice, classLoaderFactory); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/DefaultMicroserviceClassLoaderFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/classloader/DefaultMicroserviceClassLoaderFactory.java deleted file mode 100644 index 6e0222dede5..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/DefaultMicroserviceClassLoaderFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -import org.apache.servicecomb.foundation.common.utils.JvmUtils; - -public class DefaultMicroserviceClassLoaderFactory implements MicroserviceClassLoaderFactory { - public static final MicroserviceClassLoaderFactory INSTANCE = new DefaultMicroserviceClassLoaderFactory(); - - @Override - public ClassLoader create(String appId, String microserviceName, String version) { - return JvmUtils.findClassLoader(); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoader.java b/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoader.java deleted file mode 100644 index 2473aaa8c14..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoader.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MicroserviceClassLoader extends ClassLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceClassLoader.class); - - private final String appId; - - private final String microserviceName; - - private final String version; - - - public MicroserviceClassLoader(String appId, String microserviceName, String version) { - super(JvmUtils.findClassLoader()); - - this.appId = appId; - this.microserviceName = microserviceName; - this.version = version; - - LOGGER.info("create classloader for microservice {}:{}:{}.", appId, microserviceName, version); - } - - public String getAppId() { - return appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public String getVersion() { - return version; - } - - @Override - public String toString() { - return String.format("MicroserviceClassLoader %s:%s:%s", appId, microserviceName, version); - } - - @Override - protected void finalize() throws Throwable { - LOGGER.info("gc: classloader of microservice {}:{}.", microserviceName, version); - - super.finalize(); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoaderFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoaderFactory.java deleted file mode 100644 index 5ac81d76410..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/MicroserviceClassLoaderFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -public interface MicroserviceClassLoaderFactory { - ClassLoader create(String appId, String microserviceName, String version); -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/PrivateMicroserviceClassLoaderFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/classloader/PrivateMicroserviceClassLoaderFactory.java deleted file mode 100644 index 34ca7d58a21..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/classloader/PrivateMicroserviceClassLoaderFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -public class PrivateMicroserviceClassLoaderFactory implements MicroserviceClassLoaderFactory { - - public static final MicroserviceClassLoaderFactory INSTANCE = new PrivateMicroserviceClassLoaderFactory(); - - private PrivateMicroserviceClassLoaderFactory() { - } - - @Override - public ClassLoader create(String appId, String microserviceName, String version) { - return new MicroserviceClassLoader(appId, microserviceName, version); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/loader/DynamicSchemaLoader.java b/core/src/main/java/org/apache/servicecomb/core/definition/loader/DynamicSchemaLoader.java deleted file mode 100644 index 2e782edac35..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/loader/DynamicSchemaLoader.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.loader; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.common.config.PaaSResourceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; - -/* - * 场景: - * 1.consumer - * 网管调用产品 - * 网管事先不知道产品对应的微服务名 - * 产品注册到网管后,网管根据注册信息,进行契约注册 - * 2.producer - * 需要支持在不同的产品中部署为不同的微服务名 - * 微服务名是由环境变量等等方式注入的 - * 此时可以在BootListener中进行注册(必须在producer初始化之前注册契约) - * - * @Deprecated This class is deprecated because when making calls to a provider, schemas will be downloaded from service enter. - * And at provider, schemas will register to service center when starting up. - */ -@Deprecated -public class DynamicSchemaLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(DynamicSchemaLoader.class); - - public static final DynamicSchemaLoader INSTANCE = new DynamicSchemaLoader(); - - private DynamicSchemaLoader() { - } - - /** - * 动态注册指定目录下的schema契约到当前服务 - * @param schemaLocation eg. "classpath*:schemas/*.yaml" - */ - public void registerSchemas(String schemaLocation) { - registerSchemas(RegistryUtils.getMicroservice().getServiceName(), schemaLocation); - } - - /** - * 动态注册指定目录下的schema契约到指定服务 - * @param microserviceName name of microservice - * @param schemaLocation eg. "classpath*:schemas/*.yaml" - */ - public void registerSchemas(String microserviceName, String schemaLocation) { - LOGGER.info("dynamic register schemas for {} in {}", microserviceName, schemaLocation); - - List schemaMetaList = new ArrayList<>(); - Resource[] resArr = PaaSResourceUtils.getResources(schemaLocation); - for (Resource resource : resArr) { - SchemaMeta schemaMeta = - CseContext.getInstance().getSchemaLoader().registerSchema(microserviceName, resource); - - schemaMetaList.add(schemaMeta); - } - - CseContext.getInstance().getSchemaListenerManager().notifySchemaListener(schemaMetaList); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListener.java b/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListener.java deleted file mode 100644 index 9166ee4d412..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListener.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.loader; - -import org.apache.servicecomb.core.definition.SchemaMeta; - -public interface SchemaListener { - // 不必考虑多线程并发 - void onSchemaLoaded(SchemaMeta... schemaMetas); -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListenerManager.java b/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListenerManager.java deleted file mode 100644 index e58c0f4baef..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaListenerManager.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.loader; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * key为microserviceName - */ -@Component -public class SchemaListenerManager { - - @Autowired(required = false) - private List schemaListenerList = new ArrayList<>(); - - public void setSchemaListenerList(List schemaListenerList) { - this.schemaListenerList = schemaListenerList; - } - - public void notifySchemaListener(MicroserviceMeta... microserviceMetas) { - List schemaMetaList = new ArrayList<>(); - for (MicroserviceMeta microserviceMeta : microserviceMetas) { - schemaMetaList.addAll(microserviceMeta.getSchemaMetas()); - } - notifySchemaListener(schemaMetaList.toArray(new SchemaMeta[schemaMetaList.size()])); - } - - public void notifySchemaListener() { - //only one instance - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - notifySchemaListener(microserviceMeta); - } - - public void notifySchemaListener(SchemaMeta... schemaMetas) { - for (SchemaListener listener : schemaListenerList) { - listener.onSchemaLoaded(schemaMetas); - } - } - - public void notifySchemaListener(List schemaMetaList) { - SchemaMeta[] schemaMetas = schemaMetaList.toArray(new SchemaMeta[schemaMetaList.size()]); - notifySchemaListener(schemaMetas); - } - - public SchemaMeta ensureFindSchemaMeta(String schemaId) { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - return microserviceMeta.ensureFindSchemaMeta(schemaId); - } - - public Collection getAllSchemaMeta() { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - return microserviceMeta.getSchemaMetas(); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaLoader.java b/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaLoader.java deleted file mode 100644 index 95f9cd5392b..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/loader/SchemaLoader.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.loader; - -import java.util.List; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.SchemaUtils; -import org.apache.servicecomb.core.handler.ConsumerHandlerManager; -import org.apache.servicecomb.core.handler.ProducerHandlerManager; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.BasePath; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicPropertyFactory; - -import io.swagger.models.Swagger; - -@Component -public class SchemaLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(SchemaLoader.class); - - /* - * resource的路径格式,至少是以这个形式结尾:schemaId.yaml - */ - public SchemaMeta registerSchema(String microserviceName, Resource resource) { - try { - String schemaId = FilenameUtils.getBaseName(resource.getFilename()); - - String swaggerContent = IOUtils.toString(resource.getURL()); - SchemaMeta schemaMeta = registerSchema(microserviceName, schemaId, swaggerContent); - - return schemaMeta; - } catch (Throwable e) { - throw new Error(e); - } - } - - public SchemaMeta registerSchema(String microserviceName, String schemaId, String swaggerContent) { - Swagger swagger = SchemaUtils.parseSwagger(swaggerContent); - if (swagger == null) { - throw new Error(String.format("Parse the swagger for %s:%s failed", microserviceName, schemaId)); - } - - return registerSchema(schemaId, swagger); - } - - public SchemaMeta registerSchema(String schemaId, - Swagger swagger) { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - return registerSchema(microserviceMeta, schemaId, swagger); - } - - public SchemaMeta registerSchema(MicroserviceMeta microserviceMeta, String schemaId, - Swagger swagger) { - String microserviceName = microserviceMeta.getName(); - LOGGER.info("register schema {}/{}/{}", microserviceMeta.getAppId(), microserviceName, schemaId); - - SchemaMeta schemaMeta = new SchemaMeta(swagger, microserviceMeta, schemaId); - - List producerHandlerChain = ProducerHandlerManager.INSTANCE.getOrCreate(microserviceName); - schemaMeta.setProviderHandlerChain(producerHandlerChain); - - List consumerHandlerChain = ConsumerHandlerManager.INSTANCE.getOrCreate(microserviceName); - schemaMeta.setConsumerHandlerChain(consumerHandlerChain); - - microserviceMeta.regSchemaMeta(schemaMeta); - - addSchemaPath2Microservice(microserviceName, swagger.getBasePath()); - - return schemaMeta; - } - - void addSchemaPath2Microservice(String microserviceName, String basePath) { - if (DynamicPropertyFactory.getInstance().getBooleanProperty(Const.REGISTER_SERVICE_PATH, false).get()) { - putSelfBasePathIfAbsent(microserviceName, basePath); - } - } - - void putSelfBasePathIfAbsent(String microserviceName, String basePath) { - if (basePath == null || basePath.length() == 0) { - return; - } - - Microservice microservice = RegistryUtils.getMicroservice(); - if (!microservice.getServiceName().equals(microserviceName)) { - return; - } - - String urlPrefix = System.getProperty(Const.URL_PREFIX); - if (!StringUtils.isEmpty(urlPrefix) && !basePath.startsWith(urlPrefix)) { - basePath = urlPrefix + basePath; - } - - List paths = microservice.getPaths(); - for (BasePath path : paths) { - if (path.getPath().equals(basePath)) { - return; - } - } - - BasePath basePathObj = new BasePath(); - basePathObj.setPath(basePath); - paths.add(basePathObj); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/AbstractSchemaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/AbstractSchemaFactory.java deleted file mode 100644 index 0db01dc8143..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/AbstractSchemaFactory.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import java.net.URL; - -import javax.inject.Inject; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.SchemaUtils; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; - -import io.swagger.models.Swagger; - -/** - * 由consumer或producer发起的契约注册 - * 在consumer场景中,如果本地没有契约,需要从服务中心下载契约 - * 在producer场景中,如果本地没有契约,需要根据实现类动态生成契约 - */ -public abstract class AbstractSchemaFactory { - - protected SchemaLoader schemaLoader; - - @Inject - protected CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext; - - @Inject - public void setSchemaLoader(SchemaLoader schemaLoader) { - this.schemaLoader = schemaLoader; - } - - // 因为aop的存在,schemaInstance的class不一定等于schemaClass - protected SchemaMeta getOrCreateSchema(CONTEXT context) { - MicroserviceMeta microserviceMeta = context.getMicroserviceMeta(); - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(context.getSchemaId()); - if (schemaMeta == null) { - schemaMeta = createSchema(context); - } - context.setSchemaMeta(schemaMeta); - - return schemaMeta; - } - - protected abstract SchemaMeta createSchema(CONTEXT context); - - protected Swagger loadSwagger(CONTEXT context) { - return loadSwagger(context.getMicroserviceName(), context.getSchemaId()); - } - - protected Swagger loadSwagger(String microserviceName, String schemaId) { - String path = generateSchemaPath(microserviceName, schemaId); - URL url = JvmUtils.findClassLoader().getResource(path); - if (url == null) { - return null; - } - - return SchemaUtils.parseSwagger(url); - } - - protected String generateSchemaPath(String microserviceName, String schemaId) { - int idxAt = microserviceName.indexOf(Const.APP_SERVICE_SEPARATOR); - if (idxAt < 0) { - return String.format("microservices/%s/%s.yaml", microserviceName, schemaId); - } - - String appId = microserviceName.substring(0, idxAt); - String realMicroserviceName = microserviceName.substring(idxAt + 1); - return String.format("applications/%s/%s/%s.yaml", - appId, - realMicroserviceName, - schemaId); - } - - protected SwaggerGenerator generateSwagger(CONTEXT context) { - SwaggerGeneratorContext generatorContext = - compositeSwaggerGeneratorContext.selectContext(context.getProviderClass()); - SwaggerGenerator generator = new SwaggerGenerator(generatorContext, context.getProviderClass()); - generator.setClassLoader(context.getMicroserviceMeta().getClassLoader()); - generator.setPackageName( - SchemaUtils.generatePackageName(context.getMicroserviceMeta(), context.getSchemaId())); - generator.generate(); - - return generator; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaContext.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaContext.java deleted file mode 100644 index 4d91daf0ae4..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaContext.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -public class ConsumerSchemaContext extends SchemaContext { - protected Microservice microservice; - - public Microservice getMicroservice() { - return microservice; - } - - public void setMicroservice(Microservice microservice) { - this.microservice = microservice; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java deleted file mode 100644 index aab39e97323..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.SchemaUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import io.swagger.models.Swagger; - -@Component -public class ConsumerSchemaFactory extends AbstractSchemaFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerSchemaFactory.class); - - // 允许consumerIntf与schemaId对应的interface原型不同,用于支持context类型的参数 - // consumerIntf为null,表示原型与契约相同 - public void createConsumerSchema(MicroserviceMeta microserviceMeta, Microservice microservice) { - long start = System.currentTimeMillis(); - for (String schemaId : microservice.getSchemas()) { - ConsumerSchemaContext context = new ConsumerSchemaContext(); - context.setMicroserviceMeta(microserviceMeta); - context.setMicroservice(microservice); - context.setSchemaId(schemaId); - context.setProviderClass(null); - - getOrCreateSchema(context); - } - - LOGGER.info("Loading schema for service {} token {}", microservice.getServiceId(), - (System.currentTimeMillis() - start)); - } - - @Override - protected SchemaMeta createSchema(ConsumerSchemaContext context) { - // 尝试从规划的目录或服务中心加载契约 - Swagger swagger = loadSwagger(context); - - // 注册契约 - return schemaLoader.registerSchema(context.getMicroserviceMeta(), context.getSchemaId(), swagger); - } - - @Override - protected Swagger loadSwagger(ConsumerSchemaContext context) { - Swagger swagger = super.loadSwagger(context); - if (swagger != null) { - return swagger; - } - - ServiceRegistryClient client = RegistryUtils.getServiceRegistryClient(); - String schemaContent = client.getAggregatedSchema(context.getMicroservice().getServiceId(), context.getSchemaId()); - LOGGER.info("load schema from service center, microservice={}:{}:{}, schemaId={}, result={}", - context.getMicroservice().getAppId(), - context.getMicroservice().getServiceName(), - context.getMicroservice().getVersion(), - context.getSchemaId(), - !StringUtils.isEmpty(schemaContent)); - LOGGER.debug(schemaContent); - if (schemaContent != null) { - return SchemaUtils.parseSwagger(schemaContent); - } - - throw new Error( - String.format("no schema in local, and can not get schema from service center, %s:%s", - context.getMicroserviceName(), - context.getSchemaId())); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaContext.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaContext.java deleted file mode 100644 index c02a8caf289..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaContext.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -public class ProducerSchemaContext extends SchemaContext { - protected Object producerInstance; - - public Object getProducerInstance() { - return producerInstance; - } - - public void setProducerInstance(Object producerInstance) { - this.producerInstance = producerInstance; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java deleted file mode 100644 index 59888d4c600..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import static org.apache.servicecomb.serviceregistry.api.Const.REGISTER_URL_PREFIX; -import static org.apache.servicecomb.serviceregistry.api.Const.URL_PREFIX; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -import javax.inject.Inject; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.executor.ExecutorManager; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; -import org.apache.servicecomb.swagger.engine.SwaggerProducer; -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicPropertyFactory; - -import io.swagger.models.Operation; -import io.swagger.models.Swagger; - -@Component -public class ProducerSchemaFactory extends AbstractSchemaFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(ProducerSchemaFactory.class); - - @Inject - private SwaggerEnvironment swaggerEnv; - - public void setSwaggerEnv(SwaggerEnvironment swaggerEnv) { - this.swaggerEnv = swaggerEnv; - } - - // 只会在启动流程中调用 - public SchemaMeta getOrCreateProducerSchema(String schemaId, - Class producerClass, - Object producerInstance) { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - ProducerSchemaContext context = new ProducerSchemaContext(); - context.setMicroserviceMeta(microserviceMeta); - context.setSchemaId(schemaId); - context.setProviderClass(producerClass); - context.setProducerInstance(producerInstance); - - SchemaMeta schemaMeta = getOrCreateSchema(context); - - SwaggerProducer producer = swaggerEnv.createProducer(producerInstance, schemaMeta.getSwaggerIntf(), - convertSwaggerOperationMap(schemaMeta)); - Executor reactiveExecutor = BeanUtils.getBean(ExecutorManager.EXECUTOR_REACTIVE); - for (OperationMeta operationMeta : schemaMeta.getOperations()) { - SwaggerProducerOperation producerOperation = producer.findOperation(operationMeta.getOperationId()); - operationMeta.putExtData(Const.PRODUCER_OPERATION, producerOperation); - - if (CompletableFuture.class.equals(producerOperation.getProducerMethod().getReturnType())) { - operationMeta.setExecutor(ExecutorManager.findExecutor(operationMeta, reactiveExecutor)); - } - } - - return schemaMeta; - } - - private Map convertSwaggerOperationMap(SchemaMeta schemaMeta) { - Map operationMap = new LinkedHashMap<>(schemaMeta.getOperations().size()); - schemaMeta.getOperations().forEach( - operationMeta -> operationMap.put(operationMeta.getOperationId(), operationMeta.getSwaggerOperation())); - return operationMap; - } - - protected SchemaMeta createSchema(ProducerSchemaContext context) { - // 尝试从规划的目录加载契约 - Swagger swagger = loadSwagger(context); - if (swagger == null) { - Set combinedNames = RegistryUtils.getServiceRegistry().getCombinedMicroserviceNames(); - for (String name : combinedNames) { - swagger = loadSwagger(name, context.getSchemaId()); - if (swagger != null) { - break; - } - } - } - - // 根据class动态产生契约 - if (swagger == null) { - SwaggerGenerator generator = generateSwagger(context); - swagger = generator.getSwagger(); - String swaggerContent = SwaggerUtils.swaggerToString(swagger); - LOGGER.info("generate swagger for {}/{}/{}, swagger: {}", - context.getMicroserviceMeta().getAppId(), - context.getMicroserviceName(), - context.getSchemaId(), - swaggerContent); - } - - String urlPrefix = System.getProperty(URL_PREFIX); - if (!StringUtils.isEmpty(urlPrefix) && !swagger.getBasePath().startsWith(urlPrefix) - && DynamicPropertyFactory.getInstance() - .getBooleanProperty(REGISTER_URL_PREFIX, false).get()) { - LOGGER.info("Add swagger base path prefix for {} with {}", swagger.getBasePath(), urlPrefix); - swagger.setBasePath(urlPrefix + swagger.getBasePath()); - } - // 注册契约 - return schemaLoader.registerSchema(context.getMicroserviceMeta(), context.getSchemaId(), swagger); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/SchemaContext.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/SchemaContext.java deleted file mode 100644 index f78a6cfa434..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/SchemaContext.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; - -public class SchemaContext { - protected MicroserviceMeta microserviceMeta; - - protected String schemaId; - - protected SchemaMeta schemaMeta; - - // consumer或producer对应的class - protected Class providerClass; - - public String getMicroserviceName() { - return microserviceMeta.getName(); - } - - public MicroserviceMeta getMicroserviceMeta() { - return microserviceMeta; - } - - public void setMicroserviceMeta(MicroserviceMeta microserviceMeta) { - this.microserviceMeta = microserviceMeta; - } - - public String getSchemaId() { - return schemaId; - } - - public void setSchemaId(String schemaId) { - this.schemaId = schemaId; - } - - public SchemaMeta getSchemaMeta() { - return schemaMeta; - } - - public void setSchemaMeta(SchemaMeta schemaMeta) { - this.schemaMeta = schemaMeta; - } - - public Class getProviderClass() { - return providerClass; - } - - public void setProviderClass(Class providerClass) { - this.providerClass = providerClass; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactory.java deleted file mode 100644 index 0606e46d8de..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import io.swagger.models.Swagger; - -@Component -public class StaticSchemaFactory extends AbstractSchemaFactory { - - private static final Logger LOGGER = LoggerFactory.getLogger(StaticSchemaFactory.class); - - public void loadSchema(MicroserviceMeta microserviceMeta, StaticMicroservice microservice) { - SchemaContext context = new SchemaContext(); - context.setMicroserviceMeta(microserviceMeta); - // use microservice name as schemaId, since currently we only allow one schema per 3rd party microservice - context.setSchemaId(microserviceMeta.getShortName()); - context.setProviderClass(microservice.getSchemaIntfCls()); - - getOrCreateSchema(context); - } - - @Override - protected SchemaMeta createSchema(SchemaContext context) { - // generate schema according to producer interface - Swagger swagger; - SwaggerGenerator generator = generateSwagger(context); - swagger = generator.getSwagger(); - String swaggerContent = SwaggerUtils.swaggerToString(swagger); - LOGGER.info("generate swagger for {}/{}/{}, swagger: {}", - context.getMicroserviceMeta().getAppId(), - context.getMicroserviceName(), - context.getSchemaId(), - swaggerContent); - - // register swagger schema - return schemaLoader.registerSchema(context.getMicroserviceMeta(), context.getSchemaId(), swagger); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/endpoint/AbstractEndpointsCache.java b/core/src/main/java/org/apache/servicecomb/core/endpoint/AbstractEndpointsCache.java deleted file mode 100644 index 8501013cc71..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/endpoint/AbstractEndpointsCache.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.endpoint; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.springframework.util.StringUtils; - -/** - * registry模块不理解core中的概念 - * 所以要将字符串的各种信息转义一下,方便运行时使用 - */ -public abstract class AbstractEndpointsCache { - protected static InstanceCacheManager instanceCacheManager; - - protected static TransportManager transportManager; - - protected List endpoints = new ArrayList<>(); - - protected String transportName; - - protected InstanceCache instanceCache = null; - - public static void init(InstanceCacheManager instanceCacheManager, TransportManager transportManager) { - AbstractEndpointsCache.instanceCacheManager = instanceCacheManager; - AbstractEndpointsCache.transportManager = transportManager; - } - - /* - * transportName 可能为"",表示走任意健康的地址即可 - */ - public AbstractEndpointsCache(String appId, String microserviceName, String microserviceVersionRule, - String transportName) { - this.transportName = transportName; - this.instanceCache = new InstanceCache(appId, microserviceName, microserviceVersionRule, null); - } - - public List getLatestEndpoints() { - InstanceCache newCache = instanceCacheManager.getOrCreate(instanceCache.getAppId(), - instanceCache.getMicroserviceName(), - instanceCache.getMicroserviceVersionRule()); - if (!instanceCache.cacheChanged(newCache)) { - return endpoints; - } - - // 走到这里,肯定已经是存在"有效"地址了(可能是个空列表,表示没有存活的实例) - // 先创建,成功了,再走下面的更新逻辑 - List tmpEndpoints = createEndpoints(newCache); - - this.instanceCache = newCache; - this.endpoints = tmpEndpoints; - return endpoints; - } - - protected List createEndpoints(InstanceCache newCache) { - Map> transportMap = getOrCreateTransportMap(newCache); - - return createEndpoints(transportMap); - } - - protected List createEndpoints(Map> transportMap) { - List tmpEndpoints = new ArrayList<>(); - for (Entry> entry : transportMap.entrySet()) { - Transport transport = transportManager.findTransport(entry.getKey()); - if (transport == null) { - continue; - } - - List endpointList = entry.getValue(); - if (endpointList == null) { - continue; - } - - for (CacheEndpoint cacheEndpoint : endpointList) { - ENDPOINT endpoint = createEndpoint(transport, cacheEndpoint); - tmpEndpoints.add(endpoint); - } - } - return tmpEndpoints; - } - - private Map> getOrCreateTransportMap(InstanceCache newCache) { - Map> allTransportMap = newCache.getOrCreateTransportMap(); - if (StringUtils.isEmpty(transportName)) { - // 未指定transport,将所有transport全取出来 - return allTransportMap; - } - - Map> transportMap = new HashMap<>(); - transportMap.put(transportName, allTransportMap.get(transportName)); - return transportMap; - } - - protected abstract ENDPOINT createEndpoint(Transport transport, CacheEndpoint cacheEndpoint); -} diff --git a/core/src/main/java/org/apache/servicecomb/core/endpoint/EndpointsCache.java b/core/src/main/java/org/apache/servicecomb/core/endpoint/EndpointsCache.java deleted file mode 100644 index 9fe526628af..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/endpoint/EndpointsCache.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.endpoint; - -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; - -public class EndpointsCache extends AbstractEndpointsCache { - - public EndpointsCache(String appId, String microserviceName, String microserviceVersionRule, - String transportName) { - super(appId, microserviceName, microserviceVersionRule, transportName); - } - - @Override - protected Endpoint createEndpoint(Transport transport, CacheEndpoint cacheEndpoint) { - return new Endpoint(transport, cacheEndpoint.getEndpoint(), cacheEndpoint.getInstance()); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationBaseEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationBaseEvent.java index 6914b31f9a7..09e2949b319 100644 --- a/core/src/main/java/org/apache/servicecomb/core/event/InvocationBaseEvent.java +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationBaseEvent.java @@ -19,7 +19,7 @@ import org.apache.servicecomb.core.Invocation; public class InvocationBaseEvent { - private Invocation invocation; + private final Invocation invocation; public InvocationBaseEvent(Invocation invocation) { this.invocation = invocation; diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationBusinessFinishEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationBusinessFinishEvent.java new file mode 100644 index 00000000000..2c3fe135836 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationBusinessFinishEvent.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.event; + +import org.apache.servicecomb.core.Invocation; + +public class InvocationBusinessFinishEvent extends InvocationBaseEvent { + public InvocationBusinessFinishEvent(Invocation invocation) { + super(invocation); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationEncodeResponseStartEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationEncodeResponseStartEvent.java new file mode 100644 index 00000000000..53ffc12e0e8 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationEncodeResponseStartEvent.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.event; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; + +public class InvocationEncodeResponseStartEvent extends InvocationWithResponseEvent { + public InvocationEncodeResponseStartEvent(Invocation invocation, Response response) { + super(invocation, response); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationFinishEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationFinishEvent.java index 7122b99756d..21a20226d01 100644 --- a/core/src/main/java/org/apache/servicecomb/core/event/InvocationFinishEvent.java +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationFinishEvent.java @@ -19,22 +19,8 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.swagger.invocation.Response; -public class InvocationFinishEvent extends InvocationBaseEvent { - private long nanoCurrent; - - private Response response; - +public class InvocationFinishEvent extends InvocationWithResponseEvent { public InvocationFinishEvent(Invocation invocation, Response response) { - super(invocation); - this.nanoCurrent = invocation.getInvocationStageTrace().getFinish(); - this.response = response; - } - - public long getNanoCurrent() { - return nanoCurrent; - } - - public Response getResponse() { - return response; + super(invocation, response); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationStartSendRequestEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationStartSendRequestEvent.java new file mode 100644 index 00000000000..9a8770ea8ec --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationStartSendRequestEvent.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.event; + +import org.apache.servicecomb.core.Invocation; + +public class InvocationStartSendRequestEvent extends InvocationBaseEvent { + public InvocationStartSendRequestEvent(Invocation invocation) { + super(invocation); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationTimeoutCheckEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationTimeoutCheckEvent.java new file mode 100644 index 00000000000..3dc563161e8 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationTimeoutCheckEvent.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.event; + +import org.apache.servicecomb.core.Invocation; + +public class InvocationTimeoutCheckEvent extends InvocationBaseEvent { + public InvocationTimeoutCheckEvent(Invocation invocation) { + super(invocation); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/InvocationWithResponseEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/InvocationWithResponseEvent.java new file mode 100644 index 00000000000..3ecbc7d8d00 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/InvocationWithResponseEvent.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.event; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; + +public class InvocationWithResponseEvent extends InvocationBaseEvent { + protected Response response; + + public InvocationWithResponseEvent(Invocation invocation, Response response) { + super(invocation); + this.response = response; + } + + public Response getResponse() { + return response; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/event/ServerAccessLogEvent.java b/core/src/main/java/org/apache/servicecomb/core/event/ServerAccessLogEvent.java new file mode 100644 index 00000000000..63e14bf0f21 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/event/ServerAccessLogEvent.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.event; + +import io.vertx.ext.web.RoutingContext; + +public class ServerAccessLogEvent { + private long milliStartTime; + + private long milliEndTime; + + private RoutingContext routingContext; + + /** + * If client send request via a short-lived connection, the connection may be closed before the corresponding + * access log is generated, and then we can not get valid host ip + * may get "0.0.0.0" as result. So we need to get local address before the connection is closed. + */ + private String localAddress; + + public ServerAccessLogEvent() { + } + + public long getMilliStartTime() { + return milliStartTime; + } + + public ServerAccessLogEvent setMilliStartTime(long milliStartTime) { + this.milliStartTime = milliStartTime; + return this; + } + + public long getMilliEndTime() { + return milliEndTime; + } + + public ServerAccessLogEvent setMilliEndTime(long milliEndTime) { + this.milliEndTime = milliEndTime; + return this; + } + + public RoutingContext getRoutingContext() { + return routingContext; + } + + public ServerAccessLogEvent setRoutingContext(RoutingContext routingContext) { + this.routingContext = routingContext; + return this; + } + + public String getLocalAddress() { + return localAddress; + } + + public ServerAccessLogEvent setLocalAddress(String localAddress) { + this.localAddress = localAddress; + return this; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/CoreExceptionConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/exception/CoreExceptionConfiguration.java new file mode 100644 index 00000000000..856888764a1 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/CoreExceptionConfiguration.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CoreExceptionConfiguration { + @Bean + public Exceptions scbExceptions() { + return new Exceptions(); + } + + @Bean + public DefaultExceptionProcessor scbDefaultExceptionProcessor() { + return new DefaultExceptionProcessor(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/DefaultExceptionProcessor.java b/core/src/main/java/org/apache/servicecomb/core/exception/DefaultExceptionProcessor.java new file mode 100644 index 00000000000..e8817af521d --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/DefaultExceptionProcessor.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static jakarta.ws.rs.core.Response.Status.TOO_MANY_REQUESTS; +import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace; +import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_SERVER; +import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.servicecomb.config.inject.InjectProperties; +import org.apache.servicecomb.config.inject.InjectProperty; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.tracing.TraceIdLogger; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.ws.rs.core.Response.StatusType; + +@InjectProperties(prefix = "servicecomb.invocation.exception") +public class DefaultExceptionProcessor implements ExceptionProcessor { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionProcessor.class); + + public static final int ORDER = Integer.MAX_VALUE; + + @JsonIgnore + @SuppressWarnings("unchecked") + private final List> converters = SPIServiceUtils + .getOrLoadSortedService(ExceptionConverter.class).stream() + .map(converter -> (ExceptionConverter) converter) + .collect(Collectors.toList()); + + @InjectProperty(keys = "print-stack-trace", defaultValue = "true") + protected boolean printStackTrace; + + @InjectProperty(keys = "print-rate-limit", defaultValue = "false") + protected boolean printRateLimit; + + private final Map, ExceptionConverter> converterCache = new ConcurrentHashMapEx<>(); + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean isPrintStackTrace() { + return printStackTrace; + } + + public DefaultExceptionProcessor setPrintStackTrace(boolean printStackTrace) { + this.printStackTrace = printStackTrace; + return this; + } + + public boolean isPrintRateLimit() { + return printRateLimit; + } + + public DefaultExceptionProcessor setPrintRateLimit(boolean printRateLimit) { + this.printRateLimit = printRateLimit; + return this; + } + + @SuppressWarnings("unchecked") + @Autowired(required = false) + public DefaultExceptionProcessor setConverters(List> converters) { + converters.forEach(converter -> this.converters.add((ExceptionConverter) converter)); + this.converters.sort(Comparator.comparingInt(ExceptionConverter::getOrder)); + this.converterCache.clear(); + return this; + } + + @Override + public InvocationException convert(Invocation invocation, Throwable throwable) { + StatusType genericStatus = CONSUMER.equals(invocation.getInvocationType()) ? BAD_REQUEST : INTERNAL_SERVER_ERROR; + return convert(invocation, throwable, genericStatus); + } + + @Override + public InvocationException convert(Invocation invocation, Throwable throwable, StatusType genericStatus) { + Throwable unwrapped = ExceptionFactory.unwrap(throwable); + try { + ExceptionConverter converter = + converterCache.computeIfAbsent(unwrapped.getClass(), clazz -> findConverter(unwrapped)); + if (invocation == null) { + LOGGER.warn("Convert unknown operation exception {}/{} using {}.", + throwable.getClass().getSimpleName(), unwrapped.getClass().getSimpleName(), + converter.getClass().getSimpleName()); + } else { + invocation.getTraceIdLogger().warn("{} Convert operation {} exception {}/{} using {}.", + TraceIdLogger.constructSource(DefaultExceptionProcessor.class.getSimpleName()), + invocation.getMicroserviceQualifiedName(), + throwable.getClass().getSimpleName(), unwrapped.getClass().getSimpleName(), + converter.getClass().getSimpleName()); + } + return converter.convert(invocation, unwrapped, genericStatus); + } catch (Exception e) { + LOGGER.error("BUG: ExceptionConverter.convert MUST not throw exception, please fix it.\n" + + "original exception :{}" + + "converter exception:{}", + getStackTrace(throwable), + getStackTrace(e)); + return new InvocationException(INTERNAL_SERVER_ERROR, + new CommonExceptionData(GENERIC_SERVER, INTERNAL_SERVER_ERROR.getReasonPhrase())); + } + } + + private ExceptionConverter findConverter(Throwable throwable) { + for (ExceptionConverter converter : converters) { + if (converter.canConvert(throwable)) { + return converter; + } + } + + throw new IllegalStateException("never happened: can not find converter for " + throwable.getClass().getName()); + } + + @Override + public Response toConsumerResponse(Invocation invocation, Throwable throwable) { + InvocationException exception = convert(invocation, throwable, BAD_REQUEST); + logConsumerException(invocation, exception); + return Response.failResp(exception); + } + + @Override + public void logConsumerException(Invocation invocation, InvocationException exception) { + if (isIgnoreLog(invocation, exception)) { + return; + } + + if (isPrintStackTrace()) { + invocation.getTraceIdLogger().error("{} Failed to invoke {}, endpoint={}.", + TraceIdLogger.constructSource(DefaultExceptionProcessor.class.getSimpleName()), + invocation.getMicroserviceQualifiedName(), + invocation.getEndpoint(), + exception); + return; + } + + invocation.getTraceIdLogger().error("{} Failed to invoke {}, endpoint={}, message={}.", + TraceIdLogger.constructSource(DefaultExceptionProcessor.class.getSimpleName()), + invocation.getMicroserviceQualifiedName(), + invocation.getEndpoint(), + ExceptionUtils.getExceptionMessageWithoutTrace(exception)); + } + + @Override + public boolean isIgnoreLog(Invocation invocation, InvocationException exception) { + if (!isPrintRateLimit() && exception.getStatusCode() == TOO_MANY_REQUESTS.getStatusCode()) { + return true; + } + + return false; + } + + @Override + public Response toProducerResponse(Invocation invocation, Throwable exception) { + InvocationException invocationException = convert(invocation, exception, INTERNAL_SERVER_ERROR); + if (invocation != null) { + logProducerException(invocation, invocationException); + } + return Response.createFail(invocationException); + } + + @Override + public void logProducerException(Invocation invocation, InvocationException exception) { + if (isIgnoreLog(invocation, exception)) { + return; + } + + if (isPrintStackTrace()) { + invocation.getTraceIdLogger().error("{} Failed to process {} invocation, operation={}.", + TraceIdLogger.constructSource(DefaultExceptionProcessor.class.getSimpleName()), + invocation.getInvocationType(), invocation.getMicroserviceQualifiedName(), exception); + return; + } + + invocation.getTraceIdLogger().error("{} Failed to process {} invocation, operation={}, message={}.", + TraceIdLogger.constructSource(DefaultExceptionProcessor.class.getSimpleName()), + invocation.getInvocationType(), invocation.getMicroserviceQualifiedName(), + ExceptionUtils.getExceptionMessageWithoutTrace(exception)); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionCodes.java b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionCodes.java new file mode 100644 index 00000000000..4c2c50885cb --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionCodes.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception; + +public interface ExceptionCodes { + String GENERIC_CLIENT = "SCB.00000000"; + String LB_ADDRESS_NOT_FOUND = "SCB.00000001"; + String NOT_DEFINED_ANY_SCHEMA = "SCB.00000002"; + String DEFAULT_VALIDATE = "SCB.00000003"; + String INVOCATION_TIMEOUT = "SCB.00000004"; + + String GENERIC_SERVER = "SCB.50000000"; +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionConverter.java new file mode 100644 index 00000000000..b6424564747 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionConverter.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception; + +import static jakarta.ws.rs.core.Response.Status.Family.CLIENT_ERROR; +import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_CLIENT; +import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_SERVER; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.utils.SPIOrder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.StatusType; + +public interface ExceptionConverter extends SPIOrder { + static boolean isClient(StatusType status) { + return CLIENT_ERROR.equals(status.getFamily()); + } + + static String getGenericCode(StatusType status) { + return isClient(status) ? GENERIC_CLIENT : GENERIC_SERVER; + } + + /** + * + * @param throwable exception will be converted + * @return can convert the exception + */ + boolean canConvert(Throwable throwable); + + /** + * + * @param invocation related invocation, will be null only when failed to prepare invocation + * @param throwable exception will be converted + * @param genericStatus if can not determine the status type, then use this input value + * @return converted invocation exception + */ + InvocationException convert(Invocation invocation, T throwable, StatusType genericStatus); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionProcessor.java b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionProcessor.java new file mode 100644 index 00000000000..ffb3619bb41 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionProcessor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.core.Ordered; + +import jakarta.ws.rs.core.Response.StatusType; + +/** + * will select the min order instance + */ +public interface ExceptionProcessor extends Ordered { + @Override + default int getOrder() { + return 0; + } + + boolean isPrintStackTrace(); + + InvocationException convert(Invocation invocation, Throwable throwable); + + InvocationException convert(Invocation invocation, Throwable throwable, StatusType genericStatus); + + boolean isIgnoreLog(Invocation invocation, InvocationException exception); + + Response toConsumerResponse(Invocation invocation, Throwable throwable); + + void logConsumerException(Invocation invocation, InvocationException exception); + + Response toProducerResponse(Invocation invocation, Throwable exception); + + void logProducerException(Invocation invocation, InvocationException exception); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionUtils.java b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionUtils.java index 5b3b754740e..016c8719e94 100644 --- a/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionUtils.java +++ b/core/src/main/java/org/apache/servicecomb/core/exception/ExceptionUtils.java @@ -30,8 +30,6 @@ public class ExceptionUtils { protected static final RegisterManager ERROR_DESC_MGR = new RegisterManager<>(ERROR_DESC_MGR_MSG); - private static final String SERVICECOMB_SCHEMA_OPERATION_ID_INVALID = "servicecomb.schema.operation.id.invalid"; - private static final String SERVICECOMB_HANDLER_REF_NOT_EXIST = "servicecomb.handler.ref.not.exist"; private static final String SERVICECOMB_PRODUCER_OPERATION_NOT_EXIST = "servicecomb.producer.operation.not.exist"; @@ -40,7 +38,6 @@ public class ExceptionUtils { static { ERROR_DESC_MGR.register(SERVICECOMB_HANDLER_REF_NOT_EXIST, "Handler not exist, id=%s"); - ERROR_DESC_MGR.register(SERVICECOMB_SCHEMA_OPERATION_ID_INVALID, "OperationId is invalid, schemaId=%s, path=%s"); ERROR_DESC_MGR.register(SERVICECOMB_PRODUCER_OPERATION_NOT_EXIST, "Producer operation not exist, schemaId=%s, operationName=%s"); ERROR_DESC_MGR.register(SERVICECOMB_LB_NO_AVAILABLE_ADDRESS, @@ -73,12 +70,6 @@ public static CseException producerOperationNotExist(String schemaId, String ope operationName); } - public static CseException operationIdInvalid(String schemaId, String path) { - return createCseException(SERVICECOMB_SCHEMA_OPERATION_ID_INVALID, - schemaId, - path); - } - public static CseException handlerRefNotExist(String id) { return createCseException(SERVICECOMB_HANDLER_REF_NOT_EXIST, id); } diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/Exceptions.java b/core/src/main/java/org/apache/servicecomb/core/exception/Exceptions.java new file mode 100644 index 00000000000..0fb8ad418a1 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/Exceptions.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_CLIENT; +import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_SERVER; +import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER; + +import java.util.Comparator; +import java.util.List; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; + +import jakarta.ws.rs.core.Response.StatusType; + +public class Exceptions { + private static ExceptionProcessor processor = new DefaultExceptionProcessor(); + + @Autowired(required = false) + public void setProcessor(List processors) { + // never be null, "orElse" just to avoid compile warning + processor = processors.stream() + .min(Comparator.comparingInt(ExceptionProcessor::getOrder)) + .orElse(new DefaultExceptionProcessor()); + } + + public static Throwable unwrapIncludeInvocationException(Throwable throwable) { + return ExceptionFactory.unwrapIncludeInvocationException(throwable); + } + + public static T unwrap(Throwable throwable) { + return ExceptionFactory.unwrap(throwable); + } + + public static InvocationException create(StatusType status, Object errorData) { + return new InvocationException(status, errorData); + } + + public static InvocationException create(StatusType status, String code, String msg) { + return new InvocationException(status, code, msg); + } + + private static InvocationException create(StatusType status, String code, String msg, Throwable cause) { + return new InvocationException(status, code, msg, cause); + } + + public static InvocationException consumer(String code, String msg) { + return create(BAD_REQUEST, code, msg); + } + + public static InvocationException consumer(String code, String msg, Throwable cause) { + if (cause instanceof InvocationException) { + return (InvocationException) cause; + } + return create(BAD_REQUEST, code, msg, cause); + } + + public static InvocationException genericConsumer(String msg) { + return consumer(GENERIC_CLIENT, msg); + } + + public static InvocationException genericConsumer(String msg, Throwable cause) { + return consumer(GENERIC_CLIENT, msg, cause); + } + + public static InvocationException producer(String code, String msg) { + return create(INTERNAL_SERVER_ERROR, code, msg); + } + + public static InvocationException producer(String code, String msg, Throwable cause) { + return create(INTERNAL_SERVER_ERROR, code, msg, cause); + } + + public static InvocationException genericProducer(String msg) { + return producer(GENERIC_SERVER, msg); + } + + public static InvocationException genericProducer(String msg, Throwable cause) { + return producer(GENERIC_SERVER, msg, cause); + } + + public static StatusType getGenericStatus(Invocation invocation) { + return CONSUMER.equals(invocation.getInvocationType()) ? BAD_REQUEST : INTERNAL_SERVER_ERROR; + } + + public static Response toConsumerResponse(Invocation invocation, Throwable throwable) { + return processor.toConsumerResponse(invocation, throwable); + } + + public static Response toProducerResponse(Invocation invocation, Throwable exception) { + return processor.toProducerResponse(invocation, exception); + } + + public static InvocationException convert(Invocation invocation, Throwable throwable) { + return processor.convert(invocation, throwable); + } + + public static InvocationException convert(Invocation invocation, Throwable throwable, + StatusType genericStatus) { + return processor.convert(invocation, throwable, genericStatus); + } + + public static boolean isPrintInvocationStackTrace() { + return processor.isPrintStackTrace(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConnectTimeoutExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConnectTimeoutExceptionConverter.java new file mode 100644 index 00000000000..72507d0a3ba --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConnectTimeoutExceptionConverter.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.ConnectTimeoutException; +import jakarta.ws.rs.core.Response.StatusType; + +public class ConnectTimeoutExceptionConverter implements ExceptionConverter { + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectTimeoutExceptionConverter.class); + + public static final int ORDER = Short.MAX_VALUE; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof ConnectTimeoutException; + } + + @Override + public InvocationException convert(Invocation invocation, ConnectTimeoutException throwable, + StatusType genericStatus) { + // throwable.getMessage: + // connection timed out: /1.1.1.1:8080 + // should not copy the message to invocationException to avoid leak server ip address + LOGGER.info("connection timed out, Details: {}.", throwable.getMessage()); + + return new InvocationException(INTERNAL_SERVER_ERROR, + ExceptionConverter.getGenericCode(genericStatus), "connection timed out.", + throwable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConstraintViolationExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConstraintViolationExceptionConverter.java new file mode 100644 index 00000000000..2898d4914ae --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ConstraintViolationExceptionConverter.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.apache.servicecomb.core.exception.ExceptionCodes.DEFAULT_VALIDATE; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.validation.ConstraintViolationException; +import jakarta.ws.rs.core.Response.StatusType; + +public class ConstraintViolationExceptionConverter implements ExceptionConverter { + public static final int ORDER = Short.MAX_VALUE; + + public static final String KEY_CODE = "servicecomb.filters.validate.code"; + + public ConstraintViolationExceptionConverter() { + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof ConstraintViolationException; + } + + @Override + public InvocationException convert(Invocation invocation, ConstraintViolationException throwable, + StatusType genericStatus) { + List details = throwable.getConstraintViolations().stream() + .map(violation -> new ValidateDetail(violation.getPropertyPath().toString(), violation.getMessage())) + .collect(Collectors.toList()); + + CommonExceptionData exceptionData = new CommonExceptionData(SCBEngine.getInstance().getEnvironment(). + getProperty(KEY_CODE, String.class, DEFAULT_VALIDATE), "invalid parameters."); + exceptionData.putDynamic("validateDetail", details); + return new InvocationException(BAD_REQUEST, exceptionData); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/DefaultExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/DefaultExceptionConverter.java new file mode 100644 index 00000000000..d0338d43628 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/DefaultExceptionConverter.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.StatusType; + +/** + *
+ *   Only very few exceptions carry sensitive data
+ *   If discard all exception messages for these very few exceptions, it will cause difficult to locate problems
+ *
+ *   so default to remain the messages, and log the exception
+ *
+ *   if want to change these:
+ *   1. customize a new converter
+ *   2. disabled log for this class by log configuration
+ * 
+ */ +public class DefaultExceptionConverter implements ExceptionConverter { + public static final int ORDER = Integer.MAX_VALUE; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return true; + } + + @Override + public InvocationException convert(Invocation invocation, Throwable throwable, StatusType genericStatus) { + String msg = String.format("Unexpected exception when processing %s. %s", + invocation == null ? "none" : invocation.getMicroserviceQualifiedName(), throwable.getMessage()); + return new InvocationException(genericStatus, ExceptionConverter.getGenericCode(genericStatus), + msg, throwable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/IllegalArgumentExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/IllegalArgumentExceptionConverter.java new file mode 100644 index 00000000000..f80f1a82519 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/IllegalArgumentExceptionConverter.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.StatusType; + +public class IllegalArgumentExceptionConverter implements ExceptionConverter { + public static final int ORDER = Short.MAX_VALUE; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof IllegalArgumentException; + } + + @Override + public InvocationException convert(Invocation invocation, IllegalArgumentException throwable, + StatusType genericStatus) { + return new InvocationException(genericStatus, ExceptionConverter.getGenericCode(genericStatus), + "Parameters not valid or types not match.", throwable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/InvocationExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/InvocationExceptionConverter.java new file mode 100644 index 00000000000..830aec3190c --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/InvocationExceptionConverter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.StatusType; + +public class InvocationExceptionConverter implements ExceptionConverter { + public static final int ORDER = Byte.MAX_VALUE; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof InvocationException; + } + + @Override + public InvocationException convert(Invocation invocation, InvocationException throwable, + StatusType genericStatus) { + return throwable; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/ServiceCombExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ServiceCombExceptionConverter.java new file mode 100644 index 00000000000..9a69f4c988c --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ServiceCombExceptionConverter.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception.converter; + +import java.util.concurrent.TimeoutException; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; + +public class ServiceCombExceptionConverter implements ExceptionConverter { + public static final int ORDER = Byte.MAX_VALUE; + + private TimeoutExceptionConverter timeoutExceptionConverter = new TimeoutExceptionConverter(); + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof ServiceCombException; + } + + @Override + public InvocationException convert(Invocation invocation, ServiceCombException throwable, + StatusType genericStatus) { + if (throwable.getCause() instanceof TimeoutException) { + return timeoutExceptionConverter.convert(invocation, (TimeoutException) throwable.getCause(), genericStatus); + } + + return new InvocationException(Status.INTERNAL_SERVER_ERROR, + ExceptionConverter.getGenericCode(genericStatus), throwable.getMessage(), + throwable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverter.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverter.java new file mode 100644 index 00000000000..31d48a82933 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverter.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +import static jakarta.ws.rs.core.Response.Status.REQUEST_TIMEOUT; + +import java.util.concurrent.TimeoutException; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.Response.StatusType; + +public class TimeoutExceptionConverter implements ExceptionConverter { + private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutExceptionConverter.class); + + public static final int ORDER = Short.MAX_VALUE; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof TimeoutException; + } + + @Override + public InvocationException convert(Invocation invocation, TimeoutException throwable, + StatusType genericStatus) { + // throwable.getMessage: + // The timeout period of 30000ms has been exceeded while executing GET /xxx for server 1.1.1.1:8080 + // should not copy the message to invocationException to avoid leak server ip address + LOGGER.info("Request timeout, Details: {}.", throwable.getMessage()); + + return new InvocationException(REQUEST_TIMEOUT, + ExceptionConverter.getGenericCode(genericStatus), "Request Timeout.", + throwable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/exception/converter/ValidateDetail.java b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ValidateDetail.java new file mode 100644 index 00000000000..06140be7ca7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/exception/converter/ValidateDetail.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.exception.converter; + +public class ValidateDetail { + private String propertyPath; + + private String message; + + public ValidateDetail() { + } + + public ValidateDetail(String propertyPath, String message) { + this.propertyPath = propertyPath; + this.message = message; + } + + public String getPropertyPath() { + return propertyPath; + } + + public ValidateDetail setPropertyPath(String propertyPath) { + this.propertyPath = propertyPath; + return this; + } + + public String getMessage() { + return message; + } + + public ValidateDetail setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/ExecutorManager.java b/core/src/main/java/org/apache/servicecomb/core/executor/ExecutorManager.java index 27dc7e3b379..f03547c171a 100644 --- a/core/src/main/java/org/apache/servicecomb/core/executor/ExecutorManager.java +++ b/core/src/main/java/org/apache/servicecomb/core/executor/ExecutorManager.java @@ -17,34 +17,65 @@ package org.apache.servicecomb.core.executor; +import java.util.Map; import java.util.concurrent.Executor; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -import com.netflix.config.DynamicPropertyFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; public final class ExecutorManager { public static final String KEY_EXECUTORS_PREFIX = "servicecomb.executors.Provider."; public static final String KEY_EXECUTORS_DEFAULT = "servicecomb.executors.default"; - public static final String EXECUTOR_GROUP_THREADPOOL = "servicecomb.executor.groupThreadPool"; + public static final String EXECUTOR_GROUP_THREAD_POOL = "servicecomb.executor.groupThreadPool"; public static final String EXECUTOR_REACTIVE = "servicecomb.executor.reactive"; - public static final String EXECUTOR_DEFAULT = EXECUTOR_GROUP_THREADPOOL; + private final Map executors = new ConcurrentHashMapEx<>(); + + static String EXECUTOR_DEFAULT = EXECUTOR_GROUP_THREAD_POOL; + + public static void setExecutorDefault(String executorDefault) { + EXECUTOR_DEFAULT = executorDefault; + } + + private Environment environment; + + public ExecutorManager() { + registerExecutor(EXECUTOR_REACTIVE, new ReactiveExecutor()); + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } - private ExecutorManager() { + public void registerExecutor(String id, Executor executor) { + Executor existing = executors.putIfAbsent(id, executor); + if (existing != null) { + throw new IllegalStateException(String.format( + "duplicated executor, id=%s, old executor=%s, new executor=%s", + id, existing.getClass().getName(), executor.getClass().getName())); + } } // 只会在初始化时执行,一点点重复的查找,没必要做缓存 - public static Executor findExecutor(OperationMeta operationMeta) { + public Executor findExecutor(OperationMeta operationMeta) { return findExecutor(operationMeta, null); } - public static Executor findExecutor(OperationMeta operationMeta, Executor defaultOperationExecutor) { - Executor executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getSchemaQualifiedName()); + public Executor findExecutor(OperationMeta operationMeta, Executor defaultOperationExecutor) { + // operation级别 + Executor executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getMicroserviceQualifiedName()); + if (executor != null) { + return executor; + } + + executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getSchemaQualifiedName()); if (executor != null) { return executor; } @@ -53,26 +84,48 @@ public static Executor findExecutor(OperationMeta operationMeta, Executor defaul return defaultOperationExecutor; } - // 尝试schema级别 - executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getSchemaMeta().getName()); + // schema级别 + executor = findByKey( + KEY_EXECUTORS_PREFIX + operationMeta.getMicroserviceName() + '.' + operationMeta.getSchemaId()); if (executor != null) { return executor; } + executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getSchemaId()); + if (executor != null) { + return executor; + } + + // microservice级别 + executor = findByKey(KEY_EXECUTORS_PREFIX + operationMeta.getMicroserviceName()); + if (executor != null) { + return executor; + } + + // 寻找config-key指定的default executor = findByKey(KEY_EXECUTORS_DEFAULT); if (executor != null) { return executor; } - return BeanUtils.getBean(EXECUTOR_DEFAULT); + return findExecutorById(EXECUTOR_DEFAULT); } - protected static Executor findByKey(String beanIdKey) { - String beanId = DynamicPropertyFactory.getInstance().getStringProperty(beanIdKey, null).get(); - if (beanId != null) { - return BeanUtils.getBean(beanId); + private Executor findByKey(String configKey) { + String id = environment.getProperty(configKey); + if (id == null) { + return null; + } + + return findExecutorById(id); + } + + public Executor findExecutorById(String id) { + Executor executor = executors.get(id); + if (executor != null) { + return executor; } - return null; + return BeanUtils.getBean(id); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/FixedThreadExecutor.java b/core/src/main/java/org/apache/servicecomb/core/executor/FixedThreadExecutor.java deleted file mode 100644 index 8ea95dff4d9..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/executor/FixedThreadExecutor.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.executor; - -import java.io.Closeable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; - -public class FixedThreadExecutor implements Executor, Closeable { - private static final Logger LOGGER = LoggerFactory.getLogger(FixedThreadExecutor.class); - - public static final String KEY_GROUP = "servicecomb.executor.default.group"; - - public static final String KEY_THREAD = "servicecomb.executor.default.thread-per-group"; - - // to avoid multiple network thread conflicted when put tasks to executor queue - private List executorList = new ArrayList<>(); - - // for bind network thread to one executor - // it's impossible that has too many network thread, so index will not too big that less than 0 - private AtomicInteger index = new AtomicInteger(); - - private Map threadExecutorMap = new ConcurrentHashMapEx<>(); - - public FixedThreadExecutor() { - int groupCount = DynamicPropertyFactory.getInstance().getIntProperty(KEY_GROUP, 2).get(); - int threadPerGroup = DynamicPropertyFactory.getInstance() - .getIntProperty(KEY_THREAD, Runtime.getRuntime().availableProcessors()) - .get(); - LOGGER.info("executor group {}, thread per group {}.", groupCount, threadPerGroup); - - for (int groupIdx = 0; groupIdx < groupCount; groupIdx++) { - executorList.add(Executors.newFixedThreadPool(threadPerGroup)); - } - } - - public List getExecutorList() { - return executorList; - } - - @Override - public void execute(Runnable command) { - long threadId = Thread.currentThread().getId(); - Executor executor = threadExecutorMap.computeIfAbsent(threadId, this::chooseExecutor); - - executor.execute(command); - } - - private Executor chooseExecutor(long threadId) { - int idx = index.getAndIncrement() % executorList.size(); - return executorList.get(idx); - } - - @Override - public void close() { - for (ExecutorService executorService : executorList) { - executorService.shutdown(); - } - executorList.clear(); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/GroupExecutor.java b/core/src/main/java/org/apache/servicecomb/core/executor/GroupExecutor.java new file mode 100644 index 00000000000..13562914fac --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/executor/GroupExecutor.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.executor; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +public class GroupExecutor implements Executor, Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(GroupExecutor.class); + + public static final String KEY_GROUP = "servicecomb.executor.default.group"; + + // Deprecated + public static final String KEY_OLD_MAX_THREAD = "servicecomb.executor.default.thread-per-group"; + + public static final String KEY_CORE_THREADS = "servicecomb.executor.default.coreThreads-per-group"; + + public static final String KEY_MAX_THREADS = "servicecomb.executor.default.maxThreads-per-group"; + + public static final String KEY_MAX_IDLE_SECOND = "servicecomb.executor.default.maxIdleSecond-per-group"; + + public static final String KEY_MAX_QUEUE_SIZE = "servicecomb.executor.default.maxQueueSize-per-group"; + + private static final AtomicBoolean LOG_PRINTED = new AtomicBoolean(); + + private final Environment environment; + + protected String groupName; + + protected int groupCount; + + protected int coreThreads; + + protected int maxThreads; + + protected int maxIdleInSecond; + + protected int maxQueueSize; + + // to avoid multiple network thread conflicted when put tasks to executor queue + private final List executorList = new ArrayList<>(); + + // for bind network thread to one executor + // it's impossible that has too many network thread, so index will not too big that less than 0 + private final AtomicInteger index = new AtomicInteger(); + + private final Map threadExecutorMap = new ConcurrentHashMapEx<>(); + + public GroupExecutor(Environment environment) { + this.environment = environment; + } + + public GroupExecutor init() { + return init("group"); + } + + public GroupExecutor init(String groupName) { + this.groupName = groupName; + initConfig(); + + for (int groupIdx = 0; groupIdx < groupCount; groupIdx++) { + GroupThreadFactory factory = new GroupThreadFactory(groupName + groupIdx); + + ThreadPoolExecutorEx executor = new ThreadPoolExecutorEx(coreThreads, + maxThreads, + maxIdleInSecond, + TimeUnit.SECONDS, + new LinkedBlockingQueueEx(maxQueueSize), + factory); + executorList.add(executor); + } + + return this; + } + + public synchronized void initConfig() { + if (LOG_PRINTED.compareAndSet(false, true)) { + LOGGER.info("thread pool rules:\n" + + "1.use core threads.\n" + + "2.if all core threads are busy, then create new thread.\n" + + "3.if thread count reach the max limitation, then queue the request.\n" + + "4.if queue is full, and threads count is max, then reject the request."); + } + + groupCount = environment.getProperty(KEY_GROUP, int.class, 2); + coreThreads = environment.getProperty(KEY_CORE_THREADS, int.class, 25); + + maxThreads = environment.getProperty(KEY_MAX_THREADS, int.class, -1); + if (maxThreads <= 0) { + maxThreads = environment.getProperty(KEY_OLD_MAX_THREAD, int.class, -1); + if (maxThreads > 0) { + LOGGER.warn("{} is deprecated, recommended to use {}.", KEY_OLD_MAX_THREAD, KEY_MAX_THREADS); + } else { + maxThreads = 100; + } + } + if (coreThreads > maxThreads) { + LOGGER.warn("coreThreads is bigger than maxThreads, change from {} to {}.", coreThreads, maxThreads); + coreThreads = maxThreads; + } + + maxIdleInSecond = environment.getProperty(KEY_MAX_IDLE_SECOND, int.class, 60); + maxQueueSize = environment.getProperty(KEY_MAX_QUEUE_SIZE, int.class, Integer.MAX_VALUE); + + LOGGER.info( + "executor name={}, group={}. per group settings, coreThreads={}, maxThreads={}, maxIdleInSecond={}, maxQueueSize={}.", + groupName, groupCount, coreThreads, maxThreads, maxIdleInSecond, maxQueueSize); + } + + public List getExecutorList() { + return executorList; + } + + @Override + public void execute(Runnable command) { + long threadId = Thread.currentThread().getId(); + Executor executor = threadExecutorMap.computeIfAbsent(threadId, this::chooseExecutor); + + executor.execute(command); + } + + private Executor chooseExecutor(long threadId) { + int idx = index.getAndIncrement() % executorList.size(); + return executorList.get(idx); + } + + @Override + public void close() { + for (ExecutorService executorService : executorList) { + executorService.shutdown(); + } + executorList.clear(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/GroupThreadFactory.java b/core/src/main/java/org/apache/servicecomb/core/executor/GroupThreadFactory.java new file mode 100644 index 00000000000..e6dbfb27227 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/executor/GroupThreadFactory.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.executor; + +import java.util.Objects; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class GroupThreadFactory implements ThreadFactory { + private static final AtomicInteger poolNumber = new AtomicInteger(1); + + private final ThreadGroup group; + + private final AtomicInteger threadNumber = new AtomicInteger(1); + + private final String namePrefix; + + public GroupThreadFactory(String prefix) { + Objects.requireNonNull(prefix); + + group = Thread.currentThread().getThreadGroup(); + + namePrefix = prefix + "-" + poolNumber.getAndIncrement() + "-thread-"; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, + namePrefix + threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/LinkedBlockingQueueEx.java b/core/src/main/java/org/apache/servicecomb/core/executor/LinkedBlockingQueueEx.java new file mode 100644 index 00000000000..aba525f73cd --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/executor/LinkedBlockingQueueEx.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.executor; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; + +public class LinkedBlockingQueueEx extends LinkedBlockingQueue { + private static final long serialVersionUID = -1L; + + private transient volatile ThreadPoolExecutorEx owner = null; + + public LinkedBlockingQueueEx(int capacity) { + super(capacity); + } + + public void setOwner(ThreadPoolExecutorEx owner) { + this.owner = owner; + } + + @Override + public boolean offer(Runnable runnable) { + // task can come before owner available + if (owner == null) { + return super.offer(runnable); + } + // can not create more thread, just queue the task + if (owner.getPoolSize() == owner.getMaximumPoolSize()) { + return super.offer(runnable); + } + // no need to create more thread, just queue the task + if (owner.getNotFinished() <= owner.getPoolSize()) { + return super.offer(runnable); + } + // all threads are busy, and can create new thread, not queue the task + if (owner.getPoolSize() < owner.getMaximumPoolSize()) { + return false; + } + return super.offer(runnable); + } + + /* + * when task is rejected (thread pool if full), force the item onto queue. + */ + public boolean force(Runnable runnable) { + if (owner == null || owner.isShutdown()) { + throw new RejectedExecutionException("queue is not running."); + } + return super.offer(runnable); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/executor/ThreadPoolExecutorEx.java b/core/src/main/java/org/apache/servicecomb/core/executor/ThreadPoolExecutorEx.java new file mode 100644 index 00000000000..7249e6e7e18 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/executor/ThreadPoolExecutorEx.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.executor; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ThreadPoolExecutorEx extends ThreadPoolExecutor { + private final AtomicInteger submittedCount = new AtomicInteger(); + + private final AtomicInteger finishedCount = new AtomicInteger(); + + private final AtomicInteger rejectedCount = new AtomicInteger(); + + public ThreadPoolExecutorEx(int coreThreads, int maxThreads, int maxIdleInSecond, TimeUnit timeUnit, + BlockingQueue queue, ThreadFactory threadFactory) { + super(coreThreads, maxThreads, maxIdleInSecond, timeUnit, queue, threadFactory); + if (queue instanceof LinkedBlockingQueueEx) { + ((LinkedBlockingQueueEx) queue).setOwner(this); + } + setRejectedExecutionHandler(this::rejectedExecution); + } + + @Override + public void execute(Runnable command) { + submittedCount.incrementAndGet(); + try { + super.execute(command); + } catch (RejectedExecutionException e) { + if (getQueue() instanceof LinkedBlockingQueueEx) { + final LinkedBlockingQueueEx queue = (LinkedBlockingQueueEx) getQueue(); + if (!queue.force(command)) { + throw new RejectedExecutionException("thread pool queue is full"); + } + } else { + throw e; + } + } + } + + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + rejectedCount.incrementAndGet(); + finishedCount.incrementAndGet(); + + throw new RejectedExecutionException("Task " + r.toString() + + " rejected from " + + e.toString()); + } + + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + finishedCount.incrementAndGet(); + } + + public int getNotFinished() { + return submittedCount.get() - finishedCount.get(); + } + + public int getRejectedCount() { + return rejectedCount.get(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/AbstractFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/AbstractFilter.java new file mode 100644 index 00000000000..17d555fc8d1 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/AbstractFilter.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; + +public abstract class AbstractFilter implements Filter, EnvironmentAware { + private static final String ORDER_KEY = "servicecomb.filter.%s.%s.%s.order"; + + private static final String ENABLE_KEY = "servicecomb.filter.%s.%s.%s.enabled"; + + protected Environment environment; + + private String nameWithOrder; + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public int getOrder(String application, String serviceName) { + Integer custom = environment.getProperty(String.format(ORDER_KEY, getName(), application, serviceName), + Integer.class); + if (custom != null) { + return custom; + } + return getOrder(); + } + + @Override + public boolean enabledForMicroservice(String application, String serviceName) { + Boolean custom = environment.getProperty(String.format(ENABLE_KEY, getName(), application, serviceName), + Boolean.class); + if (custom != null) { + return custom; + } + return true; + } + + @Override + public String getNameWithOrder() { + if (nameWithOrder == null) { + nameWithOrder = String.format("F(%1$06d)-%2$s", getOrder(), getName()); + } + return nameWithOrder; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java new file mode 100644 index 00000000000..de13aa0ac2e --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/ConsumerFilter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +public interface ConsumerFilter extends Filter { + +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/CoreFilterConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/filter/CoreFilterConfiguration.java new file mode 100644 index 00000000000..0d9ce402624 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/CoreFilterConfiguration.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +import org.apache.servicecomb.core.filter.impl.ContextMapperFilter; +import org.apache.servicecomb.core.filter.impl.ParameterValidatorFilter; +import org.apache.servicecomb.core.filter.impl.ProviderOperationFilter; +import org.apache.servicecomb.core.filter.impl.RetryFilter; +import org.apache.servicecomb.core.filter.impl.ScheduleFilter; +import org.apache.servicecomb.governance.handler.MapperHandler; +import org.apache.servicecomb.governance.handler.RetryHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CoreFilterConfiguration { + @Bean + public ProviderOperationFilter scbProducerOperationFilter() { + return new ProviderOperationFilter(); + } + + @Bean + public ScheduleFilter scbScheduleFilter() { + return new ScheduleFilter(); + } + + @Bean + public RetryFilter scbRetryFilter(RetryHandler retryHandler) { + return new RetryFilter(retryHandler); + } + + @Bean + public ContextMapperFilter scbContextMapperFilter(MapperHandler mapperHandler) { + return new ContextMapperFilter(mapperHandler); + } + + @Bean + public FilterChainsManager scbFilterChainsManager() { + return new FilterChainsManager(); + } + + @Bean + public ParameterValidatorFilter scbParameterValidatorFilter() { + return new ParameterValidatorFilter(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/EdgeFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/EdgeFilter.java new file mode 100644 index 00000000000..70d8bef4ef5 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/EdgeFilter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +public interface EdgeFilter extends Filter { + +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/EndpointDiscoveryFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/EndpointDiscoveryFilter.java deleted file mode 100644 index d05c59d6d0c..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/filter/EndpointDiscoveryFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.filter; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.AbstractEndpointDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EndpointDiscoveryFilter extends AbstractEndpointDiscoveryFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(EndpointDiscoveryFilter.class); - - @Override - public int getOrder() { - return (int) Short.MAX_VALUE; - } - - @Override - protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { - Invocation invocation = context.getInputParameters(); - return invocation.getConfigTransportName(); - } - - @Override - protected Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance) { - Transport transport = CseContext.getInstance().getTransportManager().findTransport(transportName); - if (transport == null) { - LOGGER.info("not deployed transport {}, ignore {}.", transportName, endpoint); - return null; - } - - return new Endpoint(transport, endpoint, instance); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java b/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java new file mode 100644 index 00000000000..99ed798e686 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/Filter.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.core.Ordered; + +/** + *
+ *  Filters are the basics of how an invocation is executed.
+ *
+ * thread rule:
+ *   assume a provider filter chains is: f1, f2, schedule, f3, f4
+ *
+ *   schedule is a builtIn filter, which will dispatch invocations to operation related threadPool
+ *
+ *   f1 and f2 are before "schedule" filter, default to run in eventLoop
+ *   if developers customize filters and switch to other threads
+ *   it's better to switch back to eventLoop, unless you know what you are doing
+ *
+ *   f3 and f4 are after "schedule" filter, default thread depend on controller's method signature
+ *     1. if controller method not return CompletableFuture
+ *        then will run in a real threadPool
+ *     2. if controller method return CompletableFuture
+ *        then will still run in eventLoop
+ *   so filters after "schedule" filter, are more complex than filters before "schedule"
+ *   if developers need to do some BLOCK logic, MUST use different Strategy when running in different thread:
+ *     1. threadPool: run do BLOCK logic directly
+ *     2. eventLoop: MUST submit to a threadPool, and then switch back
+ *        (reactive golden rule)
+ * 
+ */ +public interface Filter extends Ordered { + int PROVIDER_SCHEDULE_FILTER_ORDER = 0; + + int CONSUMER_LOAD_BALANCE_ORDER = 0; + + default boolean enabledForTransport(String transport) { + return true; + } + + default boolean enabledForMicroservice(String application, String serviceName) { + return true; + } + + default int getOrder(String application, String serviceName) { + return 0; + } + + default int getOrder() { + return 0; + } + + default String getName() { + throw new IllegalStateException("must provide unique filter name."); + } + + String getNameWithOrder(); + + /** + * + * @param invocation invocation + * @param nextNode node filter node + * @return response future
+ * even Response can express fail data
+ * but Response only express success data in filter chain
+ * all fail data can only express by exception
+ *
+ * special for producer:
+ * if response is failure, then after encode response, response.result will + * be exception.errorData, not a exception + */ + CompletableFuture onFilter(Invocation invocation, FilterNode nextNode); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java new file mode 100644 index 00000000000..2cc6281d018 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; +import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.deleteLast; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; + +public class FilterChainsManager { + private InvocationFilterChains consumerChains; + + private InvocationFilterChains providerChains; + + private InvocationFilterChains edgeChains; + + @Autowired + public FilterChainsManager setEdgeFilters(List filters) { + edgeChains = new InvocationFilterChains(filters); + return this; + } + + @Autowired + public FilterChainsManager setConsumerFilters(List filters) { + consumerChains = new InvocationFilterChains(filters); + return this; + } + + @Autowired + public FilterChainsManager setProviderFilters(List filters) { + providerChains = new InvocationFilterChains(filters); + return this; + } + + public FilterChainsManager init() { + return this; + } + + public FilterNode findConsumerChain(String application, String serviceName) { + return consumerChains.findChain(application, serviceName); + } + + public FilterNode findProducerChain(String application, String serviceName) { + return providerChains.findChain(application, serviceName); + } + + public FilterNode findEdgeChain(String application, String serviceName) { + return edgeChains.findChain(application, serviceName); + } + + public String collectResolvedChains() { + StringBuilder sb = new StringBuilder(); + + appendLine(sb, "consumer: "); + appendLine(sb, " filters: %s", collectFilterNames(consumerChains)); + + appendLine(sb, "producer: "); + appendLine(sb, " filters: %s", collectFilterNames(providerChains)); + + appendLine(sb, "edge: "); + appendLine(sb, " filters: %s", collectFilterNames(edgeChains)); + + return deleteLast(sb, 1).toString(); + } + + private List collectFilterNames(InvocationFilterChains chains) { + return chains.getFilters().stream() + .map(filter -> filter.getName() + "(" + filter.getOrder() + ")") + .collect(Collectors.toList()); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java new file mode 100644 index 00000000000..44a5b34d901 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.swagger.invocation.Response; + +public class FilterNode { + public static final FilterNode EMPTY = new FilterNode(null) { + @Override + public CompletableFuture onFilter(Invocation invocation) { + return CompletableFuture.completedFuture(Response.ok(null)); + } + }; + + public static FilterNode buildChain(Filter... filters) { + return buildChain(Arrays.asList(filters)); + } + + public static FilterNode buildChain(List filters) { + List filterNodes = filters.stream() + .map(FilterNode::new).toList(); + + for (int idx = 0; idx < filterNodes.size() - 1; idx++) { + FilterNode currentNode = filterNodes.get(idx); + FilterNode nextNode = filterNodes.get(idx + 1); + currentNode.setNextNode(nextNode); + } + + return filterNodes.get(0); + } + + private final Filter filter; + + private FilterNode nextNode; + + public FilterNode(Filter filter) { + this.filter = filter; + } + + private void setNextNode(FilterNode nextNode) { + this.nextNode = nextNode; + } + + public CompletableFuture onFilter(Invocation invocation) { + // When transport name is empty, maybe edge transport filters need to be executed. + // Can't set Endpoint before load balance in edge. + if (invocation.getTransportName() != null && !filter.enabledForTransport(invocation.getTransportName())) { + return nextNode.onFilter(invocation); + } + + String stage = invocation.getInvocationStageTrace().recordStageBegin(this.filter.getNameWithOrder()); + return AsyncUtils.tryCatchSupplierFuture(() -> filter.onFilter(invocation, nextNode) + .whenComplete((r, e) -> invocation.getInvocationStageTrace().recordStageEnd(stage))); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java b/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java new file mode 100644 index 00000000000..6dde66c3354 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/InvocationFilterChains.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.filter; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; + +public class InvocationFilterChains { + + private final List filters; + + private final Map> microserviceChains = new ConcurrentHashMapEx<>(); + + public InvocationFilterChains(List filters) { + this.filters = filters; + } + + public List getFilters() { + return filters; + } + + public FilterNode findChain(String application, String serviceName) { + return microserviceChains.computeIfAbsent(application, key -> new ConcurrentHashMapEx<>()) + .computeIfAbsent(serviceName, (serviceNameInner) -> { + List serviceFilters = filters.stream() + .filter(e -> e.enabledForMicroservice(application, serviceName)) + .sorted(Comparator.comparingInt(a -> a.getOrder(application, serviceName))) + .collect(Collectors.toList()); + return FilterNode.buildChain(serviceFilters); + }); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/OperationInstancesDiscoveryFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/OperationInstancesDiscoveryFilter.java deleted file mode 100644 index 7fcbe4bab00..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/filter/OperationInstancesDiscoveryFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.filter; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.discovery.AbstractDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.apache.servicecomb.serviceregistry.version.VersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleUtils; - -import com.netflix.config.DynamicPropertyFactory; - -public class OperationInstancesDiscoveryFilter extends AbstractDiscoveryFilter { - private final static String VERSION_RULE = "versionRule"; - - @Override - public int getOrder() { - return -10000; - } - - @Override - public boolean enabled() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.loadbalance.filter.operation.enabled", true).get(); - } - - @Override - public boolean isGroupingFilter() { - return true; - } - - @Override - protected String findChildName(DiscoveryContext context, DiscoveryTreeNode parent) { - Invocation invocation = context.getInputParameters(); - return invocation.getMicroserviceQualifiedName(); - } - - @Override - public void init(DiscoveryContext context, DiscoveryTreeNode parent) { - Map> versionMap = - groupByVersion(context.getInputParameters(), parent.data()); - Map operationNodes = initOperationNodes(parent, versionMap); - fillInstances(operationNodes, versionMap); - - parent.children(operationNodes); - } - - protected void fillInstances(Map operationNodes, - Map> versionMap) { - for (Entry> entry : versionMap.entrySet()) { - for (DiscoveryTreeNode node : operationNodes.values()) { - // versionRule is startFrom logic, so isAccept is enough - VersionRule versionRule = node.attribute(VERSION_RULE); - if (versionRule.isAccept(entry.getKey().getVersion())) { - node.mapData().putAll(entry.getValue()); - } - } - } - } - - protected Map initOperationNodes(DiscoveryTreeNode parent, - Map> versionMap) { - Map tmpChildren = new ConcurrentHashMapEx<>(); - versionMap - .keySet() - .stream() - .sorted(Comparator.comparing(MicroserviceVersion::getVersion)) - .forEach(meta -> { - for (OperationMeta operationMeta : meta.getMicroserviceMeta().getOperations()) { - tmpChildren.computeIfAbsent(operationMeta.getMicroserviceQualifiedName(), qualifiedName -> { - VersionRule versionRule = VersionRuleUtils.getOrCreate(meta.getVersion().getVersion() + "+"); - return new DiscoveryTreeNode() - .attribute(VERSION_RULE, versionRule) - .subName(parent, versionRule.getVersionRule()) - .data(new HashMap<>()); - }); - } - }); - return tmpChildren; - } - - protected Map> groupByVersion(Invocation invocation, - Map instances) { - OperationMeta latestOperationMeta = invocation.getOperationMeta(); - MicroserviceMeta latestMicroserviceMeta = latestOperationMeta.getSchemaMeta().getMicroserviceMeta(); - AppManager appManager = RegistryUtils.getServiceRegistry().getAppManager(); - MicroserviceVersions MicroserviceVersions = - appManager.getOrCreateMicroserviceVersions(latestMicroserviceMeta.getAppId(), latestMicroserviceMeta.getName()); - - Map> versionMap = new IdentityHashMap<>(); - for (MicroserviceInstance instance : instances.values()) { - MicroserviceVersionMeta versionMeta = MicroserviceVersions.getVersion(instance.getServiceId()); - Map versionInstances = versionMap - .computeIfAbsent(versionMeta, vm -> new HashMap<>()); - versionInstances.put(instance.getInstanceId(), instance); - } - return versionMap; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/ProviderFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/ProviderFilter.java new file mode 100644 index 00000000000..6d5edd7814e --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/ProviderFilter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter; + +public interface ProviderFilter extends Filter { + +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ContextMapperFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ContextMapperFilter.java new file mode 100644 index 00000000000..a14e41dd660 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ContextMapperFilter.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.MapperHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.processor.mapping.Mapper; +import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.util.CollectionUtils; + +public class ContextMapperFilter extends AbstractFilter implements ProviderFilter, EdgeFilter { + private final MapperHandler mapperHandler; + + public ContextMapperFilter(MapperHandler mapperHandler) { + this.mapperHandler = mapperHandler; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.RESTFUL.equals(transport); + } + + @Override + public int getOrder() { + return -1995; + } + + @Override + public String getName() { + return "context-mapper"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + Mapper mapper = mapperHandler.getActuator(request); + if (mapper == null || CollectionUtils.isEmpty(mapper.target())) { + return nextNode.onFilter(invocation); + } + Map properties = mapper.target(); + properties.forEach((k, v) -> { + if (StringUtils.isEmpty(v)) { + return; + } + if ("$U".equals(v)) { + invocation.addContext(k, request.apiPath()); + } else if ("$M".equals(v)) { + invocation.addContext(k, request.method()); + } else if (v.startsWith("$H{") && v.endsWith("}")) { + invocation.addContext(k, request.header(v.substring(3, v.length() - 1))); + } else if (v.startsWith("$Q{") && v.endsWith("}")) { + invocation.addContext(k, request.query(v.substring(3, v.length() - 1))); + } else { + invocation.addContext(k, v); + } + }); + return nextNode.onFilter(invocation); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java new file mode 100644 index 00000000000..d2b8eb82319 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/EmptyFilter.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.swagger.invocation.Response; + +// just for test +public class EmptyFilter extends AbstractFilter implements ProviderFilter, ConsumerFilter, EdgeFilter { + @Override + public String getName() { + return "empty"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + return CompletableFuture.completedFuture(Response.ok(null)); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/JacksonPropertyNodeNameProvider.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/JacksonPropertyNodeNameProvider.java new file mode 100644 index 00000000000..f617f5fe567 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/JacksonPropertyNodeNameProvider.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.filter.impl; + +import org.hibernate.validator.spi.nodenameprovider.JavaBeanProperty; +import org.hibernate.validator.spi.nodenameprovider.Property; +import org.hibernate.validator.spi.nodenameprovider.PropertyNodeNameProvider; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; + +import io.vertx.core.json.jackson.DatabindCodec; + +/** + * hibernate validator will cache the resolved data
+ * no need to worry about performance problem + */ +public class JacksonPropertyNodeNameProvider implements PropertyNodeNameProvider { + @Override + public String getName(Property property) { + if (property instanceof JavaBeanProperty) { + return getJavaBeanPropertyName((JavaBeanProperty) property); + } + + return property.getName(); + } + + private String getJavaBeanPropertyName(JavaBeanProperty property) { + ObjectMapper objectMapper = DatabindCodec.mapper(); + JavaType type = objectMapper.constructType(property.getDeclaringClass()); + BeanDescription desc = objectMapper.getSerializationConfig().introspect(type); + + return desc.findProperties() + .stream() + .filter(prop -> prop.getInternalName().equals(property.getName())) + .map(BeanPropertyDefinition::getName) + .findFirst() + .orElse(property.getName()); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java new file mode 100644 index 00000000000..b4bf065792f --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilter.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; + +import jakarta.validation.Configuration; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Valid; +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.executable.ExecutableValidator; +import jakarta.validation.groups.Default; + +public class ParameterValidatorFilter extends AbstractFilter implements ProviderFilter, InitializingBean { + private static class Service { + @SuppressWarnings("unused") + public void service(@Valid Model model) { + + } + } + + private static class Model { + @NotNull + String name; + + @Min(10) + int age; + + Model(String name, int age) { + this.name = name; + this.age = age; + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ParameterValidatorFilter.class); + + public static final String NAME = "validator"; + + public static final String HIBERNATE_VALIDATE_PREFIX = "hibernate.validator"; + + public static final String ENABLE_EL = "servicecomb.filters.validation.useResourceBundleMessageInterpolator"; + + protected ExecutableValidator validator; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER + 1000; + } + + @Override + public void afterPropertiesSet() { + validator = createValidatorFactory() + .getValidator().forExecutables(); + initValidate(); + } + + private void initValidate() { + // This method is intended to make first rpc call faster + // Because validation cache bean class, this way only make first rpc call a little faster. + try { + Model model = new Model("foo", 23); + Service instance = new Service(); + Method method = Service.class.getMethod("service", Model.class); + Object[] args = new Object[] {model}; + validator.validateParameters(instance, method, args, Default.class); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + protected ValidatorFactory createValidatorFactory() { + Configuration validatorConfiguration = Validation.byProvider(HibernateValidator.class) + .configure() + .propertyNodeNameProvider(new JacksonPropertyNodeNameProvider()) + .messageInterpolator(messageInterpolator()); + Map properties = ConfigUtil.stringPropertiesWithPrefix(environment, HIBERNATE_VALIDATE_PREFIX); + if (!properties.isEmpty()) { + for (Map.Entry entry : properties.entrySet()) { + validatorConfiguration.addProperty(entry.getKey(), entry.getValue()); + } + } + return validatorConfiguration.buildValidatorFactory(); + } + + protected AbstractMessageInterpolator messageInterpolator() { + if (useResourceBundleMessageInterpolator()) { + return new ResourceBundleMessageInterpolator(); + } + return new ParameterMessageInterpolator(); + } + + private boolean useResourceBundleMessageInterpolator() { + return environment.getProperty(ENABLE_EL, boolean.class, false); + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + Set> violations = doValidate(invocation); + if (violations.size() > 0) { + LOGGER.error("Parameter validation failed : " + violations); + return AsyncUtils.completeExceptionally(new ConstraintViolationException(violations)); + } + + return nextNode.onFilter(invocation); + } + + protected Set> doValidate(Invocation invocation) { + SwaggerProducerOperation producerOperation = invocation.getOperationMeta().getSwaggerProducerOperation(); + return validator.validateParameters(producerOperation.getProducerInstance(), producerOperation.getProducerMethod(), + invocation.toProducerArguments(), Default.class); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProviderOperationFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProviderOperationFilter.java new file mode 100644 index 00000000000..c8f757bf3e2 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ProviderOperationFilter.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.Status; + +public class ProviderOperationFilter extends AbstractFilter implements ProviderFilter { + public static final String NAME = "producer-operation"; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + // almost time, should be the last filter. + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER + 2000; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (!transportAccessAllowed(invocation)) { + return CompletableFuture.failedFuture(new InvocationException(Status.UNAUTHORIZED, + new CommonExceptionData("transport access not allowed."))); + } + invocation.onBusinessMethodStart(); + + SwaggerProducerOperation producerOperation = invocation.getOperationMeta().getSwaggerProducerOperation(); + Object instance = producerOperation.getProducerInstance(); + Method method = producerOperation.getProducerMethod(); + Object[] args = invocation.toProducerArguments(); + return invoke(invocation, instance, method, args) + .thenApply(result -> convertResultToResponse(invocation, producerOperation, result)) + .whenComplete((response, throwable) -> processMetrics(invocation)); + } + + private boolean transportAccessAllowed(Invocation invocation) { + if (invocation.getProviderTransportName() == null) { + return true; + } + return invocation.getProviderTransportName().equals(invocation.getTransportName()); + } + + @SuppressWarnings("unchecked") + protected CompletableFuture invoke(Invocation invocation, Object instance, Method method, Object[] args) { + ContextUtils.setInvocationContext(invocation); + + try { + Object result = method.invoke(instance, args); + if (result instanceof CompletableFuture) { + return (CompletableFuture) result; + } + + return CompletableFuture.completedFuture(result); + } catch (Throwable e) { + return AsyncUtils.completeExceptionally(Exceptions.unwrap(e)); + } finally { + ContextUtils.removeInvocationContext(); + } + } + + protected Response convertResultToResponse(Invocation invocation, SwaggerProducerOperation producerOperation, + Object result) { + return producerOperation.getResponseMapper().mapResponse(invocation.getStatus(), result); + } + + protected void processMetrics(Invocation invocation) { + invocation.onBusinessFinish(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/RetryFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/RetryFilter.java new file mode 100644 index 00000000000..e423b8f7ebb --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/RetryFilter.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.governance.GovernanceConfiguration; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.core.governance.RetryContext; +import org.apache.servicecomb.governance.handler.RetryHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; +import io.github.resilience4j.retry.Retry; + +public class RetryFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Object LOCK = new Object(); + + private static volatile ScheduledExecutorService reactiveRetryPool; + + private static ScheduledExecutorService getOrCreateRetryPool() { + if (reactiveRetryPool == null) { + synchronized (LOCK) { + if (reactiveRetryPool == null) { + reactiveRetryPool = Executors.newScheduledThreadPool(2, new ThreadFactory() { + private final AtomicInteger count = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "reactive-retry-pool-thread-" + count.getAndIncrement()); + // avoid block shutdown + thread.setDaemon(true); + return thread; + } + }); + } + } + } + return reactiveRetryPool; + } + + private final RetryHandler retryHandler; + + @Autowired + public RetryFilter(RetryHandler retryHandler) { + this.retryHandler = retryHandler; + } + + @Override + public String getName() { + return "retry"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + Retry retry = retryHandler.getActuator(request); + if (retry == null) { + return nextNode.onFilter(invocation); + } + + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + dcs.withRetry(retry, getOrCreateRetryPool()); + CompletableFuture future = new CompletableFuture<>(); + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + future.completeExceptionally(e); + }); + + return future; + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> { + updateRetryStatus(invocation); + return nextNode.onFilter(invocation); + }; + } + + private static void updateRetryStatus(Invocation invocation) { + if (invocation.getLocalContext(RetryContext.RETRY_CONTEXT) != null) { + if (invocation.getLocalContext(RetryContext.RETRY_LOAD_BALANCE) != null + && (boolean) invocation.getLocalContext(RetryContext.RETRY_LOAD_BALANCE)) { + // clear last server to avoid using user defined endpoint + invocation.setEndpoint(null); + } + RetryContext retryContext = invocation.getLocalContext(RetryContext.RETRY_CONTEXT); + retryContext.incrementRetry(); + return; + } + + invocation.addLocalContext(RetryContext.RETRY_CONTEXT, + new RetryContext(GovernanceConfiguration.getRetrySameServer(invocation.getMicroserviceName()))); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1990; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java new file mode 100644 index 00000000000..341c01fa877 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/filter/impl/ScheduleFilter.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.filter.impl; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.core.tracing.TraceIdLogger; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.MDC; + +import jakarta.ws.rs.core.Response.Status; + +public class ScheduleFilter extends AbstractFilter implements ProviderFilter { + public static final String NAME = "schedule"; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode next) { + invocation.getInvocationStageTrace().startProviderQueue(); + Executor executor = invocation.getOperationMeta().getExecutor(); + return CompletableFuture.completedFuture(null) + .thenComposeAsync(response -> runInExecutor(invocation, next), executor); + } + + protected CompletableFuture runInExecutor(Invocation invocation, FilterNode next) { + invocation.getInvocationStageTrace().finishProviderQueue(); + MDC.put(TraceIdLogger.KEY_TRACE_ID, invocation.getTraceId()); + checkInQueueTimeout(invocation); + return next.onFilter(invocation); + } + + private void checkInQueueTimeout(Invocation invocation) { + long nanoTimeout = invocation.getOperationMeta().getConfig() + .getNanoRequestWaitInPoolTimeout(invocation.getTransport().getName()); + + if (invocation.getInvocationStageTrace().calcQueue() > nanoTimeout) { + throw new InvocationException(Status.REQUEST_TIMEOUT, "Request in the queue timed out."); + } + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/CoreGovernanceConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/governance/CoreGovernanceConfiguration.java new file mode 100644 index 00000000000..948c12bb46a --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/CoreGovernanceConfiguration.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.governance; + +import org.apache.servicecomb.core.SCBEngine; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CoreGovernanceConfiguration { + @Bean + public ServiceCombCircuitBreakerExtension serviceCombCircuitBreakerExtension() { + return new ServiceCombCircuitBreakerExtension(); + } + + @Bean + public ServiceCombInstanceIsolationExtension serviceCombInstanceIsolationExtension() { + return new ServiceCombInstanceIsolationExtension(); + } + + @Bean + public ServiceCombMicroserviceMeta serviceCombMicroserviceMeta(SCBEngine scbEngine) { + return new ServiceCombMicroserviceMeta(scbEngine); + } + + @Bean + public ServiceCombRetryExtension serviceCombRetryExtension() { + return new ServiceCombRetryExtension(); + } + + @Bean + public ServiceCombConfigurationEventAdapter serviceCombConfigurationEventAdapter() { + return new ServiceCombConfigurationEventAdapter(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/GovernanceConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/governance/GovernanceConfiguration.java new file mode 100644 index 00000000000..e0e65b9eec8 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/GovernanceConfiguration.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.governance; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; + +public class GovernanceConfiguration { + public static final String ROOT = "servicecomb.loadbalance."; + + // retry configurations + public static final String RETRY_ENABLED = "retryEnabled"; + + public static final String RETRY_ON_NEXT = "retryOnNext"; + + public static final String RETRY_ON_SAME = "retryOnSame"; + + public static boolean isRetryEnabled(String microservice) { + String p = getStringProperty("false", + ROOT + microservice + "." + RETRY_ENABLED, + ROOT + RETRY_ENABLED); + return Boolean.parseBoolean(p); + } + + public static int getRetryNextServer(String microservice) { + return getRetryServer(microservice, RETRY_ON_NEXT); + } + + public static int getRetrySameServer(String microservice) { + return getRetryServer(microservice, RETRY_ON_SAME); + } + + private static int getRetryServer(String microservice, String retryType) { + final int defaultValue = 0; + String p = getStringProperty("0", + ROOT + microservice + "." + retryType, + ROOT + retryType); + try { + int result = Integer.parseInt(p); + if (result > 0) { + return result; + } + return defaultValue; + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public static String getStringProperty(String defaultValue, String... keys) { + String property; + for (String key : keys) { + property = LegacyPropertyFactory.getStringProperty(key); + if (property != null) { + return property; + } + } + return defaultValue; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/MatchType.java b/core/src/main/java/org/apache/servicecomb/core/governance/MatchType.java new file mode 100644 index 00000000000..15d58d66610 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/MatchType.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + +import java.util.Map; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.SwaggerUtils; + +public final class MatchType { + private static class GovernanceRequestExtractorImpl implements GovernanceRequestExtractor { + private final Invocation invocation; + + private GovernanceRequestExtractorImpl(Invocation invocation) { + this.invocation = invocation; + } + + @Override + public String apiPath() { + if (MatchType.REST.equalsIgnoreCase(invocation.getOperationMeta().getConfig().getGovernanceMatchType())) { + if (!invocation.isProducer()) { + return SwaggerUtils.concatAbsolutePath(invocation.getSchemaMeta().getSwagger(), + invocation.getOperationMeta().getOperationPath()); + } + // not highway + if (invocation.getRequestEx() != null) { + return invocation.getRequestEx().getRequestURI(); + } + } + + if (!invocation.isProducer()) { + return invocation.getOperationMeta().getMicroserviceQualifiedName(); + } + return invocation.getOperationMeta().getSchemaQualifiedName(); + } + + @Override + public String method() { + return invocation.getOperationMeta().getHttpMethod(); + } + + @Override + public String header(String key) { + Map arguments = invocation.getSwaggerArguments(); + if (arguments != null && arguments.get(key) != null) { + return arguments.get(key).toString(); + } + + if (invocation.getContext(key) != null) { + return invocation.getContext(key); + } + + if (invocation.getRequestEx() != null) { + return invocation.getRequestEx().getHeader(key); + } + + return null; + } + + @Override + public String query(String key) { + HttpServletRequestEx requestEx = invocation.getRequestEx(); + if (requestEx == null) { + return null; + } + return requestEx.getParameter(key); + } + + @Override + public String instanceId() { + if (!invocation.isProducer()) { + if (invocation.getEndpoint() != null && invocation.getEndpoint().getMicroserviceInstance() != null) { + return invocation.getEndpoint().getMicroserviceInstance().getInstanceId(); + } + } + return null; + } + + @Override + public String serviceName() { + if (!invocation.isProducer()) { + return invocation.getMicroserviceName(); + } + return null; + } + + @Override + public Object sourceRequest() { + return invocation; + } + } + + public static final String REST = "rest"; + + public static final String RPC = "rpc"; + + public static GovernanceRequestExtractor createGovHttpRequest(Invocation invocation) { + return new GovernanceRequestExtractorImpl(invocation); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/RetryContext.java b/core/src/main/java/org/apache/servicecomb/core/governance/RetryContext.java new file mode 100644 index 00000000000..47792792e14 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/RetryContext.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.governance; + +public class RetryContext { + public static final String RETRY_CONTEXT = "x-context-retry"; + + // weather need reset Endpoint in retry + public static final String RETRY_LOAD_BALANCE = "x-context-retry-loadbalance"; + + private boolean retry; + + private int triedCount; + + private final int retryOnSame; + + public RetryContext(int retryOnSame) { + this.retryOnSame = retryOnSame; + this.retry = false; + this.triedCount = 0; + } + + public boolean isRetry() { + return retry; + } + + public void incrementRetry() { + this.retry = true; + this.triedCount++; + } + + public boolean trySameServer() { + return triedCount <= retryOnSame; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombCircuitBreakerExtension.java b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombCircuitBreakerExtension.java new file mode 100644 index 00000000000..9177ca71820 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombCircuitBreakerExtension.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + +import java.util.List; + +import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +public class ServiceCombCircuitBreakerExtension extends AbstractCircuitBreakerExtension { + @Override + protected String extractStatusCode(Object result) { + if (!(result instanceof Response)) { + return null; + } + Response resp = (Response) result; + if (resp.isFailed()) { + if (resp.getResult() instanceof InvocationException) { + InvocationException e = resp.getResult(); + return String.valueOf(e.getStatusCode()); + } + } + return String.valueOf(resp.getStatusCode()); + } + + @Override + public boolean isFailedResult(List statusList, Throwable e) { + if (e instanceof InvocationException) { + InvocationException invocationException = (InvocationException) e; + return statusList.contains(String.valueOf(invocationException.getStatusCode())); + } + return super.isFailedResult(statusList, e); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombConfigurationEventAdapter.java b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombConfigurationEventAdapter.java new file mode 100644 index 00000000000..e5ee61cd586 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombConfigurationEventAdapter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; + +import com.google.common.eventbus.Subscribe; + +public class ServiceCombConfigurationEventAdapter { + public ServiceCombConfigurationEventAdapter() { + EventManager.register(this); + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + GovernanceConfigurationChangedEvent newEvent = new GovernanceConfigurationChangedEvent(event.getChanged()); + GovernanceEventManager.post(newEvent); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombInstanceIsolationExtension.java b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombInstanceIsolationExtension.java new file mode 100644 index 00000000000..2bbf6d3c87d --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombInstanceIsolationExtension.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + +import java.util.List; + +import org.apache.servicecomb.governance.handler.ext.AbstractInstanceIsolationExtension; + +public class ServiceCombInstanceIsolationExtension extends AbstractInstanceIsolationExtension { + private final ServiceCombRetryExtension retryExtension = new ServiceCombRetryExtension(); + + @Override + protected String extractStatusCode(Object result) { + return retryExtension.extractStatusCode(result); + } + + @Override + public boolean isFailedResult(List statusList, Throwable e) { + return retryExtension.isFailedResult(statusList, e); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombMicroserviceMeta.java b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombMicroserviceMeta.java new file mode 100644 index 00000000000..3893e3e4207 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombMicroserviceMeta.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.governance.MicroserviceMeta; + +public class ServiceCombMicroserviceMeta implements MicroserviceMeta { + private SCBEngine scbEngine; + + public ServiceCombMicroserviceMeta(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + @Override + public String getName() { + return BootStrapProperties.readServiceName(scbEngine.getEnvironment()); + } + + @Override + public String getVersion() { + return BootStrapProperties.readServiceVersion(scbEngine.getEnvironment()); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombRetryExtension.java b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombRetryExtension.java new file mode 100644 index 00000000000..871a03bfa30 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/governance/ServiceCombRetryExtension.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.governance; + +import java.util.List; + +import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +public class ServiceCombRetryExtension extends AbstractRetryExtension { + @Override + protected String extractStatusCode(Object result) { + if (!(result instanceof Response)) { + return null; + } + Response resp = (Response) result; + if (resp.isFailed()) { + if (resp.getResult() instanceof InvocationException) { + InvocationException e = resp.getResult(); + return String.valueOf(e.getStatusCode()); + } + } + return String.valueOf(resp.getStatusCode()); + } + + @Override + public boolean isFailedResult(List statusList, Throwable e) { + if (e instanceof InvocationException) { + InvocationException invocationException = (InvocationException) e; + return statusList.contains(String.valueOf(invocationException.getStatusCode())); + } + return super.isFailedResult(statusList, e); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/AbstractHandlerManager.java b/core/src/main/java/org/apache/servicecomb/core/handler/AbstractHandlerManager.java deleted file mode 100644 index 20fd8325815..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/AbstractHandlerManager.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.handler.config.Config; -import org.apache.servicecomb.foundation.common.AbstractObjectManager; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicPropertyFactory; - -// key为microserviceName -public abstract class AbstractHandlerManager extends AbstractObjectManager> { - - private String defaultChainDef; - - private Config config; - - protected abstract String getName(); - - // consumer、provider端,最后一个handler,都是由框架指定的,业务不可配置 - protected abstract Handler getLastHandler(); - - // 内置默认值,用于业务未指定时的取值 - protected abstract String getInnerDefaultChainDef(); - - private void loadDefaultChainDef() { - String key = "servicecomb.handler.chain." + getName() + ".default"; - - defaultChainDef = DynamicPropertyFactory.getInstance() - .getStringProperty(key, getInnerDefaultChainDef()) - .get(); - } - - private List> convertToChainClass(String chainDef) { - List> result = new ArrayList<>(); - if (StringUtils.isEmpty(chainDef)) { - return result; - } - - String[] handlerIds = chainDef.split(","); - Map> handlerMaps = config.getHandlerClassMap(); - for (String handlerId : handlerIds) { - if (handlerId != null) { - handlerId = handlerId.trim(); - } - if (StringUtils.isEmpty(handlerId)) { - continue; - } - - Class cls = handlerMaps.get(handlerId); - if (cls == null) { - throw new Error("can not find handler :" + handlerId); - } - result.add(cls); - } - return result; - } - - public void init(Config config) { - this.config = config; - - loadDefaultChainDef(); - } - - private List createHandlerChain(String chainDef) { - List> chainClasses = convertToChainClass(chainDef); - - List handlerList = new ArrayList<>(); - for (Class cls : chainClasses) { - try { - handlerList.add(cls.newInstance()); - } catch (Exception e) { - // 在启动阶段直接抛异常出来 - throw new Error(e); - } - } - handlerList.add(getLastHandler()); - return handlerList; - } - - @Override - protected String getKey(String microserviceName) { - return microserviceName; - } - - @Override - protected List create(String microserviceName) { - String chainDef = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.handler.chain." + getName() + ".service." + microserviceName, - defaultChainDef) - .get(); - return createHandlerChain(chainDef); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/ConsumerHandlerManager.java b/core/src/main/java/org/apache/servicecomb/core/handler/ConsumerHandlerManager.java deleted file mode 100644 index 954a2e2dac9..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/ConsumerHandlerManager.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.handler.impl.TransportClientHandler; - -public class ConsumerHandlerManager extends AbstractHandlerManager { - public static final ConsumerHandlerManager INSTANCE = new ConsumerHandlerManager(); - - @Override - protected String getName() { - return "Consumer"; - } - - @Override - protected String getInnerDefaultChainDef() { - return "simpleLB"; - } - - @Override - protected Handler getLastHandler() { - return TransportClientHandler.INSTANCE; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/HandlerConfigUtils.java b/core/src/main/java/org/apache/servicecomb/core/handler/HandlerConfigUtils.java deleted file mode 100644 index 19e2482dec4..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/HandlerConfigUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler; - -import java.util.List; - -import org.apache.servicecomb.core.handler.config.Config; -import org.apache.servicecomb.foundation.common.config.PaaSResourceUtils; -import org.apache.servicecomb.foundation.common.config.impl.XmlLoaderUtils; -import org.springframework.core.io.Resource; - -public final class HandlerConfigUtils { - private HandlerConfigUtils() { - } - - private static Config loadConfig() throws Exception { - Config config = new Config(); - - List resList = - PaaSResourceUtils.getSortedResources("classpath*:config/cse.handler.xml", ".handler.xml"); - for (Resource res : resList) { - Config tmpConfig = XmlLoaderUtils.load(res, Config.class); - config.mergeFrom(tmpConfig); - } - - return config; - } - - public static void init() throws Exception { - Config config = loadConfig(); - ConsumerHandlerManager.INSTANCE.init(config); - ProducerHandlerManager.INSTANCE.init(config); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/ProducerHandlerManager.java b/core/src/main/java/org/apache/servicecomb/core/handler/ProducerHandlerManager.java deleted file mode 100644 index 2a92aea4e24..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/ProducerHandlerManager.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.handler.impl.ProducerOperationHandler; - -public class ProducerHandlerManager extends AbstractHandlerManager { - public static final ProducerHandlerManager INSTANCE = new ProducerHandlerManager(); - - @Override - protected String getName() { - return "Provider"; - } - - @Override - protected String getInnerDefaultChainDef() { - return ""; - } - - @Override - protected Handler getLastHandler() { - return ProducerOperationHandler.INSTANCE; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/config/Config.java b/core/src/main/java/org/apache/servicecomb/core/handler/config/Config.java deleted file mode 100644 index 53dee5a79bf..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/config/Config.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.config; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.core.Handler; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; - -@JacksonXmlRootElement -public class Config { - // key为handler id - private Map> handlerClassMap = new HashMap<>(); - - public void mergeFrom(Config otherConfig) { - handlerClassMap.putAll(otherConfig.handlerClassMap); - } - - public Map> getHandlerClassMap() { - return this.handlerClassMap; - } - - @JacksonXmlProperty(localName = "handler") - @JacksonXmlElementWrapper(useWrapping = false) - public void setHandlerConfigList(List handlerConfigList) { - for (HandlerConfig handlerConfig : handlerConfigList) { - handlerClassMap.put(handlerConfig.getHandlerId(), handlerConfig.getClazz()); - } - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/config/HandlerConfig.java b/core/src/main/java/org/apache/servicecomb/core/handler/config/HandlerConfig.java deleted file mode 100644 index cf00c7f3aba..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/config/HandlerConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.config; - -import org.apache.servicecomb.core.Handler; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -public class HandlerConfig { - private String handlerId; - - private Class clazz; - - @JacksonXmlProperty(localName = "id", isAttribute = true) - public String getHandlerId() { - return handlerId; - } - - public void setHandlerId(String handlerId) { - this.handlerId = handlerId; - } - - @JacksonXmlProperty(localName = "class", isAttribute = true) - public Class getClazz() { - return clazz; - } - - public void setClazz(Class clazz) { - this.clazz = clazz; - } - - @SuppressWarnings("unchecked") - public void setClazz(String clazz) throws ClassNotFoundException { - this.clazz = (Class) Class.forName(clazz); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/AbstractHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/AbstractHandler.java deleted file mode 100644 index 940fd97859e..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/AbstractHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.swagger.invocation.InvocationType; - -@Deprecated -public abstract class AbstractHandler implements Handler { - @Override - public void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) { - - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java deleted file mode 100644 index 62853217d5e..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.exception.ExceptionUtils; -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; - -public class ProducerOperationHandler implements Handler { - public static final ProducerOperationHandler INSTANCE = new ProducerOperationHandler(); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - SwaggerProducerOperation producerOperation = - invocation.getOperationMeta().getExtData(Const.PRODUCER_OPERATION); - if (producerOperation == null) { - asyncResp.producerFail( - ExceptionUtils.producerOperationNotExist(invocation.getSchemaId(), - invocation.getOperationName())); - return; - } - producerOperation.invoke(invocation, asyncResp); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/SimpleLoadBalanceHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/SimpleLoadBalanceHandler.java deleted file mode 100644 index 0618b35b2b0..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/SimpleLoadBalanceHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.exception.ExceptionUtils; -import org.apache.servicecomb.core.filter.EndpointDiscoveryFilter; -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 内置轮询lb,方便demo之类的场景,不必去依赖lb包 - */ -public class SimpleLoadBalanceHandler implements Handler { - private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLoadBalanceHandler.class); - - private DiscoveryTree discoveryTree = new DiscoveryTree(); - - // key为grouping filter qualified name - private volatile Map indexMap = new ConcurrentHashMapEx<>(); - - public SimpleLoadBalanceHandler() { - discoveryTree.loadFromSPI(DiscoveryFilter.class); - discoveryTree.addFilter(new EndpointDiscoveryFilter()); - discoveryTree.sort(); - } - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - DiscoveryContext context = new DiscoveryContext(); - context.setInputParameters(invocation); - VersionedCache endpointsVersionedCache = discoveryTree.discovery(context, - invocation.getAppId(), - invocation.getMicroserviceName(), - invocation.getMicroserviceVersionRule()); - if (endpointsVersionedCache.isEmpty()) { - asyncResp.consumerFail(ExceptionUtils.lbAddressNotFound(invocation.getMicroserviceName(), - invocation.getMicroserviceVersionRule(), - endpointsVersionedCache.name())); - return; - } - - List endpoints = endpointsVersionedCache.data(); - AtomicInteger index = indexMap.computeIfAbsent(endpointsVersionedCache.name(), name -> { - LOGGER.info("Create loadBalancer for {}.", name); - return new AtomicInteger(); - }); - LOGGER.debug("invocation {} use discoveryGroup {}.", - invocation.getMicroserviceQualifiedName(), - endpointsVersionedCache.name()); - - int idx = Math.abs(index.getAndIncrement()); - idx = idx % endpoints.size(); - Endpoint endpoint = endpoints.get(idx); - - invocation.setEndpoint(endpoint); - - invocation.next(asyncResp); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/TransportClientHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/TransportClientHandler.java deleted file mode 100644 index 2213df90373..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/TransportClientHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TransportClientHandler implements Handler { - - private static final Logger log = LoggerFactory.getLogger(TransportClientHandler.class); - - public static final TransportClientHandler INSTANCE = new TransportClientHandler(); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - Transport transport = invocation.getTransport(); - - log.debug( - "Sending request {} to {}", - invocation.getMicroserviceQualifiedName(), - invocation.getEndpoint().getEndpoint()); - - transport.send(invocation, asyncResp); - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/CoreInvocationConfiguration.java b/core/src/main/java/org/apache/servicecomb/core/invocation/CoreInvocationConfiguration.java new file mode 100644 index 00000000000..abfe2f05330 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/CoreInvocationConfiguration.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation; + +import java.util.List; + +import org.apache.servicecomb.core.invocation.timeout.PassingTimeStrategy; +import org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; + +@Configuration +public class CoreInvocationConfiguration { + @Bean + public InvocationTimeoutBootListener scbInvocationTimeoutBootListener(EventBus eventBus, + List strategies, + Environment environment) { + return new InvocationTimeoutBootListener(eventBus, strategies, environment); + } + + @Bean + public PassingTimeStrategy scbPassingTimeStrategy() { + return new PassingTimeStrategy(); + } + + @Bean + public ProcessingTimeStrategy scbProcessingTimeStrategy() { + return new ProcessingTimeStrategy(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationCreator.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationCreator.java new file mode 100644 index 00000000000..323ad924a09 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationCreator.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; + +public interface InvocationCreator { + CompletableFuture createAsync(); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationFactory.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationFactory.java index 8c72f935547..776fdb32568 100644 --- a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationFactory.java +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationFactory.java @@ -17,50 +17,53 @@ package org.apache.servicecomb.core.invocation; -import org.apache.servicecomb.core.Const; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.serviceregistry.RegistryUtils; public final class InvocationFactory { private InvocationFactory() { } - private static String getMicroserviceName() { - return RegistryUtils.getMicroservice().getServiceName(); - } - public static Invocation forConsumer(ReferenceConfig referenceConfig, OperationMeta operationMeta, - Object[] swaggerArguments) { + InvocationRuntimeType invocationRuntimeType, Map swaggerArguments) { Invocation invocation = new Invocation(referenceConfig, operationMeta, + invocationRuntimeType, swaggerArguments); - invocation.addContext(Const.SRC_MICROSERVICE, getMicroserviceName()); + return setSrcMicroservice(invocation); + } + + public static Invocation setSrcMicroservice(Invocation invocation) { + invocation.addContext(CoreConst.SRC_MICROSERVICE, + BootStrapProperties.readServiceName(SCBEngine.getInstance().getEnvironment())); + // TODO: hard code registry name here. This is an old feature not for all registry implementations. + if (addSourceServiceId()) { + invocation.addContext(CoreConst.SRC_SERVICE_ID, + SCBEngine.getInstance().getRegistrationManager().getServiceId("sc-registration")); + } + if (addSourceInstanceId()) { + invocation.addContext(CoreConst.SRC_INSTANCE_ID, + SCBEngine.getInstance().getRegistrationManager().getInstanceId("sc-registration")); + } return invocation; } - /* - * consumer端使用,schemaMeta级别的缓存,每次调用根据operationName来执行 - */ - public static Invocation forConsumer(ReferenceConfig referenceConfig, SchemaMeta schemaMeta, String operationName, - Object[] swaggerArguments) { - OperationMeta operationMeta = schemaMeta.ensureFindOperation(operationName); - return forConsumer(referenceConfig, operationMeta, swaggerArguments); + public static boolean addSourceServiceId() { + return SCBEngine.getInstance().getEnvironment(). + getProperty("servicecomb.context.source.serviceId", boolean.class, true); } - /* - * 为tcc场景提供的快捷方式,consumer端使用 - */ - public static Invocation forConsumer(ReferenceConfig referenceConfig, String operationQualifiedName, - Object[] swaggerArguments) { - MicroserviceMeta microserviceMeta = referenceConfig.getMicroserviceMeta(); - OperationMeta operationMeta = microserviceMeta.ensureFindOperation(operationQualifiedName); - return forConsumer(referenceConfig, operationMeta, swaggerArguments); + public static boolean addSourceInstanceId() { + return SCBEngine.getInstance().getEnvironment(). + getProperty("servicecomb.context.source.instanceId", boolean.class, true); } /* @@ -68,7 +71,7 @@ public static Invocation forConsumer(ReferenceConfig referenceConfig, String ope */ public static Invocation forProvider(Endpoint endpoint, OperationMeta operationMeta, - Object[] swaggerArguments) { + Map swaggerArguments) { SCBEngine.getInstance().ensureStatusUp(); return new Invocation(endpoint, operationMeta, diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java index 27296b29b49..f9d0166a458 100644 --- a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationStageTrace.java @@ -16,341 +16,336 @@ */ package org.apache.servicecomb.core.invocation; +import java.util.HashMap; +import java.util.Map; + import org.apache.servicecomb.core.Invocation; /** *
- * important:
- *   all time point is about invocation stage, not java method
- *   all time is nanoTime
- *   not all stage relate to a event, currently, we only have 4 event:
- *     start/finish/startBusiness/finishBusiness
- *
  * for consumer:
- *         (prepare)                      (handlerReq)                                       (clientFilterReq)
- *   start --------> startHandlersRequest -----------> startClientFiltersRequest --------------------------------------
- *                                                        <----------------(sendRequest)----------------->            |
- *                        (receiveResponse)              (writeToBuffer)                   (getConnection)            |
- *    ---finishReceiveResponse <----- finishWriteToBuffer <----------- finishGetConnection <-------------- startSend <-
- *   | (wakeConsumer)            (clientFiltersResponse)               (handlersResponse)
- *   |-----> startClientFiltersResponse -------> finishClientFiltersResponse -------> finishHandlersResponse --> finish
  *
- * for producer:
- *       (prepare)       (threadPoolQueue)                                (serverFiltersRequest)
- *   start ----> startSchedule -----> startExecution -> startServerFiltersRequest -------> startHandlersRequest -------
- *                          (handlersResponse)          <-------------(business)------------->      (handlersRequest) |
- *   -----finishHandlersResponse <------ finishBusiness <------- finishBusinessMethod <------ startBusinessMethod------
- *   | (serverFiltersResponse)     (sendResponse)
- *   |---> finishServerFiltersResponse ------> finish
+ *  1. total: start create invocation -> all filters finished
+ *  2. prepare: start create invocation -> finish create invocation
+ *  3. filters-(filter-name): start call on filter -> on complete
+ *  4. connection: start get connection -> finish get connection
+ *  5. consumer-encode: start encode request -> finish encode request
+ *  6. consumer-decode: start decode response -> finish decode response
+ *  7. consumer-send: start send request -> finish send request
+ *  8. wait: finish send request -> start decode response
+ *
+ * for provider:
+ *  1. total: start create invocation -> all filters finished
+ *  2. prepare: start create invocation -> finish create invocation
+ *  3. filters-(filter-name): start call on filter -> on complete
+ *  4. queue: add in queue -> execute in thread
+ *  5. provider-decode: start decode request -> finish decode request
+ *  6. provider-encode: start encode response -> finish encode response
+ *  7. provider-send: start send response -> finish send response
+ *  8. execute: start business execute -> finish business execute
  *
  * for edge:
- *      (prepare)         (threadPoolQueue)                               (serverFiltersRequest)
- *   start ----> startSchedule -----> startExecution -> startServerFiltersRequest ----> startHandlersRequest ----------
- *                           <----------(sendRequest)---------->                                                      |
- *                       (writeToBuffer)              (getConnection)  (clientFilterReq)            (handlersRequest) |
- *   --- finishWriteToBuffer <------ finishGetConnection <------ startSend <------ startClientFiltersRequest <---------
- *   | (receiveResponse)     (wakeConsumer)                 (clientFiltersResponse)
- *   ---> finishReceiveResponse ------> startClientFiltersResponse ------> finishClientFiltersResponse ----------------
- *                                   (sendResponse)                  (serverFiltersResponse)       (handlersResponse) |
- *                              finish <------ finishServerFiltersResponse <------ finishHandlersResponse <------------
+ *
+ *  *  1. total: start create invocation -> all filters finished
+ *  *  2. prepare: start create invocation -> finish create invocation
+ *  *  3. filters-(filter-name): start call on filter -> on complete
+ *  *  4. connection: start get connection -> finish get connection
+ *  *  5. provider-decode: start decode request -> finish decode request
+ *  *  6. provider-encode: start encode response -> finish encode response
+ *  *  7. consumer-encode: start encode request -> finish encode request
+ *  *  8. consumer-decode: start decode response -> finish decode response
+ *  *  9. consumer-send: start send request -> finish send request
+ *  *  10. provider-send: start send response -> finish send response
+ *  *  11. wait: finish send request -> start decode response
  *
  * 
*/ public class InvocationStageTrace { - public static final String PREPARE = "prepare"; + public static class Stage { + private long beginTime; - public static final String HANDLERS_REQUEST = "handlers request"; + private long endTime; - public static final String HANDLERS_RESPONSE = "handlers response"; + public long getBeginTime() { + return beginTime; + } - public static final String CLIENT_FILTERS_REQUEST = "client filters request"; + public long getEndTime() { + return endTime; + } + } + + public static final String STAGE_TOTAL = "total"; + + public static final String STAGE_PREPARE = "prepare"; - public static final String CONSUMER_SEND_REQUEST = "send request"; + public static final String STAGE_PROVIDER_QUEUE = "queue"; - public static final String CONSUMER_GET_CONNECTION = "get connection"; + public static final String STAGE_PROVIDER_DECODE_REQUEST = "provider-decode"; - public static final String CONSUMER_WRITE_TO_BUF = "write to buf"; + public static final String STAGE_PROVIDER_ENCODE_RESPONSE = "provider-encode"; - public static final String CONSUMER_WAIT_RESPONSE = "wait response"; + public static final String STAGE_PROVIDER_SEND = "provider-send"; - public static final String CONSUMER_WAKE_CONSUMER = "wake consumer"; + public static final String STAGE_PROVIDER_BUSINESS = "execute"; - public static final String CLIENT_FILTERS_RESPONSE = "client filters response"; + public static final String STAGE_CONSUMER_CONNECTION = "connection"; - public static final String THREAD_POOL_QUEUE = "threadPoolQueue"; + public static final String STAGE_CONSUMER_ENCODE_REQUEST = "consumer-encode"; - public static final String SERVER_FILTERS_REQUEST = "server filters request"; + public static final String STAGE_CONSUMER_DECODE_RESPONSE = "consumer-decode"; - public static final String SERVER_FILTERS_RESPONSE = "server filters response"; + public static final String STAGE_CONSUMER_SEND = "consumer-send"; - public static final String PRODUCER_SEND_RESPONSE = "send response"; + public static final String STAGE_CONSUMER_WAIT = "wait"; - private Invocation invocation; + private final Invocation invocation; + // invocation start time in millis, for passing strategy use only + private long startInMillis; + + // invocation start time in nanos, for passing strategy use only private long start; - private long startHandlersRequest; + private long finish; - private long startClientFiltersRequest; + private long startCreateInvocation; - // only for consumer - private long startSend; + private long finishCreateInvocation; - // only for consumer - private long finishGetConnection; + private long startProviderQueue; - // only for consumer - private long finishWriteToBuffer; + private long finishProviderQueue; - // only for consumer - private long finishReceiveResponse; + private long startConsumerConnection; - private long startClientFiltersResponse; + private long finishConsumerConnection; - private long finishClientFiltersResponse; + private long startProviderDecodeRequest; - private long finishHandlersResponse; + private long finishProviderDecodeRequest; - private long finish; + private long startProviderEncodeResponse; - // only for producer: put producer task to thread pool - private long startSchedule; + private long finishProviderEncodeResponse; - private long startServerFiltersRequest; + private long startConsumerEncodeRequest; - private long finishServerFiltersResponse; + private long finishConsumerEncodeRequest; - // only for producer: start execute in work thread - // for reactive mode, work thread is eventloop - private long startExecution; + private long startConsumerDecodeResponse; - // only for producer - private long startBusinessMethod; + private long finishConsumerDecodeResponse; - // only for producer - private long finishBusiness; + private long startProviderSendResponse; - public InvocationStageTrace(Invocation invocation) { - this.invocation = invocation; - } + private long finishProviderSendResponse; - public void start(long start) { - this.start = start; - } + private long startConsumerSendRequest; - public long getStart() { - return start; - } + private long finishConsumerSendRequest; - public long getStartHandlersRequest() { - return startHandlersRequest; - } + private long startBusinessExecute; - public void startHandlersRequest() { - this.startHandlersRequest = System.nanoTime(); - } + private long finishBusinessExecute; - public long getStartClientFiltersRequest() { - return startClientFiltersRequest; - } + private long startWaitResponse; - public void startClientFiltersRequest() { - this.startClientFiltersRequest = System.nanoTime(); - } + private long finishWaitResponse; - public long getStartSchedule() { - return startSchedule; - } + // invocation stage can not be used in concurrent access + private final Map stages = new HashMap<>(); - public void startSchedule() { - this.startSchedule = System.nanoTime(); + public InvocationStageTrace(Invocation invocation) { + this.invocation = invocation; } - public long getStartExecution() { - return startExecution; + public String recordStageBegin(String stageName) { + String realStageName = stageName; + while (stages.get(realStageName) != null) { + realStageName = realStageName + "@"; + } + Stage stage = new Stage(); + stage.beginTime = System.nanoTime(); + stages.put(realStageName, stage); + return realStageName; } - public void startExecution() { - this.startExecution = System.nanoTime(); + public void recordStageEnd(String realStageName) { + Stage stage = stages.get(realStageName); + stage.endTime = nanoTime(); } - public long getStartSend() { - return startSend; + public Map getStages() { + return stages; } - public void startSend() { - this.startSend = System.nanoTime(); + public void finish() { + this.finish = nanoTime(); } - public long getFinishGetConnection() { - return finishGetConnection; + public void startCreateInvocation(long nano) { + this.startCreateInvocation = nano; + this.startInMillis = millisTime(); + this.start = nanoTime(); } - public void finishGetConnection(long finishGetConnection) { - this.finishGetConnection = finishGetConnection; + public void finishCreateInvocation() { + this.finishCreateInvocation = nanoTime(); } - public long getFinishWriteToBuffer() { - return finishWriteToBuffer; + public long calcPrepare() { + return calc(finishCreateInvocation, startCreateInvocation); } - public void finishWriteToBuffer(long finishWriteToBuffer) { - this.finishWriteToBuffer = finishWriteToBuffer; + public void startProviderQueue() { + this.startProviderQueue = nanoTime(); } - public long getFinishReceiveResponse() { - return finishReceiveResponse; + public void finishProviderQueue() { + this.finishProviderQueue = nanoTime(); } - public void finishReceiveResponse() { - this.finishReceiveResponse = System.nanoTime(); + public long calcQueue() { + return calc(finishProviderQueue, startProviderQueue); } - public long getStartClientFiltersResponse() { - return startClientFiltersResponse; + public void startProviderDecodeRequest() { + this.startProviderDecodeRequest = nanoTime(); } - public void startClientFiltersResponse() { - this.startClientFiltersResponse = System.nanoTime(); + public void finishProviderDecodeRequest() { + this.finishProviderDecodeRequest = nanoTime(); } - public long getFinishClientFiltersResponse() { - return finishClientFiltersResponse; + public long calcProviderDecodeRequest() { + return calc(finishProviderDecodeRequest, startProviderDecodeRequest); } - public void finishClientFiltersResponse() { - this.finishClientFiltersResponse = System.nanoTime(); + public void startProviderEncodeResponse() { + this.startProviderEncodeResponse = nanoTime(); } - public long getFinishHandlersResponse() { - return finishHandlersResponse; + public void finishProviderEncodeResponse() { + this.finishProviderEncodeResponse = nanoTime(); } - public void finishHandlersResponse() { - this.finishHandlersResponse = System.nanoTime(); + public long calcProviderEncodeResponse() { + return calc(finishProviderEncodeResponse, startProviderEncodeResponse); } - public long getStartServerFiltersRequest() { - return startServerFiltersRequest; + public void startConsumerEncodeRequest() { + this.startConsumerEncodeRequest = nanoTime(); } - public void startServerFiltersRequest() { - this.startServerFiltersRequest = System.nanoTime(); + public void finishConsumerEncodeRequest() { + this.finishConsumerEncodeRequest = nanoTime(); } - public long getFinishServerFiltersResponse() { - return finishServerFiltersResponse; + public long calcConsumerEncodeRequest() { + return calc(finishConsumerEncodeRequest, startConsumerEncodeRequest); } - public void finishServerFiltersResponse() { - this.finishServerFiltersResponse = System.nanoTime(); + public void startConsumerDecodeResponse() { + this.startConsumerDecodeResponse = nanoTime(); } - public long getStartBusinessMethod() { - return startBusinessMethod; + public void finishConsumerDecodeResponse() { + this.finishConsumerDecodeResponse = nanoTime(); } - public void startBusinessMethod() { - this.startBusinessMethod = System.nanoTime(); + public long calcConsumerDecodeResponse() { + return calc(finishConsumerDecodeResponse, startConsumerDecodeResponse); } - public long getFinishBusiness() { - return finishBusiness; + public void startProviderSendResponse() { + this.startProviderSendResponse = nanoTime(); } - public void finishBusiness() { - this.finishBusiness = System.nanoTime(); + public void finishProviderSendResponse() { + this.finishProviderSendResponse = nanoTime(); } - public long getFinish() { - return finish; + public long calcProviderSendResponse() { + return calc(finishProviderSendResponse, startProviderSendResponse); } - public void finish() { - this.finish = System.nanoTime(); + public void startBusinessExecute() { + this.startBusinessExecute = nanoTime(); } - private double calc(long finish, long start) { - if (finish == 0 || start == 0) { - return Double.NaN; - } - - return finish - start; + public void finishBusinessExecute() { + this.finishBusinessExecute = nanoTime(); } - public double calcTotalTime() { - return calc(finish, start); + public long calcBusinessExecute() { + return calc(finishBusinessExecute, startBusinessExecute); } - public double calcInvocationPrepareTime() { - if (invocation.isConsumer() && !invocation.isEdge()) { - return calc(startHandlersRequest, start); - } - - return calc(startSchedule, start); + public void startConsumerConnection() { + this.startConsumerConnection = nanoTime(); } - public double calcHandlersRequestTime() { - if (invocation.isConsumer()) { - return calc(startClientFiltersRequest, startHandlersRequest); - } + public void finishConsumerConnection() { + this.finishConsumerConnection = nanoTime(); + } - return calc(startBusinessMethod, startHandlersRequest); + public long calcConnection() { + return calc(finishConsumerConnection, startConsumerConnection); } - public double calcClientFiltersRequestTime() { - return calc(startSend, startClientFiltersRequest); + public void startConsumerSendRequest() { + this.startConsumerSendRequest = nanoTime(); } - public double calcServerFiltersRequestTime() { - return calc(startHandlersRequest, startServerFiltersRequest); + public void finishConsumerSendRequest() { + this.finishConsumerSendRequest = nanoTime(); } - public double calcSendRequestTime() { - return calc(finishWriteToBuffer, startSend); + public long calcConsumerSendRequest() { + return calc(finishConsumerSendRequest, startConsumerSendRequest); } - public double calcGetConnectionTime() { - return calc(finishGetConnection, startSend); + public void startWaitResponse() { + this.startWaitResponse = nanoTime(); } - public double calcWriteToBufferTime() { - return calc(finishWriteToBuffer, finishGetConnection); + public void finishWaitResponse() { + this.finishWaitResponse = nanoTime(); } - public double calcReceiveResponseTime() { - return calc(finishReceiveResponse, finishWriteToBuffer); + public long calcWait() { + return calc(finishWaitResponse, startWaitResponse); } - public double calcWakeConsumer() { - return calc(startClientFiltersResponse, finishReceiveResponse); + public long calcTotal() { + return calc(finish, this.startCreateInvocation); } - public double calcClientFiltersResponseTime() { - return calc(finishClientFiltersResponse, startClientFiltersResponse); + public long getStartInMillis() { + return this.startInMillis; } - public double calcServerFiltersResponseTime() { - return calc(finishServerFiltersResponse, finishHandlersResponse); + public long getStart() { + return this.start; } - public double calcHandlersResponseTime() { - if (invocation.isConsumer()) { - return calc(finishHandlersResponse, finishClientFiltersResponse); + public static long calc(long finish, long start) { + if (finish == 0 || start == 0) { + return 0; } - return calc(finishHandlersResponse, finishBusiness); - } - - public double calcThreadPoolQueueTime() { - return calc(startExecution, startSchedule); + return finish - start; } - public double calcBusinessTime() { - return calc(finishBusiness, startBusinessMethod); + /* + * Holder for testing purpose + */ + protected long nanoTime() { + return System.nanoTime(); } - public double calcSendResponseTime() { - return calc(finish, finishServerFiltersResponse); + protected long millisTime() { + return System.currentTimeMillis(); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java new file mode 100644 index 00000000000..6a5e929a8bd --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutBootListener.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation; + +import java.util.List; + +import org.apache.servicecomb.core.event.InvocationBusinessFinishEvent; +import org.apache.servicecomb.core.event.InvocationBusinessMethodStartEvent; +import org.apache.servicecomb.core.event.InvocationStartEvent; +import org.apache.servicecomb.core.event.InvocationStartSendRequestEvent; +import org.apache.servicecomb.core.event.InvocationTimeoutCheckEvent; +import org.apache.servicecomb.core.invocation.timeout.PassingTimeStrategy; +import org.apache.servicecomb.foundation.common.event.EnableExceptionPropagation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +@SuppressWarnings({"unused"}) +public final class InvocationTimeoutBootListener { + private static final Logger LOGGER = LoggerFactory.getLogger(InvocationTimeoutBootListener.class); + + public static final String PREFIX = "servicecomb.invocation.timeout.check"; + + public static final String STRATEGY = PREFIX + ".strategy"; + + public static final String ENABLED = PREFIX + ".enabled"; + + private final InvocationTimeoutStrategy strategy; + + public InvocationTimeoutBootListener(EventBus eventBus, List strategies, + Environment environment) { + if (!environment.getProperty(ENABLED, boolean.class, false)) { + strategy = null; + return; + } + + String strategyName = environment.getProperty(STRATEGY, PassingTimeStrategy.NAME); + // if strategyName is wrong, then just throw exception + strategy = strategies.stream() + .filter(invocationTimeoutStrategy -> strategyName.equals(invocationTimeoutStrategy.name())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("can not find InvocationTimeoutStrategy, name=" + strategyName)); + eventBus.register(this); + } + + @Subscribe + @EnableExceptionPropagation + public void onInvocationTimeoutCheckEvent(InvocationTimeoutCheckEvent event) { + strategy.checkTimeout(event.getInvocation()); + } + + @Subscribe + public void onInvocationStartEvent(InvocationStartEvent event) { + strategy.start(event.getInvocation()); + } + + @Subscribe + @EnableExceptionPropagation + public void onInvocationBusinessMethodStartEvent(InvocationBusinessMethodStartEvent event) { + strategy.startBusinessMethod(event.getInvocation()); + } + + @Subscribe + @EnableExceptionPropagation + public void onInvocationBusinessFinishEvent(InvocationBusinessFinishEvent event) { + strategy.finishBusinessMethod(event.getInvocation()); + } + + @Subscribe + @EnableExceptionPropagation + public void onInvocationStartSendRequestEvent(InvocationStartSendRequestEvent event) { + strategy.beforeSendRequest(event.getInvocation()); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java new file mode 100644 index 00000000000..c530acfca29 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/InvocationTimeoutStrategy.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation; + +import static jakarta.ws.rs.core.Response.Status.REQUEST_TIMEOUT; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionCodes; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +public interface InvocationTimeoutStrategy { + // indicate whether invocation already timeout inside a process + // null is not timeout + // other value is timeout + String CHAIN_ALREADY_TIMED_OUT = "x-scb-chain-timed-out"; + + String name(); + + void start(Invocation invocation); + + default void startRunInExecutor(Invocation invocation) { + checkTimeout(invocation); + } + + default void startBusinessMethod(Invocation invocation) { + checkTimeout(invocation); + } + + default void finishBusinessMethod(Invocation invocation) { + checkTimeout(invocation); + } + + default void beforeSendRequest(Invocation invocation) { + checkTimeout(invocation); + } + + default void checkTimeout(Invocation invocation) { + long nanoInvocationTimeout = invocation.getOperationMeta().getConfig().getNanoInvocationTimeout(); + if (nanoInvocationTimeout <= 0 || alreadyTimeout(invocation)) { + return; + } + + long nanoTime = calculateElapsedNanoTime(invocation); + if (nanoTime <= nanoInvocationTimeout) { + return; + } + + invocation.addLocalContext(CHAIN_ALREADY_TIMED_OUT, true); + throw new InvocationException(REQUEST_TIMEOUT, ExceptionCodes.INVOCATION_TIMEOUT, "Invocation Timeout."); + } + + default boolean alreadyTimeout(Invocation invocation) { + return invocation.getLocalContext(CHAIN_ALREADY_TIMED_OUT) != null; + } + + long calculateElapsedNanoTime(Invocation invocation); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlow.java b/core/src/main/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlow.java new file mode 100644 index 00000000000..ec589f37733 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlow.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.Response.Status; + +public abstract class ProducerInvocationFlow { + private static final Logger LOGGER = LoggerFactory.getLogger(ProducerInvocationFlow.class); + + private final long startTime = System.nanoTime(); + + private final InvocationCreator invocationCreator; + + protected final HttpServletRequestEx requestEx; + + protected final HttpServletResponseEx responseEx; + + public ProducerInvocationFlow(InvocationCreator invocationCreator) { + this(invocationCreator, null, null); + } + + public ProducerInvocationFlow(InvocationCreator invocationCreator, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + this.invocationCreator = invocationCreator; + this.requestEx = requestEx; + this.responseEx = responseEx; + } + + public void run() { + CompletableFuture.completedFuture(null) + .thenCompose(v -> invocationCreator.createAsync()) + .exceptionally(this::sendCreateInvocationException) + .thenAccept(this::tryRunInvocation); + } + + private void tryRunInvocation(Invocation invocation) { + if (invocation == null) { + return; + } + invocation.getInvocationStageTrace().startCreateInvocation(this.startTime); + invocation.getInvocationStageTrace().finishCreateInvocation(); + invocation.onStart(requestEx); + if (invocation.isEdge()) { + invocation.getMicroserviceMeta().getEdgeFilterChain() + .onFilter(invocation) + .whenComplete((response, throwable) -> { + if (throwable != null) { + // Server codec operates on Response. So the filter chain result should be Response and + // will never throw exception. + // Sometimes Server Codec will throw exception, e.g. Connection Closed. + LOGGER.error("Maybe a fatal bug that should be addressed or codec exception for {}.", + invocation.getInvocationQualifiedName(), throwable); + response = Response.createFail(new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData("Internal error, check logs for details."))); + } + endResponse(invocation, response); + finishInvocation(invocation, response); + }); + return; + } + invocation.getMicroserviceMeta().getProviderFilterChain() + .onFilter(invocation) + .whenComplete((response, throwable) -> { + if (throwable != null) { + // Server codec operates on Response. So the filter chain result should be Response and + // will never throw exception. + // Sometimes Server Codec will throw exception, e.g. Connection Closed. + LOGGER.error("Maybe a fatal bug that should be addressed or codec exception for {}.", + invocation.getInvocationQualifiedName(), throwable); + response = Response.createFail(new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData("Internal error, check logs for details."))); + } + endResponse(invocation, response); + finishInvocation(invocation, response); + }); + } + + private void finishInvocation(Invocation invocation, Response response) { + invocation.onFinish(response); + } + + protected abstract Invocation sendCreateInvocationException(Throwable throwable); + + protected abstract void endResponse(Invocation invocation, Response response); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointCacheUtils.java b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointCacheUtils.java new file mode 100644 index 00000000000..141a6e9063b --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointCacheUtils.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.endpoint; + +import org.apache.servicecomb.core.Endpoint; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +public final class EndpointCacheUtils { + private static final LoadingCache CACHE = CacheBuilder.newBuilder() + .maximumSize(10000) + .build(new CacheLoader() { + @Override + public Endpoint load(String uri) { + return EndpointCacheUtils.create(uri); + } + }); + + /** + * @param uri https://www.abc.com:12345 + * @return endpoint + */ + public static Endpoint getOrCreate(String uri) { + return CACHE.getUnchecked(uri); + } + + public static Endpoint create(String uri) { + return EndpointUtils.parse(EndpointUtils.formatFromUri(uri)); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointContextRegister.java b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointContextRegister.java new file mode 100644 index 00000000000..ff0da7e2398 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointContextRegister.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation.endpoint; + +import java.lang.reflect.Type; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.swagger.generator.SwaggerContextRegister; + +public class EndpointContextRegister implements SwaggerContextRegister { + @Override + public Type getContextType() { + return Endpoint.class; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapper.java b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapper.java new file mode 100644 index 00000000000..a792b9ccd9f --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapper.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation.endpoint; + +import java.util.Map; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentMapper; + +public class EndpointMapper extends ConsumerArgumentMapper { + private final String invocationArgumentName; + + public EndpointMapper(String invocationArgumentName) { + this.invocationArgumentName = invocationArgumentName; + } + + @Override + public void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, Map invocationArguments) { + Invocation invocation = (Invocation) swaggerInvocation; + invocation.setEndpoint((Endpoint) invocationArguments.get(invocationArgumentName)); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapperFactory.java b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapperFactory.java new file mode 100644 index 00000000000..ab1cebd11e7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointMapperFactory.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation.endpoint; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory; + +public class EndpointMapperFactory implements ConsumerContextArgumentMapperFactory { + @Override + public Class getContextClass() { + return Endpoint.class; + } + + @Override + public ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName) { + return new EndpointMapper(invocationArgumentName); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtils.java b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtils.java new file mode 100644 index 00000000000..2d8b37c997a --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtils.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.invocation.endpoint; + +import static com.google.common.collect.ImmutableMap.of; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; + +import org.apache.http.client.utils.URIBuilder; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.exception.Exceptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class EndpointUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(EndpointUtils.class); + + private static final String HTTP = "http"; + + private static final String HTTPS = "https"; + + private static final String H2C = "h2c"; + + private static final String H2 = "h2"; + + private static final String HTTP2 = "http2"; + + private static final int DEFAULT_HTTP_PORT = 80; + + private static final int DEFAULT_HTTPS_PORT = 443; + + private static class SchemeMeta { + String protocol; + + boolean ssl; + + int defaultPort; + + public SchemeMeta(String protocol, boolean ssl, int defaultPort) { + this.protocol = protocol; + this.ssl = ssl; + this.defaultPort = defaultPort; + } + } + + private static final Map SCHEME_META_MAP = of( + HTTP, new SchemeMeta(null, false, DEFAULT_HTTP_PORT), + HTTPS, new SchemeMeta(null, true, DEFAULT_HTTPS_PORT), + H2C, new SchemeMeta(HTTP2, false, DEFAULT_HTTP_PORT), + H2, new SchemeMeta(HTTP2, true, DEFAULT_HTTPS_PORT) + ); + + private EndpointUtils() { + } + + /** + * + * @param uriEndpoint eg: rest://xxx?sslEnabled=true + * @return Endpoint object + */ + public static Endpoint parse(String uriEndpoint) { + URI uri = URI.create(uriEndpoint); + Transport transport = SCBEngine.getInstance().getTransportManager().findTransport(uri.getScheme()); + if (transport == null) { + LOGGER.error("not deployed transport, uri={}.", uriEndpoint); + throw Exceptions.genericConsumer("the endpoint's transport is not found."); + } + + return new Endpoint(transport, uriEndpoint); + } + + /** + * {@code + * http://xxx -> rest://xxx + * https://xxx -> rest://xxx?sslEnabled=true + * + * h2c://xxx -> rest://xxx?protocol=http2 + * h2://xxx -> rest://xxx?sslEnabled=true&protocol=http2 + * + * xxx -> rest://xxx:port?protocol=http2 + * xxx?a=a1 -> rest://xxx:port?a=a1&protocol=http2 + * other://xxx -> other://xxx + * } + * + * This method provided for convenience of handling user input endpoints, and do not have a strict meaning. Make sure all unit test cases + * work before change. + **/ + public static String formatFromUri(String inputUri) { + try { + return doFormatFromUri(inputUri); + } catch (URISyntaxException e) { + throw new IllegalStateException("failed to convert uri to endpoint.", e); + } + } + + private static String doFormatFromUri(String inputUri) throws URISyntaxException { + URIBuilder builder = new URIBuilder(inputUri); + if (builder.getScheme() == null) { + builder.setScheme(H2C); + builder.setHost(extractHostFromPath(builder)); + builder.setPath(null); + } + + SchemeMeta schemeMeta = SCHEME_META_MAP.get(builder.getScheme()); + if (schemeMeta == null) { + return inputUri; + } + + return format(builder, schemeMeta); + } + + private static String extractHostFromPath(URIBuilder builder) { + String path = builder.getPath(); + if (path == null) { + return null; + } + if (path.startsWith("/")) { + path = path.substring(1); + } + if (path.contains("/")) { + path = path.substring(0, path.indexOf("/")); + } + return path; + } + + private static String format(URIBuilder builder, SchemeMeta schemeMeta) throws URISyntaxException { + if (schemeMeta.ssl) { + builder.addParameter("sslEnabled", "true"); + } + if (schemeMeta.protocol != null) { + builder.addParameter("protocol", schemeMeta.protocol); + } + if (builder.getPort() == -1) { + builder.setPort(schemeMeta.defaultPort); + } + + return builder.setScheme("rest").build().toString(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java new file mode 100644 index 00000000000..6d55c7a7f51 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategy.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.timeout; + +import java.time.Clock; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.invocation.InvocationTimeoutStrategy; + +/** + *
+ * based on time synchronization
+ * any time to calculate timeout: now - start time of invocation chain
+ *
+ * consumer: c
+ * producer: p
+ * ---------------------------------------------------------------
+ * | process 2                                                   |
+ * |                 c-send(T5)                       c-send(T8) |
+ * |                    ↑                               ↑      |
+ * | p-start(T3) → c-start(T4) → p-operation(T6) → c-start(T7)|
+ * -----↑--------------------------------------------------------
+ *      ↑
+ * -----↑-----------------
+ * |    ↑     process 1  |
+ * |  c-send(T2)          |
+ * |    ↑                |
+ * |  c-start(T1)         |
+ * ------------------------
+ *
+ * T2 timeout: T2 - T1
+ * T3 timeout: T3 - T1
+ * T4 timeout: T4 - T1
+ * ......
+ * 
+ */ +public class PassingTimeStrategy implements InvocationTimeoutStrategy { + public static final String NAME = "passing-time"; + + // milliseconds + // depend on time synchronization + // transfer between processes + public static final String CHAIN_START_TIME = "x-scb-chain-start"; + + private Clock clock = Clock.systemDefaultZone(); + + public PassingTimeStrategy setClock(Clock clock) { + this.clock = clock; + return this; + } + + @Override + public String name() { + return NAME; + } + + @Override + public void start(Invocation invocation) { + if (invocation.getLocalContext(CHAIN_START_TIME) != null) { + return; + } + + long startTimeMillis = invocation.getInvocationStageTrace().getStartInMillis(); + String contextChainStartTime = invocation.getContext(CHAIN_START_TIME); + if (StringUtils.isEmpty(contextChainStartTime)) { + invocation.addContext(CHAIN_START_TIME, String.valueOf(startTimeMillis)); + invocation.addLocalContext(CHAIN_START_TIME, startTimeMillis); + return; + } + + long chainStartTime = NumberUtils.toLong(contextChainStartTime, startTimeMillis); + invocation.addLocalContext(CHAIN_START_TIME, chainStartTime); + } + + @Override + public long calculateElapsedNanoTime(Invocation invocation) { + long passingTimeMillis = clock.millis() - invocation.getLocalContext(CHAIN_START_TIME); + return TimeUnit.MILLISECONDS.toNanos(passingTimeMillis); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java new file mode 100644 index 00000000000..4c2c021a42b --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategy.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.timeout; + +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.invocation.InvocationTimeoutStrategy; + +import com.google.common.base.Ticker; + +/** + *
+ * Cumulative Processing Time
+ * not depend on time synchronization
+ * but lost network and framework outside of servicecomb processing time
+ *
+ * consumer: c
+ * producer: p
+ * ---------------------------------------------------------------
+ * | process 2                                                   |
+ * |                 c-send(T5)                       c-send(T8) |
+ * |                    ↑                               ↑      |
+ * | p-start(T3) → c-start(T4) → p-operation(T6) → c-start(T7)|
+ * -----↑--------------------------------------------------------
+ *      ↑
+ * -----↑-----------------
+ * |    ↑     process 1  |
+ * |  c-send(T2)          |
+ * |    ↑                |
+ * |  c-start(T1)         |
+ * ------------------------
+ *
+ * T2 timeout: T2 - T1
+ * T3 timeout: (T2 - T1) + (T3 - T3)
+ * T4 timeout: (T2 - T1) + (T4 - T3)
+ * T5 timeout: (T2 - T1) + (T5 - T3)
+ * T6 timeout: (T2 - T1) + (T6 - T3)
+ * T7 timeout: (T2 - T1) + (T7 - T3)
+ * T8 timeout: (T2 - T1) + (T8 - T3)
+ * ......
+ * 
+ */ +public class ProcessingTimeStrategy implements InvocationTimeoutStrategy { + public static final String NAME = "processing-time"; + + // nanoseconds + // used inside one process + // not depend on time synchronization + public static final String CHAIN_START_TIME = "x-scb-process-chain-start"; + + // nanoseconds + // processing time of all previous process + // transfer between processes + public static final String CHAIN_PROCESSING = "x-scb-processing-time"; + + private Ticker ticker = Ticker.systemTicker(); + + public ProcessingTimeStrategy setTicker(Ticker ticker) { + this.ticker = ticker; + return this; + } + + @Override + public String name() { + return NAME; + } + + @Override + public void start(Invocation invocation) { + initProcessChainStart(invocation); + initChainProcessing(invocation); + } + + private void initProcessChainStart(Invocation invocation) { + if (invocation.getLocalContext(CHAIN_START_TIME) != null) { + return; + } + + invocation.addLocalContext(CHAIN_START_TIME, invocation.getInvocationStageTrace().getStart()); + } + + private void initChainProcessing(Invocation invocation) { + if (invocation.getLocalContext(CHAIN_PROCESSING) != null) { + return; + } + + String contextChainProcessing = invocation.getContext(CHAIN_PROCESSING); + long chainProcessingTime = NumberUtils.toLong(contextChainProcessing, 0L); + invocation.addLocalContext(CHAIN_PROCESSING, chainProcessingTime); + } + + @Override + public void beforeSendRequest(Invocation invocation) { + InvocationTimeoutStrategy.super.beforeSendRequest(invocation); + + long processingTime = calculateElapsedNanoTime(invocation); + invocation.addContext(CHAIN_PROCESSING, Long.toString(processingTime)); + } + + @Override + public long calculateElapsedNanoTime(Invocation invocation) { + long chainStartTime = invocation.getLocalContext(CHAIN_START_TIME); + long previousProcessingTime = invocation.getLocalContext(CHAIN_PROCESSING); + return ticker.read() - chainStartTime + previousProcessingTime; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/LocalOpenAPIRegistry.java b/core/src/main/java/org/apache/servicecomb/core/provider/LocalOpenAPIRegistry.java new file mode 100644 index 00000000000..14a27530c92 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/LocalOpenAPIRegistry.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider; + +import java.util.Collections; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager.OpenAPIChangeListener; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * register and load OpenAPI from local file store or memory + */ +public class LocalOpenAPIRegistry implements OpenAPIRegistry { + private static final Logger LOGGER = LoggerFactory.getLogger(LocalOpenAPIRegistry.class); + + // first key : appId + // second key: microservice short name + // third key : schemaId + private final Map>> apps = new ConcurrentHashMapEx<>(); + + private final Environment environment; + + private OpenAPIChangeListener openAPIChangeListener; + + public LocalOpenAPIRegistry(Environment environment) { + this.environment = environment; + } + + @Override + public boolean enabled() { + return true; + } + + @Override + public void registerOpenAPI(String application, String serviceName, String schemaId, OpenAPI api) { + apps.computeIfAbsent(application, k -> new ConcurrentHashMapEx<>()) + .computeIfAbsent(serviceName, k -> new ConcurrentHashMapEx<>()) + .put(schemaId, api); + openAPIChangeListener.onOpenAPIChanged(application, serviceName); + LOGGER.info("register swagger appId={}, name={}, schemaId={}.", + application, serviceName, schemaId); + } + + /** + * Method for retrieve myself schema contents. + */ + public Map loadOpenAPI() { + return loadOpenAPI(BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment)); + } + + @Override + public Map loadOpenAPI(String application, String serviceName) { + if (apps.get(application) != null && apps.get(application).get(serviceName) != null) { + return apps.get(application).get(serviceName); + } + return Collections.emptyMap(); + } + + @Override + public void setOpenAPIChangeListener(OpenAPIChangeListener listener) { + this.openAPIChangeListener = listener; + } + + @Override + public int getOrder() { + return -10000; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistry.java b/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistry.java new file mode 100644 index 00000000000..440c297d7ae --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistry.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider; + +import java.util.Map; + +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager.OpenAPIChangeListener; +import org.springframework.core.Ordered; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * Register and load OpenAPI extensions. + */ +public interface OpenAPIRegistry extends Ordered { + String CONFIG_PREFIX = "servicecomb.openAPI.registry"; + + boolean enabled(); + + void registerOpenAPI(String application, String serviceName, String schemaId, OpenAPI api); + + Map loadOpenAPI(String application, String serviceName); + + void setOpenAPIChangeListener(OpenAPIChangeListener listener); +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistryManager.java b/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistryManager.java new file mode 100644 index 00000000000..c357e6a24ae --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/OpenAPIRegistryManager.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FilenameUtils; +import org.apache.servicecomb.foundation.common.utils.ResourceUtil; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * Register and load OpenAPI from various OpenAPIRegistry + */ +public class OpenAPIRegistryManager { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIRegistryManager.class); + + public interface OpenAPIChangeListener { + void onOpenAPIChanged(String application, String serviceName); + } + + private List openAPIRegistries; + + private final List changeListeners = new ArrayList<>(); + + @Autowired + public void setOpenAPIRegistries(List openAPIRegistries) { + List target = new ArrayList<>(openAPIRegistries.size()); + for (OpenAPIRegistry registry : openAPIRegistries) { + if (registry.enabled()) { + registry.setOpenAPIChangeListener(this::onOpenAPIChanged); + target.add(registry); + } + } + this.openAPIRegistries = target; + } + + public void addOpenAPIChangeListener(OpenAPIChangeListener changeListener) { + this.changeListeners.add(changeListener); + } + + public void onOpenAPIChanged(String application, String serviceName) { + for (OpenAPIChangeListener listener : this.changeListeners) { + try { + listener.onOpenAPIChanged(application, serviceName); + } catch (Exception e) { + LOGGER.warn("event process error {}/{}, {}", application, serviceName, e.getMessage()); + } + } + } + + public void registerOpenAPI(String application, String serviceName, String schemaId, OpenAPI api) { + for (OpenAPIRegistry registry : this.openAPIRegistries) { + registry.registerOpenAPI(application, serviceName, schemaId, api); + } + } + + public void registerOpenAPI(String application, String serviceName, String schemaId, Class cls) { + OpenAPI api = SwaggerGenerator.generate(cls); + registerOpenAPI(application, serviceName, schemaId, api); + } + + public void registerOpenAPIInLocation(String application, String serviceName, String swaggersLocation) { + try { + List resourceUris = ResourceUtil.findResourcesBySuffix(swaggersLocation, ".yaml"); + if (resourceUris.isEmpty()) { + return; + } + for (URI uri : resourceUris) { + URL url = uri.toURL(); + OpenAPI swagger = SwaggerUtils.parseAndValidateSwagger(url); + String schemaId = FilenameUtils.getBaseName(url.getPath()); + registerOpenAPI(application, serviceName, schemaId, swagger); + } + } catch (Throwable e) { + throw new IllegalStateException(String.format( + "failed to register swaggers, microserviceName=%s, location=%s.", + serviceName, swaggersLocation), e); + } + } + + public Map loadOpenAPI(String appId, String microserviceName) { + for (OpenAPIRegistry registry : this.openAPIRegistries) { + Map result = registry.loadOpenAPI(appId, microserviceName); + if (!CollectionUtils.isEmpty(result)) { + return result; + } + } + return Collections.emptyMap(); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/RegistryOpenAPIRegistry.java b/core/src/main/java/org/apache/servicecomb/core/provider/RegistryOpenAPIRegistry.java new file mode 100644 index 00000000000..cc5e6fe22dd --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/RegistryOpenAPIRegistry.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager.OpenAPIChangeListener; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.router.util.VersionCompareUtil; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import io.swagger.v3.oas.models.OpenAPI; +import jakarta.ws.rs.core.Response.Status; + +/** + * register and load OpenAPI from registration and discovery registry. + */ +public class RegistryOpenAPIRegistry implements OpenAPIRegistry { + private DiscoveryManager discoveryManager; + + private Environment environment; + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + + @Override + public boolean enabled() { + return environment.getProperty(OpenAPIRegistry.CONFIG_PREFIX + ".registry.enabled", boolean.class, false); + } + + @Override + public void registerOpenAPI(String application, String serviceName, String schemaId, OpenAPI api) { + // do noting + } + + @Override + public Map loadOpenAPI(String application, String serviceName) { + List discoveryInstances = + discoveryManager.findServiceInstances(application, serviceName); + if (discoveryInstances.isEmpty()) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "no instances"); + } + discoveryInstances.sort((a, b) -> VersionCompareUtil.compareVersion(b.getVersion(), a.getVersion())); + + Map result = new HashMap<>(); + String version = null; + for (DiscoveryInstance instance : discoveryInstances) { + if (version != null && !version.equals(instance.getVersion())) { + break; + } + version = instance.getVersion(); + instance.getSchemas().forEach((k, v) -> result.computeIfAbsent(k, (key) -> SwaggerUtils.parseSwagger(v))); + } + return result; + } + + @Override + public void setOpenAPIChangeListener(OpenAPIChangeListener listener) { + this.discoveryManager.addInstanceChangeListener( + (registryName, application, serviceName, instances) -> { + if (CollectionUtils.isEmpty(instances)) { + return; + } + listener.onOpenAPIChanged(application, serviceName); + }); + } + + @Override + public int getOrder() { + return -8000; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/AbstractConsumerProvider.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/AbstractConsumerProvider.java deleted file mode 100644 index 2c7b2ffc35c..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/AbstractConsumerProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.provider.consumer; - -import org.apache.servicecomb.core.ConsumerProvider; - -public abstract class AbstractConsumerProvider implements ConsumerProvider { - - @Override - public void init() throws Exception { - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ConsumerProviderManager.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ConsumerProviderManager.java index dee80d3ded3..615063bd3b4 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ConsumerProviderManager.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ConsumerProviderManager.java @@ -17,85 +17,70 @@ package org.apache.servicecomb.core.provider.consumer; -import java.util.Collections; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.List; -import java.util.Map; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.ConsumerProvider; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager; +import org.apache.servicecomb.foundation.common.utils.ResourceUtil; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; -import com.netflix.config.DynamicPropertyFactory; - -@Component public class ConsumerProviderManager { - @Autowired(required = false) - private List consumerProviderList = Collections.emptyList(); + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerProviderManager.class); - private AppManager appManager; + private final OpenAPIRegistryManager openAPIRegistryManager; - // key为微服务名 - private Map referenceConfigMap = new ConcurrentHashMapEx<>(); + private final Environment environment; - public void setAppManager(AppManager appManager) { - this.appManager = appManager; + public ConsumerProviderManager(Environment environment, OpenAPIRegistryManager openAPIRegistryManager) { + this.environment = environment; + this.openAPIRegistryManager = openAPIRegistryManager; } public void init() throws Exception { - for (ConsumerProvider provider : consumerProviderList) { - provider.init(); - } + registerSwaggerFromApplications(); + registerSwaggerFromMicroservices(); } - public ReferenceConfig createReferenceConfig(String microserviceName, String versionRule, String transport) { - ReferenceConfig referenceConfig = new ReferenceConfig(appManager, microserviceName, versionRule, transport); - - MicroserviceVersionRule microserviceVersionRule = referenceConfig.getMicroserviceVersionRule(); - if (microserviceVersionRule.getLatestMicroserviceVersion() == null) { - throw new IllegalStateException( - String.format( - "Probably invoke a service before it is registered, or no instance found for it, appId=%s, name=%s", - microserviceVersionRule.getAppId(), - microserviceVersionRule.getMicroserviceName())); + private void registerSwaggerFromApplications() { + try { + List resourceUris = ResourceUtil.findResourcesBySuffix("applications", ".yaml"); + for (URI uri : resourceUris) { + String path = uri.toURL().getPath(); + String[] segments = path.split("/"); + if (segments.length < 4 || !"applications".equals(segments[segments.length - 4])) { + continue; + } + openAPIRegistryManager.registerOpenAPI(segments[segments.length - 3], segments[segments.length - 2], + segments[segments.length - 1].substring(0, segments[segments.length - 1].indexOf(".yaml")), + SwaggerUtils.parseAndValidateSwagger(uri.toURL())); + } + } catch (IOException | URISyntaxException e) { + LOGGER.error("Load schema ids failed from applications. {}.", e.getMessage()); } - - return referenceConfig; } - public ReferenceConfig createReferenceConfig(String microserviceName) { - String key = "servicecomb.references." + microserviceName; - - String defaultVersionRule = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.references.version-rule", DefinitionConst.VERSION_RULE_ALL) - .get(); - String versionRule = DynamicPropertyFactory.getInstance() - .getStringProperty(key + ".version-rule", defaultVersionRule) - .get(); - - String defaultTransport = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.references.transport", Const.ANY_TRANSPORT) - .get(); - String transport = DynamicPropertyFactory.getInstance() - .getStringProperty(key + ".transport", defaultTransport) - .get(); - - return createReferenceConfig(microserviceName, versionRule, transport); - } - - public ReferenceConfig getReferenceConfig(String microserviceName) { - return referenceConfigMap.computeIfAbsent(microserviceName, this::createReferenceConfig); - } - - // 只用于测试场景 - public ReferenceConfig setTransport(String microserviceName, String transport) { - ReferenceConfig config = getReferenceConfig(microserviceName); - config.setTransport(transport); - - return config; + private void registerSwaggerFromMicroservices() { + try { + List resourceUris = ResourceUtil.findResourcesBySuffix("microservices", ".yaml"); + for (URI uri : resourceUris) { + String path = uri.toURL().getPath(); + String[] segments = path.split("/"); + if (segments.length < 3 || !"microservices".equals(segments[segments.length - 3])) { + continue; + } + openAPIRegistryManager.registerOpenAPI(BootStrapProperties.readApplication(environment), + segments[segments.length - 2], + segments[segments.length - 1].substring(0, segments[segments.length - 1].indexOf(".yaml")), + SwaggerUtils.parseAndValidateSwagger(uri.toURL())); + } + } catch (IOException | URISyntaxException e) { + LOGGER.error("Load schema ids failed from microservices. {}.", e.getMessage()); + } } } diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java index 17ffcb21925..152f43a5034 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java @@ -17,118 +17,175 @@ package org.apache.servicecomb.core.provider.consumer; +import static org.apache.servicecomb.core.exception.Exceptions.toConsumerResponse; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import io.vertx.core.Context; +import jakarta.ws.rs.core.Response.Status; public final class InvokerUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(InvokerUtils.class); + @SuppressWarnings({"unchecked"}) + public static T syncInvoke(String microserviceName, String transport, + String schemaId, String operationId, Map swaggerArguments, Type responseType) { + Invocation invocation = createInvocation(microserviceName, transport, schemaId, operationId, + swaggerArguments, responseType); + return (T) syncInvoke(invocation); + } - public static Object syncInvoke(String microserviceName, String schemaId, String operationName, Object[] args) { - ReferenceConfig referenceConfig = SCBEngine.getInstance().getReferenceConfigForInvoke(microserviceName); - return syncInvoke(generateInvocation(schemaId, operationName, args, referenceConfig)); + public static void reactiveInvoke(String microserviceName, String transport, + String schemaId, String operationId, Map swaggerArguments, Type responseType, + AsyncResponse asyncResp) { + Invocation invocation = createInvocation(microserviceName, transport, schemaId, operationId, + swaggerArguments, responseType); + reactiveInvoke(invocation, asyncResp); } - public static Object syncInvoke(String microserviceName, String microserviceVersion, String transport, - String schemaId, String operationName, Object[] args) { - ReferenceConfig referenceConfig = SCBEngine.getInstance() - .createReferenceConfigForInvoke(microserviceName, microserviceVersion, transport); - return syncInvoke(generateInvocation(schemaId, operationName, args, referenceConfig)); + public static T syncInvoke(String microserviceName, String schemaId, String operationId, + Map swaggerArguments, Type responseType) { + return syncInvoke(microserviceName, null, + schemaId, operationId, swaggerArguments, responseType); + } + + public static void reactiveInvoke(String microserviceName, String schemaId, String operationId, + Map swaggerArguments, Type responseType, + AsyncResponse asyncResp) { + reactiveInvoke(microserviceName, null, + schemaId, operationId, swaggerArguments, responseType, asyncResp); + } + + public static Invocation createInvocation(String microserviceName, String transport, + String schemaId, String operationId, Map swaggerArguments, Type responseType) { + long startCreateInvocation = System.nanoTime(); + MicroserviceReferenceConfig microserviceReferenceConfig = SCBEngine.getInstance() + .getOrCreateReferenceConfig(microserviceName); + if (microserviceReferenceConfig == null) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData(String.format("Failed to invoke service %s. Maybe service" + + " not registered or no active instance.", microserviceName))); + } + MicroserviceMeta microserviceMeta = microserviceReferenceConfig.getMicroserviceMeta(); + SchemaMeta schemaMeta = microserviceMeta.ensureFindSchemaMeta(schemaId); + OperationMeta operationMeta = schemaMeta.ensureFindOperation(operationId); + + ReferenceConfig referenceConfig = microserviceReferenceConfig.createReferenceConfig(transport, operationMeta); + InvocationRuntimeType invocationRuntimeType = operationMeta.buildBaseConsumerRuntimeType(); + invocationRuntimeType.setSuccessResponseType(responseType); + Invocation result = InvocationFactory + .forConsumer(referenceConfig, operationMeta, invocationRuntimeType, swaggerArguments); + result.getInvocationStageTrace().startCreateInvocation(startCreateInvocation); + result.getInvocationStageTrace().finishCreateInvocation(); + return result; + } + + /** + * + * use of this method , the response type can not be determined. + * use {@link #syncInvoke(String, String, String, String, Map, Type)} instead. + * + */ + @Deprecated + public static Object syncInvoke(String microserviceName, String transport, + String schemaId, String operationId, Map swaggerArguments) { + return syncInvoke(microserviceName, transport, schemaId, operationId, swaggerArguments, + null); } /** - * it's a internal API, caller make sure already invoked SCBEngine.ensureStatusUp - * @param invocation - * @return contract result - * @throws InvocationException + * This is an internal API, caller make sure already invoked SCBEngine.ensureStatusUp */ public static Object syncInvoke(Invocation invocation) throws InvocationException { Response response = innerSyncInvoke(invocation); - if (response.isSuccessed()) { + if (response.isSucceed()) { return response.getResult(); } throw ExceptionFactory.convertConsumerException(response.getResult()); } + public static boolean isInEventLoop() { + return Context.isOnEventLoopThread(); + } + /** - * it's a internal API, caller make sure already invoked SCBEngine.ensureStatusUp - * @param invocation - * @return servicecomb response object + * This is an internal API, caller make sure already invoked SCBEngine.ensureStatusUp */ public static Response innerSyncInvoke(Invocation invocation) { - try { - invocation.onStart(null, System.nanoTime()); - SyncResponseExecutor respExecutor = new SyncResponseExecutor(); - invocation.setResponseExecutor(respExecutor); - - invocation.getInvocationStageTrace().startHandlersRequest(); - invocation.next(respExecutor::setResponse); - - Response response = respExecutor.waitResponse(); - invocation.getInvocationStageTrace().finishHandlersResponse(); - invocation.onFinish(response); - return response; - } catch (Throwable e) { - String msg = - String.format("invoke failed, %s", invocation.getOperationMeta().getMicroserviceQualifiedName()); - LOGGER.error(msg, e); - - Response response = Response.createConsumerFail(e); - invocation.onFinish(response); - return response; + if (isInEventLoop() && + SCBEngine.getInstance() + .getEnvironment() + .getProperty("servicecomb.invocation.enableEventLoopBlockingCallCheck", boolean.class, true)) { + throw new IllegalStateException("Can not execute sync logic in event loop."); } + return toSync(invoke(invocation), invocation.getWaitTime()); } /** - * it's a internal API, caller make sure already invoked SCBEngine.ensureStatusUp - * @param invocation - * @param asyncResp + * This is an internal API, caller make sure already invoked SCBEngine.ensureStatusUp */ public static void reactiveInvoke(Invocation invocation, AsyncResponse asyncResp) { + invoke(invocation).whenComplete((r, e) -> { + if (e == null) { + asyncResp.complete(r); + } else { + asyncResp.consumerFail(e); + } + }); + } + + public static boolean isSyncMethod(Method method) { + return !isAsyncMethod(method); + } + + public static boolean isAsyncMethod(Method method) { + // currently only support CompletableFuture for async method definition + return method.getReturnType().equals(CompletableFuture.class); + } + + public static T toSync(CompletableFuture future, long waitInMillis) { try { - invocation.onStart(null, System.nanoTime()); - invocation.setSync(false); - - ReactiveResponseExecutor respExecutor = new ReactiveResponseExecutor(); - invocation.setResponseExecutor(respExecutor); - - invocation.getInvocationStageTrace().startHandlersRequest(); - invocation.next(ar -> { - ContextUtils.setInvocationContext(invocation.getParentContext()); - try { - invocation.getInvocationStageTrace().finishHandlersResponse(); - invocation.onFinish(ar); - asyncResp.handle(ar); - } finally { - ContextUtils.removeInvocationContext(); - } - }); + if (waitInMillis > 0) { + return future.get(waitInMillis, TimeUnit.MILLISECONDS); + } + return future.get(); + } catch (ExecutionException executionException) { + throw AsyncUtils.rethrow(executionException.getCause()); + } catch (TimeoutException timeoutException) { + throw new InvocationException(Status.REQUEST_TIMEOUT, + new CommonExceptionData("Invocation Timeout."), timeoutException); } catch (Throwable e) { - invocation.getInvocationStageTrace().finishHandlersResponse(); - //if throw exception,we can use 500 for status code ? - Response response = Response.createConsumerFail(e); - invocation.onFinish(response); - LOGGER.error("invoke failed, {}", invocation.getOperationMeta().getMicroserviceQualifiedName()); - asyncResp.handle(response); + throw AsyncUtils.rethrow(e); } } - private static Invocation generateInvocation(String schemaId, String operationName, Object[] args, - ReferenceConfig referenceConfig) { - SchemaMeta schemaMeta = referenceConfig.getMicroserviceMeta().ensureFindSchemaMeta(schemaId); - return InvocationFactory.forConsumer(referenceConfig, schemaMeta, operationName, args); - } - - @Deprecated - public static Object invoke(Invocation invocation) { - return syncInvoke(invocation); + /** + * This method is used in new Filter implementation to replace Handler + * NOTE: this method should never throw exception directly + */ + public static CompletableFuture invoke(Invocation invocation) { + invocation.onStart(null); + return invocation.getMicroserviceMeta().getConsumerFilterChain() + .onFilter(invocation) + .exceptionally(throwable -> toConsumerResponse(invocation, throwable)) + .whenComplete((response, throwable) -> invocation.onFinish(response)); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java new file mode 100644 index 00000000000..60948bd130d --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider.consumer; + +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; + +/** + * microservice meta data for consumer. + */ +public class MicroserviceReferenceConfig { + private final String appId; + + private final String microserviceName; + + private final MicroserviceMeta microserviceMeta; + + public MicroserviceReferenceConfig( + String appId, + String microserviceName, + MicroserviceMeta microserviceMeta) { + this.appId = appId; + this.microserviceName = microserviceName; + this.microserviceMeta = microserviceMeta; + } + + public MicroserviceMeta getMicroserviceMeta() { + if (microserviceMeta == null) { + throw new IllegalStateException( + String.format( + "Probably invoke a service before it is registered, or no instance found for it, appId=%s, name=%s.", + appId, + microserviceName)); + } + + return microserviceMeta; + } + + public ReferenceConfig createReferenceConfig(OperationMeta operationMeta) { + return createReferenceConfig(null, operationMeta); + } + + public ReferenceConfig createReferenceConfig(String transport, OperationMeta operationMeta) { + if (transport == null) { + transport = operationMeta.getConfig().getTransport(); + } + final ReferenceConfig referenceConfig = new ReferenceConfig(transport); + return referenceConfig; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfig.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfig.java index 69b576f9807..3b6ad24e610 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfig.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfig.java @@ -17,55 +17,14 @@ package org.apache.servicecomb.core.provider.consumer; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; - +// operation level, to keep compatible, not change name public class ReferenceConfig { - private MicroserviceVersionRule microserviceVersionRule; - - private String transport = Const.ANY_TRANSPORT; - - public ReferenceConfig() { - } - - public ReferenceConfig(AppManager appManager, String microserviceName, String versionRule, String transport) { - String appId = new MicroserviceMeta(microserviceName).getAppId(); - this.microserviceVersionRule = appManager.getOrCreateMicroserviceVersionRule(appId, - microserviceName, - versionRule); + protected String transport; + public ReferenceConfig(String transport) { this.transport = transport; } - public MicroserviceMeta getMicroserviceMeta() { - MicroserviceVersion microserviceVersion = microserviceVersionRule.getLatestMicroserviceVersion(); - if (microserviceVersion == null) { - throw new IllegalStateException( - String.format( - "Probably invoke a service before it is registered, or no instance found for it, appId=%s, name=%s", - microserviceVersionRule.getAppId(), - microserviceVersionRule.getMicroserviceName())); - } - - return ((MicroserviceVersionMeta) microserviceVersion).getMicroserviceMeta(); - } - - public MicroserviceVersionRule getMicroserviceVersionRule() { - return microserviceVersionRule; - } - - public String getVersionRule() { - return microserviceVersionRule.getVersionRule().getVersionRule(); - } - - public void setMicroserviceVersionRule(MicroserviceVersionRule microserviceVersionRule) { - this.microserviceVersionRule = microserviceVersionRule; - } - public String getTransport() { return transport; } diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfigManager.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfigManager.java new file mode 100644 index 00000000000..dffecfd62bf --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/ReferenceConfigManager.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.provider.consumer; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.SCBEngine.CreateMicroserviceMetaEvent; +import org.apache.servicecomb.core.definition.ConsumerMicroserviceVersionsMeta; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.vertx.executor.VertxWorkerExecutor; +import org.apache.servicecomb.registry.definition.MicroserviceNameParser; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; + +import io.swagger.v3.oas.models.OpenAPI; +import jakarta.ws.rs.core.Response.Status; + +public class ReferenceConfigManager { + // application -> microservice name + private final Map> referenceConfigs = new ConcurrentHashMapEx<>(); + + private final Map> referenceConfigsLocks = new ConcurrentHashMapEx<>(); + + private OpenAPIRegistryManager openAPIRegistryManager; + + @Autowired + public void setOpenAPIRegistryManager(OpenAPIRegistryManager openAPIRegistryManager) { + this.openAPIRegistryManager = openAPIRegistryManager; + this.openAPIRegistryManager.addOpenAPIChangeListener(this::onOpenAPIChanged); + } + + private void onOpenAPIChanged(String application, String serviceName) { + if (referenceConfigs.get(application) != null && referenceConfigs.get(application).get(serviceName) != null) { + MicroserviceReferenceConfig config = buildMicroserviceReferenceConfig(SCBEngine.getInstance(), application, + serviceName); + referenceConfigs.get(application).put(serviceName, config); + } + } + + public CompletableFuture getOrCreateReferenceConfigAsync + (SCBEngine scbEngine, String qualifiedName) { + MicroserviceNameParser parser = parseMicroserviceName(scbEngine, qualifiedName); + MicroserviceReferenceConfig config = referenceConfigs.computeIfAbsent(parser.getAppId(), + app -> new ConcurrentHashMapEx<>()) + .get(parser.getMicroserviceName()); + + if (config != null) { + return CompletableFuture.completedFuture(config); + } + + if (InvokerUtils.isInEventLoop()) { + CompletableFuture result = new CompletableFuture<>(); + VertxWorkerExecutor executor = new VertxWorkerExecutor(); + executor.execute(() -> { + synchronized (referenceConfigsLocks.computeIfAbsent(parser.getAppId(), key -> new ConcurrentHashMapEx<>()) + .computeIfAbsent(parser.getMicroserviceName(), key -> new Object())) { + try { + MicroserviceReferenceConfig temp = referenceConfigs.get(parser.getAppId()) + .get(parser.getMicroserviceName()); + if (temp != null) { + result.complete(temp); + return; + } + temp = buildMicroserviceReferenceConfig(scbEngine, parser.getAppId(), + parser.getMicroserviceName()); + referenceConfigs.get(parser.getAppId()).put(parser.getMicroserviceName(), temp); + result.complete(temp); + } catch (Exception e) { + result.completeExceptionally(e); + } + } + }); + return result; + } else { + synchronized (referenceConfigsLocks.computeIfAbsent(parser.getAppId(), key -> new ConcurrentHashMapEx<>()) + .computeIfAbsent(parser.getMicroserviceName(), key -> new Object())) { + MicroserviceReferenceConfig temp = referenceConfigs.get(parser.getAppId()) + .get(parser.getMicroserviceName()); + if (temp != null) { + return CompletableFuture.completedFuture(temp); + } + temp = buildMicroserviceReferenceConfig(scbEngine, parser.getAppId(), + parser.getMicroserviceName()); + referenceConfigs.get(parser.getAppId()).put(parser.getMicroserviceName(), temp); + return CompletableFuture.completedFuture(temp); + } + } + } + + public MicroserviceReferenceConfig getOrCreateReferenceConfig(SCBEngine scbEngine, String qualifiedName) { + MicroserviceNameParser parser = parseMicroserviceName(scbEngine, qualifiedName); + MicroserviceReferenceConfig config = referenceConfigs.computeIfAbsent(parser.getAppId(), + app -> new ConcurrentHashMapEx<>()) + .get(parser.getMicroserviceName()); + if (config == null) { + synchronized (referenceConfigsLocks.computeIfAbsent(parser.getAppId(), key -> new ConcurrentHashMapEx<>()) + .computeIfAbsent(parser.getMicroserviceName(), key -> new Object())) { + config = referenceConfigs.get(parser.getAppId()).get(parser.getMicroserviceName()); + if (config != null) { + return config; + } + config = buildMicroserviceReferenceConfig(scbEngine, parser.getAppId(), parser.getMicroserviceName()); + referenceConfigs.get(parser.getAppId()).put(parser.getMicroserviceName(), config); + return config; + } + } + return config; + } + + private MicroserviceNameParser parseMicroserviceName(SCBEngine scbEngine, String microserviceName) { + return new MicroserviceNameParser(scbEngine.getAppId(), microserviceName); + } + + private MicroserviceReferenceConfig buildMicroserviceReferenceConfig(SCBEngine engine, + String application, String microserviceName) { + ConsumerMicroserviceVersionsMeta microserviceVersionsMeta = new ConsumerMicroserviceVersionsMeta(engine); + MicroserviceMeta microserviceMeta = new MicroserviceMeta(engine, application, microserviceName, true); + microserviceMeta.setConsumerFilterChain(engine.getFilterChainsManager() + .findConsumerChain(application, microserviceName)); + microserviceMeta.setEdgeFilterChain(engine.getFilterChainsManager() + .findEdgeChain(application, microserviceName)); + microserviceMeta.setMicroserviceVersionsMeta(microserviceVersionsMeta); + + Map schemas = this.openAPIRegistryManager.loadOpenAPI(application, microserviceName); + for (Entry entry : schemas.entrySet()) { + OpenAPI swagger = entry.getValue(); + if (swagger != null) { + microserviceMeta.registerSchemaMeta(entry.getKey(), entry.getValue()); + continue; + } + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, + String.format("Swagger %s/%s/%s can not be empty or load swagger failed.", + application, microserviceName, entry.getKey())); + } + + EventManager.getEventBus().post(new CreateMicroserviceMetaEvent(microserviceMeta)); + return new MicroserviceReferenceConfig(application, + microserviceName, microserviceMeta); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/SyncResponseExecutor.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/SyncResponseExecutor.java index 59c2af2caae..8e86d9d7f90 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/SyncResponseExecutor.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/SyncResponseExecutor.java @@ -17,17 +17,23 @@ package org.apache.servicecomb.core.provider.consumer; +import static jakarta.ws.rs.core.Response.Status.REQUEST_TIMEOUT; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionCodes; import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; /** * 业务线程在阻塞等待着,不必另起线程 * 将应答流程包装为Runnable,先唤醒业务线程,再在业务线程中执行runnable */ public class SyncResponseExecutor implements Executor { - private CountDownLatch latch; + private final CountDownLatch latch; private Runnable cmd; @@ -48,9 +54,9 @@ public void execute(Runnable cmd) { latch.countDown(); } - public Response waitResponse() throws InterruptedException { - // TODO:增加配置,指定超时时间 - latch.await(); + public Response waitResponse(Invocation invocation) throws InvocationException { + guardedWait(invocation); + // cmd为null,是没走execute,直接返回的场景 if (cmd != null) { cmd.run(); @@ -62,11 +68,37 @@ public Response waitResponse() throws InterruptedException { public void setResponse(Response response) { this.response = response; if (cmd == null) { - // 走到这里,没有cmd - // 说明没走到网络线程,直接就返回了 - // 或者在网络线程中没使用execute的方式返回,这会导致返回流程在网络线程中执行 - // 虽然不合适,但是也不应该导致业务线程无法唤醒 + // 1. 走到这里,没有cmd,说明没走到网络线程,直接就返回了。 + // 2. 或者在网络线程中没使用execute的方式返回,这会导致返回流程在网络线程中执行,虽然不合适,但是也不应该导致业务线程无法唤醒 latch.countDown(); } } + + private void guardedWait(Invocation invocation) throws InvocationException { + long wait = getWaitTime(invocation); + try { + if (wait <= 0) { + latch.await(); + return; + } + if (latch.await(wait, TimeUnit.MILLISECONDS)) { + return; + } + } catch (InterruptedException e) { + //ignore + } + throw new InvocationException(REQUEST_TIMEOUT, ExceptionCodes.INVOCATION_TIMEOUT, "Invocation Timeout."); + } + + private long getWaitTime(Invocation invocation) { + if (invocation.getOperationMeta().getConfig().getMsInvocationTimeout() > 0) { + // if invocation timeout configured, use it. + return invocation.getOperationMeta().getConfig().getMsInvocationTimeout(); + } + + // In invocation handlers, may call other microservices, invocation + // timeout may be much longer than request timeout. + // For simplicity, default 30000 or two times of request timeout. + return Math.max(invocation.getOperationMeta().getConfig().getMsRequestTimeout() * 2, 30000); + } } diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java new file mode 100644 index 00000000000..7dc291157d3 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.provider.producer; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ExecutorService; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.foundation.common.utils.IOUtils; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import io.swagger.v3.oas.models.OpenAPI; + +public class ProducerBootListener implements BootListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ProducerBootListener.class); + + private static final String PATTERN = File.separator + "microservices" + + File.separator + "%s" + File.separator + "%s.yaml"; + + private static final String TMP_DIR = System.getProperty("java.io.tmpdir"); + + private RegistrationManager registrationManager; + + private Environment environment; + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void onAfterTransport(BootEvent event) { + boolean exportToFile = environment.getProperty(CoreConst.SWAGGER_EXPORT_ENABLED, boolean.class, true); + String filePath = environment.getProperty(CoreConst.SWAGGER_DIRECTORY, String.class, TMP_DIR) + PATTERN; + + if (exportToFile) { + LOGGER.info("export microservice swagger file to path {}", filePath); + } + // register schema to microservice; + MicroserviceMeta microserviceMeta = event.getScbEngine().getProducerMicroserviceMeta(); + for (SchemaMeta schemaMeta : microserviceMeta.getSchemaMetas().values()) { + OpenAPI swagger = schemaMeta.getSwagger(); + String content = SwaggerUtils.swaggerToString(swagger); + if (exportToFile) { + exportToFile(String.format(filePath, + BootStrapProperties.readServiceName(environment), schemaMeta.getSchemaId()), content); + } else { + LOGGER.info("generate swagger for {}/{}/{}, swagger: {}", + microserviceMeta.getAppId(), + microserviceMeta.getMicroserviceName(), + schemaMeta.getSchemaId(), + content); + } + this.registrationManager.addSchema(schemaMeta.getSchemaId(), content); + } + } + + + // bug: can not close all thread for edge + @Override + public void onAfterClose(BootEvent event) { + MicroserviceMeta microserviceMeta = event.getScbEngine().getProducerMicroserviceMeta(); + if (microserviceMeta == null) { + return; + } + + for (OperationMeta operationMeta : microserviceMeta.getOperations()) { + if (operationMeta.getExecutor() instanceof ExecutorService) { + ((ExecutorService) operationMeta.getExecutor()).shutdown(); + continue; + } + + if (operationMeta.getExecutor() instanceof Closeable) { + IOUtils.closeQuietly((Closeable) operationMeta.getExecutor()); + continue; + } + + LOGGER.warn("Executor {} do not support close or shutdown, it may block service shutdown.", + operationMeta.getExecutor().getClass().getName()); + } + } + + private void exportToFile(String fileName, String content) { + File file = new File(fileName); + if (!file.getParentFile().exists()) { + if (!file.getParentFile().mkdirs()) { + LOGGER.error("create file directory failed"); + return; + } + } + if (file.exists()) { + file.delete(); + } + try { + file.createNewFile(); + FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8, false); + file.setReadOnly(); + } catch (IOException e) { + LOGGER.error("export swagger content to file failed, message: {}", e.getMessage()); + } + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerMeta.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerMeta.java index e8081200c4c..87a14817476 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerMeta.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerMeta.java @@ -22,16 +22,14 @@ public class ProducerMeta { private Object instance; - // 因为aop的存在,instance的class不一定等于instanceClass - private Class instanceClass; + private Class schemaInterface; public ProducerMeta() { } - public ProducerMeta(String schemaId, Object instance, Class instanceClass) { + public ProducerMeta(String schemaId, Object instance) { this.schemaId = schemaId; this.instance = instance; - this.instanceClass = instanceClass; } public String getSchemaId() { @@ -50,11 +48,11 @@ public void setInstance(Object instance) { this.instance = instance; } - public Class getInstanceClass() { - return instanceClass; + public Class getSchemaInterface() { + return schemaInterface; } - public void setInstanceClass(Class instanceClass) { - this.instanceClass = instanceClass; + public void setSchemaInterface(Class schemaInterface) { + this.schemaInterface = schemaInterface; } } diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java index 737792a1663..391bc6a4723 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerProviderManager.java @@ -17,68 +17,117 @@ package org.apache.servicecomb.core.provider.producer; -import java.io.Closeable; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; -import org.apache.commons.io.IOUtils; -import org.apache.servicecomb.core.BootListener; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.core.ProducerProvider; import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.CoreMetaUtils; import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.SchemaUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.core.executor.ExecutorManager; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -@Component -public class ProducerProviderManager implements BootListener { +import io.swagger.v3.oas.models.OpenAPI; + +public class ProducerProviderManager { private static final Logger LOGGER = LoggerFactory.getLogger(ProducerProviderManager.class); - @Autowired(required = false) - private List producerProviderList = Collections.emptyList(); + private final List producerProviderList = new ArrayList<>( + SPIServiceUtils.getOrLoadSortedService(ProducerProvider.class)); + + private final SCBEngine scbEngine; + + private final List producerMetas = new ArrayList<>(); + + public ProducerProviderManager(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + public List getProducerProviderList() { + return producerProviderList; + } - private MicroserviceMeta microserviceMeta; + public void init() { + registerProducerMetas(producerMetas); - public void init() throws Exception { for (ProducerProvider provider : producerProviderList) { - provider.init(); - } - Microservice microservice = RegistryUtils.getMicroservice(); - microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - for (SchemaMeta schemaMeta : microserviceMeta.getSchemaMetas()) { - String content = SchemaUtils.swaggerToString(schemaMeta.getSwagger()); - microservice.addSchema(schemaMeta.getSchemaId(), content); + List producerMetas = provider.init(); + if (producerMetas == null) { + LOGGER.warn("ProducerProvider {} not provide any producer.", provider.getClass().getName()); + continue; + } + + registerProducerMetas(producerMetas); } } - @Override - public void onBootEvent(BootEvent event) { - if (!EventType.AFTER_CLOSE.equals(event.getEventType())) { - return; - } - if (microserviceMeta == null) { - return; + public void addProducerMeta(String schemaId, Object instance) { + addProducerMeta(new ProducerMeta(schemaId, instance)); + } + + public void addProducerMeta(ProducerMeta producerMeta) { + producerMetas.add(producerMeta); + } + + private void registerProducerMetas(List producerMetas) { + for (ProducerMeta producerMeta : producerMetas) { + registerSchema(producerMeta.getSchemaId(), producerMeta.getSchemaInterface(), producerMeta.getInstance()); } - for (OperationMeta operationMeta : microserviceMeta.getOperations()) { - if (ExecutorService.class.isInstance(operationMeta.getExecutor())) { - ((ExecutorService) operationMeta.getExecutor()).shutdown(); - continue; - } + } - if (Closeable.class.isInstance(operationMeta.getExecutor())) { - IOUtils.closeQuietly((Closeable) operationMeta.getExecutor()); - continue; + public SchemaMeta registerSchema(String schemaId, Object instance) { + return registerSchema(schemaId, null, instance); + } + + public SchemaMeta registerSchema(String schemaId, Class schemaInterface, Object instance) { + MicroserviceMeta producerMicroserviceMeta = scbEngine.getProducerMicroserviceMeta(); + SwaggerProducer swaggerProducer = scbEngine.getSwaggerEnvironment() + .createProducer(instance, schemaInterface); + OpenAPI swagger = swaggerProducer.getSwagger(); + registerUrlPrefixToSwagger(swagger); + + // register self OpenAPI to registry + scbEngine.getOpenAPIRegistryManager() + .registerOpenAPI(BootStrapProperties.readApplication(scbEngine.getEnvironment()), + BootStrapProperties.readServiceName(scbEngine.getEnvironment()), schemaId, swagger); + + SchemaMeta schemaMeta = producerMicroserviceMeta.registerSchemaMeta(schemaId, swagger); + schemaMeta.putExtData(CoreMetaUtils.SWAGGER_PRODUCER, swaggerProducer); + Executor reactiveExecutor = scbEngine.getExecutorManager().findExecutorById(ExecutorManager.EXECUTOR_REACTIVE); + for (SwaggerProducerOperation producerOperation : swaggerProducer.getAllOperations()) { + OperationMeta operationMeta = schemaMeta.ensureFindOperation(producerOperation.getOperationId()); + operationMeta.setSwaggerProducerOperation(producerOperation); + + if (CompletableFuture.class.equals(producerOperation.getProducerMethod().getReturnType())) { + operationMeta.setExecutor(scbEngine.getExecutorManager().findExecutor(operationMeta, reactiveExecutor)); } + } + + return schemaMeta; + } - LOGGER.warn("Executor {} do not support close or shutdown, it may block service shutdown.", - operationMeta.getExecutor().getClass().getName()); + // This is special requirement by users: When service deployed in tomcat,user want to use RestTemplate to + // call REST service by the full url. e.g. restTemplate.getForObject("cse://serviceName/root/prefix/health") + // By default, user's do not need context prefix, e.g. restTemplate.getForObject("cse://serviceName/health") + private void registerUrlPrefixToSwagger(OpenAPI swagger) { + String urlPrefix = ClassLoaderScopeContext.getClassLoaderScopeProperty(DefinitionConst.URL_PREFIX); + if (!StringUtils.isEmpty(urlPrefix) && !SwaggerUtils.getBasePath(swagger).startsWith(urlPrefix) + && scbEngine.getEnvironment().getProperty(DefinitionConst.REGISTER_URL_PREFIX, boolean.class, false)) { + LOGGER.info("Add swagger base path prefix for {} with {}", SwaggerUtils.getBasePath(swagger), urlPrefix); + SwaggerUtils.setBasePath(swagger, urlPrefix + SwaggerUtils.getBasePath(swagger)); } } } diff --git a/core/src/main/java/org/apache/servicecomb/core/registry/discovery/EndpointDiscoveryFilter.java b/core/src/main/java/org/apache/servicecomb/core/registry/discovery/EndpointDiscoveryFilter.java new file mode 100644 index 00000000000..666626b0697 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/registry/discovery/EndpointDiscoveryFilter.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.registry.discovery; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.registry.discovery.AbstractEndpointDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class EndpointDiscoveryFilter extends AbstractEndpointDiscoveryFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(EndpointDiscoveryFilter.class); + + protected SCBEngine scbEngine; + + public EndpointDiscoveryFilter() { + } + + @Autowired + public void setScbEngine(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + @Override + public int getOrder() { + return Short.MAX_VALUE; + } + + @Override + protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { + Invocation invocation = context.getInputParameters(); + return invocation.getConfigTransportName(); + } + + @Override + protected Object createEndpoint(DiscoveryContext context, String transportName, String endpoint, + StatefulDiscoveryInstance instance) { + Transport transport = scbEngine.getTransportManager().findTransport(transportName); + if (transport == null) { + LOGGER.info("not deployed transport {}, ignore {}.", transportName, endpoint); + return null; + } + + return new Endpoint(transport, endpoint, instance); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/tracing/BraveTraceIdGenerator.java b/core/src/main/java/org/apache/servicecomb/core/tracing/BraveTraceIdGenerator.java index 7a2eee0ead0..6f888c813e7 100644 --- a/core/src/main/java/org/apache/servicecomb/core/tracing/BraveTraceIdGenerator.java +++ b/core/src/main/java/org/apache/servicecomb/core/tracing/BraveTraceIdGenerator.java @@ -17,14 +17,14 @@ package org.apache.servicecomb.core.tracing; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import brave.internal.Platform; public class BraveTraceIdGenerator implements TraceIdGenerator { @Override public String getTraceIdKeyName() { - return Const.TRACE_ID_NAME; + return CoreConst.TRACE_ID_NAME; } @Override diff --git a/core/src/main/java/org/apache/servicecomb/core/tracing/ScbMarker.java b/core/src/main/java/org/apache/servicecomb/core/tracing/ScbMarker.java new file mode 100644 index 00000000000..a7d4bdaddc6 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/tracing/ScbMarker.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.tracing; + +import org.apache.servicecomb.foundation.common.log.AbstractMarker; + +public class ScbMarker extends AbstractMarker { + private static final long serialVersionUID = -1L; + + private static final String MARKER_NAME = "SERVICECOMB_MARKER"; + + public ScbMarker() { + + } + + @Override + public final String getName() { + return MARKER_NAME; + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/tracing/TraceIdLogger.java b/core/src/main/java/org/apache/servicecomb/core/tracing/TraceIdLogger.java new file mode 100644 index 00000000000..3819bb90218 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/tracing/TraceIdLogger.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.tracing; + +import org.apache.servicecomb.core.Invocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; + +public class TraceIdLogger { + private static final Logger LOGGER = LoggerFactory.getLogger("scb-trace-id"); + + private static final Marker MARKER = new ScbMarker(); + + public static final String KEY_TRACE_ID = "SERVICECOMB_TRACE_ID"; + + private final Invocation invocation; + + public TraceIdLogger(Invocation invocation) { + this.invocation = invocation; + } + + public Invocation getInvocation() { + return invocation; + } + + public static String constructSource(String source) { + return "[" + source + "(" + + Thread.currentThread().getStackTrace()[2].getLineNumber() + ")]"; + } + + public final String getName() { + return invocation.getTraceId(); + } + + public void error(String format, Object... arguments) { + MDC.put(KEY_TRACE_ID, getName()); + LOGGER.error(MARKER, format, arguments); + MDC.remove(KEY_TRACE_ID); + } + + public void warn(String format, Object... arguments) { + MDC.put(KEY_TRACE_ID, getName()); + LOGGER.warn(MARKER, format, arguments); + MDC.remove(KEY_TRACE_ID); + } + + public void info(String format, Object... arguments) { + MDC.put(KEY_TRACE_ID, getName()); + LOGGER.info(MARKER, format, arguments); + MDC.remove(KEY_TRACE_ID); + } + + public void debug(String format, Object... arguments) { + MDC.put(KEY_TRACE_ID, getName()); + LOGGER.debug(MARKER, format, arguments); + MDC.remove(KEY_TRACE_ID); + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/AbstractTransport.java b/core/src/main/java/org/apache/servicecomb/core/transport/AbstractTransport.java index 3dc525c0936..5c1ee3cc177 100644 --- a/core/src/main/java/org/apache/servicecomb/core/transport/AbstractTransport.java +++ b/core/src/main/java/org/apache/servicecomb/core/transport/AbstractTransport.java @@ -17,59 +17,49 @@ package org.apache.servicecomb.core.transport; -import java.io.UnsupportedEncodingException; +import java.net.Inet6Address; +import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.stream.Collectors; +import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.message.BasicNameValuePair; -import org.apache.servicecomb.core.Const; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.foundation.common.net.IpPort; import org.apache.servicecomb.foundation.common.net.NetUtils; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.apache.servicecomb.foundation.vertx.SharedVertxFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; +import org.springframework.core.env.Environment; import io.vertx.core.Vertx; public abstract class AbstractTransport implements Transport { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTransport.class); - public static final String PROP_ROOT = "servicecomb.request"; + public static final String PUBLISH_ADDRESS = "servicecomb.service.publishAddress"; - public static final String PROP_TIMEOUT = ".timeout"; + private static final String PUBLISH_PORT = "servicecomb.{transport_name}.publishPort"; /* * 用于参数传递:比如向RestServerVerticle传递endpoint地址。 */ public static final String ENDPOINT_KEY = "servicecomb.endpoint"; - private static final long REQUEST_TIMEOUT_CFG_FAIL = -1; - - private static final long DEFAULT_TIMEOUT_MILLIS = 30000; - - // 所有transport使用同一个vertx实例,避免创建太多的线程 - private static TransportVertxFactory transportVertxFactory = new TransportVertxFactory(); - - public static TransportVertxFactory getTransportVertxFactory() { - return transportVertxFactory; - } - - protected Vertx transportVertx = getTransportVertxFactory().getTransportVertx(); + protected Vertx transportVertx; protected Endpoint endpoint; protected Endpoint publishEndpoint; + protected Environment environment; + @Override public Endpoint getPublishEndpoint() { return publishEndpoint; @@ -80,6 +70,12 @@ public Endpoint getEndpoint() { return endpoint; } + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + this.transportVertx = SharedVertxFactory.getSharedVertx(environment); + } + protected void setListenAddressWithoutSchema(String addressWithoutSchema) { setListenAddressWithoutSchema(addressWithoutSchema, null); } @@ -94,7 +90,7 @@ protected void setListenAddressWithoutSchema(String addressWithoutSchema, this.endpoint = new Endpoint(this, NetUtils.getRealListenAddress(getName(), addressWithoutSchema)); if (this.endpoint.getEndpoint() != null) { - this.publishEndpoint = new Endpoint(this, RegistryUtils.getPublishAddress(getName(), + this.publishEndpoint = new Endpoint(this, getPublishAddress(getName(), addressWithoutSchema)); } else { this.publishEndpoint = null; @@ -113,41 +109,12 @@ private String genAddressWithoutSchema(String addressWithoutSchema, Map { - return new BasicNameValuePair(entry.getKey(), entry.getValue()); - }).collect(Collectors.toList()), StandardCharsets.UTF_8.name()); + String encodedQuery = URLEncodedUtils.format( + pairs.entrySet().stream().map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()), StandardCharsets.UTF_8.name()); - if (!RegistryUtils.getServiceRegistry().getFeatures().isCanEncodeEndpoint()) { - addressWithoutSchema = genAddressWithoutSchemaForOldSC(addressWithoutSchema, encodedQuery); - } else { - addressWithoutSchema += encodedQuery; - } - - return addressWithoutSchema; - } - - private String genAddressWithoutSchemaForOldSC(String addressWithoutSchema, String encodedQuery) { - // old service center do not support encodedQuery - // sdk must query service center's version, and determine if encode query - // traced by JAV-307 - try { - LOGGER.warn("Service center do not support encoded query, so we use unencoded query, " - + "this caused not support chinese/space (and maybe other char) in query value."); - String decodedQuery = URLDecoder.decode(encodedQuery, StandardCharsets.UTF_8.name()); - addressWithoutSchema += decodedQuery; - } catch (UnsupportedEncodingException e) { - // never happened - throw new ServiceCombException("Failed to decode query.", e); - } + addressWithoutSchema += encodedQuery; - try { - // make sure consumer can handle this endpoint - new URI(Const.RESTFUL + "://" + addressWithoutSchema); - } catch (URISyntaxException e) { - throw new ServiceCombException( - "current service center not support encoded endpoint, please do not use chinese or space or anything need to be encoded.", - e); - } return addressWithoutSchema; } @@ -160,33 +127,65 @@ public Object parseAddress(String address) { } /** - * Handles the request timeout configurations. - * @param operationName operation name - * @param schema schema id - * @param microservice micro service name - * @return configured value + * In the case that listening address configured as 0.0.0.0, the publish address will be determined + * by the query result for the net interfaces. + * + * @return the publish address, or {@code null} if the param {@code address} is null. */ - public static long getReqTimeout(String operationName, String schema, String microservice) { - return getLongProperty(DEFAULT_TIMEOUT_MILLIS, - PROP_ROOT + "." + microservice + "." + schema + "." + operationName + PROP_TIMEOUT, - PROP_ROOT + "." + microservice + "." + schema + PROP_TIMEOUT, - PROP_ROOT + "." + microservice + PROP_TIMEOUT, - PROP_ROOT + PROP_TIMEOUT); + protected String getPublishAddress(String schema, String address) { + if (address == null) { + return address; + } + + try { + URI originalURI = new URI(schema + "://" + address); + IpPort ipPort = NetUtils.parseIpPort(originalURI); + if (ipPort == null) { + LOGGER.warn("address {} not valid.", address); + return null; + } + + IpPort publishIpPort = genPublishIpPort(schema, ipPort); + URIBuilder builder = new URIBuilder(originalURI); + return builder.setHost(publishIpPort.getHostOrIp()).setPort(publishIpPort.getPort()).build().toString(); + } catch (URISyntaxException e) { + LOGGER.warn("address {} not valid.", address); + return null; + } } - /** - * Handles the request timeout configurations. - * @param defaultValue - * @param keys list of keys - * @return configured value - */ - private static long getLongProperty(long defaultValue, String... keys) { - for (String key : keys) { - long property = DynamicPropertyFactory.getInstance().getLongProperty(key, REQUEST_TIMEOUT_CFG_FAIL).get(); - if (property != REQUEST_TIMEOUT_CFG_FAIL) { - return property; + private IpPort genPublishIpPort(String schema, IpPort ipPort) { + String publicAddressSetting = environment.getProperty(PUBLISH_ADDRESS, ""); + publicAddressSetting = publicAddressSetting.trim(); + + String publishPortKey = PUBLISH_PORT.replace("{transport_name}", schema); + int publishPortSetting = environment.getProperty(publishPortKey, int.class, 0); + int publishPort = publishPortSetting == 0 ? ipPort.getPort() : publishPortSetting; + + if (publicAddressSetting.isEmpty()) { + InetSocketAddress socketAddress = ipPort.getSocketAddress(); + if (socketAddress.getAddress().isAnyLocalAddress()) { + String host = NetUtils.getHostAddress(); + if (Inet6Address.class.isInstance(socketAddress.getAddress())) { + host = NetUtils.getIpv6HostAddress(); + } + LOGGER.warn("address {}, auto select a host address to publish {}:{}, maybe not the correct one", + socketAddress, + host, + publishPort); + return new IpPort(host, publishPort); } + + return ipPort; + } + + if (publicAddressSetting.startsWith("{") && publicAddressSetting.endsWith("}")) { + publicAddressSetting = NetUtils + .ensureGetInterfaceAddress( + publicAddressSetting.substring(1, publicAddressSetting.length() - 1)) + .getHostAddress(); } - return defaultValue; + + return new IpPort(publicAddressSetting, publishPort); } } diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportClassAnnotationProcessor.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportClassAnnotationProcessor.java new file mode 100644 index 00000000000..5af6705abc7 --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/transport/TransportClassAnnotationProcessor.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.transport; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.models.OpenAPI; + +public class TransportClassAnnotationProcessor implements ClassAnnotationProcessor { + @Override + public Type getProcessType() { + return Transport.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, Transport transport) { + OpenAPI swagger = swaggerGenerator.getOpenAPI(); + if (StringUtils.isNotEmpty(transport.name())) { + swagger.addExtension(CoreConst.TRANSPORT_NAME, transport.name()); + } + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java index 119bedf6e54..64ed82a5c93 100644 --- a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java +++ b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java @@ -24,31 +24,48 @@ import java.util.Map; import java.util.Map.Entry; -import javax.inject.Inject; - import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; -@Component public class TransportManager { private static final Logger LOGGER = LoggerFactory.getLogger(TransportManager.class); - @Inject - private List transports; + private final List transports = new ArrayList<>(SPIServiceUtils.getOrLoadSortedService(Transport.class)); + + private final Map transportMap = new HashMap<>(); + + public Map getTransportMap() { + return transportMap; + } + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + public void clearTransportBeforeInit() { + transports.clear(); + } - private Map transportMap = new HashMap<>(); + public void addTransportBeforeInit(Transport transport) { + this.transports.add(transport); + } - public void setTransports(List transports) { - this.transports = transports; + public void addTransportsBeforeInit(List transports) { + this.transports.addAll(transports); } - public void init() throws Exception { + public void init(SCBEngine scbEngine) throws Exception { + initEnvironment(); buildTransportMap(); for (Transport transport : transportMap.values()) { @@ -56,14 +73,19 @@ public void init() throws Exception { Endpoint endpoint = transport.getPublishEndpoint(); if (endpoint != null && endpoint.getEndpoint() != null) { LOGGER.info("endpoint to publish: {}", endpoint.getEndpoint()); - Microservice microservice = RegistryUtils.getMicroservice(); - microservice.getInstance().getEndpoints().add(endpoint.getEndpoint()); + scbEngine.getRegistrationManager().addEndpoint(endpoint.getEndpoint()); } continue; } } } + private void initEnvironment() { + for (Transport transport : transports) { + transport.setEnvironment(environment); + } + } + protected void buildTransportMap() { Map> groups = groupByName(); @@ -107,9 +129,7 @@ protected void checkTransportGroup(List group) { protected Map> groupByName() { Map> groups = new HashMap<>(); for (Transport transport : transports) { - List list = groups.computeIfAbsent(transport.getName(), name -> { - return new ArrayList<>(); - }); + List list = groups.computeIfAbsent(transport.getName(), name -> new ArrayList<>()); list.add(transport); } return groups; diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportMethodAnnotationProcessor.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportMethodAnnotationProcessor.java new file mode 100644 index 00000000000..617f4b87d5e --- /dev/null +++ b/core/src/main/java/org/apache/servicecomb/core/transport/TransportMethodAnnotationProcessor.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.transport; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.models.Operation; + +public class TransportMethodAnnotationProcessor implements MethodAnnotationProcessor { + @Override + public Type getProcessType() { + return Transport.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Transport transport) { + Operation operation = operationGenerator.getOperation(); + if (StringUtils.isNotEmpty(transport.name())) { + operation.addExtension(CoreConst.TRANSPORT_NAME, transport.name()); + } + } +} diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportVertxFactory.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportVertxFactory.java deleted file mode 100644 index 3aa8ab1bb2d..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/transport/TransportVertxFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.transport; - -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.metrics.DefaultVertxMetricsFactory; -import org.apache.servicecomb.foundation.vertx.metrics.MetricsOptionsEx; - -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; - -public class TransportVertxFactory { - private VertxOptions vertxOptions = new VertxOptions(); - - private DefaultVertxMetricsFactory metricsFactory = new DefaultVertxMetricsFactory(); - - private MetricsOptionsEx metricsOptionsEx = (MetricsOptionsEx) metricsFactory.newOptions(); - - private Vertx transportVertx; - - public TransportVertxFactory() { - vertxOptions.setMetricsOptions(metricsOptionsEx); - transportVertx = VertxUtils.getOrCreateVertxByName("transport", vertxOptions); - } - - public DefaultVertxMetricsFactory getMetricsFactory() { - return metricsFactory; - } - - public Vertx getTransportVertx() { - return transportVertx; - } -} diff --git a/core/src/main/java/org/apache/servicecomb/core/unittest/UnitTestMeta.java b/core/src/main/java/org/apache/servicecomb/core/unittest/UnitTestMeta.java deleted file mode 100644 index 53bde6af8d5..00000000000 --- a/core/src/main/java/org/apache/servicecomb/core/unittest/UnitTestMeta.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.unittest; - -import java.util.Collections; -import java.util.List; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.PrivateMicroserviceVersionMetaFactory; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.core.handler.ConsumerHandlerManager; -import org.apache.servicecomb.core.handler.ProducerHandlerManager; -import org.apache.servicecomb.core.handler.config.Config; -import org.apache.servicecomb.core.handler.impl.SimpleLoadBalanceHandler; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.mockito.Mockito; -import org.springframework.context.ApplicationContext; - -import io.swagger.models.Swagger; -import mockit.Mock; -import mockit.MockUp; - -/** - * when SCBEngine finished, UnitTestMeta will be deleted - */ -public class UnitTestMeta { - - private SchemaListenerManager schemaListenerManager = new SchemaListenerManager(); - - private ConsumerProviderManager consumerProviderManager; - - public ConsumerProviderManager getConsumerProviderManager() { - return consumerProviderManager; - } - - private ConsumerSchemaFactory consumerSchemaFactory; - - private SchemaLoader schemaLoader = new SchemaLoader(); - - private MicroserviceMeta microserviceMeta; - - private ServiceRegistry serviceRegistry; - - public ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - - public ConsumerSchemaFactory getConsumerSchemaFactory() { - return consumerSchemaFactory; - } - - @SuppressWarnings("unchecked") - public void init() { - serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - serviceRegistry.getAppManager().setMicroserviceVersionFactory(new PrivateMicroserviceVersionMetaFactory()); - RegistryUtils.setServiceRegistry(serviceRegistry); - microserviceMeta = new MicroserviceMeta(RegistryUtils.getMicroservice().getServiceName()); - SCBEngine.getInstance().setProducerMicroserviceMeta(microserviceMeta); - consumerProviderManager = new ConsumerProviderManager(); - - consumerSchemaFactory = new ConsumerSchemaFactory(); - - consumerSchemaFactory.setSchemaLoader(schemaLoader); - - consumerProviderManager.setAppManager(RegistryUtils.getServiceRegistry().getAppManager()); - - CseContext.getInstance().setConsumerProviderManager(consumerProviderManager); - CseContext.getInstance().setConsumerSchemaFactory(consumerSchemaFactory); - CseContext.getInstance().setSchemaListenerManager(schemaListenerManager); - - Config config = new Config(); - Class cls = SimpleLoadBalanceHandler.class; - config.getHandlerClassMap().put("simpleLB", (Class) cls); - ProducerHandlerManager.INSTANCE.init(new Config()); - ConsumerHandlerManager.INSTANCE.init(config); - - ApplicationContext applicationContext = Mockito.mock(ApplicationContext.class); - Mockito.when(applicationContext.getBean(Mockito.anyString())).thenReturn(null); - BeanUtils.setContext(applicationContext); - } - - public UnitTestMeta() { - new MockUp() { - @Mock - public List getOrCreate(String name) { - return Collections.emptyList(); - } - }; - new MockUp() { - @Mock - public List getOrCreate(String name) { - return Collections.emptyList(); - } - }; - - init(); - } - - public SchemaMeta getOrCreateSchemaMeta(Class impl) { - return getOrCreateSchemaMeta("app", "test", impl.getName(), impl); - } - - public SchemaMeta getOrCreateSchemaMeta(String appId, String microserviceName, String schemaId, Class impl) { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(schemaId); - if (schemaMeta != null) { - return schemaMeta; - } - - Swagger swagger = UnitTestSwaggerUtils.generateSwagger(impl).getSwagger(); - return schemaLoader.registerSchema(microserviceMeta, schemaId, swagger); - } - - public void registerSchema(SwaggerGeneratorContext swaggerGeneratorContext, Class schemaCls) { - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(swaggerGeneratorContext, schemaCls); - swaggerGenerator.setClassLoader(new ClassLoader() { - }); - Swagger swagger = swaggerGenerator.generate(); - - Microservice microservice = new Microservice(); - microservice.setAppId("app"); - microservice.setServiceName("app:test"); - microservice.setVersion("1.0.0"); - microservice.getSchemas().add(schemaCls.getName()); - microservice.setServiceId(serviceRegistry.getServiceRegistryClient().registerMicroservice(microservice)); - - serviceRegistry.getServiceRegistryClient() - .registerSchema(microservice.getServiceId(), schemaCls.getName(), - SwaggerUtils.swaggerToString(swagger)); - - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setServiceId(microservice.getServiceId()); - instance.setInstanceId(serviceRegistry.getServiceRegistryClient().registerMicroserviceInstance(instance)); - } -} diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter new file mode 100644 index 00000000000..e170e610bf4 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.exception.converter.ConstraintViolationExceptionConverter +org.apache.servicecomb.core.exception.converter.InvocationExceptionConverter +org.apache.servicecomb.core.exception.converter.IllegalArgumentExceptionConverter +org.apache.servicecomb.core.exception.converter.TimeoutExceptionConverter +org.apache.servicecomb.core.exception.converter.ConnectTimeoutExceptionConverter +org.apache.servicecomb.core.exception.converter.DefaultExceptionConverter +org.apache.servicecomb.core.exception.converter.ServiceCombExceptionConverter diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider new file mode 100644 index 00000000000..d21d7c1fe15 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.filter.FilterProvider @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.filter.impl.DefaultFilterProvider diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.tracing.TraceIdGenerator b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.tracing.TraceIdGenerator index 3a57a7db661..8e61e1f2b81 100644 --- a/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.tracing.TraceIdGenerator +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.core.tracing.TraceIdGenerator @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.core.tracing.BraveTraceIdGenerator \ No newline at end of file +org.apache.servicecomb.core.tracing.BraveTraceIdGenerator diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter b/core/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter deleted file mode 100644 index f9189c8b4c8..00000000000 --- a/core/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.core.filter.OperationInstancesDiscoveryFilter diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor new file mode 100644 index 00000000000..57d906d8131 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.transport.TransportClassAnnotationProcessor diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor new file mode 100644 index 00000000000..a003fcbd204 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.transport.TransportMethodAnnotationProcessor diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister new file mode 100644 index 00000000000..1356e33ecf8 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.invocation.endpoint.EndpointContextRegister diff --git a/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory new file mode 100644 index 00000000000..6eb082fc473 --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.core.invocation.endpoint.EndpointMapperFactory diff --git a/core/src/main/resources/META-INF/spring/cse.bean.xml b/core/src/main/resources/META-INF/spring/cse.bean.xml deleted file mode 100644 index 092187ca9f3..00000000000 --- a/core/src/main/resources/META-INF/spring/cse.bean.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..74f863c2bda --- /dev/null +++ b/core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,22 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.core.filter.CoreFilterConfiguration +org.apache.servicecomb.core.invocation.CoreInvocationConfiguration +org.apache.servicecomb.core.governance.CoreGovernanceConfiguration +org.apache.servicecomb.core.exception.CoreExceptionConfiguration +org.apache.servicecomb.core.ServiceCombCoreConfiguration diff --git a/core/src/main/resources/config/config.cse.inc.xml b/core/src/main/resources/config/config.cse.inc.xml deleted file mode 100644 index 99780f53a00..00000000000 --- a/core/src/main/resources/config/config.cse.inc.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - classpath*:config/cse.properties - - diff --git a/core/src/main/resources/config/cse.handler.xml b/core/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 89510b4db65..00000000000 --- a/core/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/core/src/main/resources/microservice.yaml b/core/src/main/resources/microservice.yaml index c51b1defe70..f77c5ce5601 100644 --- a/core/src/main/resources/microservice.yaml +++ b/core/src/main/resources/microservice.yaml @@ -16,5 +16,3 @@ ## --------------------------------------------------------------------------- servicecomb-config-order: -500 -servicecomb: - microserviceVersionFactory: org.apache.servicecomb.core.definition.PrivateMicroserviceVersionMetaFactory diff --git a/core/src/test/java/org/apache/servicecomb/core/TestConfig.java b/core/src/test/java/org/apache/servicecomb/core/TestConfig.java index b8264ac8f29..a4584b1e64f 100644 --- a/core/src/test/java/org/apache/servicecomb/core/TestConfig.java +++ b/core/src/test/java/org/apache/servicecomb/core/TestConfig.java @@ -19,41 +19,27 @@ import java.util.HashMap; import java.util.Map; -import java.util.Properties; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; -import org.apache.servicecomb.core.config.ConfigurationSpringInitializer; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestConfig { - class MyConfigurationSpringInitializer extends ConfigurationSpringInitializer { - Properties p; - - MyConfigurationSpringInitializer(Properties p) { - this.p = p; - } - - public void test() throws Exception { - this.loadProperties(p); - } - } - @Test public void testConstants() { - Assert.assertEquals("x-cse-context", Const.CSE_CONTEXT); - Assert.assertEquals("rest", Const.RESTFUL); - Assert.assertEquals("", Const.ANY_TRANSPORT); - Assert.assertEquals("latest", Const.VERSION_RULE_LATEST); - Assert.assertEquals("0.0.0+", Const.DEFAULT_VERSION_RULE); + Assertions.assertEquals("x-cse-context", CoreConst.CSE_CONTEXT); + Assertions.assertEquals("rest", CoreConst.RESTFUL); + Assertions.assertEquals("", CoreConst.ANY_TRANSPORT); + Assertions.assertEquals("latest", CoreConst.VERSION_RULE_LATEST); + Assertions.assertEquals("0.0.0.0+", CoreConst.DEFAULT_VERSION_RULE); } @Test @@ -61,84 +47,69 @@ public void testHttpResponse() { String objectString = new String("Unit Testing"); Response oResponse = Response.success(objectString, Status.OK); - Assert.assertEquals(true, oResponse.isSuccessed()); + Assertions.assertTrue(oResponse.isSucceed()); oResponse = Response.succResp(objectString); - Assert.assertEquals(true, oResponse.isSuccessed()); - Assert.assertEquals(200, oResponse.getStatusCode()); + Assertions.assertTrue(oResponse.isSucceed()); + Assertions.assertEquals(200, oResponse.getStatusCode()); Throwable oThrowable = new Throwable("Error"); oResponse = Response.consumerFailResp(oThrowable); - Assert.assertEquals(true, oResponse.isFailed()); + Assertions.assertTrue(oResponse.isFailed()); oResponse = Response.providerFailResp(oThrowable); - Assert.assertEquals(true, oResponse.isFailed()); + Assertions.assertTrue(oResponse.isFailed()); } @Test public void testHttpStatus() { StatusType oStatus = new HttpStatus(204, "InternalServerError"); - Assert.assertEquals("InternalServerError", oStatus.getReasonPhrase()); + Assertions.assertEquals("InternalServerError", oStatus.getReasonPhrase()); } @Test public void testContextUtils() { ThreadLocal contextMgr = new ThreadLocal<>(); - Assert.assertEquals(contextMgr.get(), ContextUtils.getInvocationContext()); + Assertions.assertEquals(contextMgr.get(), ContextUtils.getInvocationContext()); SwaggerInvocation invocation = new SwaggerInvocation(); invocation.addContext("test1", "testObject"); - Assert.assertEquals("testObject", invocation.getContext("test1")); + Assertions.assertEquals("testObject", invocation.getContext("test1")); Map context = new HashMap<>(); context.put("test2", new String("testObject")); invocation.setContext(context); - Assert.assertEquals(context, invocation.getContext()); + Assertions.assertEquals(context, invocation.getContext()); invocation.setStatus(Status.OK); - Assert.assertEquals(200, invocation.getStatus().getStatusCode()); + Assertions.assertEquals(200, invocation.getStatus().getStatusCode()); invocation.setStatus(204); - Assert.assertEquals(204, invocation.getStatus().getStatusCode()); + Assertions.assertEquals(204, invocation.getStatus().getStatusCode()); invocation.setStatus(Status.OK); - Assert.assertEquals((Status.OK).getStatusCode(), invocation.getStatus().getStatusCode()); + Assertions.assertEquals((Status.OK).getStatusCode(), invocation.getStatus().getStatusCode()); invocation.setStatus(203, "Done"); - Assert.assertEquals(203, invocation.getStatus().getStatusCode()); + Assertions.assertEquals(203, invocation.getStatus().getStatusCode()); ContextUtils.setInvocationContext(invocation); - Assert.assertEquals(invocation, ContextUtils.getInvocationContext()); + Assertions.assertEquals(invocation, ContextUtils.getInvocationContext()); ContextUtils.removeInvocationContext(); - Assert.assertEquals(null, ContextUtils.getInvocationContext()); + Assertions.assertNull(ContextUtils.getInvocationContext()); } @Test public void testResponse() { Response response = Response.create(400, "test", null); InvocationException exception = response.getResult(); - Assert.assertEquals(null, exception.getErrorData()); + Assertions.assertNull(exception.getErrorData()); response = Response.create(400, "test", "errorData"); exception = response.getResult(); - Assert.assertEquals("errorData", exception.getErrorData()); - } - - @Test - public void testConfigurationSpringInitializer() throws Exception { - Properties p = new Properties(); - MyConfigurationSpringInitializer oConf = new MyConfigurationSpringInitializer(p); - oConf.setConfigId("testkey:testvalue,testkey2:testvalue2"); - boolean failed = false; - try { - oConf.test(); - } catch (Exception e) { - Assert.assertEquals(e.getMessage().contains("can not find config for testkey:testvalue"), true); - failed = true; - } - Assert.assertEquals(failed, true); + Assertions.assertEquals("errorData", exception.getErrorData()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/TestConfigurationSpringInitializer.java b/core/src/test/java/org/apache/servicecomb/core/TestConfigurationSpringInitializer.java new file mode 100644 index 00000000000..27b38f60110 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/TestConfigurationSpringInitializer.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.jndi.JndiPropertySource; + +public class TestConfigurationSpringInitializer { + @BeforeEach + public void beforeTest() { + Configurator.setRootLevel(Level.OFF); + + Configurator.setRootLevel(Level.INFO); + } + + @AfterEach + public void afterTest() { + + } + + @Test + public void testSetEnvironment() { + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources = new MutablePropertySources(); + Map propertyMap = new HashMap<>(); + final String map0Key0 = "map0-Key0"; + final String map1Key0 = "map1-Key0"; + final String map2Key0 = "map2-Key0"; + final String map3Key0 = "map3-Key0"; + propertyMap.put(map0Key0, "map0-Value0"); + propertyMap.put(map1Key0, "map1-Value0"); + propertyMap.put(map2Key0, "map2-Value0"); + propertyMap.put(map3Key0, "map3-Value0"); + + /* + propertySources + |- compositePropertySource0 + | |- mapPropertySource0 + | | |- map0-Key0 = map0-Value0 + | |- compositePropertySource1 + | |- mapPropertySource1 + | | |- map1-Key0 = map1-Value0 + | |- mapPropertySource2 + | |- map2-Key0 = map2-Value0 + | |- JndiPropertySource(mocked) + |- mapPropertySource3 + |- map3-Key0 = map3-Value0 + */ + CompositePropertySource compositePropertySource0 = new CompositePropertySource("compositePropertySource0"); + propertySources.addFirst(compositePropertySource0); + + HashMap map0 = new HashMap<>(); + map0.put(map0Key0, propertyMap.get(map0Key0)); + MapPropertySource mapPropertySource0 = new MapPropertySource("mapPropertySource0", map0); + compositePropertySource0.addFirstPropertySource(mapPropertySource0); + + CompositePropertySource compositePropertySource1 = new CompositePropertySource("compositePropertySource1"); + compositePropertySource0.addPropertySource(compositePropertySource1); + HashMap map1 = new HashMap<>(); + map1.put(map1Key0, propertyMap.get(map1Key0)); + MapPropertySource mapPropertySource1 = new MapPropertySource("mapPropertySource1", map1); + compositePropertySource1.addPropertySource(mapPropertySource1); + HashMap map2 = new HashMap<>(); + map2.put(map2Key0, propertyMap.get(map2Key0)); + MapPropertySource mapPropertySource2 = new MapPropertySource("mapPropertySource2", map2); + compositePropertySource1.addPropertySource(mapPropertySource2); + compositePropertySource1.addPropertySource(Mockito.mock(JndiPropertySource.class)); + + HashMap map3 = new HashMap<>(); + map3.put(map3Key0, propertyMap.get(map3Key0)); + MapPropertySource mapPropertySource3 = new MapPropertySource("mapPropertySource3", map3); + compositePropertySource0.addPropertySource(mapPropertySource3); + + Mockito.when(environment.getPropertySources()).thenReturn(propertySources); + Mockito.doAnswer((Answer) invocation -> { + Object[] args = invocation.getArguments(); + String propertyName = (String) args[0]; + + if ("spring.config.name".equals(propertyName) || "spring.application.name".equals(propertyName)) { + return null; + } + + String value = propertyMap.get(propertyName); + if (null == value) { + Assertions.fail("get unexpected property name: " + propertyName); + } + return value; + }).when(environment).getProperty(ArgumentMatchers.anyString(), ArgumentMatchers.eq(Object.class)); + } + + @Test + public void testSetEnvironmentOnEnvironmentName() { + // get environment name from spring.config.name + ConfigurableEnvironment environment0 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources0 = new MutablePropertySources(); + Mockito.when(environment0.getPropertySources()).thenReturn(propertySources0); + Map map0 = new HashMap<>(1); + map0.put("spring.config.name", "application"); + propertySources0.addFirst(new MapPropertySource("mapPropertySource0", map0)); + Mockito.when(environment0.getProperty("spring.config.name", Object.class)).thenReturn("application"); + Mockito.when(environment0.getProperty("spring.config.name")).thenReturn("application"); + + // get environment name from spring.application.name + ConfigurableEnvironment environment1 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources1 = new MutablePropertySources(); + Mockito.when(environment1.getPropertySources()).thenReturn(propertySources1); + Map map1 = new HashMap<>(1); + map1.put("spring.application.name", "bootstrap"); + propertySources1.addFirst(new MapPropertySource("mapPropertySource1", map1)); + Mockito.when(environment1.getProperty("spring.application.name", Object.class)).thenReturn("bootstrap"); + Mockito.when(environment1.getProperty("spring.application.name")).thenReturn("bootstrap"); + + // get environment name from className+hashcode + ConfigurableEnvironment environment2 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources2 = new MutablePropertySources(); + Mockito.when(environment2.getPropertySources()).thenReturn(propertySources2); + Map map2 = new HashMap<>(1); + map2.put("key2", "value2"); + propertySources2.addFirst(new MapPropertySource("mapPropertySource2", map2)); + Mockito.when(environment2.getProperty("key2", Object.class)).thenReturn("value2"); + Mockito.when(environment2.getProperty("key2")).thenReturn("value2"); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestConsumer.java b/core/src/test/java/org/apache/servicecomb/core/TestConsumer.java deleted file mode 100644 index b8840c77bc7..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestConsumer.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; - -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor; -import org.apache.servicecomb.foundation.common.RegisterManager; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestConsumer { - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void testConsumerProviderManager() { - ConsumerProviderManager oConsumerProviderManager = new ConsumerProviderManager(); - RegisterManager oRegisterManager = new RegisterManager("cse consumer provider manager"); - oRegisterManager.register("servicecomb.references.cse consumer provider manager", - "cse consumer provider manager"); - boolean validAssert = true; - try { - oConsumerProviderManager.getReferenceConfig("consumer provider manager"); - } catch (Throwable ee) { - Assert.assertNotEquals(null, ee); - validAssert = false; - } - Assert.assertFalse(validAssert); - } - - @Test - public void testReferenceConfig() throws InterruptedException { - Map oMap = new ConcurrentHashMap<>(); - oMap.put("test1", "value1"); - RegisterManager oManager = new RegisterManager<>("test"); - oManager.register("test1", "value1"); - - SyncResponseExecutor oExecutor = new SyncResponseExecutor(); - oExecutor.execute(new Runnable() { - - @Override - public void run() { - oExecutor.setResponse(Response.succResp("success")); - } - }); - Assert.assertEquals(true, oExecutor.waitResponse().isSuccessed()); - } - - @Test - public void testInvocation() { - OperationMeta oOperationMeta = Mockito.mock(OperationMeta.class); - SchemaMeta oSchemaMeta = Mockito.mock(SchemaMeta.class); - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - List oHandlerList = new ArrayList<>(); - - Mockito.when(oSchemaMeta.getProviderHandlerChain()).thenReturn(oHandlerList); - Mockito.when(oSchemaMeta.getMicroserviceName()).thenReturn("TMK"); - Mockito.when(oOperationMeta.getSchemaMeta()).thenReturn(oSchemaMeta); - Endpoint oEndpoint = Mockito.mock(Endpoint.class); - Transport oTransport = Mockito.mock(Transport.class); - Mockito.when(oEndpoint.getTransport()).thenReturn(oTransport); - Mockito.when(oOperationMeta.getOperationId()).thenReturn("TMK"); - - Invocation oInvocation = new Invocation(oEndpoint, oOperationMeta, null); - Assert.assertNotNull(oInvocation.getTransport()); - Assert.assertNotNull(oInvocation.getInvocationType()); - oInvocation.setResponseExecutor(Mockito.mock(Executor.class)); - Assert.assertNotNull(oInvocation.getResponseExecutor()); - Assert.assertNotNull(oInvocation.getSchemaMeta()); - Assert.assertNotNull(oInvocation.getOperationMeta()); - Assert.assertNull(oInvocation.getArgs()); - Assert.assertNotNull(oInvocation.getEndpoint()); - oInvocation.setEndpoint(null); - Map map = oInvocation.getContext(); - Assert.assertNotNull(map); - String str = oInvocation.getSchemaId(); - Assert.assertEquals(null, str); - String str1 = oInvocation.getMicroserviceName(); - Assert.assertEquals("TMK", str1); - Map mapp = oInvocation.getHandlerContext(); - Assert.assertNotNull(mapp); - Assert.assertEquals(true, oInvocation.getHandlerIndex() >= 0); - oInvocation.setHandlerIndex(8); - Assert.assertEquals("TMK", oInvocation.getOperationName()); - Assert.assertEquals("TMK", oInvocation.getMicroserviceName()); - - boolean validAssert; - - try { - - validAssert = true; - - oInvocation.next(asyncResp); - } catch (Exception e) { - validAssert = false; - } - Assert.assertFalse(validAssert); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestDefinition.java b/core/src/test/java/org/apache/servicecomb/core/TestDefinition.java deleted file mode 100644 index 3416048eecb..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestDefinition.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.core.definition.CommonService; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.junit.Assert; -import org.junit.Test; - -public class TestDefinition { - @Test - public void testCommonService() { - CommonService oCommonService = new CommonService<>(); - - boolean validCreateOperation = true; - try { - oCommonService.createOperationMgr("test1"); - } catch (Exception e) { - validCreateOperation = false; - } - Assert.assertTrue(validCreateOperation); - oCommonService.setName("test1"); - boolean validRegOperation = true; - try { - oCommonService.regOperation("oName1", "op1"); - } catch (Exception e) { - validRegOperation = false; - } - Assert.assertTrue(validRegOperation); - - Assert.assertEquals(1, oCommonService.getOperations().size()); - Assert.assertEquals("test1", oCommonService.getName()); - Assert.assertEquals("op1", oCommonService.findOperation("oName1")); - Assert.assertEquals("op1", oCommonService.ensureFindOperation("oName1")); - } - - @Test - public void testMicroServiceMeta() { - MicroserviceMeta oMicroMeta = new MicroserviceMeta("app:micro1"); - Assert.assertEquals(0, oMicroMeta.getSchemaMetas().size()); - Assert.assertEquals(0, oMicroMeta.getOperations().size()); - Assert.assertEquals("micro1", oMicroMeta.getShortName()); - Assert.assertEquals("app:micro1", oMicroMeta.getName()); - try { - oMicroMeta.putExtData("key1", new String("value1")); - Assert.assertNotEquals(null, oMicroMeta.getExtData("key1")); - } catch (Exception e) { - Assert.assertNotNull(e); - } - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestEndpoint.java b/core/src/test/java/org/apache/servicecomb/core/TestEndpoint.java index bed295d99f4..17e1ef0c5e1 100644 --- a/core/src/test/java/org/apache/servicecomb/core/TestEndpoint.java +++ b/core/src/test/java/org/apache/servicecomb/core/TestEndpoint.java @@ -17,25 +17,32 @@ package org.apache.servicecomb.core; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestEndpoint { @Test - public void testEndpoint(@Mocked Transport transport) { - new Expectations() { - { - transport.parseAddress("rest://123.6.6.6:8080"); - result = "rest://123.6.6.6:8080"; - } - }; + public void testEndpoint() { + Transport transport = Mockito.mock(Transport.class); + Mockito.when(transport.parseAddress("rest://123.6.6.6:8080")).thenReturn("rest://123.6.6.6:8080"); + Endpoint endpoint = new Endpoint(transport, "rest://123.6.6.6:8080"); - Assert.assertEquals(endpoint.getAddress(), "rest://123.6.6.6:8080"); - Assert.assertEquals(endpoint.getEndpoint(), "rest://123.6.6.6:8080"); - Assert.assertEquals(endpoint.getTransport(), transport); - Assert.assertEquals(endpoint.toString(), "rest://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getAddress(), "rest://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getEndpoint(), "rest://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getTransport(), transport); + Assertions.assertEquals(endpoint.toString(), "rest://123.6.6.6:8080"); + } + + @Test + public void testEndpointAddressConstructor() { + Transport transport = Mockito.mock(Transport.class); + StatefulDiscoveryInstance instance = Mockito.mock(StatefulDiscoveryInstance.class); + Endpoint endpoint = new Endpoint(transport, "rest://123.6.6.6:8080", instance, "iot://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getAddress(), "iot://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getEndpoint(), "rest://123.6.6.6:8080"); + Assertions.assertEquals(endpoint.getTransport(), transport); + Assertions.assertEquals(endpoint.toString(), "rest://123.6.6.6:8080"); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/TestException.java b/core/src/test/java/org/apache/servicecomb/core/TestException.java index 3d4d4b1a6e3..58bce6bce43 100644 --- a/core/src/test/java/org/apache/servicecomb/core/TestException.java +++ b/core/src/test/java/org/apache/servicecomb/core/TestException.java @@ -19,40 +19,38 @@ import org.apache.servicecomb.core.exception.CseException; import org.apache.servicecomb.core.exception.ExceptionUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestException { @Test public void testCseException() { - CseException oExeception = new CseException("500", "InternalServerError"); - Assert.assertEquals("500", oExeception.getCode()); - Assert.assertEquals("ServiceDefinitionException Code:500, Message:InternalServerError", - oExeception.toString()); + CseException oException = new CseException("500", "InternalServerError"); + Assertions.assertEquals("500", oException.getCode()); + Assertions.assertEquals("ServiceDefinitionException Code:500, Message:InternalServerError", + oException.toString()); - oExeception = new CseException("503", "OwnException", new Throwable()); - Assert.assertEquals("503", oExeception.getCode()); + oException = new CseException("503", "OwnException", new Throwable()); + Assertions.assertEquals("503", oException.getCode()); } @Test public void testExceptionUtils() { - CseException oExeception = ExceptionUtils.createCseException("servicecomb.handler.ref.not.exist", new String("test")); - Assert.assertEquals("servicecomb.handler.ref.not.exist", oExeception.getCode()); + CseException oException = ExceptionUtils + .createCseException("servicecomb.handler.ref.not.exist", new String("test")); + Assertions.assertEquals("servicecomb.handler.ref.not.exist", oException.getCode()); - oExeception = + oException = ExceptionUtils.createCseException("servicecomb.handler.ref.not.exist", new Throwable(), new String("test")); - Assert.assertEquals("servicecomb.handler.ref.not.exist", oExeception.getCode()); + Assertions.assertEquals("servicecomb.handler.ref.not.exist", oException.getCode()); - oExeception = ExceptionUtils.producerOperationNotExist("servicecomb.error", "unit-testing"); - Assert.assertEquals("servicecomb.producer.operation.not.exist", oExeception.getCode()); + oException = ExceptionUtils.producerOperationNotExist("servicecomb.error", "unit-testing"); + Assertions.assertEquals("servicecomb.producer.operation.not.exist", oException.getCode()); - oExeception = ExceptionUtils.operationIdInvalid("servicecomb.double.error", "what path are you talking about"); - Assert.assertEquals("servicecomb.schema.operation.id.invalid", oExeception.getCode()); + oException = ExceptionUtils.handlerRefNotExist("servicecomb.double.error"); + Assertions.assertEquals("servicecomb.handler.ref.not.exist", oException.getCode()); - oExeception = ExceptionUtils.handlerRefNotExist("servicecomb.double.error"); - Assert.assertEquals("servicecomb.handler.ref.not.exist", oExeception.getCode()); - - oExeception = ExceptionUtils.lbAddressNotFound("microServiceName", "my rule my world", "transportChannel"); - Assert.assertEquals("servicecomb.lb.no.available.address", oExeception.getCode()); + oException = ExceptionUtils.lbAddressNotFound("microServiceName", "my rule my world", "transportChannel"); + Assertions.assertEquals("servicecomb.lb.no.available.address", oException.getCode()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/TestExecutors.java b/core/src/test/java/org/apache/servicecomb/core/TestExecutors.java deleted file mode 100644 index 22f933cb5f5..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestExecutors.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -import org.apache.servicecomb.core.executor.FixedThreadExecutor; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; - -public class TestExecutors { - - String strThreadTest = "default"; - - @Test - public void testFixedThreadExecutor() { - FixedThreadExecutor oFixedThreadExecutor = new FixedThreadExecutor(); - oFixedThreadExecutor.execute(new Runnable() { - - @Override - public void run() { - - } - }); - Map threadExecutorMap = Deencapsulation.getField(oFixedThreadExecutor, "threadExecutorMap"); - Assert.assertEquals(true, (threadExecutorMap.size() > 0)); - - List executorList = Deencapsulation.getField(oFixedThreadExecutor, "executorList"); - Assert.assertEquals(true, (executorList.size() > 1)); - - ReactiveExecutor oReactiveExecutor = new ReactiveExecutor(); - oReactiveExecutor.execute(new Runnable() { - @Override - public void run() { - strThreadTest = "thread Ran"; - } - }); - oReactiveExecutor.close(); - Assert.assertEquals("thread Ran", strThreadTest); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestHandler.java b/core/src/test/java/org/apache/servicecomb/core/TestHandler.java deleted file mode 100644 index 3e9f1e7bd42..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.core.handler.ConsumerHandlerManager; -import org.apache.servicecomb.core.handler.HandlerConfigUtils; -import org.junit.Assert; -import org.junit.Test; - -public class TestHandler { - - @Test - public void testAbstractHandlerManager() throws Exception { - HandlerConfigUtils.init(); - Assert.assertNotEquals(null, ConsumerHandlerManager.INSTANCE.getOrCreate("test")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestInvocation.java b/core/src/test/java/org/apache/servicecomb/core/TestInvocation.java index fb3e0010344..80b6bbda461 100644 --- a/core/src/test/java/org/apache/servicecomb/core/TestInvocation.java +++ b/core/src/test/java/org/apache/servicecomb/core/TestInvocation.java @@ -18,26 +18,26 @@ import java.util.Arrays; -import javax.xml.ws.Holder; - +import org.apache.servicecomb.core.definition.InvocationRuntimeType; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.event.InvocationBaseEvent; -import org.apache.servicecomb.core.event.InvocationBusinessMethodFinishEvent; import org.apache.servicecomb.core.event.InvocationBusinessMethodStartEvent; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.event.InvocationStartEvent; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; import org.apache.servicecomb.core.tracing.BraveTraceIdGenerator; import org.apache.servicecomb.core.tracing.TraceIdGenerator; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.swagger.invocation.Response; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; @@ -48,7 +48,6 @@ import mockit.Mocked; public class TestInvocation { - Invocation invocation; @Mocked Endpoint endpoint; @@ -57,7 +56,7 @@ public class TestInvocation { OperationMeta operationMeta; @Mocked - Object[] swaggerArguments; + InvocationRuntimeType invocationRuntimeType; static long nanoTime = 123; @@ -82,8 +81,6 @@ public static void classTeardown() { @Test public void onStart() { - mockNonaTime(); - Holder result = new Holder<>(); Object subscriber = new Object() { @Subscribe @@ -93,25 +90,13 @@ public void onStart(InvocationStartEvent event) { }; EventManager.register(subscriber); - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - invocation.onStart(nanoTime); - - Assert.assertSame(invocation, result.value); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStart()); + Invocation invocation = new Invocation(endpoint, operationMeta, null); + invocation.onStart(); + Assertions.assertSame(invocation, result.value); EventManager.unregister(subscriber); } - @Test - public void onStartExecute() { - mockNonaTime(); - - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - invocation.onExecuteStart(); - - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartExecution()); - } - @Test public void onFinish() { mockNonaTime(); @@ -125,54 +110,53 @@ public void onStart(InvocationFinishEvent event) { }; EventManager.register(subscriber); - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - Assert.assertFalse(invocation.isFinished()); + Invocation invocation = new Invocation(endpoint, operationMeta, null); + Assertions.assertFalse(invocation.isFinished()); Response response = Response.succResp(null); invocation.onFinish(response); - Assert.assertEquals(nanoTime, result.value.getNanoCurrent()); - Assert.assertSame(invocation, result.value.getInvocation()); - Assert.assertSame(response, result.value.getResponse()); - Assert.assertTrue(invocation.isFinished()); + Assertions.assertSame(invocation, result.value.getInvocation()); + Assertions.assertSame(response, result.value.getResponse()); + Assertions.assertTrue(invocation.isFinished()); // should not post event again InvocationFinishEvent oldEvent = result.value; invocation.onFinish(null); - Assert.assertSame(oldEvent, result.value); + Assertions.assertSame(oldEvent, result.value); EventManager.unregister(subscriber); } @Test public void isConsumer_yes() { - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - Assert.assertFalse(invocation.isConsumer()); + Invocation invocation = new Invocation(endpoint, operationMeta, null); + Assertions.assertFalse(invocation.isConsumer()); } @Test public void isConsumer_no(@Mocked ReferenceConfig referenceConfig) { - Invocation invocation = new Invocation(referenceConfig, operationMeta, swaggerArguments); - Assert.assertTrue(invocation.isConsumer()); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); + Assertions.assertTrue(invocation.isConsumer()); } @Test public void localContext(@Mocked ReferenceConfig referenceConfig) { - Invocation invocation = new Invocation(referenceConfig, operationMeta, swaggerArguments); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); invocation.addLocalContext("k", 1); - Assert.assertSame(invocation.getHandlerContext(), invocation.getLocalContext()); - Assert.assertEquals(1, (int) invocation.getLocalContext("k")); + Assertions.assertSame(invocation.getHandlerContext(), invocation.getLocalContext()); + Assertions.assertEquals(1, (int) invocation.getLocalContext("k")); } @Test public void traceId_fromContext(@Mocked ReferenceConfig referenceConfig) { - Invocation invocation = new Invocation(referenceConfig, operationMeta, swaggerArguments); - invocation.addContext(Const.TRACE_ID_NAME, "abc"); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); + invocation.addContext(CoreConst.TRACE_ID_NAME, "abc"); - invocation.onStart(0); + invocation.onStart(); - Assert.assertEquals("abc", invocation.getTraceId()); - Assert.assertEquals("abc", invocation.getTraceId(Const.TRACE_ID_NAME)); + Assertions.assertEquals("abc", invocation.getTraceId()); + Assertions.assertEquals("abc", invocation.getTraceId(CoreConst.TRACE_ID_NAME)); } @Test @@ -184,32 +168,33 @@ public void traceId_consumerCreateTraceId(@Mocked ReferenceConfig referenceConfi result = "abc"; } }; - Invocation invocation = new Invocation(referenceConfig, operationMeta, swaggerArguments); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); - invocation.onStart(0); + invocation.onStart(); - Assert.assertEquals("abc", invocation.getTraceId()); - Assert.assertEquals("abc", invocation.getTraceId(Const.TRACE_ID_NAME)); + Assertions.assertEquals("abc", invocation.getTraceId()); + Assertions.assertEquals("abc", invocation.getTraceId(CoreConst.TRACE_ID_NAME)); } @Test public void traceId_fromRequest(@Mocked Endpoint endpoint, @Mocked HttpServletRequestEx requestEx) { new Expectations() { { - requestEx.getHeader(Const.TRACE_ID_NAME); + requestEx.getHeader(CoreConst.TRACE_ID_NAME); result = "abc"; } }; - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); + Invocation invocation = new Invocation(endpoint, operationMeta, null); - invocation.onStart(requestEx, 0); + invocation.onStart(requestEx); - Assert.assertEquals("abc", invocation.getTraceId()); - Assert.assertEquals("abc", invocation.getTraceId(Const.TRACE_ID_NAME)); + Assertions.assertEquals("abc", invocation.getTraceId()); + Assertions.assertEquals("abc", invocation.getTraceId(CoreConst.TRACE_ID_NAME)); } @Test public void traceId_producerCreateTraceId(@Mocked Endpoint endpoint, @Mocked HttpServletRequestEx requestEx) { + TraceIdGenerator generator = SPIServiceUtils.getTargetService(TraceIdGenerator.class, BraveTraceIdGenerator.class); new Expectations(generator) { { @@ -217,12 +202,12 @@ public void traceId_producerCreateTraceId(@Mocked Endpoint endpoint, @Mocked Htt result = "abc"; } }; - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); + Invocation invocation = new Invocation(endpoint, operationMeta, null); - invocation.onStart(requestEx, 0); + invocation.onStart(requestEx); - Assert.assertEquals("abc", invocation.getTraceId()); - Assert.assertEquals("abc", invocation.getTraceId(Const.TRACE_ID_NAME)); + Assertions.assertEquals("abc", invocation.getTraceId()); + Assertions.assertEquals("abc", invocation.getTraceId(CoreConst.TRACE_ID_NAME)); } @Test @@ -247,13 +232,13 @@ public void traceIdGeneratorInit(@Mocked TraceIdGenerator gen1, @Mocked TraceIdG } }; - Assert.assertThat(Invocation.loadTraceIdGenerators(), Matchers.contains(gen1, gen3)); + MatcherAssert.assertThat(Invocation.loadTraceIdGenerators(), Matchers.containsInAnyOrder(gen1, gen3)); } InvocationBaseEvent invocationBaseEvent; @Test - public void onBusinessMethodStart() { + public void test_business_execute_time_correct() { Object listener = new Object() { @Subscribe public void onBusinessMethodStart(InvocationBusinessMethodStartEvent event) { @@ -261,37 +246,29 @@ public void onBusinessMethodStart(InvocationBusinessMethodStartEvent event) { } }; EventManager.getEventBus().register(listener); - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); + Invocation invocation = new Invocation(endpoint, operationMeta, null); mockNonaTime(); invocation.onBusinessMethodStart(); EventManager.getEventBus().unregister(listener); - Assert.assertSame(invocation, invocationBaseEvent.getInvocation()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - } - - @Test - public void onBusinessMethodFinish() { - Object listener = new Object() { - @Subscribe - public void onBusinessMethodStart(InvocationBusinessMethodFinishEvent event) { - invocationBaseEvent = event; - } - }; - EventManager.getEventBus().register(listener); - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - invocation.onBusinessMethodFinish(); - EventManager.getEventBus().unregister(listener); - - Assert.assertSame(invocation, invocationBaseEvent.getInvocation()); + Assertions.assertSame(invocation, invocationBaseEvent.getInvocation()); + nanoTime++; + invocation.onBusinessFinish(); + Assertions.assertEquals(1, invocation.getInvocationStageTrace().calcBusinessExecute()); } @Test - public void onBusinessFinish() { - Invocation invocation = new Invocation(endpoint, operationMeta, swaggerArguments); - mockNonaTime(); - invocation.onBusinessFinish(); - - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); + public void marker(@Mocked ReferenceConfig referenceConfig) { + Invocation.INVOCATION_ID.set(0); + + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); + invocation.addContext(CoreConst.TRACE_ID_NAME, "abc"); + invocation.onStart(); + Assertions.assertEquals("abc", invocation.getTraceIdLogger().getName()); + + invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, null); + invocation.addContext(CoreConst.TRACE_ID_NAME, "abc"); + invocation.onStart(); + Assertions.assertEquals("abc", invocation.getTraceIdLogger().getName()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/TestInvocationFactory.java b/core/src/test/java/org/apache/servicecomb/core/TestInvocationFactory.java deleted file mode 100644 index b91cad1c128..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestInvocationFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import mockit.Injectable; - -public class TestInvocationFactory { - @BeforeClass - public static void setUp() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - RegistryUtils.setServiceRegistry(serviceRegistry); - SCBEngine.getInstance().setStatus(SCBStatus.UP); - } - - @Test - public void testInvocationFactoryforConsumer(@Injectable ReferenceConfig referenceConfig, - @Injectable OperationMeta operationMeta) { - Invocation invocation = - InvocationFactory.forConsumer(referenceConfig, operationMeta, new String[] {"a", "b"}); - Assert.assertEquals("perfClient", invocation.getContext(Const.SRC_MICROSERVICE)); - } - - @Test - public void testInvocationFactoryforConsumer(@Injectable ReferenceConfig referenceConfig, - @Injectable SchemaMeta schemaMeta) { - Invocation invocation = - InvocationFactory.forConsumer(referenceConfig, schemaMeta, "test", new String[] {"a", "b"}); - Assert.assertEquals("perfClient", invocation.getContext(Const.SRC_MICROSERVICE)); - } - - @Test - public void testInvocationFactoryforConsumer(@Injectable ReferenceConfig referenceConfig) { - Invocation invocation = - InvocationFactory.forConsumer(referenceConfig, "test", new String[] {"a", "b"}); - Assert.assertEquals("perfClient", invocation.getContext(Const.SRC_MICROSERVICE)); - } - - @Test - public void testInvocationFactoryforProvider(@Injectable Endpoint endpoint, - @Injectable OperationMeta operationMeta) { - Invocation invocation = - InvocationFactory.forProvider(endpoint, operationMeta, new String[] {"a", "b"}); - Assert.assertEquals(invocation.getEndpoint(), endpoint); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestSCBApplicationListener.java b/core/src/test/java/org/apache/servicecomb/core/TestSCBApplicationListener.java new file mode 100644 index 00000000000..99690c3c310 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/TestSCBApplicationListener.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core; + +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.core.env.Environment; + +public class TestSCBApplicationListener { + @BeforeEach + public void before() { + } + + @AfterAll + public static void classTeardown() { + } + + @Test + public void onApplicationEvent_close() { + ContextClosedEvent contextClosedEvent = Mockito.mock(ContextClosedEvent.class); + Environment environment = Mockito.mock(Environment.class); + SCBEngine scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + scbEngine.setEnvironment(environment); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + scbEngine.setStatus(SCBStatus.UP); + + SCBApplicationListener listener = new SCBApplicationListener(scbEngine); + listener.onApplicationEvent(contextClosedEvent); + + Assertions.assertEquals(SCBStatus.DOWN, scbEngine.getStatus()); + + scbEngine.destroy(); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestSCBEngine.java b/core/src/test/java/org/apache/servicecomb/core/TestSCBEngine.java deleted file mode 100644 index 7ad7ce489f6..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/TestSCBEngine.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.core.BootListener.EventType; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.core.provider.producer.ProducerProviderManager; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestSCBEngine { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void test(@Injectable ProducerProviderManager producerProviderManager, - @Injectable ConsumerProviderManager consumerProviderManager, - @Injectable TransportManager transportManager, - @Injectable AppManager appManager) { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry().getAppManager(); - RegistryUtils.getInstanceCacheManager(); - RegistryUtils.run(); - RegistryUtils.destroy(); - } - }; - AtomicBoolean configDestroy = new AtomicBoolean(); - new MockUp() { - @Mock - void destroyConfigCenterConfigurationSource() { - configDestroy.set(true); - } - }; - - SchemaListenerManager schemaListenerManager = Mockito.mock(SchemaListenerManager.class); - - VertxUtils.getOrCreateVertxByName("transport", null); - - SCBEngine engine = new SCBEngine(); - engine.setBootListenerList(new ArrayList<>()); - engine.setConsumerProviderManager(consumerProviderManager); - engine.setProducerProviderManager(producerProviderManager); - engine.setTransportManager(transportManager); - engine.setSchemaListenerManager(schemaListenerManager); - - ArchaiusUtils.setProperty(SCBEngine.CFG_KEY_WAIT_UP_TIMEOUT, 0); - engine.init(); - ArchaiusUtils.updateProperty(SCBEngine.CFG_KEY_WAIT_UP_TIMEOUT, null); - - Assert.assertEquals(SCBStatus.STARTING, engine.getStatus()); - - engine.destroy(); - - Assert.assertEquals(SCBStatus.DOWN, engine.getStatus()); - Assert.assertTrue(configDestroy.get()); - } - - @Test - public void createReferenceConfigForInvoke_up(@Mocked ConsumerProviderManager consumerProviderManager) { - SCBEngine engine = new SCBEngine(); - engine.setStatus(SCBStatus.UP); - engine.setConsumerProviderManager(consumerProviderManager); - - ReferenceConfig referenceConfig = engine.createReferenceConfigForInvoke(null, null, null); - Assert.assertTrue(ReferenceConfig.class.isInstance(referenceConfig)); - } - - @Test - public void createReferenceConfigForInvoke_down(@Mocked ConsumerProviderManager consumerProviderManager) { - SCBEngine engine = new SCBEngine(); - engine.setStatus(SCBStatus.DOWN); - engine.setConsumerProviderManager(consumerProviderManager); - - expectedException.expect(InvocationException.class); - expectedException.expectMessage( - Matchers - .is("InvocationException: code=503;msg=CommonExceptionData [message=The request is rejected. Cannot process the request due to STATUS = DOWN]")); - engine.createReferenceConfigForInvoke(null, null, null); - } - - @Test - public void getReferenceConfigForInvoke_up(@Mocked ConsumerProviderManager consumerProviderManager) { - SCBEngine engine = new SCBEngine(); - engine.setStatus(SCBStatus.UP); - engine.setConsumerProviderManager(consumerProviderManager); - - ReferenceConfig referenceConfig = engine.getReferenceConfigForInvoke(null); - Assert.assertTrue(ReferenceConfig.class.isInstance(referenceConfig)); - } - - @Test - public void getReferenceConfigForInvoke_down(@Mocked ConsumerProviderManager consumerProviderManager) { - SCBEngine engine = new SCBEngine(); - engine.setStatus(SCBStatus.DOWN); - engine.setConsumerProviderManager(consumerProviderManager); - - expectedException.expect(InvocationException.class); - expectedException.expectMessage( - Matchers - .is("InvocationException: code=503;msg=CommonExceptionData [message=The request is rejected. Cannot process the request due to STATUS = DOWN]")); - engine.getReferenceConfigForInvoke(null); - } - - @Test - public void setBootListenerList(@Mocked BootListener beanListener, @Mocked BootListener spiListener) { - new Expectations(SPIServiceUtils.class) { - { - beanListener.getOrder(); - result = 1; - spiListener.getOrder(); - result = 0; - SPIServiceUtils.getOrLoadSortedService(BootListener.class); - result = Arrays.asList(spiListener); - } - }; - - SCBEngine engine = new SCBEngine(); - engine.setBootListenerList(Arrays.asList(beanListener)); - - Assert.assertThat(engine.getBootListenerList(), Matchers.contains(spiListener, beanListener)); - } - - @Test - public void bootEvent_refEngine() { - Holder eventEngine = new Holder<>(); - SCBEngine engine = new SCBEngine(); - engine.setBootListenerList(Arrays.asList(event -> eventEngine.value = event.getScbEngine())); - engine.triggerEvent(EventType.AFTER_REGISTRY); - - Assert.assertNotNull(eventEngine.value); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/TestTransport.java b/core/src/test/java/org/apache/servicecomb/core/TestTransport.java index d6a118308bd..4ab2f99ff80 100644 --- a/core/src/test/java/org/apache/servicecomb/core/TestTransport.java +++ b/core/src/test/java/org/apache/servicecomb/core/TestTransport.java @@ -17,40 +17,34 @@ package org.apache.servicecomb.core; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.core.env.Environment; -import org.apache.servicecomb.core.endpoint.EndpointsCache; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.Assert; -import org.junit.Test; +public class TestTransport { + @BeforeAll + public static void classSetup() { -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; + } + + @AfterAll + public static void classTeardown() { + } -public class TestTransport { @Test public void testEndpoint() throws Exception { Endpoint oEndpoint = new Endpoint(new Transport() { - - @Override - public void send(Invocation invocation, AsyncResponse asyncResp) { - } - @Override public Object parseAddress(String address) { return "127.0.0.1"; } + @Override + public void setEnvironment(Environment environment) { + + } @Override public boolean init() { return true; @@ -72,40 +66,9 @@ public Endpoint getPublishEndpoint() { } }, "rest://127.0.0.1:8080"); oEndpoint.getTransport().init(); - Assert.assertEquals("rest://127.0.0.1:8080", oEndpoint.getEndpoint()); - Assert.assertEquals("127.0.0.1", oEndpoint.getAddress()); - Assert.assertEquals("test", oEndpoint.getTransport().getName()); - Assert.assertEquals("rest://127.0.0.1:8080", oEndpoint.getEndpoint()); - } - - @Test - public void testAbstractTransport(@Mocked Microservice microservice, - @Injectable InstanceCacheManager instanceCacheManager, @Injectable TransportManager transportManager, - @Mocked InstanceCache instanceCache, @Injectable MicroserviceInstance instance) { - EndpointsCache.init(instanceCacheManager, transportManager); - EndpointsCache oEndpointsCache = new EndpointsCache("app", "testname", "test", "rest"); - - List endpoionts = oEndpointsCache.getLatestEndpoints(); - Assert.assertEquals(endpoionts.size(), 0); - - Map> allTransportMap = new HashMap<>(); - CacheEndpoint cacheEndpoint = new CacheEndpoint("rest://127.0.0.1:9999", instance); - List restEndpoints = new ArrayList<>(); - restEndpoints.add(cacheEndpoint); - allTransportMap.put("rest", restEndpoints); - - new Expectations() { - { - instanceCacheManager.getOrCreate(anyString, anyString, anyString); - result = instanceCache; - instanceCache.cacheChanged((InstanceCache) any); - result = true; - instanceCache.getOrCreateTransportMap(); - result = allTransportMap; - } - }; - - endpoionts = oEndpointsCache.getLatestEndpoints(); - Assert.assertEquals(endpoionts.size(), 1); + Assertions.assertEquals("rest://127.0.0.1:8080", oEndpoint.getEndpoint()); + Assertions.assertEquals("127.0.0.1", oEndpoint.getAddress()); + Assertions.assertEquals("test", oEndpoint.getTransport().getName()); + Assertions.assertEquals("rest://127.0.0.1:8080", oEndpoint.getEndpoint()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/Utils.java b/core/src/test/java/org/apache/servicecomb/core/Utils.java deleted file mode 100644 index 998a8ca4be8..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/Utils.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core; - -import java.lang.reflect.Method; - -import org.springframework.util.ReflectionUtils; - -import com.netflix.config.DynamicProperty; - -public class Utils { - private static Method updatePropertyMethod = - ReflectionUtils.findMethod(DynamicProperty.class, "updateProperty", String.class, Object.class); - - static { - updatePropertyMethod.setAccessible(true); - } - - public static void updateProperty(String key, Object value) { - ReflectionUtils.invokeMethod(updatePropertyMethod, null, key, value); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/consumer/TestReactiveResponseExecutor.java b/core/src/test/java/org/apache/servicecomb/core/consumer/TestReactiveResponseExecutor.java index 48269827b7d..0e2b33b9012 100644 --- a/core/src/test/java/org/apache/servicecomb/core/consumer/TestReactiveResponseExecutor.java +++ b/core/src/test/java/org/apache/servicecomb/core/consumer/TestReactiveResponseExecutor.java @@ -18,8 +18,8 @@ package org.apache.servicecomb.core.consumer; import org.apache.servicecomb.core.provider.consumer.ReactiveResponseExecutor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestReactiveResponseExecutor { @@ -33,6 +33,6 @@ public void testReactiveResponseExecutor() { } catch (Exception e) { validAssert = false; } - Assert.assertTrue(validAssert); + Assertions.assertTrue(validAssert); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/consumer/TestSyncResponseExecutor.java b/core/src/test/java/org/apache/servicecomb/core/consumer/TestSyncResponseExecutor.java index 988005dceb2..750203072b7 100644 --- a/core/src/test/java/org/apache/servicecomb/core/consumer/TestSyncResponseExecutor.java +++ b/core/src/test/java/org/apache/servicecomb/core/consumer/TestSyncResponseExecutor.java @@ -17,10 +17,11 @@ package org.apache.servicecomb.core.consumer; +import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestSyncResponseExecutor { @@ -29,14 +30,15 @@ public void testSyncResponseExecutor() { SyncResponseExecutor executor = new SyncResponseExecutor(); Runnable cmd = Mockito.mock(Runnable.class); Response response = Mockito.mock(Response.class); + Invocation invocation = Mockito.mock(Invocation.class); executor.execute(cmd); executor.setResponse(response); try { - Response responseValue = executor.waitResponse(); - Assert.assertNotNull(responseValue); + Response responseValue = executor.waitResponse(invocation); + Assertions.assertNotNull(responseValue); } catch (Exception e) { - Assert.assertNotNull(e); + Assertions.assertNotNull(e); } } } diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/MicroServicePropertyExtendedStub.java b/core/src/test/java/org/apache/servicecomb/core/definition/MicroServicePropertyExtendedStub.java index 64224d98f0a..96550b1214f 100644 --- a/core/src/test/java/org/apache/servicecomb/core/definition/MicroServicePropertyExtendedStub.java +++ b/core/src/test/java/org/apache/servicecomb/core/definition/MicroServicePropertyExtendedStub.java @@ -19,7 +19,7 @@ import java.util.Map; -import org.apache.servicecomb.serviceregistry.api.PropertyExtended; +import org.apache.servicecomb.registry.api.PropertyExtended; public class MicroServicePropertyExtendedStub implements PropertyExtended { @Override diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/OperationConfigTest.java b/core/src/test/java/org/apache/servicecomb/core/definition/OperationConfigTest.java new file mode 100644 index 00000000000..ad664261980 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/definition/OperationConfigTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.definition; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.CoreConst; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class OperationConfigTest { + OperationConfig config = new OperationConfig(); + + @Nested + class InPoolTimeout { + @Test + void should_get_rest_value() { + config.setMsDefaultRequestWaitInPoolTimeout(1); + config.setMsRestRequestWaitInPoolTimeout(2); + + long nano = TimeUnit.MILLISECONDS.toNanos(2); + assertThat(config.getNanoRestRequestWaitInPoolTimeout()).isEqualTo(nano); + assertThat(config.getNanoRequestWaitInPoolTimeout(CoreConst.RESTFUL)).isEqualTo(nano); + } + + @Test + void should_get_highway_value() { + config.setMsDefaultRequestWaitInPoolTimeout(1); + config.setMsHighwayRequestWaitInPoolTimeout(2); + + long nano = TimeUnit.MILLISECONDS.toNanos(2); + assertThat(config.getNanoHighwayRequestWaitInPoolTimeout()).isEqualTo(nano); + assertThat(config.getNanoRequestWaitInPoolTimeout(CoreConst.HIGHWAY)).isEqualTo(nano); + } + + @Test + void should_support_register_customize_transport() { + config.setMsDefaultRequestWaitInPoolTimeout(1); + config.registerRequestWaitInPoolTimeout("abc", 2); + + long nano = TimeUnit.MILLISECONDS.toNanos(2); + assertThat(config.getNanoRequestWaitInPoolTimeout("abc")).isEqualTo(nano); + } + + @Test + void should_get_invocation_timeout_value() { + config.setMsInvocationTimeout(1); + + long nano = TimeUnit.MILLISECONDS.toNanos(1); + assertThat(config.getNanoInvocationTimeout()).isEqualTo(nano); + assertThat(config.getMsInvocationTimeout()).isEqualTo(1); + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaTest.java b/core/src/test/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaTest.java deleted file mode 100644 index a06f0870188..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/StaticMicroserviceVersionMetaTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.schema.StaticSchemaFactory; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import mockit.Mock; -import mockit.MockUp; - -public class StaticMicroserviceVersionMetaTest { - - private static final String APP_ID_FROM_REGISTRY_UTIL = "appIdFromRegistryUtil"; - - @BeforeClass - public static void beforeClass() { - new MockUp() { - @Mock - String getAppId() { - return APP_ID_FROM_REGISTRY_UTIL; - } - }; - } - - @Test - public void testConstruct() { - StaticMicroservice staticMicroservice = new StaticMicroservice(); - String appId = "testAppId"; - String serviceName = "testServiceName"; - String version = "1.2.1"; - staticMicroservice.setAppId(appId); - staticMicroservice.setServiceName(serviceName); - staticMicroservice.setVersion(version); - - MicroserviceClassLoaderFactory classLoaderFactory = Mockito.mock(MicroserviceClassLoaderFactory.class); - ClassLoader classLoader = Mockito.mock(ClassLoader.class); - Mockito.when(classLoaderFactory.create(appId, serviceName, version)).thenReturn(classLoader); - - Holder schemaLoaded = new Holder<>(false); - SCBEngine.getInstance().setStaticSchemaFactory(new MockUp() { - @Mock - void loadSchema(MicroserviceMeta microserviceMeta, StaticMicroservice microservice) { - Assert.assertSame(classLoader, microserviceMeta.getClassLoader()); - Assert.assertSame(APP_ID_FROM_REGISTRY_UTIL, microserviceMeta.getAppId()); - Assert.assertSame(serviceName, microserviceMeta.getName()); - Assert.assertSame(serviceName, microserviceMeta.getShortName()); - Assert.assertSame(staticMicroservice, microservice); - schemaLoaded.value = true; - } - }.getMockInstance()); - Holder listenerNotified = new Holder<>(false); - CseContext.getInstance().setSchemaListenerManager(new MockUp() { - @Mock - void notifySchemaListener(MicroserviceMeta... microserviceMetas) { - Assert.assertEquals(1, microserviceMetas.length); - MicroserviceMeta microserviceMeta = microserviceMetas[0]; - Assert.assertEquals(serviceName, microserviceMeta.getShortName()); - listenerNotified.value = true; - } - }.getMockInstance()); - - StaticMicroserviceVersionMeta staticMicroserviceVersionMeta = new StaticMicroserviceVersionMeta(staticMicroservice, - classLoaderFactory); - - Assert.assertTrue(schemaLoaded.value); - Assert.assertTrue(listenerNotified.value); - Assert.assertSame(staticMicroservice, staticMicroserviceVersionMeta.getMicroservice()); - Assert.assertEquals(serviceName, staticMicroserviceVersionMeta.getMicroserviceMeta().getName()); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMeta.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMeta.java deleted file mode 100644 index e9d6378c25c..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMeta.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import java.util.Collection; - -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoader; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceMeta { - MicroserviceMeta microserviceMeta = new MicroserviceMeta("app:microservice"); - - @Test - public void classloader() { - ClassLoader loader = new MicroserviceClassLoader("", "", ""); - microserviceMeta.setClassLoader(loader); - Assert.assertSame(loader, microserviceMeta.getClassLoader()); - } - - @Test - public void testGetSchemaMetas() { - Collection schemaMetas = microserviceMeta.getSchemaMetas(); - Assert.assertNotNull(schemaMetas); - } - - @Test - public void testGetExtData() { - Object data = new Object(); - microserviceMeta.putExtData("pruthi", data); - Object response = microserviceMeta.getExtData("pruthi"); - Assert.assertNotNull(response); - } - - @Test - public void testIntf(@Mocked SchemaMeta sm1, @Mocked SchemaMeta sm2) { - Class intf = Object.class; - new Expectations() { - { - sm1.getSchemaId(); - result = "a"; - sm2.getSchemaId(); - result = "b"; - sm1.getSwaggerIntf(); - result = intf; - sm2.getSwaggerIntf(); - result = intf; - } - }; - - try { - microserviceMeta.ensureFindSchemaMeta(intf); - Assert.assertEquals(1, 2); - } catch (Throwable e) { - Assert.assertEquals( - "No schema interface is java.lang.Object.", - e.getMessage()); - } - microserviceMeta.regSchemaMeta(sm1); - Assert.assertEquals(sm1, microserviceMeta.findSchemaMeta(intf)); - Assert.assertEquals(sm1, microserviceMeta.ensureFindSchemaMeta(intf)); - - microserviceMeta.regSchemaMeta(sm2); - Assert.assertEquals(sm1, microserviceMeta.ensureFindSchemaMeta("a")); - Assert.assertEquals(sm2, microserviceMeta.ensureFindSchemaMeta("b")); - try { - microserviceMeta.findSchemaMeta(intf); - Assert.assertEquals(1, 2); - } catch (Throwable e) { - Assert.assertEquals( - "More than one schema interface is java.lang.Object, please use schemaId to choose a schema.", - e.getMessage()); - } - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMetaManager.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMetaManager.java index 55ea9b76b57..8d89a10a285 100644 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMetaManager.java +++ b/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceMetaManager.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.core.definition; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestMicroserviceMetaManager { @@ -28,6 +28,6 @@ public void testEnsureFindSchemaMeta() { SchemaMeta meta = Mockito.mock(SchemaMeta.class); MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); Mockito.when(microserviceMeta.ensureFindSchemaMeta("yhfghj")).thenReturn(meta); - Assert.assertEquals(meta, microserviceMeta.ensureFindSchemaMeta("yhfghj")); + Assertions.assertEquals(meta, microserviceMeta.ensureFindSchemaMeta("yhfghj")); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMeta.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMeta.java deleted file mode 100644 index 9f5d6804112..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMeta.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.definition.classloader.MicroserviceClassLoader; -import org.apache.servicecomb.core.definition.classloader.PrivateMicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestMicroserviceVersionMeta { - @AfterClass - public static void teardown() { - CseContext.getInstance().setConsumerSchemaFactory(null); - CseContext.getInstance().setSchemaListenerManager(null); - } - - @Test - public void construct(@Mocked ServiceRegistry serviceRegistry) { - String microserviceName = "app:ms"; - String microserviceId = "id"; - Microservice microservice = new Microservice(); - microservice.setVersion("1.0.0"); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAggregatedRemoteMicroservice(microserviceId); - result = microservice; - } - }; - - List logs = new ArrayList<>(); - CseContext.getInstance().setConsumerSchemaFactory(new MockUp() { - @Mock - void createConsumerSchema(MicroserviceMeta microserviceMeta, Microservice microservice) { - logs.add("createConsumerSchema"); - } - }.getMockInstance()); - CseContext.getInstance().setSchemaListenerManager(new MockUp() { - @Mock - void notifySchemaListener(MicroserviceMeta... microserviceMetas) { - logs.add("notifySchemaListener"); - } - }.getMockInstance()); - - MicroserviceVersionMeta microserviceVersionMeta = - new MicroserviceVersionMeta(microserviceName, microserviceId, PrivateMicroserviceClassLoaderFactory.INSTANCE); - - Assert.assertThat(logs, Matchers.contains("createConsumerSchema", "notifySchemaListener")); - Assert.assertEquals(microserviceName, microserviceVersionMeta.getMicroserviceMeta().getName()); - Assert.assertThat(microserviceVersionMeta.getMicroserviceMeta().getClassLoader(), - Matchers.instanceOf(MicroserviceClassLoader.class)); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMetaFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMetaFactory.java deleted file mode 100644 index 8e5382abf34..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestMicroserviceVersionMetaFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.definition.classloader.DefaultMicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.classloader.PrivateMicroserviceClassLoaderFactory; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceVersionMetaFactory { - @AfterClass - public static void teardown() { - CseContext.getInstance().setConsumerSchemaFactory(null); - CseContext.getInstance().setSchemaListenerManager(null); - } - - @Test - public void construct() { - MicroserviceVersionMetaFactory factory = new MicroserviceVersionMetaFactory(); - Assert.assertSame(DefaultMicroserviceClassLoaderFactory.INSTANCE, - Deencapsulation.getField(factory, "classLoaderFactory")); - } - - @Test - public void constructWithFactory() { - MicroserviceVersionMetaFactory factory = - new MicroserviceVersionMetaFactory(PrivateMicroserviceClassLoaderFactory.INSTANCE); - Assert.assertSame(PrivateMicroserviceClassLoaderFactory.INSTANCE, - Deencapsulation.getField(factory, "classLoaderFactory")); - } - - @Test - public void create(@Mocked ConsumerSchemaFactory consumerSchemaFactory, - @Mocked SchemaListenerManager schemaListenerManager, @Mocked ServiceRegistry serviceRegistry) { - String microserviceName = "app:ms"; - String microserviceId = "id"; - Microservice microservice = new Microservice(); - microservice.setVersion("1.0.0"); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAggregatedRemoteMicroservice(microserviceId); - result = microservice; - } - }; - CseContext.getInstance().setConsumerSchemaFactory(consumerSchemaFactory); - CseContext.getInstance().setSchemaListenerManager(schemaListenerManager); - - MicroserviceVersionMetaFactory factory = new MicroserviceVersionMetaFactory(); - MicroserviceVersion microserviceVersion = factory.create(microserviceName, microserviceId); - Assert.assertThat(microserviceVersion, Matchers.instanceOf(MicroserviceVersionMeta.class)); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestOperationMeta.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestOperationMeta.java deleted file mode 100644 index efd56eb4a09..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestOperationMeta.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; - -public class TestOperationMeta { - class Impl { - @ApiResponse( - code = 300, - response = String.class, - message = "", - responseHeaders = {@ResponseHeader(name = "h3", response = int.class)}) - @ResponseHeaders({@ResponseHeader(name = "h1", response = int.class), - @ResponseHeader(name = "h2", response = String.class, responseContainer = "List")}) - public int test(int x) { - return 100; - } - } - - @Test - public void testOperationMeta() { - UnitTestMeta meta = new UnitTestMeta(); - SchemaMeta schemaMeta = meta.getOrCreateSchemaMeta(Impl.class); - OperationMeta operationMeta = schemaMeta.findOperation("test"); - - Assert.assertEquals("POST", operationMeta.getHttpMethod()); - Assert.assertEquals("/test", operationMeta.getOperationPath()); - Assert.assertEquals(schemaMeta, operationMeta.getSchemaMeta()); - Assert.assertEquals(Impl.class.getName() + ".test", - operationMeta.getSchemaQualifiedName()); - Assert.assertEquals("perfClient." + Impl.class.getName() + ".test", - operationMeta.getMicroserviceQualifiedName()); - Assert.assertEquals("perfClient", operationMeta.getMicroserviceName()); - Assert.assertEquals("test", operationMeta.getOperationId()); - Assert.assertEquals("x", operationMeta.getParamName(0)); - - operationMeta.putExtData("ext", 1); - Assert.assertEquals(1, (int) operationMeta.getExtData("ext")); - - ResponseMeta responseMeta = operationMeta.findResponseMeta(200); - Assert.assertEquals("Ljava/lang/Integer;", responseMeta.getJavaType().getGenericSignature()); - Assert.assertEquals("Ljava/lang/Integer;", responseMeta.getHeaders().get("h1").getGenericSignature()); - Assert.assertEquals("Ljava/util/List;", - responseMeta.getHeaders().get("h2").getGenericSignature()); - Assert.assertEquals(null, responseMeta.getHeaders().get("h3")); - - responseMeta = operationMeta.findResponseMeta(300); - Assert.assertEquals("Ljava/lang/String;", responseMeta.getJavaType().getGenericSignature()); - Assert.assertEquals("Ljava/lang/Integer;", responseMeta.getHeaders().get("h1").getGenericSignature()); - Assert.assertEquals("Ljava/util/List;", - responseMeta.getHeaders().get("h2").getGenericSignature()); - Assert.assertEquals("Ljava/lang/Integer;", responseMeta.getHeaders().get("h3").getGenericSignature()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestPrivateMicroserviceVersionMetaFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestPrivateMicroserviceVersionMetaFactory.java deleted file mode 100644 index c4e382efe9e..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestPrivateMicroserviceVersionMetaFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.core.definition.classloader.PrivateMicroserviceClassLoaderFactory; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; - -public class TestPrivateMicroserviceVersionMetaFactory { - @Test - public void construct() { - PrivateMicroserviceVersionMetaFactory factory = new PrivateMicroserviceVersionMetaFactory(); - Assert.assertSame(PrivateMicroserviceClassLoaderFactory.INSTANCE, - Deencapsulation.getField(factory, "classLoaderFactory")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaMeta.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaMeta.java deleted file mode 100644 index 96fba28376a..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaMeta.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.Swagger; -import mockit.Mocked; - -public class TestSchemaMeta { - static interface V1 { - void a(); - } - - static interface V2 extends V1 { - void b(); - } - - @Test - public void testMethodNotExist(@Mocked OperationMeta operationMeta) { - Swagger swagger = UnitTestSwaggerUtils.generateSwagger(V2.class).getSwagger(); - // make swagger have more operations than interface - swagger.getInfo().setVendorExtension(SwaggerConst.EXT_JAVA_INTF, V1.class.getName()); - - MicroserviceMeta microserviceMeta = new MicroserviceMeta("app:ms"); - SchemaMeta schemaMeta = new SchemaMeta(swagger, microserviceMeta, "schemaId"); - Assert.assertEquals(1, schemaMeta.getOperations().size()); - Assert.assertNotNull(schemaMeta.findOperation("a")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaUtils.java b/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaUtils.java deleted file mode 100644 index 415b9eba581..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/TestSchemaUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition; - -import org.junit.Assert; -import org.junit.Test; - -public class TestSchemaUtils { - @Test - public void generatePackageName() { - MicroserviceMeta microserviceMeta = new MicroserviceMeta("app:ms"); - Assert.assertEquals("cse.gen.app.ms.schemaId", SchemaUtils.generatePackageName(microserviceMeta, "schemaId")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestDefaultMicroserviceClassLoaderFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestDefaultMicroserviceClassLoaderFactory.java deleted file mode 100644 index 7b5dfa13983..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestDefaultMicroserviceClassLoaderFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -import org.junit.Assert; -import org.junit.Test; - -public class TestDefaultMicroserviceClassLoaderFactory { - @Test - public void create() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - - Assert.assertSame(loader, DefaultMicroserviceClassLoaderFactory.INSTANCE.create("", "", "")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestPrivateMicroserviceClassLoaderFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestPrivateMicroserviceClassLoaderFactory.java deleted file mode 100644 index 2c4f4bde0f5..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/classloader/TestPrivateMicroserviceClassLoaderFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.classloader; - -import org.junit.Assert; -import org.junit.Test; - -public class TestPrivateMicroserviceClassLoaderFactory { - @Test - public void create() { - String appId = "app"; - String microserviceName = "ms"; - String version = "1"; - - MicroserviceClassLoader loader = - (MicroserviceClassLoader) PrivateMicroserviceClassLoaderFactory.INSTANCE - .create(appId, microserviceName, version); - - Assert.assertEquals(appId, loader.getAppId()); - Assert.assertEquals(microserviceName, loader.getMicroserviceName()); - Assert.assertEquals(version, loader.getVersion()); - Assert.assertEquals("MicroserviceClassLoader app:ms:1", loader.toString()); - Assert.assertSame(Thread.currentThread().getContextClassLoader(), loader.getParent()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestDynamicSchemaLoader.java b/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestDynamicSchemaLoader.java deleted file mode 100644 index 74e47e830b2..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestDynamicSchemaLoader.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.definition.loader; - -import java.util.ArrayList; -import java.util.Collections; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestDynamicSchemaLoader { - - private static SchemaLoader loader = new SchemaLoader(); - - private static Microservice microservice; - - @BeforeClass - public static void init() { - new UnitTestMeta(); - - SchemaListenerManager schemaListenerManager = new SchemaListenerManager(); - schemaListenerManager.setSchemaListenerList(Collections.emptyList()); - - CseContext context = CseContext.getInstance(); - context.setSchemaLoader(loader); - context.setSchemaListenerManager(schemaListenerManager); - - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - - microservice = serviceRegistry.getMicroservice(); - RegistryUtils.setServiceRegistry(serviceRegistry); - } - - @AfterClass - public static void teardown() { - RegistryUtils.setServiceRegistry(null); - } - - @SuppressWarnings("deprecation") - @Test - public void testRegisterSchemas() { - DynamicSchemaLoader.INSTANCE.registerSchemas("classpath*:test/test/schema.yaml"); - SchemaMeta schemaMeta = SCBEngine.getInstance().getProducerMicroserviceMeta().ensureFindSchemaMeta("schema"); - Assert.assertEquals("cse.gen.app.perfClient.schema", schemaMeta.getPackageName()); - } - - @SuppressWarnings("deprecation") - @Test - public void testRegisterShemasAcrossApp() { - //we can not register repeat data - init(); - //as we can not set microserviceName any more, hence we should use the default name - DynamicSchemaLoader.INSTANCE - .registerSchemas(RegistryUtils.getMicroservice().getServiceName(), "classpath*:test/test/schema.yaml"); - SchemaMeta schemaMeta = - SCBEngine.getInstance().getProducerMicroserviceMeta().ensureFindSchemaMeta("schema"); - Assert.assertEquals("cse.gen.app.perfClient.schema", schemaMeta.getPackageName()); - } - - @Test - public void testPutSelfBasePathIfAbsent_noUrlPrefix() { - System.clearProperty(Const.URL_PREFIX); - microservice.setPaths(new ArrayList<>()); - - loader.putSelfBasePathIfAbsent("perfClient", "/test"); - - Assert.assertThat(microservice.getPaths().size(), Matchers.is(1)); - Assert.assertThat(microservice.getPaths().get(0).getPath(), Matchers.is("/test")); - } - - @Test - public void testPutSelfBasePathIfAbsent_WithUrlPrefix() { - System.setProperty(Const.URL_PREFIX, "/root/rest"); - microservice.setPaths(new ArrayList<>()); - - loader.putSelfBasePathIfAbsent("perfClient", "/test"); - - Assert.assertThat(microservice.getPaths().size(), Matchers.is(1)); - Assert.assertThat(microservice.getPaths().get(0).getPath(), Matchers.is("/root/rest/test")); - - System.clearProperty(Const.URL_PREFIX); - } - - @Test - public void testPutSelfBasePathIfAbsent_WithUrlPrefix_StartWithUrlPrefix() { - System.setProperty(Const.URL_PREFIX, "/root/rest"); - microservice.setPaths(new ArrayList<>()); - - loader.putSelfBasePathIfAbsent("perfClient", "/root/rest/test"); - - Assert.assertThat(microservice.getPaths().size(), Matchers.is(1)); - Assert.assertThat(microservice.getPaths().get(0).getPath(), Matchers.is("/root/rest/test")); - - System.clearProperty(Const.URL_PREFIX); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestSchemaListenerManager.java b/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestSchemaListenerManager.java deleted file mode 100644 index 445cf1af7bc..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/loader/TestSchemaListenerManager.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.loader; - -import java.util.Arrays; - -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestSchemaListenerManager { - - SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); - - @Before - public void setUp() { - Mockito.when(schemaMeta.getSchemaId()).thenReturn("test"); - } - - @Test - public void testInitializationListener() { - SchemaListener listener = new SchemaListener() { - @Override - public void onSchemaLoaded(SchemaMeta... schemaMetas) { - Assert.assertEquals(1, schemaMetas.length); - Assert.assertEquals("test", schemaMetas[0].getSchemaId()); - } - }; - - SchemaListenerManager mgr = new SchemaListenerManager(); - mgr.setSchemaListenerList(Arrays.asList(listener)); - - mgr.notifySchemaListener(schemaMeta); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactoryTest.java b/core/src/test/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactoryTest.java deleted file mode 100644 index 2f254ae7c7d..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/schema/StaticSchemaFactoryTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.definition.schema; - -import java.lang.reflect.Method; -import java.util.concurrent.CompletableFuture; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class StaticSchemaFactoryTest { - - private static final StaticSchemaFactory staticSchemaFactory = new StaticSchemaFactory(); - - private static final String APPLICATION_ID_KEY = "APPLICATION_ID"; - - private static final String APP_ID_VALUE = "appIdTest"; - - @BeforeClass - public static void beforeClass() { - System.setProperty(APPLICATION_ID_KEY, APP_ID_VALUE); - new UnitTestMeta(); - - CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext = new CompositeSwaggerGeneratorContext(); - ReflectUtils.setField(staticSchemaFactory, "compositeSwaggerGeneratorContext", compositeSwaggerGeneratorContext); - - SchemaLoader schemaLoader = new SchemaLoader(); - ReflectUtils.setField(staticSchemaFactory, "schemaLoader", schemaLoader); - } - - @AfterClass - public static void afterClass() { - TestProducerSchemaFactory.teardown(); - System.clearProperty(APPLICATION_ID_KEY); - } - - @Test - public void testLoadSchema() { - String serviceAndSchemaName = "3rdPartyService"; - StaticMicroservice staticMicroservice = new StaticMicroservice(); - staticMicroservice.setSchemaIntfCls(Test3rdPartyServiceIntf.class); - MicroserviceMeta microserviceMeta = new MicroserviceMeta(serviceAndSchemaName); - staticSchemaFactory.loadSchema(microserviceMeta, staticMicroservice); - - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(serviceAndSchemaName); - Assert.assertEquals(EXPECTED_SCHEMA_CONTENT, - SwaggerUtils.swaggerToString(schemaMeta.getSwagger())); - - Assert.assertEquals(2, schemaMeta.getOperations().size()); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("add"); - Assert.assertEquals("add", operationMeta.getOperationId()); - Method swaggerProducerMethod = operationMeta.getMethod(); - Class[] parameterTypes = swaggerProducerMethod.getParameterTypes(); - Assert.assertEquals(2, parameterTypes.length); - Assert.assertEquals(Integer.class, parameterTypes[0]); - Assert.assertEquals(Integer.class, parameterTypes[1]); - Assert.assertEquals(Integer.class, swaggerProducerMethod.getGenericReturnType()); - - operationMeta = schemaMeta.ensureFindOperation("addAsync"); - Assert.assertEquals("addAsync", operationMeta.getOperationId()); - swaggerProducerMethod = operationMeta.getMethod(); - parameterTypes = swaggerProducerMethod.getParameterTypes(); - Assert.assertEquals(2, parameterTypes.length); - Assert.assertEquals(Integer.class, parameterTypes[0]); - Assert.assertEquals(Integer.class, parameterTypes[1]); - // ensure reactive operation's return type is set correctly, not CompletableFuture - Assert.assertEquals(Integer.class, swaggerProducerMethod.getGenericReturnType()); - } - - @Path("/3rdParty") - interface Test3rdPartyServiceIntf { - - @Path("/add") - @GET - int add(@QueryParam("x") int x, @QueryParam("y") int y); - - @Path("/addAsync") - @GET - CompletableFuture addAsync(@QueryParam("x") int x, @QueryParam("y") int y); - } - - private static final String EXPECTED_SCHEMA_CONTENT = "---\n" - + "swagger: \"2.0\"\n" - + "info:\n" - + " version: \"1.0.0\"\n" - + " title: \"swagger definition for org.apache.servicecomb.core.definition.schema.StaticSchemaFactoryTest$Test3rdPartyServiceIntf\"\n" - + " x-java-interface: \"cse.gen.appIdTest._3rdPartyService._3rdPartyService.Test3rdPartyServiceIntfIntf\"\n" - + "basePath: \"/3rdParty\"\n" - + "consumes:\n" - + "- \"application/json\"\n" - + "produces:\n" - + "- \"application/json\"\n" - + "paths:\n" - + " /add:\n" - + " get:\n" - + " operationId: \"add\"\n" - + " parameters:\n" - + " - name: \"x\"\n" - + " in: \"query\"\n" - + " required: false\n" - + " type: \"integer\"\n" - + " default: 0\n" - + " format: \"int32\"\n" - + " - name: \"y\"\n" - + " in: \"query\"\n" - + " required: false\n" - + " type: \"integer\"\n" - + " default: 0\n" - + " format: \"int32\"\n" - + " responses:\n" - + " 200:\n" - + " description: \"response of 200\"\n" - + " schema:\n" - + " type: \"integer\"\n" - + " format: \"int32\"\n" - + " /addAsync:\n" - + " get:\n" - + " operationId: \"addAsync\"\n" - + " parameters:\n" - + " - name: \"x\"\n" - + " in: \"query\"\n" - + " required: false\n" - + " type: \"integer\"\n" - + " default: 0\n" - + " format: \"int32\"\n" - + " - name: \"y\"\n" - + " in: \"query\"\n" - + " required: false\n" - + " type: \"integer\"\n" - + " default: 0\n" - + " format: \"int32\"\n" - + " responses:\n" - + " 200:\n" - + " description: \"response of 200\"\n" - + " schema:\n" - + " type: \"integer\"\n" - + " format: \"int32\"\n"; -} \ No newline at end of file diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestConsumerSchemaFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestConsumerSchemaFactory.java deleted file mode 100644 index ec59bd71c13..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestConsumerSchemaFactory.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.definition.schema; - -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -public class TestConsumerSchemaFactory { - class TestConsumerSchemaFactoryImpl { - public int add(int x, int y) { - return x + y; - } - } - - @Test - public void createConsumerSchema() { - UnitTestMeta meta = new UnitTestMeta(); - meta.registerSchema(new PojoSwaggerGeneratorContext(), TestConsumerSchemaFactoryImpl.class); - - MicroserviceVersionRule microserviceVersionRule = meta.getServiceRegistry().getAppManager() - .getOrCreateMicroserviceVersionRule("app", "app:test", DefinitionConst.VERSION_RULE_ALL); - MicroserviceMeta microserviceMeta = ((MicroserviceVersionMeta) microserviceVersionRule - .getLatestMicroserviceVersion()).getMicroserviceMeta(); - - OperationMeta operationMeta = microserviceMeta - .ensureFindOperation(TestConsumerSchemaFactoryImpl.class.getName() + ".add"); - Assert.assertEquals("add", operationMeta.getOperationId()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestProducerSchemaFactory.java b/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestProducerSchemaFactory.java deleted file mode 100644 index f33b47d6e0d..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/definition/schema/TestProducerSchemaFactory.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.definition.schema; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.core.executor.ExecutorManager; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.engine.bootstrap.BootstrapNormal; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.swagger.models.Swagger; -import mockit.Mock; -import mockit.MockUp; - -public class TestProducerSchemaFactory { - private static SwaggerEnvironment swaggerEnv = new BootstrapNormal().boot(); - - private static ProducerSchemaFactory producerSchemaFactory = new ProducerSchemaFactory(); - - static boolean rejectAdd; - - public static class TestProducerSchemaFactoryImpl { - public int add(int x, int y) { - if (rejectAdd) { - throw new Error("reject add"); - } - return x + y; - } - - public CompletableFuture asyncAdd(int x, int y) { - if (rejectAdd) { - throw new Error("reject add"); - } - return CompletableFuture.completedFuture(String.valueOf(x + y)); - } - } - - static long nanoTime = 123; - - @BeforeClass - public static void init() { - new MockUp() { - @Mock - long nanoTime() { - return nanoTime; - } - }; - - new UnitTestMeta(); - - ConverterMgr converterMgr = new ConverterMgr(); - ProducerArgumentsMapperFactory producerArgsMapperFactory = new ProducerArgumentsMapperFactory(); - producerArgsMapperFactory.setConverterMgr(converterMgr); - - SchemaLoader schemaLoader = new SchemaLoader(); - CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext = new CompositeSwaggerGeneratorContext(); - - producerSchemaFactory.setSwaggerEnv(swaggerEnv); - ReflectUtils.setField(producerSchemaFactory, "schemaLoader", schemaLoader); - ReflectUtils.setField(producerSchemaFactory, - "compositeSwaggerGeneratorContext", - compositeSwaggerGeneratorContext); - - Executor reactiveExecutor = new ReactiveExecutor(); - Executor normalExecutor = (cmd) -> { - }; - new MockUp() { - @SuppressWarnings("unchecked") - @Mock - T getBean(String name) { - if (ExecutorManager.EXECUTOR_REACTIVE.equals(name)) { - return (T) reactiveExecutor; - } - - return (T) normalExecutor; - } - }; - } - - @AfterClass - public static void teardown() { - RegistryUtils.setServiceRegistry(null); - } - - @Test - public void testGetOrCreateProducer() throws Exception { - SchemaMeta schemaMeta = producerSchemaFactory.getOrCreateProducerSchema("schema", - TestProducerSchemaFactoryImpl.class, - new TestProducerSchemaFactoryImpl()); - Swagger swagger = schemaMeta.getSwagger(); - Assert.assertEquals(swagger.getBasePath(), "/TestProducerSchemaFactoryImpl"); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("add"); - Assert.assertEquals("add", operationMeta.getOperationId()); - - SwaggerProducerOperation producerOperation = operationMeta.getExtData(Const.PRODUCER_OPERATION); - //we can not set microserviceName any more,use the default name - Object addBody = Class.forName("cse.gen.app.perfClient.schema.addBody").newInstance(); - ReflectUtils.setField(addBody, "x", 1); - ReflectUtils.setField(addBody, "y", 2); - Invocation invocation = new Invocation((Endpoint) null, operationMeta, new Object[] {addBody}) { - @Override - public String getInvocationQualifiedName() { - return ""; - } - }; - Holder holder = new Holder<>(); - rejectAdd = false; - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals(3, (int) holder.value.getResult()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - - nanoTime++; - rejectAdd = true; - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals(true, holder.value.isFailed()); - InvocationException exception = holder.value.getResult(); - CommonExceptionData data = (CommonExceptionData) exception.getErrorData(); - Assert.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, exception.getStatusCode()); - Assert.assertEquals("Cse Internal Server Error", data.getMessage()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - - nanoTime++; - invocation.setSwaggerArguments(new Object[] {1, 2}); - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals(true, holder.value.isFailed()); - exception = holder.value.getResult(); - data = (CommonExceptionData) exception.getErrorData(); - Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), exception.getStatusCode()); - Assert.assertEquals("Parameters not valid or types not match.", data.getMessage()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - } - - @Test - public void testGetOrCreateProducerWithPrefix() { - ArchaiusUtils.setProperty(org.apache.servicecomb.serviceregistry.api.Const.REGISTER_URL_PREFIX, "true"); - System.setProperty(org.apache.servicecomb.serviceregistry.api.Const.URL_PREFIX, "/pojo/test"); - SchemaMeta schemaMeta = producerSchemaFactory.getOrCreateProducerSchema("schema2", - TestProducerSchemaFactoryImpl.class, - new TestProducerSchemaFactoryImpl()); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("add"); - Assert.assertEquals("add", operationMeta.getOperationId()); - Swagger swagger = schemaMeta.getSwagger(); - Assert.assertEquals(swagger.getBasePath(), "/pojo/test/TestProducerSchemaFactoryImpl"); - - ArchaiusUtils.resetConfig(); - System.getProperties().remove(org.apache.servicecomb.serviceregistry.api.Const.URL_PREFIX); - } - - @Test - public void testCompletableFuture() throws ClassNotFoundException, IllegalAccessException, InstantiationException { - SchemaMeta schemaMeta = producerSchemaFactory.getOrCreateProducerSchema("schema", - TestProducerSchemaFactoryImpl.class, - new TestProducerSchemaFactoryImpl()); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("asyncAdd"); - Assert.assertThat(operationMeta.getExecutor(), Matchers.instanceOf(ReactiveExecutor.class)); - - SwaggerProducerOperation producerOperation = operationMeta.getExtData(Const.PRODUCER_OPERATION); - //we can not set microserviceName any more,use the default name - Object addBody = Class.forName("cse.gen.app.perfClient.schema.asyncAddBody").newInstance(); - ReflectUtils.setField(addBody, "x", 1); - ReflectUtils.setField(addBody, "y", 2); - Invocation invocation = new Invocation((Endpoint) null, operationMeta, new Object[] {addBody}) { - @Override - public String getInvocationQualifiedName() { - return ""; - } - }; - Holder holder = new Holder<>(); - rejectAdd = false; - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals("3", holder.value.getResult()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - - nanoTime++; - rejectAdd = true; - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals(true, holder.value.isFailed()); - InvocationException exception = holder.value.getResult(); - CommonExceptionData data = (CommonExceptionData) exception.getErrorData(); - Assert.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, exception.getStatusCode()); - Assert.assertEquals("Cse Internal Server Error", data.getMessage()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - - nanoTime++; - invocation.setSwaggerArguments(new Object[] {1, 2}); - producerOperation.invoke(invocation, resp -> holder.value = resp); - Assert.assertEquals(true, holder.value.isFailed()); - exception = holder.value.getResult(); - data = (CommonExceptionData) exception.getErrorData(); - Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), exception.getStatusCode()); - Assert.assertEquals("Parameters not valid or types not match.", data.getMessage()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartBusinessMethod()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishBusiness()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationFinishEvent.java b/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationFinishEvent.java deleted file mode 100644 index daae2d6357d..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationFinishEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.event; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestInvocationFinishEvent { - InvocationFinishEvent event; - - @Test - public void construct(@Mocked Invocation invocation, @Mocked Response response) { - InvocationStageTrace stageTrace = new InvocationStageTrace(invocation); - long time = 123; - new MockUp() { - @Mock - long nanoTime() { - return time; - } - }; - new Expectations() { - { - invocation.getInvocationStageTrace(); - result = stageTrace; - } - }; - stageTrace.finish(); - - event = new InvocationFinishEvent(invocation, response); - - Assert.assertEquals(time, event.getNanoCurrent()); - Assert.assertSame(invocation, event.getInvocation()); - Assert.assertSame(response, event.getResponse()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationStartEvent.java b/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationStartEvent.java index 9181520bc46..6e0649d4aa1 100644 --- a/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationStartEvent.java +++ b/core/src/test/java/org/apache/servicecomb/core/event/TestInvocationStartEvent.java @@ -17,18 +17,18 @@ package org.apache.servicecomb.core.event; import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestInvocationStartEvent { InvocationStartEvent event; @Test - public void construct(@Mocked Invocation invocation) { + public void construct() { + Invocation invocation = Mockito.mock(Invocation.class); event = new InvocationStartEvent(invocation); - Assert.assertSame(invocation, event.getInvocation()); + Assertions.assertSame(invocation, event.getInvocation()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/exception/ExceptionsTest.java b/core/src/test/java/org/apache/servicecomb/core/exception/ExceptionsTest.java new file mode 100644 index 00000000000..0594084e30c --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/exception/ExceptionsTest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.assertj.core.api.Assertions.assertThat; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Collections; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.Test; + +import io.vertx.core.json.Json; +import jakarta.ws.rs.core.Response.StatusType; + +class ExceptionsTest { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void should_not_convert_invocation_exception() { + InvocationException exception = Exceptions.genericConsumer("msg"); + + assertThat(Exceptions.convert(null, exception, BAD_REQUEST)) + .isSameAs(exception); + } + + @Test + void should_convert_unknown_client_exception_to_invocation_exception() { + IllegalStateException exception = new IllegalStateException("msg"); + + InvocationException invocationException = Exceptions.convert(null, exception, BAD_REQUEST); + + assertThat(invocationException).hasCause(exception); + assertThat(invocationException.getStatus()).isEqualTo(BAD_REQUEST); + assertThat(invocationException.getErrorData()).isInstanceOf(CommonExceptionData.class); + + try { + assertThat(objectMapper.readTree(Json.encode(invocationException.getErrorData()))) + .isEqualTo(objectMapper.readTree("{\"code\":\"SCB.00000000\",\"message\":\"Unexpected exception when processing none. msg\"}")); + } catch (Exception e) { + throw new AssertionError("Error during JSON comparison: " + e.getMessage(), e); + } + } + + @Test + void should_convert_unknown_server_exception_to_invocation_exception() { + IllegalStateException exception = new IllegalStateException("msg"); + + InvocationException invocationException = Exceptions.convert(null, exception, INTERNAL_SERVER_ERROR); + + assertThat(invocationException).hasCause(exception); + assertThat(invocationException.getStatus()).isEqualTo(INTERNAL_SERVER_ERROR); + assertThat(invocationException.getErrorData()).isInstanceOf(CommonExceptionData.class); + + try { + assertThat(objectMapper.readTree(Json.encode(invocationException.getErrorData()))) + .isEqualTo(objectMapper.readTree("{\"code\":\"SCB.50000000\",\"message\":\"Unexpected exception when processing none. msg\"}")); + } catch (Exception e) { + throw new AssertionError("Error during JSON comparison: " + e.getMessage(), e); + } + } + + static class ThrowExceptionWhenConvert implements ExceptionConverter { + @Override + public int getOrder() { + return Integer.MIN_VALUE; + } + + @Override + public boolean canConvert(Throwable throwable) { + return true; + } + + @Override + public InvocationException convert(Invocation invocation, Throwable throwable, StatusType genericStatus) { + throw new RuntimeExceptionWithoutStackTrace("mock exception when convert"); + } + } + + @Test + void should_protect_when_converter_throw_exception() { + DefaultExceptionProcessor processor = new DefaultExceptionProcessor() + .setConverters(Collections.singletonList(new ThrowExceptionWhenConvert())); + + try (LogCollector logCollector = new LogCollector()) { + InvocationException exception = processor + .convert(null, new RuntimeExceptionWithoutStackTrace("exception need convert"), BAD_REQUEST); + + assertThat(exception.getStatus()) + .isSameAs(INTERNAL_SERVER_ERROR); + assertThat(exception.getErrorData().toString()) + .isEqualTo("CommonExceptionData{code='SCB.50000000', message='Internal Server Error', dynamic={}}"); + assertThat(logCollector.getLastEvents().getMessage().getFormattedMessage().replace("\r\n", "\n")) + .isEqualTo("BUG: ExceptionConverter.convert MUST not throw exception, please fix it.\n" + + "original exception :org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace: exception need convert\n" + + "converter exception:org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace: mock exception when convert\n"); + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverterTest.java b/core/src/test/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverterTest.java new file mode 100644 index 00000000000..3a1b69908bb --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/exception/converter/TimeoutExceptionConverterTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.exception.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeoutException; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.Test; + +class TimeoutExceptionConverterTest { + private InvocationException convert() { + TimeoutException timeoutException = new TimeoutException( + "The timeout period of 30000ms has been exceeded while executing GET /xxx for server 1.1.1.1:8080"); + + return Exceptions.convert(null, timeoutException, Status.BAD_REQUEST); + } + + @Test + void should_not_leak_server_ip() { + InvocationException exception = convert(); + + assertThat(exception) + .hasMessage( + "InvocationException: code=408;msg=CommonExceptionData{code='SCB.00000000', message='Request Timeout.', dynamic={}}"); + } + + @Test + void should_log_detail() { + try (LogCollector logCollector = new LogCollector()) { + convert(); + + assertThat(logCollector.getLastEvents().getMessage().getFormattedMessage()) + .isEqualTo( + "Request timeout, Details: The timeout period of 30000ms has been exceeded while executing GET /xxx for server 1.1.1.1:8080."); + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/executor/TestExecutorManager.java b/core/src/test/java/org/apache/servicecomb/core/executor/TestExecutorManager.java index b0f365416d4..2fc689efb05 100644 --- a/core/src/test/java/org/apache/servicecomb/core/executor/TestExecutorManager.java +++ b/core/src/test/java/org/apache/servicecomb/core/executor/TestExecutorManager.java @@ -21,11 +21,12 @@ import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import mockit.Expectations; import mockit.Mocked; @@ -34,14 +35,17 @@ public class TestExecutorManager { @Mocked Executor defaultExecutor; + ExecutorManager executorManager = new ExecutorManager(); + + Environment environment = Mockito.mock(Environment.class); + @Before public void setup() { - ArchaiusUtils.resetConfig(); + executorManager.setEnvironment(environment); } @After public void teardown() { - ArchaiusUtils.resetConfig(); } @Test @@ -53,69 +57,74 @@ public void findExecutor_oneParam(@Mocked Executor executor, @Mocked OperationMe } }; - Assert.assertSame(executor, ExecutorManager.findExecutor(operationMeta)); + Assertions.assertSame(executor, executorManager.findExecutor(operationMeta)); } @Test public void findExecutor_twoParam_opCfg_withoutOpDef(@Mocked Executor executor, @Mocked OperationMeta operationMeta) { - String schemaQualifiedName = "schemaId.opId"; + // String schemaQualifiedName = "schemaId.opId"; + String microserviceQualifiedName = "microserviceName.schemaId.opId"; String opBeanId = "opBeanId"; - ArchaiusUtils.setProperty(ExecutorManager.KEY_EXECUTORS_PREFIX + schemaQualifiedName, opBeanId); + Mockito.when(environment.getProperty( + ExecutorManager.KEY_EXECUTORS_PREFIX + microserviceQualifiedName)).thenReturn(opBeanId); new Expectations(BeanUtils.class) { { - operationMeta.getSchemaQualifiedName(); - result = schemaQualifiedName; + operationMeta.getMicroserviceQualifiedName(); + result = microserviceQualifiedName; BeanUtils.getBean(opBeanId); result = executor; } }; - Assert.assertSame(executor, ExecutorManager.findExecutor(operationMeta, null)); + Assertions.assertSame(executor, executorManager.findExecutor(operationMeta, null)); } @Test public void findExecutor_twoParam_opCfg_withOpDef(@Mocked Executor executor, @Mocked Executor defExecutor, @Mocked OperationMeta operationMeta) { - String schemaQualifiedName = "schemaId.opId"; + String microserviceQualifiedName = "microserviceName.schemaId.opId"; String opBeanId = "opBeanId"; - ArchaiusUtils.setProperty(ExecutorManager.KEY_EXECUTORS_PREFIX + schemaQualifiedName, opBeanId); + Mockito.when(environment.getProperty( + ExecutorManager.KEY_EXECUTORS_PREFIX + microserviceQualifiedName)).thenReturn(opBeanId); new Expectations(BeanUtils.class) { { - operationMeta.getSchemaQualifiedName(); - result = schemaQualifiedName; + operationMeta.getMicroserviceQualifiedName(); + result = microserviceQualifiedName; BeanUtils.getBean(opBeanId); result = executor; } }; - Assert.assertSame(executor, ExecutorManager.findExecutor(operationMeta, defExecutor)); + Assertions.assertSame(executor, executorManager.findExecutor(operationMeta, defExecutor)); } @Test public void findExecutor_twoParam_schemaCfg_withOpDef(@Mocked OperationMeta operationMeta, @Mocked Executor defExecutor) { - Assert.assertSame(defExecutor, ExecutorManager.findExecutor(operationMeta, defExecutor)); + Assertions.assertSame(defExecutor, executorManager.findExecutor(operationMeta, defExecutor)); } @Test public void findExecutor_twoParam_schemaCfg_withoutOpDef(@Mocked Executor executor, - @Mocked SchemaMeta schemaMeta, @Mocked OperationMeta operationMeta) { + String microserviceName = "serviceName"; String schemaName = "schemaId"; String opBeanId = "opBeanId"; - ArchaiusUtils.setProperty(ExecutorManager.KEY_EXECUTORS_PREFIX + schemaName, opBeanId); + Mockito.when(environment.getProperty(ExecutorManager.KEY_EXECUTORS_PREFIX + microserviceName + "." + schemaName)) + .thenReturn(opBeanId); new Expectations(BeanUtils.class) { { - schemaMeta.getName(); + operationMeta.getSchemaId(); result = schemaName; + operationMeta.getMicroserviceName(); + result = microserviceName; BeanUtils.getBean(opBeanId); result = executor; } }; - - Assert.assertSame(executor, ExecutorManager.findExecutor(operationMeta, null)); + Assertions.assertSame(executor, executorManager.findExecutor(operationMeta, null)); } @Test @@ -123,7 +132,7 @@ public void findExecutor_twoParam_defaultCfg(@Mocked Executor executor, @Mocked SchemaMeta schemaMeta, @Mocked OperationMeta operationMeta) { String beanId = "beanId"; - ArchaiusUtils.setProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, beanId); + Mockito.when(environment.getProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT)).thenReturn(beanId); new Expectations(BeanUtils.class) { { BeanUtils.getBean(beanId); @@ -131,6 +140,6 @@ public void findExecutor_twoParam_defaultCfg(@Mocked Executor executor, } }; - Assert.assertSame(executor, ExecutorManager.findExecutor(operationMeta, null)); + Assertions.assertSame(executor, executorManager.findExecutor(operationMeta, null)); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/executor/TestGroupExecutor.java b/core/src/test/java/org/apache/servicecomb/core/executor/TestGroupExecutor.java new file mode 100644 index 00000000000..dd95105992b --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/executor/TestGroupExecutor.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.executor; + +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_CORE_THREADS; +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_GROUP; +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_MAX_IDLE_SECOND; +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_MAX_QUEUE_SIZE; +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_MAX_THREADS; +import static org.apache.servicecomb.core.executor.GroupExecutor.KEY_OLD_MAX_THREAD; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import mockit.Deencapsulation; + +public class TestGroupExecutor { + String strThreadTest = "default"; + + @BeforeEach + public void setup() { + Mockito.when(environment.getProperty(KEY_GROUP, int.class, 2)).thenReturn(2); + Mockito.when(environment.getProperty(KEY_CORE_THREADS, int.class, 25)).thenReturn(25); + Mockito.when(environment.getProperty(KEY_MAX_IDLE_SECOND, int.class, 60)).thenReturn(60); + Mockito.when(environment.getProperty(KEY_MAX_THREADS, int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty(KEY_OLD_MAX_THREAD, int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty(KEY_MAX_QUEUE_SIZE, int.class, Integer.MAX_VALUE)) + .thenReturn(Integer.MAX_VALUE); + } + + @AfterAll + public static void teardown() { + } + + Environment environment = Mockito.mock(Environment.class); + + GroupExecutor groupExecutor = new GroupExecutor(environment); + + @Test + public void groupCount() { + groupExecutor.initConfig(); + Assertions.assertEquals(2, groupExecutor.groupCount); + + Mockito.when(environment.getProperty(KEY_GROUP, int.class, 2)).thenReturn(4); + groupExecutor.initConfig(); + Assertions.assertEquals(4, groupExecutor.groupCount); + } + + @Test + public void coreThreads() { + groupExecutor.initConfig(); + Assertions.assertEquals(25, groupExecutor.coreThreads); + + Mockito.when(environment.getProperty(KEY_CORE_THREADS, int.class, 25)).thenReturn(100); + groupExecutor.initConfig(); + Assertions.assertEquals(100, groupExecutor.coreThreads); + } + + @Test + public void maxIdleInSecond() { + groupExecutor.initConfig(); + Assertions.assertEquals(60, groupExecutor.maxIdleInSecond); + + Mockito.when(environment.getProperty(KEY_MAX_IDLE_SECOND, int.class, 60)).thenReturn(100); + groupExecutor.initConfig(); + Assertions.assertEquals(100, groupExecutor.maxIdleInSecond); + } + + @Test + public void maxQueueSize() { + groupExecutor.initConfig(); + Assertions.assertEquals(Integer.MAX_VALUE, groupExecutor.maxQueueSize); + Mockito.when(environment.getProperty(KEY_MAX_QUEUE_SIZE, int.class, Integer.MAX_VALUE)).thenReturn(100); + groupExecutor.initConfig(); + Assertions.assertEquals(100, groupExecutor.maxQueueSize); + } + + @Test + public void maxThreads() { + groupExecutor.initConfig(); + Assertions.assertEquals(100, groupExecutor.maxThreads); + + LogCollector collector = new LogCollector(); + Mockito.when(environment.getProperty(KEY_OLD_MAX_THREAD, int.class, -1)).thenReturn(200); + groupExecutor.initConfig(); + Assertions.assertEquals(200, groupExecutor.maxThreads); + Assertions.assertEquals( + "servicecomb.executor.default.thread-per-group is deprecated, recommended to use servicecomb.executor.default.maxThreads-per-group.", + collector.getEvents().get(collector.getEvents().size() - 2).getMessage().getFormattedMessage()); + collector.tearDown(); + + Mockito.when(environment.getProperty(KEY_MAX_THREADS, int.class, -1)).thenReturn(300); + groupExecutor.initConfig(); + Assertions.assertEquals(300, groupExecutor.maxThreads); + } + + @Test + public void adjustCoreThreads() { + Mockito.when(environment.getProperty(KEY_MAX_THREADS, int.class, -1)).thenReturn(10); + LogCollector collector = new LogCollector(); + groupExecutor.initConfig(); + Assertions.assertEquals(10, groupExecutor.maxThreads); + Assertions.assertEquals( + "coreThreads is bigger than maxThreads, change from 25 to 10.", + collector.getEvents().get(collector.getEvents().size() - 2).getMessage().getFormattedMessage()); + collector.tearDown(); + } + + @Test + public void testGroupExecutor() { + groupExecutor.init(); + groupExecutor.execute(() -> { + }); + Map threadExecutorMap = Deencapsulation.getField(groupExecutor, "threadExecutorMap"); + Assertions.assertTrue((threadExecutorMap.size() > 0)); + + List executorList = Deencapsulation.getField(groupExecutor, "executorList"); + Assertions.assertTrue((executorList.size() > 1)); + + ReactiveExecutor oReactiveExecutor = new ReactiveExecutor(); + oReactiveExecutor.execute(() -> strThreadTest = "thread Ran"); + oReactiveExecutor.close(); + Assertions.assertEquals("thread Ran", strThreadTest); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/executor/TestThreadPoolExecutorEx.java b/core/src/test/java/org/apache/servicecomb/core/executor/TestThreadPoolExecutorEx.java new file mode 100644 index 00000000000..7382d3793a4 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/executor/TestThreadPoolExecutorEx.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.core.executor; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.function.IntSupplier; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestThreadPoolExecutorEx { + private static final Logger LOGGER = LoggerFactory.getLogger(TestThreadPoolExecutorEx.class); + + static class TestTask implements Runnable { + CountDownLatch notify = new CountDownLatch(1); + + Future future; + + public void quit() throws ExecutionException, InterruptedException { + notify.countDown(); + future.get(); + } + + @Override + public void run() { + try { + notify.await(); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + } + } + + ThreadPoolExecutorEx executorEx = new ThreadPoolExecutorEx(2, 4, 2, TimeUnit.SECONDS, + new LinkedBlockingQueueEx(2), Executors.defaultThreadFactory()); + + public TestTask submitTask() { + TestTask task = new TestTask(); + task.future = executorEx.submit(task); + return task; + } + + @Test + public void schedule() throws ExecutionException, InterruptedException { + // init + Assertions.assertEquals(0, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(0, executorEx.getNotFinished()); + Assertions.assertEquals(0, executorEx.getQueue().size()); + + // use core threads + TestTask t1 = submitTask(); + Assertions.assertEquals(1, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(1, executorEx.getNotFinished()); + Assertions.assertEquals(0, executorEx.getQueue().size()); + + TestTask t2 = submitTask(); + Assertions.assertEquals(2, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(2, executorEx.getNotFinished()); + Assertions.assertEquals(0, executorEx.getQueue().size()); + + // extend threads + TestTask t3 = submitTask(); + Assertions.assertEquals(3, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(3, executorEx.getNotFinished()); + Assertions.assertEquals(0, executorEx.getQueue().size()); + + TestTask t4 = submitTask(); + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(4, executorEx.getNotFinished()); + Assertions.assertEquals(0, executorEx.getQueue().size()); + + // queue the tasks + TestTask t5 = submitTask(); + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(5, executorEx.getNotFinished()); + Assertions.assertEquals(1, executorEx.getQueue().size()); + + TestTask t6 = submitTask(); + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(0, executorEx.getRejectedCount()); + Assertions.assertEquals(6, executorEx.getNotFinished()); + Assertions.assertEquals(2, executorEx.getQueue().size()); + + // reject the task + try { + submitTask(); + } catch (RejectedExecutionException e) { + + } + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(1, executorEx.getRejectedCount()); + Assertions.assertEquals(6, executorEx.getNotFinished()); + Assertions.assertEquals(2, executorEx.getQueue().size()); + + // t1/t2/t3 finish + t1.quit(); + t2.quit(); + t3.quit(); + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(1, executorEx.getRejectedCount()); + waitForResult(3, executorEx::getNotFinished); + waitForResult(0, executorEx.getQueue()::size); + + // reuse thread + t3 = submitTask(); + Assertions.assertEquals(4, executorEx.getPoolSize()); + Assertions.assertEquals(1, executorEx.getRejectedCount()); + waitForResult(4, executorEx::getNotFinished); + waitForResult(0, executorEx.getQueue()::size); + + t3.quit(); + t4.quit(); + t5.quit(); + t6.quit(); + waitForResult(2, executorEx::getPoolSize); + executorEx.shutdown(); + } + + private void waitForResult(int expect, IntSupplier supplier) { + long max = 30000; + long waited = 0; + + for (; ; ) { + if (waited > max) { + throw new IllegalStateException("timed out waiting."); + } + int actual = supplier.getAsInt(); + if (expect == actual) { + return; + } + + LOGGER.info("waiting for thread result, expect:{}, actual: {}.", expect, actual); + try { + TimeUnit.MILLISECONDS.sleep(200); + waited += 200; + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainTest.java b/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainTest.java new file mode 100644 index 00000000000..5a5dc1cb05e --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/filter/FilterChainTest.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.filter; + +import static org.apache.servicecomb.core.filter.FilterNode.buildChain; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.util.List; +import java.util.Vector; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationConfig; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.filter.impl.ScheduleFilter; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.BeforeClass; +import org.junit.Test; + +import mockit.Expectations; +import mockit.Mocked; + +public class FilterChainTest { + static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(); + + static String THREAD_NAME; + + @Mocked + Invocation invocation; + + @Mocked + OperationMeta operationMeta; + + @Mocked + OperationConfig operationConfig; + + List msg = new Vector<>(); + + Filter recordThreadFilter = new AbstractFilter() { + @Override + public String getName() { + return "f2"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + msg.add(Thread.currentThread().getName()); + if (nextNode == null) { + return CompletableFuture.completedFuture(Response.ok(null)); + } + + return nextNode.onFilter(invocation); + } + }; + + Filter scheduler = new ScheduleFilter(); + + Filter exceptionFilter = new AbstractFilter() { + @Override + public String getName() { + return "f1"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + throw new IllegalStateException("e1"); + } + }; + + @BeforeClass + public static void beforeClass() { + try { + THREAD_NAME = EXECUTOR.submit(() -> Thread.currentThread().getName()).get(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private void mockInvocation() { + new Expectations() { + { + invocation.getOperationMeta(); + result = operationMeta; + + operationMeta.getExecutor(); + result = EXECUTOR; + + operationConfig.getNanoRequestWaitInPoolTimeout(anyString); + result = Long.MAX_VALUE; + } + }; + } + + @Test + public void should_switch_thread_after_schedule() throws ExecutionException, InterruptedException { + mockInvocation(); + + buildChain(recordThreadFilter, scheduler, recordThreadFilter) + .onFilter(invocation) + .get(); + + assertThat(msg).containsExactly("main", THREAD_NAME); + } + + @Test + public void should_stop_chain_when_first_filter_throw_exception() { + ExecutionException executionException = (ExecutionException) catchThrowable( + () -> buildChain(exceptionFilter, recordThreadFilter) + .onFilter(invocation) + .get()); + + assertThat(msg).isEmpty(); + assertThat(executionException.getCause()) + .isInstanceOf(IllegalStateException.class) + .hasMessage("e1"); + } + + @Test + public void should_stop_chain_when_middle_filter_throw_exception() { + ExecutionException executionException = (ExecutionException) catchThrowable( + () -> buildChain(recordThreadFilter, exceptionFilter, recordThreadFilter) + .onFilter(invocation) + .get()); + + assertThat(msg).containsExactly("main"); + assertThat(executionException.getCause()) + .isInstanceOf(IllegalStateException.class) + .hasMessage("e1"); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/TestEndpointDiscoveryFilter.java b/core/src/test/java/org/apache/servicecomb/core/filter/TestEndpointDiscoveryFilter.java deleted file mode 100644 index 2c443beec93..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/filter/TestEndpointDiscoveryFilter.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.filter; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestEndpointDiscoveryFilter { - EndpointDiscoveryFilter filter = new EndpointDiscoveryFilter(); - - DiscoveryContext context = new DiscoveryContext(); - - @Mocked - Invocation invocation; - - @Mocked - TransportManager transportManager; - - @Before - public void setup() { - CseContext.getInstance().setTransportManager(transportManager); - context.setInputParameters(invocation); - } - - @After - public void teardown() { - CseContext.getInstance().setTransportManager(null); - } - - @Test - public void getOrder() { - Assert.assertEquals(Short.MAX_VALUE, filter.getOrder()); - } - - @Test - public void getTransportName() { - new Expectations() { - { - invocation.getConfigTransportName(); - result = Const.RESTFUL; - } - }; - - Assert.assertEquals(Const.RESTFUL, filter.findTransportName(context, null)); - } - - @Test - public void createEndpointNullTransport() { - new Expectations() { - { - transportManager.findTransport(Const.RESTFUL); - result = null; - } - }; - - Assert.assertNull(filter.createEndpoint(Const.RESTFUL, "", null)); - } - - @Test - public void createEndpointNormal(@Mocked Transport transport, @Mocked MicroserviceInstance instance) { - String endpoint = "rest://ip:port"; - Object address = new Object(); - - new Expectations() { - { - transportManager.findTransport(Const.RESTFUL); - result = transport; - transport.parseAddress(endpoint); - result = address; - } - }; - - Endpoint ep = (Endpoint) filter.createEndpoint(Const.RESTFUL, endpoint, instance); - Assert.assertSame(transport, ep.getTransport()); - Assert.assertSame(address, ep.getAddress()); - Assert.assertSame(instance, ep.getMicroserviceInstance()); - Assert.assertEquals(endpoint, ep.getEndpoint()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/TestOperationInstancesDiscoveryFilter.java b/core/src/test/java/org/apache/servicecomb/core/filter/TestOperationInstancesDiscoveryFilter.java deleted file mode 100644 index 49a5ce72034..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/filter/TestOperationInstancesDiscoveryFilter.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.filter; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMetaFactory; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.loader.SchemaListenerManager; -import org.apache.servicecomb.core.definition.loader.SchemaLoader; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.apache.servicecomb.serviceregistry.registry.LocalServiceRegistry; -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.context.ApplicationContext; - -import com.google.common.eventbus.EventBus; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.SwaggerDefinition; -import mockit.Expectations; -import mockit.Mocked; - -public class TestOperationInstancesDiscoveryFilter { - @SwaggerDefinition(basePath = "/v1") - private static class V1_0_0 { - @ApiOperation(value = "", httpMethod = "GET") - public void add() { - } - } - - @SwaggerDefinition(basePath = "/v1") - private static class V1_1_0 { - @ApiOperation(value = "", httpMethod = "GET") - public void add() { - } - - @ApiOperation(value = "", httpMethod = "GET") - public void dec() { - } - } - - OperationInstancesDiscoveryFilter filter = new OperationInstancesDiscoveryFilter(); - - DiscoveryContext context = new DiscoveryContext(); - - SwaggerGeneratorContext swaggerGeneratorContext = new PojoSwaggerGeneratorContext(); - - EventBus eventBus = new EventBus(); - - String appId = "app"; - - String microserviceName = "ms"; - - ServiceRegistry serviceRegistry = - new LocalServiceRegistry(eventBus, ServiceRegistryConfig.INSTANCE, - MicroserviceDefinition.create(appId, "self")); - - @Mocked - ApplicationContext applicationContext; - - @Mocked - Invocation invocation; - - OperationMeta latestOperationMeta; - - SchemaLoader schemaLoader = new SchemaLoader(); - - ConsumerSchemaFactory consumerSchemaFactory = new ConsumerSchemaFactory(); - - DiscoveryTreeNode result; - - @Mocked - SchemaListenerManager schemaListenerManager; - - @Before - public void setup() { - serviceRegistry.init(); - BeanUtils.setContext(applicationContext); - - serviceRegistry.getAppManager().setMicroserviceVersionFactory(new MicroserviceVersionMetaFactory()); - - consumerSchemaFactory.setSchemaLoader(schemaLoader); - CseContext.getInstance().setConsumerSchemaFactory(consumerSchemaFactory); - CseContext.getInstance().setSchemaListenerManager(schemaListenerManager); - - RegistryUtils.setServiceRegistry(serviceRegistry); - } - - private void setupOnChange() { - new Expectations(RegistryUtils.class) { - { - invocation.getOperationMeta(); - result = latestOperationMeta; - invocation.getMicroserviceQualifiedName(); - result = latestOperationMeta.getMicroserviceQualifiedName(); - } - }; - - context.setInputParameters(invocation); - } - - @After - public void teardown() { - RegistryUtils.setServiceRegistry(null); - BeanUtils.setContext(null); - CseContext.getInstance().setConsumerSchemaFactory(null); - CseContext.getInstance().setSchemaListenerManager(null); - } - - private MicroserviceInstance createInstance(String serviceId) { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId(UUID.randomUUID().toString()); - instance.setServiceId(serviceId); - return instance; - } - - private Microservice regMicroservice(String serviceId, String version, Class schemaCls, int instanceCount) { - String schemaId = "sid"; - - Microservice microservice = new Microservice(); - microservice.setServiceId(serviceId); - microservice.setAppId(appId); - microservice.setServiceName(microserviceName); - microservice.setVersion(version); - microservice.setSchemas(Arrays.asList(schemaId)); - serviceRegistry.getServiceRegistryClient().registerMicroservice(microservice); - - SwaggerGenerator generator = new SwaggerGenerator(swaggerGeneratorContext, schemaCls); - String schemaContent = SwaggerUtils.swaggerToString(generator.generate()); - serviceRegistry.getServiceRegistryClient().registerSchema(serviceId, schemaId, schemaContent); - - for (int idx = 0; idx < instanceCount; idx++) { - MicroserviceInstance instance = createInstance(serviceId); - serviceRegistry.getServiceRegistryClient().registerMicroserviceInstance(instance); - } - - return microservice; - } - - @Test - public void getOrder() { - Assert.assertEquals(-10000, filter.getOrder()); - } - - @Test - public void isGroupingFilterAndEnabled() { - Assert.assertTrue(filter.isGroupingFilter()); - Assert.assertTrue(filter.enabled()); - } - - @Test - public void discovery_v1_0_0() { - regMicroservice("1", "1.0.0", V1_0_0.class, 2); - - MicroserviceVersions MicroserviceVersions = - serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); - MicroserviceVersions.submitPull(); - MicroserviceVersionRule microserviceVersionRule = - MicroserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL); - MicroserviceVersionMeta latestMicroserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - latestOperationMeta = latestMicroserviceVersionMeta.getMicroserviceMeta().ensureFindOperation("sid.add"); - DiscoveryTreeNode parent = new DiscoveryTreeNode().fromCache(microserviceVersionRule.getVersionedCache()); - - setupOnChange(); - - result = filter.discovery(context, parent); - - Assert.assertEquals(2, result.mapData().size()); - result.mapData().values().forEach(instance -> { - Assert.assertEquals("1", ((MicroserviceInstance) instance).getServiceId()); - }); - } - - @Test - public void discovery_v1_1_0_add() { - regMicroservice("1", "1.0.0", V1_0_0.class, 2); - regMicroservice("2", "1.1.0", V1_1_0.class, 2); - - MicroserviceVersions MicroserviceVersions = - serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); - MicroserviceVersions.submitPull(); - MicroserviceVersionRule microserviceVersionRule = - MicroserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL); - MicroserviceVersionMeta latestMicroserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - latestOperationMeta = latestMicroserviceVersionMeta.getMicroserviceMeta().ensureFindOperation("sid.add"); - DiscoveryTreeNode parent = new DiscoveryTreeNode().fromCache(microserviceVersionRule.getVersionedCache()); - - setupOnChange(); - - result = filter.discovery(context, parent); - - Assert.assertEquals(4, result.mapData().size()); - Set ids = new HashSet<>(); - result.mapData().values().forEach(instance -> { - ids.add(((MicroserviceInstance) instance).getServiceId()); - }); - Assert.assertThat(ids, Matchers.containsInAnyOrder("1", "2")); - } - - @Test - public void discovery_v1_1_0_dec() { - regMicroservice("1", "1.0.0", V1_0_0.class, 2); - regMicroservice("2", "1.1.0", V1_1_0.class, 2); - - MicroserviceVersions MicroserviceVersions = - serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); - MicroserviceVersions.submitPull(); - MicroserviceVersionRule microserviceVersionRule = - MicroserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL); - MicroserviceVersionMeta latestMicroserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - latestOperationMeta = latestMicroserviceVersionMeta.getMicroserviceMeta().ensureFindOperation("sid.dec"); - DiscoveryTreeNode parent = new DiscoveryTreeNode().fromCache(microserviceVersionRule.getVersionedCache()); - - setupOnChange(); - - result = filter.discovery(context, parent); - - Assert.assertEquals(2, result.mapData().size()); - Set ids = new HashSet<>(); - result.mapData().values().forEach(instance -> { - ids.add(((MicroserviceInstance) instance).getServiceId()); - }); - Assert.assertThat(ids, Matchers.containsInAnyOrder("2")); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java new file mode 100644 index 00000000000..4afed2d7dde --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ParameterValidatorFilterTest.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.filter.impl; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.apache.servicecomb.core.exception.ExceptionCodes.DEFAULT_VALIDATE; +import static org.apache.servicecomb.core.exception.converter.ConstraintViolationExceptionConverter.KEY_CODE; +import static org.apache.servicecomb.core.filter.impl.ParameterValidatorFilter.ENABLE_EL; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.util.List; + +import org.apache.commons.lang3.reflect.MethodUtils; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.exception.converter.ConstraintViolationExceptionConverter; +import org.apache.servicecomb.core.exception.converter.ValidateDetail; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MutablePropertySources; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import mockit.Expectations; +import mockit.Mocked; + +public class ParameterValidatorFilterTest { + public static class BaseModel { + @NotNull(message = "can not be null") + private String name; + + public String getName() { + return name; + } + + public BaseModel setName(String name) { + this.name = name; + return this; + } + } + + public static class Model extends BaseModel { + @NotBlank(message = "can not be blank") + @JsonProperty(value = "nick-name") + private String nickName; + + public String getNickName() { + return nickName; + } + + public Model setNickName(String nickName) { + this.nickName = nickName; + return this; + } + } + + public static class Controller { + public void op(@NotNull(message = "not null") String query, @Valid Model model) { + + } + } + + ParameterValidatorFilter filter = new ParameterValidatorFilter(); + + @Mocked + Invocation invocation; + + @Mocked + SwaggerProducerOperation operation; + + ConfigurableEnvironment environment; + + @Before + public void setUp() throws Exception { + environment = Mockito.mock(ConfigurableEnvironment.class); + SCBEngine engine = SCBBootstrap.createSCBEngineForTest(environment); + MutablePropertySources sources = new MutablePropertySources(); + + Mockito.when(environment.getProperty(ENABLE_EL, boolean.class, false)).thenReturn(false); + Mockito.when(environment.getPropertySources()).thenReturn(sources); + filter.setEnvironment(environment); + filter.afterPropertiesSet(); + engine.setEnvironment(environment); + new Expectations() { + { + operation.getProducerInstance(); + result = new Controller(); + + operation.getProducerMethod(); + result = MethodUtils.getAccessibleMethod(Controller.class, "op", String.class, Model.class); + + invocation.toProducerArguments(); + result = new Object[] {null, new Model()}; + } + }; + } + + private InvocationException getException() { + Throwable throwable = catchThrowable(() -> filter.onFilter(invocation, FilterNode.EMPTY).get()); + return Exceptions.convert(invocation, throwable, BAD_REQUEST); + } + + private CommonExceptionData getExceptionData() { + InvocationException invocationException = getException(); + return (CommonExceptionData) invocationException.getErrorData(); + } + + @Test + public void status_code_should_be_bad_request() { + InvocationException invocationException = getException(); + + assertThat(invocationException.getStatusCode()).isEqualTo(BAD_REQUEST.getStatusCode()); + } + + @Test + public void error_code_and_message_should_be_build_in_value() { + Mockito.when(environment.getProperty(KEY_CODE, String.class, DEFAULT_VALIDATE)).thenReturn(DEFAULT_VALIDATE); + CommonExceptionData errorData = getExceptionData(); + + assertThat(errorData.getCode()).isEqualTo(DEFAULT_VALIDATE); + assertThat(errorData.getMessage()).isEqualTo("invalid parameters."); + } + + @Test + public void should_allow_customize_error_code_by_configuration() { + Mockito.when(environment.getProperty(KEY_CODE, String.class, DEFAULT_VALIDATE)).thenReturn("test.0001"); + SPIServiceUtils.getTargetService(ExceptionConverter.class, ConstraintViolationExceptionConverter.class); + CommonExceptionData errorData = getExceptionData(); + + assertThat(errorData.getCode()).isEqualTo("test.0001"); + } + + @Test + public void should_use_json_property_value_as_property_name() { + CommonExceptionData errorData = getExceptionData(); + List details = errorData.getDynamic("validateDetail"); + + assertThat(details.stream().map(ValidateDetail::getPropertyPath)) + .contains("op.model.nick-name"); + } + + @Test + public void should_include_all_validate_detail() { + CommonExceptionData errorData = getExceptionData(); + List details = errorData.getDynamic("validateDetail"); + + assertThat(details.stream().map(ValidateDetail::getPropertyPath)) + .contains("op.query", "op.model.name", "op.model.nick-name"); + assertThat(details.stream().map(ValidateDetail::getMessage)) + .contains("not null", "can not be null", "can not be blank"); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilterTest.java b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilterTest.java new file mode 100644 index 00000000000..dd46b17d28b --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/filter/impl/ProducerOperationFilterTest.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.filter.impl; + +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.lang.reflect.Method; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.Test; + +import mockit.Expectations; +import mockit.Injectable; +import mockit.Mocked; +import mockit.Verifications; + +public class ProducerOperationFilterTest { + ProviderOperationFilter filter = new ProviderOperationFilter(); + + @Injectable + Invocation invocation; + + @Mocked + SwaggerProducerOperation producerOperation; + + static InvocationContext threadInvocationContext; + + public static class Controller { + public void sync() { + threadInvocationContext = ContextUtils.getInvocationContext(); + } + + public void syncException() { + throw new RuntimeExceptionWithoutStackTrace("syncException"); + } + + public CompletableFuture async() { + threadInvocationContext = ContextUtils.getInvocationContext(); + return CompletableFuture.completedFuture(null); + } + + public CompletableFuture asyncException() { + throw new RuntimeExceptionWithoutStackTrace("asyncException"); + } + } + + @Test + public void should_record_invocation_trace_time() throws NoSuchMethodException { + setInvokeSyncMethod(); + filter.onFilter(invocation, FilterNode.EMPTY); + + new Verifications() { + { + invocation.onBusinessMethodStart(); + times = 1; + + invocation.onBusinessFinish(); + times = 1; + } + }; + } + + private void setInvokeMethod(String name) throws NoSuchMethodException { + Controller instance = new Controller(); + Method method = instance.getClass().getMethod(name); + new Expectations() { + { + producerOperation.getProducerInstance(); + result = instance; + + producerOperation.getProducerMethod(); + result = method; + } + }; + } + + private void setInvokeSyncMethod() throws NoSuchMethodException { + setInvokeMethod("sync"); + } + + private void setInvokeAsyncMethod() throws NoSuchMethodException { + setInvokeMethod("async"); + } + + @Test + public void should_provide_thread_local_invocation_context_for_sync_method() throws NoSuchMethodException { + setInvokeSyncMethod(); + + filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(threadInvocationContext).isSameAs(invocation); + } + + @Test + public void should_clear_thread_local_invocation_context_after_sync_method() throws NoSuchMethodException { + setInvokeSyncMethod(); + + filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(ContextUtils.getInvocationContext()).isNull(); + } + + @Test + public void should_catch_sync_business_exception() throws NoSuchMethodException { + setInvokeMethod("syncException"); + + CompletableFuture future = filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(future) + .failsWithin(Duration.ofSeconds(1)) + .withThrowableOfType(ExecutionException.class) + .withCauseExactlyInstanceOf(RuntimeExceptionWithoutStackTrace.class) + .withMessage("org.apache.servicecomb.foundation.test.scaffolding.exception" + + ".RuntimeExceptionWithoutStackTrace: syncException"); + } + + @Test + public void should_provide_thread_local_invocation_context_for_async_method() throws NoSuchMethodException { + setInvokeAsyncMethod(); + + filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(threadInvocationContext).isSameAs(invocation); + } + + @Test + public void should_clear_thread_local_invocation_context_after_async_method() throws NoSuchMethodException { + setInvokeAsyncMethod(); + + filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(ContextUtils.getInvocationContext()).isNull(); + } + + @Test + public void should_catch_async_business_exception() throws NoSuchMethodException { + setInvokeMethod("asyncException"); + + CompletableFuture future = filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(future) + .failsWithin(Duration.ofSeconds(1)) + .withThrowableOfType(ExecutionException.class) + .withCauseExactlyInstanceOf(RuntimeExceptionWithoutStackTrace.class) + .withMessage("org.apache.servicecomb.foundation.test.scaffolding" + + ".exception.RuntimeExceptionWithoutStackTrace: asyncException"); + } + + @Test + public void should_unify_IllegalArgumentException_message_when_convert_exception() throws NoSuchMethodException { + setInvokeSyncMethod(); + new Expectations() { + { + invocation.toProducerArguments(); + result = new Object[] {1}; + } + }; + CompletableFuture future = filter.onFilter(invocation, FilterNode.EMPTY); + + assertThat(future) + .failsWithin(Duration.ofSeconds(1)) + .withThrowableOfType(ExecutionException.class) + .withCauseExactlyInstanceOf(IllegalArgumentException.class); + + InvocationException throwable = Exceptions + .convert(invocation, catchThrowable(future::get), INTERNAL_SERVER_ERROR); + assertThat(throwable).hasCauseInstanceOf(IllegalArgumentException.class); + CommonExceptionData data = (CommonExceptionData) throwable.getErrorData(); + assertThat(data.getMessage()).isEqualTo("Parameters not valid or types not match."); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestServiceProviderHandler.java b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestServiceProviderHandler.java deleted file mode 100644 index cbdd007f6ca..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestServiceProviderHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestServiceProviderHandler { - - ProducerOperationHandler serviceProviderHandler = null; - - Invocation invocation = null; - - AsyncResponse asyncResp = null; - - OperationMeta OperationMeta = null; - - @Before - public void setUp() throws Exception { - serviceProviderHandler = new ProducerOperationHandler(); - invocation = Mockito.mock(Invocation.class); - asyncResp = Mockito.mock(AsyncResponse.class); - OperationMeta = Mockito.mock(OperationMeta.class); - } - - @After - public void tearDown() throws Exception { - serviceProviderHandler = null; - invocation = null; - asyncResp = null; - OperationMeta = null; - } - - @Test - public void testHandle() { - boolean status = false; - try { - Assert.assertNotNull(serviceProviderHandler); - Mockito.when(invocation.getOperationMeta()).thenReturn(OperationMeta); - serviceProviderHandler.handle(invocation, asyncResp); - } catch (Exception e) { - status = true; - } - Assert.assertFalse(status); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java deleted file mode 100644 index d5b890d901e..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.filter.OperationInstancesDiscoveryFilter; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestSimpleLoadBalanceHandler { - SimpleLoadBalanceHandler handler; - - Map indexMap; - - @Mocked - OperationInstancesDiscoveryFilter operationInstancesDiscoveryFilter; - - @Mocked - Invocation invocation; - - @Mocked - ServiceRegistry serviceRegistry; - - @Mocked - InstanceCacheManager instanceCacheManager; - - @Mocked - TransportManager transportManager; - - VersionedCache instanceVersionedCache = new VersionedCache().data(Collections.emptyMap()).name("parent"); - - Response response; - - AsyncResponse ar = resp -> { - response = resp; - }; - - @Before - public void setUp() throws Exception { - CseContext.getInstance().setTransportManager(transportManager); - - RegistryUtils.setServiceRegistry(serviceRegistry); - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(DiscoveryFilter.class); - result = Collections.emptyList(); - serviceRegistry.getInstanceCacheManager(); - result = instanceCacheManager; - instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); - result = instanceVersionedCache; - invocation.getConfigTransportName(); - result = ""; - } - }; - - handler = new SimpleLoadBalanceHandler(); - indexMap = Deencapsulation.getField(handler, "indexMap"); - } - - @After - public void tearDown() throws Exception { - CseContext.getInstance().setTransportManager(null); - RegistryUtils.setServiceRegistry(null); - } - - @Test - public void handle_emptyEndPoint() throws Exception { - handler.handle(invocation, ar); - - Throwable result = response.getResult(); - Assert.assertEquals("InvocationException: code=490;msg=CommonExceptionData [message=Cse Internal Bad Request]", - result.getMessage()); - Assert.assertEquals("No available address found. microserviceName=null, version=null, discoveryGroupName=parent/", - result.getCause().getMessage()); - } - - @Test - public void handle(@Mocked Transport transport) throws Exception { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("id"); - instance.getEndpoints().add("rest://localhost:8080"); - instance.getEndpoints().add("highway://localhost:8081"); - instanceVersionedCache.data(Collections.singletonMap("id", instance)).autoCacheVersion().name("vr"); - - new Expectations() { - { - transportManager.findTransport(anyString); - result = transport; - invocation.getConfigTransportName(); - result = ""; - } - }; - - handler.handle(invocation, ar); - AtomicInteger idx = indexMap.values().iterator().next(); - Assert.assertEquals(1, idx.get()); - - handler.handle(invocation, ar); - Assert.assertEquals(2, idx.get()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestTransportClientHandler.java b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestTransportClientHandler.java deleted file mode 100644 index 60209679996..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestTransportClientHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.handler.impl; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.Before; -import org.junit.Test; - -public class TestTransportClientHandler { - - private final Endpoint endpoint = mock(Endpoint.class); - - private final TransportClientHandler transportClientHandler = TransportClientHandler.INSTANCE; - - private final Invocation invocation = mock(Invocation.class); - - private final AsyncResponse asyncResp = mock(AsyncResponse.class); - - private final Transport transport = mock(Transport.class); - - @Before - public void setUp() throws Exception { - when(transport.getEndpoint()).thenReturn(endpoint); - when(endpoint.getEndpoint()).thenReturn("rest://localhost:8080"); - } - - @Test - public void test() throws Exception { - when(invocation.getTransport()).thenReturn(transport); - when(invocation.getEndpoint()).thenReturn(endpoint); - transportClientHandler.handle(invocation, asyncResp); - - verify(transport).send(invocation, asyncResp); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlowTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlowTest.java new file mode 100644 index 00000000000..e2e3b2c421d --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/ProducerInvocationFlowTest.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation; + +import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.Test; + +import mockit.Expectations; +import mockit.Injectable; +import mockit.Mocked; +import mockit.Verifications; + +public class ProducerInvocationFlowTest { + class TestFlow extends ProducerInvocationFlow { + public TestFlow(InvocationCreator invocationCreator) { + super(invocationCreator); + } + + @Override + protected Invocation sendCreateInvocationException(Throwable throwable) { + sendException = Exceptions.unwrap(throwable); + return null; + } + + @Override + protected void endResponse(Invocation invocation, Response response) { + sendInvocation = invocation; + } + } + + FilterNode filterNode = FilterNode.EMPTY; + + Throwable sendException; + + Invocation sendInvocation; + + @Injectable + Invocation invocation; + + @Mocked + MicroserviceMeta microserviceMeta; + + @Test + public void should_send_exception_response_when_failed_to_create_invocation() { + RuntimeException exception = new RuntimeExceptionWithoutStackTrace(); + TestFlow flow = new TestFlow(() -> { + throw exception; + }); + + flow.run(); + + assertThat(sendException).isSameAs(exception); + } + + private void mockFilterChain() { + new Expectations() { + { + microserviceMeta.getProviderFilterChain(); + result = filterNode; + } + }; + } + + @Test + public void should_start_invocation_when_succeed_to_create_invocation() { + mockFilterChain(); + TestFlow flow = new TestFlow(() -> completedFuture(invocation)); + + flow.run(); + + new Verifications() { + { + invocation.onStart((HttpServletRequestEx) any); + times = 1; + } + }; + } + + @Test + public void should_send_response_when_invocation_success() { + mockFilterChain(); + TestFlow flow = new TestFlow(() -> completedFuture(invocation)); + + flow.run(); + + assertThat(sendInvocation).isSameAs(invocation); + } + + @Test + public void should_finish_invocation_when_invocation_success() { + mockFilterChain(); + TestFlow flow = new TestFlow(() -> completedFuture(invocation)); + + flow.run(); + + new Verifications() { + { + invocation.onFinish((Response) any); + times = 1; + } + }; + } + + private void mockInvocationFailed() { + filterNode = new FilterNode(new AbstractFilter() { + @Override + public String getName() { + return "test"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + throw new RuntimeExceptionWithoutStackTrace(); + } + }); + mockFilterChain(); + } + + @Test + public void should_send_response_when_invocation_fail() { + mockInvocationFailed(); + TestFlow flow = new TestFlow(() -> completedFuture(invocation)); + + flow.run(); + + assertThat(sendInvocation).isSameAs(invocation); + } + + @Test + public void should_finish_invocation_when_invocation_fail() { + mockInvocationFailed(); + TestFlow flow = new TestFlow(() -> completedFuture(invocation)); + + flow.run(); + + new Verifications() { + { + invocation.onFinish((Response) any); + times = 1; + } + }; + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/TestInvocationStageTrace.java b/core/src/test/java/org/apache/servicecomb/core/invocation/TestInvocationStageTrace.java index 64c468d50c8..5b9c7040caa 100644 --- a/core/src/test/java/org/apache/servicecomb/core/invocation/TestInvocationStageTrace.java +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/TestInvocationStageTrace.java @@ -16,13 +16,17 @@ */ package org.apache.servicecomb.core.invocation; +import java.util.HashMap; +import java.util.Map; + import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import mockit.Mock; import mockit.MockUp; @@ -42,7 +46,10 @@ public class TestInvocationStageTrace { @Mocked OperationMeta operationMeta; - Object[] args = new Object[] {}; + @Mocked + InvocationRuntimeType invocationRuntimeType; + + Map args = new HashMap<>(); static long nanoTime = 0; @@ -58,52 +65,37 @@ long nanoTime() { @Test public void consumer() { - invocation = new Invocation(referenceConfig, operationMeta, args); + invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, args); stageTrace = new InvocationStageTrace(invocation); - stageTrace.start(1); + stageTrace.startCreateInvocation(1); nanoTime = 2; - stageTrace.startHandlersRequest(); + stageTrace.finishCreateInvocation(); + stageTrace.startConsumerConnection(); nanoTime = 3; - stageTrace.startClientFiltersRequest(); + stageTrace.finishConsumerConnection(); + stageTrace.startConsumerEncodeRequest(); nanoTime = 4; - stageTrace.startSend(); - stageTrace.finishGetConnection(5); - stageTrace.finishWriteToBuffer(6); + stageTrace.finishConsumerEncodeRequest(); + stageTrace.startConsumerSendRequest(); + nanoTime = 5; + stageTrace.finishConsumerSendRequest(); + stageTrace.startWaitResponse(); + nanoTime = 6; + stageTrace.finishWaitResponse(); + stageTrace.startConsumerDecodeResponse(); nanoTime = 7; - stageTrace.finishReceiveResponse(); - nanoTime = 8; - stageTrace.startClientFiltersResponse(); - nanoTime = 9; - stageTrace.finishClientFiltersResponse(); - nanoTime = 10; - stageTrace.finishHandlersResponse(); - nanoTime = 11; + stageTrace.finishConsumerDecodeResponse(); + stageTrace.finish(); - Assert.assertEquals(1, stageTrace.getStart()); - Assert.assertEquals(2, stageTrace.getStartHandlersRequest()); - Assert.assertEquals(3, stageTrace.getStartClientFiltersRequest()); - Assert.assertEquals(4, stageTrace.getStartSend()); - Assert.assertEquals(5, stageTrace.getFinishGetConnection()); - Assert.assertEquals(6, stageTrace.getFinishWriteToBuffer()); - Assert.assertEquals(7, stageTrace.getFinishReceiveResponse()); - Assert.assertEquals(8, stageTrace.getStartClientFiltersResponse()); - Assert.assertEquals(9, stageTrace.getFinishClientFiltersResponse()); - Assert.assertEquals(10, stageTrace.getFinishHandlersResponse()); - Assert.assertEquals(11, stageTrace.getFinish()); - - Assert.assertEquals(1f, stageTrace.calcInvocationPrepareTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcHandlersRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcClientFiltersRequestTime(), 0.1f); - Assert.assertEquals(2f, stageTrace.calcSendRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcGetConnectionTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcWriteToBufferTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcReceiveResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcWakeConsumer(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcClientFiltersResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcHandlersResponseTime(), 0.1f); - Assert.assertEquals(10f, stageTrace.calcTotalTime(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcPrepare(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConnection(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConsumerEncodeRequest(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConsumerSendRequest(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcWait(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConsumerDecodeResponse(), 0.1f); + Assertions.assertEquals(6f, stageTrace.calcTotal(), 0.1f); } @Test @@ -111,114 +103,81 @@ public void producer() { invocation = new Invocation(endpoint, operationMeta, args); stageTrace = new InvocationStageTrace(invocation); - stageTrace.start(1); + stageTrace.startCreateInvocation(1); nanoTime = 2; - stageTrace.startSchedule(); + stageTrace.finishCreateInvocation(); + stageTrace.startProviderDecodeRequest(); nanoTime = 3; - stageTrace.startExecution(); + stageTrace.finishProviderDecodeRequest(); + stageTrace.startProviderQueue(); nanoTime = 4; - stageTrace.startServerFiltersRequest(); + stageTrace.finishProviderQueue(); + stageTrace.startBusinessExecute(); nanoTime = 5; - stageTrace.startHandlersRequest(); + stageTrace.finishBusinessExecute(); + stageTrace.startProviderEncodeResponse(); nanoTime = 6; - stageTrace.startBusinessMethod(); + stageTrace.finishProviderEncodeResponse(); + stageTrace.startProviderSendResponse(); nanoTime = 7; - stageTrace.finishBusiness(); - nanoTime = 8; - stageTrace.finishHandlersResponse(); - nanoTime = 9; - stageTrace.finishServerFiltersResponse(); - nanoTime = 10; + stageTrace.finishProviderSendResponse(); + stageTrace.finish(); - Assert.assertEquals(1, stageTrace.getStart()); - Assert.assertEquals(2, stageTrace.getStartSchedule()); - Assert.assertEquals(3, stageTrace.getStartExecution()); - Assert.assertEquals(4, stageTrace.getStartServerFiltersRequest()); - Assert.assertEquals(5, stageTrace.getStartHandlersRequest()); - Assert.assertEquals(6, stageTrace.getStartBusinessMethod()); - Assert.assertEquals(7, stageTrace.getFinishBusiness()); - Assert.assertEquals(8, stageTrace.getFinishHandlersResponse()); - Assert.assertEquals(9, stageTrace.getFinishServerFiltersResponse()); - Assert.assertEquals(10, stageTrace.getFinish()); - - Assert.assertEquals(1f, stageTrace.calcInvocationPrepareTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcThreadPoolQueueTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcServerFiltersRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcHandlersRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcBusinessTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcHandlersResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcServerFiltersResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcSendResponseTime(), 0.1f); - Assert.assertEquals(9f, stageTrace.calcTotalTime(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcPrepare(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcQueue(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcProviderDecodeRequest(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcProviderEncodeResponse(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcBusinessExecute(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcProviderSendResponse(), 0.1f); + Assertions.assertEquals(6f, stageTrace.calcTotal(), 0.1f); } @Test public void edge() { - invocation = new Invocation(referenceConfig, operationMeta, args); + invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, args); stageTrace = new InvocationStageTrace(invocation); - invocation.setEdge(true); + invocation.setEdge(); - stageTrace.start(1); + stageTrace.startCreateInvocation(1); nanoTime = 2; - stageTrace.startSchedule(); + stageTrace.finishCreateInvocation(); + stageTrace.startProviderDecodeRequest(); nanoTime = 3; - stageTrace.startExecution(); + stageTrace.finishProviderDecodeRequest(); + stageTrace.startConsumerConnection(); nanoTime = 4; - stageTrace.startServerFiltersRequest(); + stageTrace.finishConsumerConnection(); + stageTrace.startConsumerEncodeRequest(); nanoTime = 5; - stageTrace.startHandlersRequest(); + stageTrace.finishConsumerEncodeRequest(); + stageTrace.startConsumerSendRequest(); nanoTime = 6; - stageTrace.startClientFiltersRequest(); + stageTrace.finishConsumerSendRequest(); + stageTrace.startWaitResponse(); nanoTime = 7; - stageTrace.startSend(); - stageTrace.finishGetConnection(8); - stageTrace.finishWriteToBuffer(9); + stageTrace.finishWaitResponse(); + stageTrace.startConsumerDecodeResponse(); + nanoTime = 8; + stageTrace.finishConsumerDecodeResponse(); + stageTrace.startProviderEncodeResponse(); nanoTime = 10; - stageTrace.finishReceiveResponse(); + stageTrace.finishProviderEncodeResponse(); + stageTrace.startProviderSendResponse(); nanoTime = 11; - stageTrace.startClientFiltersResponse(); - nanoTime = 12; - stageTrace.finishClientFiltersResponse(); - nanoTime = 13; - stageTrace.finishHandlersResponse(); - nanoTime = 14; - stageTrace.finishServerFiltersResponse(); - nanoTime = 15; + stageTrace.finishProviderSendResponse(); stageTrace.finish(); - Assert.assertEquals(1, stageTrace.getStart()); - Assert.assertEquals(2, stageTrace.getStartSchedule()); - Assert.assertEquals(3, stageTrace.getStartExecution()); - Assert.assertEquals(4, stageTrace.getStartServerFiltersRequest()); - Assert.assertEquals(5, stageTrace.getStartHandlersRequest()); - Assert.assertEquals(6, stageTrace.getStartClientFiltersRequest()); - Assert.assertEquals(7, stageTrace.getStartSend()); - Assert.assertEquals(8, stageTrace.getFinishGetConnection()); - Assert.assertEquals(9, stageTrace.getFinishWriteToBuffer()); - Assert.assertEquals(10, stageTrace.getFinishReceiveResponse()); - Assert.assertEquals(11, stageTrace.getStartClientFiltersResponse()); - Assert.assertEquals(12, stageTrace.getFinishClientFiltersResponse()); - Assert.assertEquals(13, stageTrace.getFinishHandlersResponse()); - Assert.assertEquals(14, stageTrace.getFinishServerFiltersResponse()); - Assert.assertEquals(15, stageTrace.getFinish()); - - Assert.assertEquals(1f, stageTrace.calcInvocationPrepareTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcThreadPoolQueueTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcServerFiltersRequestTime(), 0.1f); - - Assert.assertEquals(1f, stageTrace.calcHandlersRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcClientFiltersRequestTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcGetConnectionTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcWriteToBufferTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcReceiveResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcWakeConsumer(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcClientFiltersResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcHandlersResponseTime(), 0.1f); - - Assert.assertEquals(1f, stageTrace.calcServerFiltersResponseTime(), 0.1f); - Assert.assertEquals(1f, stageTrace.calcSendResponseTime(), 0.1f); - - Assert.assertEquals(14f, stageTrace.calcTotalTime(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcPrepare(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConnection(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConsumerEncodeRequest(), 0.1f); + + Assertions.assertEquals(1f, stageTrace.calcConsumerSendRequest(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcWait(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcConsumerDecodeResponse(), 0.1f); + Assertions.assertEquals(2f, stageTrace.calcProviderEncodeResponse(), 0.1f); + Assertions.assertEquals(1f, stageTrace.calcProviderSendResponse(), 0.1f); + + Assertions.assertEquals(10f, stageTrace.calcTotal(), 0.1f); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointTest.java new file mode 100644 index 00000000000..b3c0733bb48 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.endpoint; + +import static com.google.common.collect.ImmutableMap.of; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.swagger.v3.oas.models.OpenAPI; + +public class EndpointTest { + public interface TestSchema { + void say(Endpoint endpoint); + } + + @Test + void should_ignore_endpoint_when_generate_swagger() { + SwaggerGenerator generator = SwaggerGenerator.create(TestSchema.class); + OpenAPI swagger = generator.generate(); + + assertThat(swagger.getInfo().getTitle()).contains("EndpointTest$TestSchema"); + assertThat(swagger.getPaths()).containsKey("/say"); + assertThat(swagger.getPaths().get("/say").getPost().getOperationId()).isEqualTo("say"); + assertThat(swagger.getPaths().get("/say").getPost().getResponses()).containsKey("200"); + } + + @Test + void should_set_endpoint_to_invocation_when_map_arguments() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + SwaggerConsumer consumer = environment + .createConsumer(TestSchema.class, SwaggerGenerator.generate(TestSchema.class)); + SwaggerConsumerOperation operation = consumer.findOperation("say"); + + Endpoint endpoint = new Endpoint(Mockito.mock(Transport.class), null); + Invocation invocation = Mockito.mock(Invocation.class); + Holder holder = new Holder<>(); + Mockito + .doAnswer(invocationOnMock -> { + holder.value = invocationOnMock.getArguments()[0]; + return null; + }) + .when(invocation) + .setEndpoint(Mockito.any()); + + Map argsMap = of("endpoint", endpoint); + operation.getArgumentsMapper().invocationArgumentToSwaggerArguments(invocation, argsMap); + + assertThat(holder.value).isSameAs(endpoint); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtilsTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtilsTest.java new file mode 100644 index 00000000000..43cc21ba478 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/endpoint/EndpointUtilsTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.endpoint; + +import static org.apache.servicecomb.core.invocation.endpoint.EndpointUtils.formatFromUri; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class EndpointUtilsTest { + @Nested + class Http { + @Test + void should_convert_without_port() { + assertThat(formatFromUri("http://host")).isEqualTo("rest://host:80"); + } + + @Test + void should_convert_with_port() { + assertThat(formatFromUri("http://host:8080")).isEqualTo("rest://host:8080"); + } + + @Test + void should_not_lost_query_parameters() { + assertThat(formatFromUri("http://host?q1=v1&q2=v2")).isEqualTo("rest://host:80?q1=v1&q2=v2"); + } + } + + @Nested + class Https { + @Test + void should_convert_without_port() { + assertThat(formatFromUri("https://host")).isEqualTo("rest://host:443?sslEnabled=true"); + } + + @Test + void should_convert_with_port() { + assertThat(formatFromUri("https://host:8443")).isEqualTo("rest://host:8443?sslEnabled=true"); + } + + @Test + void should_not_lost_query_parameters() { + assertThat(formatFromUri("https://host?q1=v1&q2=v2")).isEqualTo("rest://host:443?q1=v1&q2=v2&sslEnabled=true"); + } + } + + @Nested + class H2C { + @Test + void should_convert_without_port() { + assertThat(formatFromUri("h2c://host")).isEqualTo("rest://host:80?protocol=http2"); + } + + @Test + void should_convert_with_port() { + assertThat(formatFromUri("h2c://host:8080")).isEqualTo("rest://host:8080?protocol=http2"); + } + + @Test + void should_not_lost_query_parameters() { + assertThat(formatFromUri("h2c://host?q1=v1&q2=v2")).isEqualTo("rest://host:80?q1=v1&q2=v2&protocol=http2"); + } + } + + @Nested + class H2 { + @Test + void should_convert_without_port() { + assertThat(formatFromUri("h2://host")).isEqualTo("rest://host:443?sslEnabled=true&protocol=http2"); + } + + @Test + void should_convert_with_port() { + assertThat(formatFromUri("h2://host:8443")).isEqualTo("rest://host:8443?sslEnabled=true&protocol=http2"); + } + + @Test + void should_not_lost_query_parameters() { + assertThat(formatFromUri("h2://host?q1=v1&q2=v2")) + .isEqualTo("rest://host:443?q1=v1&q2=v2&sslEnabled=true&protocol=http2"); + } + } + + @Nested + class NotProvideScheme { + @Test + void should_set_scheme_to_h2c() { + assertThat(formatFromUri("host")).isEqualTo("rest://host:80?protocol=http2"); + } + + @Test + void should_not_lost_query_parameters() { + assertThat(formatFromUri("host?q1=v1&q2=v2")).isEqualTo("rest://host:80?q1=v1&q2=v2&protocol=http2"); + } + } + + @Nested + class UnknownScheme { + @Test + void should_not_change() { + assertThat(formatFromUri("abc://host:123?q1=v1")).isEqualTo("abc://host:123?q1=v1"); + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java new file mode 100644 index 00000000000..58de7e9d2a0 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/PassingTimeStrategyTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.timeout; + +import static org.apache.servicecomb.core.invocation.timeout.PassingTimeStrategy.CHAIN_START_TIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.test.scaffolding.time.MockClock; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; + +class PassingTimeStrategyTest { + PassingTimeStrategy strategy = new PassingTimeStrategy(); + + @Test + void should_init_when_start_as_first_node_of_a_process_but_not_first_of_a_chain() { + Invocation invocation = new Invocation(); + invocation.setContext(ImmutableMap.of(CHAIN_START_TIME, "10")); + + strategy.start(invocation); + + assertThat(invocation.getContext(CHAIN_START_TIME)).isEqualTo("10"); + assertThat(invocation.getLocalContext(CHAIN_START_TIME)).isEqualTo(10L); + } + + @Test + void should_do_nothing_when_start_not_as_first_node_of_a_process() { + Invocation invocation = new Invocation(); + invocation.setContext(ImmutableMap.of()); + invocation.setLocalContext(ImmutableMap.of(CHAIN_START_TIME, 10L)); + + Throwable throwable = catchThrowable(() -> strategy.start(invocation)); + + assertThat(throwable).isNull(); + } + + @Test + void should_calc_elapsed_time_as_passing_time() { + Invocation invocation = new Invocation(); + invocation.addLocalContext(CHAIN_START_TIME, 10L); + strategy.setClock(new MockClock(100L)); + + long elapsedNanoTime = strategy.calculateElapsedNanoTime(invocation); + + assertThat(elapsedNanoTime).isEqualTo(TimeUnit.MILLISECONDS.toNanos(90)); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java new file mode 100644 index 00000000000..05d744e15db --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/invocation/timeout/ProcessingTimeStrategyTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.invocation.timeout; + +import static org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy.CHAIN_PROCESSING; +import static org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy.CHAIN_START_TIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.test.scaffolding.time.MockTicker; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; + +class ProcessingTimeStrategyTest { + ProcessingTimeStrategy strategy = new ProcessingTimeStrategy(); + + @Test + void should_do_nothing_when_not_first_node_of_a_process() { + Invocation invocation = new Invocation(); + invocation.setLocalContext(ImmutableMap.of( + CHAIN_START_TIME, 10L, + CHAIN_PROCESSING, 0L + )); + + Throwable throwable = catchThrowable(() -> strategy.start(invocation)); + + assertThat(throwable).isNull(); + } + + @Test + void should_calc_elapsed_time_as_processing_time() { + strategy.setTicker(new MockTicker(50L)); + + Invocation invocation = new Invocation(); + invocation.addLocalContext(CHAIN_START_TIME, 10L); + invocation.addLocalContext(CHAIN_PROCESSING, 20L); + + long elapsedNanoTime = strategy.calculateElapsedNanoTime(invocation); + + assertThat(elapsedNanoTime).isEqualTo(60L); + } + + @Test + void should_update_processing_time_before_send() { + strategy = new ProcessingTimeStrategy() { + @Override + public void checkTimeout(Invocation invocation) { + + } + }; + strategy.setTicker(new MockTicker(50L)); + + Invocation invocation = new Invocation(); + invocation.addLocalContext(CHAIN_START_TIME, 10L); + invocation.addLocalContext(CHAIN_PROCESSING, 20L); + + strategy.beforeSendRequest(invocation); + + assertThat(invocation.getContext(CHAIN_PROCESSING)).isEqualTo("60"); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/org/apache/servicecomb/core/TestCseApplicationListener.java b/core/src/test/java/org/apache/servicecomb/core/org/apache/servicecomb/core/TestCseApplicationListener.java deleted file mode 100644 index aeac7e1f5d9..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/org/apache/servicecomb/core/TestCseApplicationListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.org.apache.servicecomb.core; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.core.CseApplicationListener; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.context.event.ContextClosedEvent; - -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestCseApplicationListener { - @Test - public void onApplicationEvent_close(@Mocked ContextClosedEvent contextClosedEvent) { - AtomicInteger count = new AtomicInteger(); - SCBEngine scbEngine = new SCBEngine() { - @Override - public synchronized void destroy() { - count.incrementAndGet(); - } - }; - new MockUp() { - @Mock - SCBEngine getInstance() { - return scbEngine; - } - }; - scbEngine.setStatus(SCBStatus.UP); - - CseApplicationListener listener = new CseApplicationListener(); - - listener.onApplicationEvent(contextClosedEvent); - - Assert.assertEquals(1, count.get()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestConsumerProviderManager.java b/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestConsumerProviderManager.java deleted file mode 100644 index 56bfe3897e7..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestConsumerProviderManager.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.provider.consumer; - -import static org.junit.Assert.fail; - -import java.util.Collections; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import com.google.common.eventbus.EventBus; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestConsumerProviderManager { - @Before - public void setUp() throws Exception { - ArchaiusUtils.resetConfig(); - } - - @After - public void tearDown() throws Exception { - ArchaiusUtils.resetConfig(); - } - - @Test - public void allowedNoProvider(@Mocked ConsumerSchemaFactory consumerSchemaFactory) { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.getBeanFactory().registerSingleton(consumerSchemaFactory.getClass().getName(), consumerSchemaFactory); - context.register(ConsumerProviderManager.class); - // must not throw exception - context.refresh(); - - context.close(); - } - - private ReferenceConfig mockCreateReferenceConfig() { - EventBus eventBus = new EventBus(); - AppManager appManager = new AppManager(eventBus); - - ConsumerProviderManager consumerProviderManager = new ConsumerProviderManager(); - consumerProviderManager.setAppManager(appManager); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, null); - result = Collections.emptyList(); - } - }; - - new MockUp() { - @Mock - MicroserviceVersion getLatestMicroserviceVersion() { - return Mockito.mock(MicroserviceVersion.class); - } - }; - return consumerProviderManager.createReferenceConfig("app:ms"); - } - - @Test - public void createReferenceConfig_default() { - ReferenceConfig referenceConfig = mockCreateReferenceConfig(); - - Assert.assertEquals("app", referenceConfig.getMicroserviceVersionRule().getAppId()); - Assert.assertEquals("app:ms", referenceConfig.getMicroserviceVersionRule().getMicroserviceName()); - Assert.assertEquals("0.0.0.0+", referenceConfig.getMicroserviceVersionRule().getVersionRule().getVersionRule()); - Assert.assertEquals(Const.ANY_TRANSPORT, referenceConfig.getTransport()); - } - - @Test - public void createReferenceConfig_config() { - ArchaiusUtils.setProperty("servicecomb.references.app:ms.version-rule", "1.0.0+"); - ArchaiusUtils.setProperty("servicecomb.references.app:ms.transport", Const.RESTFUL); - - ReferenceConfig referenceConfig = mockCreateReferenceConfig(); - - Assert.assertEquals("app", referenceConfig.getMicroserviceVersionRule().getAppId()); - Assert.assertEquals("app:ms", referenceConfig.getMicroserviceVersionRule().getMicroserviceName()); - Assert.assertEquals("1.0.0.0+", referenceConfig.getMicroserviceVersionRule().getVersionRule().getVersionRule()); - Assert.assertEquals(Const.RESTFUL, referenceConfig.getTransport()); - } - - @Test - public void createReferenceConfig_ProviderNotFound() { - EventBus eventBus = new EventBus(); - AppManager appManager = new AppManager(eventBus); - - ConsumerProviderManager consumerProviderManager = new ConsumerProviderManager(); - consumerProviderManager.setAppManager(appManager); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, null); - result = Collections.emptyList(); - } - }; - - new MockUp() { - @Mock - String getAppId() { - return "aId"; - } - - @Mock - String getMicroserviceName() { - return "ms"; - } - }; - - try { - consumerProviderManager.createReferenceConfig("app:ms"); - fail("an IllegalStateException is expected!"); - } catch (Exception e) { - Assert.assertEquals(IllegalStateException.class, e.getClass()); - Assert.assertEquals( - "Probably invoke a service before it is registered, or no instance found for it, appId=aId, name=ms", - e.getMessage()); - e.printStackTrace(); - } - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestInvokerUtils.java b/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestInvokerUtils.java index 3ac309cdd5b..3b3e56092c3 100644 --- a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestInvokerUtils.java +++ b/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestInvokerUtils.java @@ -17,230 +17,11 @@ package org.apache.servicecomb.core.provider.consumer; -import java.util.Arrays; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import org.junit.jupiter.api.Test; public class TestInvokerUtils { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Mocked - ReferenceConfig referenceConfig; - - @Mocked - SchemaMeta schemaMeta; - - @Mocked - OperationMeta operationMeta; - - Invocation invocation; - - static Object invokeResult; - - SCBEngine scbEngine = new SCBEngine(); - - static long nanoTime = 1; - - @BeforeClass - public static void classSetup() { - new MockUp() { - @Mock - long nanoTime() { - return nanoTime; - } - }; - } - - @Before - public void setup() { - new MockUp() { - @Mock - SCBEngine getInstance() { - return scbEngine; - } - }; - scbEngine.setStatus(SCBStatus.UP); - - new Expectations() { - { - operationMeta.getSchemaMeta(); - result = schemaMeta; - schemaMeta.getConsumerHandlerChain(); - result = Arrays.asList((Handler) (i, ar) -> { - System.out.println(invokeResult); - ar.success(invokeResult); - }); - } - }; - invocation = new Invocation(referenceConfig, operationMeta, new Object[] {}); - } - - @Test - public void testSyncInvokeInvocationWithException() { - Invocation invocation = Mockito.mock(Invocation.class); - InvocationStageTrace stageTrace = new InvocationStageTrace(invocation); - Mockito.when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); - - Response response = Mockito.mock(Response.class); - new MockUp() { - @Mock - public Response waitResponse() { - return response; - } - }; - Mockito.when(response.isSuccessed()).thenReturn(false); - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn("test"); - - expectedException.expect(InvocationException.class); - expectedException.expect(Matchers.hasProperty("statusCode", Matchers.is(490))); - InvokerUtils.syncInvoke(invocation); - } - - @Test - public void testSyncInvokeNormal() { - invokeResult = 1; - Assert.assertEquals(1, (int) InvokerUtils.syncInvoke(invocation)); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStart()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStartHandlersRequest()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinishHandlersResponse()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinish()); - } - - @Test - public void testReactiveInvoke(@Mocked InvocationContext parentContext, @Mocked Response response) { - new MockUp(invocation) { - @Mock - InvocationContext getParentContext() { - return parentContext; - } - - @Mock - void next(AsyncResponse asyncResp) { - asyncResp.handle(response); - } - }; - - Holder holder = new Holder<>(); - InvokerUtils.reactiveInvoke(invocation, ar -> holder.value = ContextUtils.getInvocationContext()); - - Assert.assertNull(ContextUtils.getInvocationContext()); - Assert.assertSame(parentContext, holder.value); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStart()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStartHandlersRequest()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinishHandlersResponse()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinish()); - } - @Test - public void reactiveInvokeException() { - new MockUp(invocation) { - @Mock - void next(AsyncResponse asyncResp) { - throw new Error(); - } - }; - - Holder holder = new Holder<>(); - InvokerUtils.reactiveInvoke(invocation, ar -> holder.value = ar); - - Assert.assertFalse(holder.value.isSuccessed()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStart()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getStartHandlersRequest()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinishHandlersResponse()); - Assert.assertEquals(1, invocation.getInvocationStageTrace().getFinish()); - } - - @SuppressWarnings("deprecation") - @Test - public void invoke() { - new MockUp() { - @Mock - Object syncInvoke(Invocation invocation) { - return 1; - } - }; - - Assert.assertEquals(1, InvokerUtils.invoke(null)); - } - - @Test - public void testSyncInvoke_4param_NotReady() { - scbEngine.setStatus(SCBStatus.DOWN); - - expectedException.expect(InvocationException.class); - expectedException.expectMessage( - Matchers - .is("InvocationException: code=503;msg=CommonExceptionData [message=The request is rejected. Cannot process the request due to STATUS = DOWN]")); - InvokerUtils.syncInvoke("ms", "schemaId", "opName", null); - } - - @Test - public void testSyncInvoke_6param_NotReady() { - scbEngine.setStatus(SCBStatus.DOWN); - - expectedException.expect(InvocationException.class); - expectedException.expectMessage( - Matchers - .is("InvocationException: code=503;msg=CommonExceptionData [message=The request is rejected. Cannot process the request due to STATUS = DOWN]")); - - InvokerUtils.syncInvoke("ms", "latest", "rest", "schemaId", "opName", null); - } - - @Test - public void testSyncInvokeReady(@Injectable ConsumerProviderManager consumerProviderManager, - @Injectable Invocation invocation) { - scbEngine.setConsumerProviderManager(consumerProviderManager); - - new Expectations(InvocationFactory.class) { - { - InvocationFactory.forConsumer((ReferenceConfig) any, (SchemaMeta) any, (String) any, (Object[]) any); - result = invocation; - } - }; - new Expectations(InvokerUtils.class) { - { - InvokerUtils.syncInvoke(invocation); - result = "ok"; - } - }; - Object result1 = InvokerUtils.syncInvoke("ms", "schemaId", "opName", null); - Assert.assertEquals("ok", result1); - - Object result2 = InvokerUtils.syncInvoke("ms", "latest", "rest", "schemaId", "opName", null); - Assert.assertEquals("ok", result2); + public void testRetryInvocation503() { - CseContext.getInstance().setConsumerProviderManager(null); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestReferenceConfig.java b/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestReferenceConfig.java deleted file mode 100644 index fa65f67d3e1..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/provider/consumer/TestReferenceConfig.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.core.provider.consumer; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestReferenceConfig { - @Mocked - MicroserviceMeta microserviceMeta; - - @Mocked - MicroserviceVersionRule microserviceVersionRule; - - @Mocked - MicroserviceVersionMeta microserviceVersionMeta; - - @Test - public void constructNoParam() { - new Expectations() { - { - microserviceVersionMeta.getMicroserviceMeta(); - result = microserviceMeta; - microserviceVersionRule.getLatestMicroserviceVersion(); - result = microserviceVersionMeta; - } - }; - String transport = Const.ANY_TRANSPORT; - - ReferenceConfig referenceConfig = new ReferenceConfig(); - referenceConfig.setMicroserviceVersionRule(microserviceVersionRule); - referenceConfig.setTransport(transport); - - Assert.assertSame(microserviceMeta, referenceConfig.getMicroserviceMeta()); - Assert.assertSame(microserviceVersionRule, referenceConfig.getMicroserviceVersionRule()); - Assert.assertSame(transport, referenceConfig.getTransport()); - } - - @Test - public void constructWithParam(@Mocked AppManager appManager, - @Mocked MicroserviceMeta microserviceMeta, - @Mocked MicroserviceVersionRule microserviceVersionRule, - @Mocked MicroserviceVersionMeta microserviceVersionMeta) { - String microserviceName = "ms"; - String transport = Const.ANY_TRANSPORT; - new Expectations() { - { - appManager.getOrCreateMicroserviceVersionRule(anyString, anyString, anyString); - result = microserviceVersionRule; - microserviceVersionMeta.getMicroserviceMeta(); - result = microserviceMeta; - microserviceVersionRule.getLatestMicroserviceVersion(); - result = microserviceVersionMeta; - } - }; - - ReferenceConfig referenceConfig = new ReferenceConfig(appManager, microserviceName, - DefinitionConst.VERSION_RULE_LATEST, - transport); - Assert.assertSame(microserviceMeta, referenceConfig.getMicroserviceMeta()); - Assert.assertSame(microserviceVersionRule, referenceConfig.getMicroserviceVersionRule()); - Assert.assertSame(transport, referenceConfig.getTransport()); - } -} diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerBootListener.java b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerBootListener.java new file mode 100644 index 00000000000..e327759eff2 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerBootListener.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.provider.producer; + +import java.util.Arrays; +import java.util.concurrent.Executor; + +import org.apache.servicecomb.core.BootListener.BootEvent; +import org.apache.servicecomb.core.BootListener.EventType; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestProducerBootListener { + ProducerBootListener producerBootListener = new ProducerBootListener(); + + @Test + public void onBootEvent_notClose() { + BootEvent event = new BootEvent(); + event.setEventType(EventType.BEFORE_CLOSE); + + // should not throw exception + producerBootListener.onBootEvent(event); + } + + @Test + public void onBootEvent_close_unknown() { + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + OperationMeta op = Mockito.mock(OperationMeta.class); + + Executor executor = new UnCloseableExecutor(); + Mockito.when(scbEngine.getProducerMicroserviceMeta()).thenReturn(microserviceMeta); + Mockito.when(microserviceMeta.getOperations()).thenReturn(Arrays.asList(op)); + Mockito.when(op.getExecutor()).thenReturn(executor); + + try (LogCollector logCollector = new LogCollector()) { + BootEvent event = new BootEvent(); + event.setScbEngine(scbEngine); + event.setEventType(EventType.AFTER_CLOSE); + + producerBootListener.onBootEvent(event); + + Assertions.assertEquals( + "Executor org.apache.servicecomb.core.provider.producer.TestProducerBootListener$UnCloseableExecutor " + + "do not support close or shutdown, it may block service shutdown.", + logCollector.getLastEvents().getMessage().getFormattedMessage()); + } + } + + public static class UnCloseableExecutor implements Executor { + @Override + public void execute(Runnable command) { + command.run(); + } + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerMeta.java b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerMeta.java index 02a214b6aa9..1c481c7189b 100644 --- a/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerMeta.java +++ b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerMeta.java @@ -16,29 +16,25 @@ */ package org.apache.servicecomb.core.provider.producer; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestProducerMeta { @Test public void test1() { Object instance = new Object(); - ProducerMeta meta = new ProducerMeta("id", instance, instance.getClass()); - Assert.assertEquals("id", meta.getSchemaId()); - Assert.assertEquals(instance, meta.getInstance()); - Assert.assertEquals(Object.class, meta.getInstanceClass()); + ProducerMeta meta = new ProducerMeta("id", instance); + Assertions.assertEquals("id", meta.getSchemaId()); + Assertions.assertEquals(instance, meta.getInstance()); } @Test public void test2() { ProducerMeta meta = new ProducerMeta(); meta.setSchemaId("id1"); - Assert.assertEquals("id1", meta.getSchemaId()); + Assertions.assertEquals("id1", meta.getSchemaId()); meta.setInstance(1); - Assert.assertEquals(1, meta.getInstance()); - - meta.setInstanceClass(Integer.class); - Assert.assertEquals(Integer.class, meta.getInstanceClass()); + Assertions.assertEquals(1, meta.getInstance()); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerProviderManager.java b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerProviderManager.java index 943183a0f94..f36229b0eea 100644 --- a/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerProviderManager.java +++ b/core/src/test/java/org/apache/servicecomb/core/provider/producer/TestProducerProviderManager.java @@ -17,117 +17,12 @@ package org.apache.servicecomb.core.provider.producer; -import java.io.Closeable; -import java.util.Arrays; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.core.BootListener.BootEvent; -import org.apache.servicecomb.core.BootListener.EventType; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.executor.FixedThreadExecutor; -import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import org.junit.jupiter.api.Test; public class TestProducerProviderManager { @Test public void allowedNoProvider() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(ProducerProviderManager.class); // must not throw exception - context.refresh(); - - context.close(); - } - - @Test - public void onBootEvent_notClose() { - BootEvent event = new BootEvent(); - event.setEventType(EventType.BEFORE_CLOSE); - - ProducerProviderManager producerProviderManager = new ProducerProviderManager(); - // should not throw exception - producerProviderManager.onBootEvent(event); - } - - @Test - public void onBootEvent_close(@Mocked MicroserviceMeta microserviceMeta, @Mocked OperationMeta op1, - @Mocked OperationMeta op2, @Mocked FixedThreadExecutor closeable) { - AtomicInteger count = new AtomicInteger(); - ExecutorService executorService = new MockUp() { - @Mock - void shutdown() { - count.incrementAndGet(); - } - }.getMockInstance(); - new MockUp(closeable) { - @Mock - void close() { - count.incrementAndGet(); - } - }; - new Expectations() { - { - microserviceMeta.getOperations(); - result = Arrays.asList(op1, op2); - op1.getExecutor(); - result = executorService; - op2.getExecutor(); - result = closeable; - } - }; - BootEvent event = new BootEvent(); - event.setEventType(EventType.AFTER_CLOSE); - - ProducerProviderManager producerProviderManager = new ProducerProviderManager(); - Deencapsulation.setField(producerProviderManager, "microserviceMeta", microserviceMeta); - - producerProviderManager.onBootEvent(event); - - Assert.assertEquals(2, count.get()); - } - - @Test - public void onBootEvent_close_unknown(@Mocked MicroserviceMeta microserviceMeta, @Mocked OperationMeta op1) { - Executor executor = new UnCloseableExecutor(); - new Expectations() { - { - microserviceMeta.getOperations(); - result = Arrays.asList(op1); - op1.getExecutor(); - result = executor; - } - }; - LogCollector logCollector = new LogCollector(); - BootEvent event = new BootEvent(); - event.setEventType(EventType.AFTER_CLOSE); - - ProducerProviderManager producerProviderManager = new ProducerProviderManager(); - Deencapsulation.setField(producerProviderManager, "microserviceMeta", microserviceMeta); - - producerProviderManager.onBootEvent(event); - - Assert.assertEquals( - "Executor org.apache.servicecomb.core.provider.producer.TestProducerProviderManager$UnCloseableExecutor " - + "do not support close or shutdown, it may block service shutdown.", - logCollector.getEvents().get(0).getMessage()); - logCollector.teardown(); - } - - public static class UnCloseableExecutor implements Executor { - @Override - public void execute(Runnable command) { - command.run(); - } + new ProducerProviderManager(null).init(); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/registry/discovery/TestEndpointDiscoveryFilter.java b/core/src/test/java/org/apache/servicecomb/core/registry/discovery/TestEndpointDiscoveryFilter.java new file mode 100644 index 00000000000..cc79ba2f684 --- /dev/null +++ b/core/src/test/java/org/apache/servicecomb/core/registry/discovery/TestEndpointDiscoveryFilter.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.core.registry.discovery; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestEndpointDiscoveryFilter { + EndpointDiscoveryFilter filter = new EndpointDiscoveryFilter(); + + DiscoveryContext context = new DiscoveryContext(); + + Invocation invocation; + + @BeforeEach + public void setup() { + + } + + @AfterEach + public void teardown() { + } + + @Test + public void getOrder() { + Assertions.assertEquals(Short.MAX_VALUE, filter.getOrder()); + } + + @Test + public void getTransportName() { + invocation = Mockito.mock(Invocation.class); + Mockito.when(invocation.getConfigTransportName()).thenReturn(CoreConst.RESTFUL); + context.setInputParameters(invocation); + Assertions.assertEquals(CoreConst.RESTFUL, filter.findTransportName(context, null)); + } + + @Test + public void createEndpointNullTransport() { + TransportManager transportManager = Mockito.mock(TransportManager.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Mockito.when(transportManager.findTransport(CoreConst.RESTFUL)).thenReturn(null); + filter.setScbEngine(scbEngine); + Assertions.assertNull(filter.createEndpoint(null, CoreConst.RESTFUL, "", null)); + } + + @Test + public void createEndpointNormal() { + Transport transport = Mockito.mock(Transport.class); + StatefulDiscoveryInstance instance = Mockito.mock(StatefulDiscoveryInstance.class); + TransportManager transportManager = Mockito.mock(TransportManager.class); + + String endpoint = "rest://ip:port"; + Object address = new Object(); + + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Mockito.when(transportManager.findTransport(CoreConst.RESTFUL)).thenReturn(transport); + Mockito.when(transport.parseAddress(endpoint)).thenReturn(address); + filter.setScbEngine(scbEngine); + + Endpoint ep = (Endpoint) filter.createEndpoint(null, CoreConst.RESTFUL, endpoint, instance); + Assertions.assertSame(transport, ep.getTransport()); + Assertions.assertSame(address, ep.getAddress()); + Assertions.assertSame(instance, ep.getMicroserviceInstance()); + Assertions.assertEquals(endpoint, ep.getEndpoint()); + } +} diff --git a/core/src/test/java/org/apache/servicecomb/core/tracing/BraveTraceIdGeneratorTest.java b/core/src/test/java/org/apache/servicecomb/core/tracing/BraveTraceIdGeneratorTest.java index 8963cd292b3..e858dd954c5 100644 --- a/core/src/test/java/org/apache/servicecomb/core/tracing/BraveTraceIdGeneratorTest.java +++ b/core/src/test/java/org/apache/servicecomb/core/tracing/BraveTraceIdGeneratorTest.java @@ -17,23 +17,21 @@ package org.apache.servicecomb.core.tracing; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.fail; - -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class BraveTraceIdGeneratorTest { @Test public void generateStringId() { TraceIdGenerator traceIdGenerator = new BraveTraceIdGenerator(); - assertNotEquals(traceIdGenerator.generate(), traceIdGenerator.generate()); + Assertions.assertNotEquals(traceIdGenerator.generate(), traceIdGenerator.generate()); String traceId = traceIdGenerator.generate(); try { Long.parseLong(traceId, 16); } catch (NumberFormatException e) { - fail("wrong traceId format: " + traceId); + Assertions.fail("wrong traceId format: " + traceId); } } } diff --git a/core/src/test/java/org/apache/servicecomb/core/transport/TestAbstractTransport.java b/core/src/test/java/org/apache/servicecomb/core/transport/TestAbstractTransport.java index 7490caa9985..65c44b12560 100644 --- a/core/src/test/java/org/apache/servicecomb/core/transport/TestAbstractTransport.java +++ b/core/src/test/java/org/apache/servicecomb/core/transport/TestAbstractTransport.java @@ -17,43 +17,27 @@ package org.apache.servicecomb.core.transport; +import static org.apache.servicecomb.core.transport.AbstractTransport.PUBLISH_ADDRESS; + import java.io.UnsupportedEncodingException; -import java.lang.reflect.Method; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Collections; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.springframework.util.ReflectionUtils; - -import com.netflix.config.DynamicProperty; +import org.springframework.core.env.Environment; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; +import io.vertx.core.impl.SysProps; public class TestAbstractTransport { - private Method updatePropertyMethod = - ReflectionUtils.findMethod(DynamicProperty.class, "updateProperty", String.class, Object.class); + Environment environment = Mockito.mock(Environment.class); - private void updateProperty(String key, Object value) { - updatePropertyMethod.setAccessible(true); - ReflectionUtils.invokeMethod(updatePropertyMethod, null, key, value); - } - - class MyAbstractTransport extends AbstractTransport { + static class MyAbstractTransport extends AbstractTransport { @Override public String getName() { @@ -61,149 +45,68 @@ public String getName() { } @Override - public boolean init() throws Exception { + public boolean init() { return true; } - - @Override - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - } - } - - @Injectable - AbstractServiceRegistry serviceRegistry; - - @Before - public void setup() { - RegistryUtils.setServiceRegistry(serviceRegistry); - } - - @After - public void teardown() { - RegistryUtils.setServiceRegistry(null); } - @AfterClass - public static void classTeardown() { - VertxUtils.closeVertxByName("transport"); + @BeforeEach + public void setUp() { + Mockito.when(environment.getProperty(PUBLISH_ADDRESS, "")).thenReturn(""); + Mockito.when(environment.getProperty("servicecomb.my.publishPort", int.class, 0)).thenReturn(0); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); } @Test public void testSetListenAddressWithoutSchemaChineseSpaceNewSC() throws UnsupportedEncodingException { - new Expectations() { - { - serviceRegistry.getFeatures().isCanEncodeEndpoint(); - result = true; - } - }; - MyAbstractTransport transport = new MyAbstractTransport(); + transport.setEnvironment(environment); transport.setListenAddressWithoutSchema("127.0.0.1:9090", Collections.singletonMap("country", "中 国")); - Assert.assertEquals("my://127.0.0.1:9090?country=" + URLEncoder.encode("中 国", StandardCharsets.UTF_8.name()), + Assertions.assertEquals("my://127.0.0.1:9090?country=" + URLEncoder.encode("中 国", StandardCharsets.UTF_8.name()), transport.getEndpoint().getEndpoint()); } @Test - public void testSetListenAddressWithoutSchemaChineseSpaceOldSC() throws UnsupportedEncodingException { - MyAbstractTransport transport = new MyAbstractTransport(); - try { - transport.setListenAddressWithoutSchema("127.0.0.1:9090", Collections.singletonMap("country", "中 国")); - Assert.fail("must throw exception"); - } catch (ServiceCombException e) { - Assert.assertEquals( - "current service center not support encoded endpoint, please do not use chinese or space or anything need to be encoded.", - e.getMessage()); - Assert.assertEquals( - "Illegal character in query at index 31: rest://127.0.0.1:9090?country=中 国", - e.getCause().getMessage()); - } - } - - @Test - public void testSetListenAddressWithoutSchemaNormalNotEncode() throws UnsupportedEncodingException { + public void testSetListenAddressWithoutSchemaNormalNotEncode() { MyAbstractTransport transport = new MyAbstractTransport(); + transport.setEnvironment(environment); transport.setListenAddressWithoutSchema("127.0.0.1:9090", Collections.singletonMap("country", "chinese")); - Assert.assertEquals("my://127.0.0.1:9090?country=chinese", transport.getEndpoint().getEndpoint()); + Assertions.assertEquals("my://127.0.0.1:9090?country=chinese", transport.getEndpoint().getEndpoint()); } @Test - public void testSetListenAddressWithoutSchemaAlreadyHaveQuery() throws UnsupportedEncodingException { + public void testSetListenAddressWithoutSchemaAlreadyHaveQuery() { MyAbstractTransport transport = new MyAbstractTransport(); + transport.setEnvironment(environment); transport.setListenAddressWithoutSchema("127.0.0.1:9090?a=aValue", Collections.singletonMap("country", "chinese")); - Assert.assertEquals("my://127.0.0.1:9090?a=aValue&country=chinese", transport.getEndpoint().getEndpoint()); + Assertions.assertEquals("my://127.0.0.1:9090?a=aValue&country=chinese", transport.getEndpoint().getEndpoint()); } @Test - public void testMyAbstractTransport() throws Exception { + public void testMyAbstractTransport() { MyAbstractTransport transport = new MyAbstractTransport(); + transport.setEnvironment(environment); transport.setListenAddressWithoutSchema("127.0.0.1:9090"); - Assert.assertEquals("my", transport.getName()); - Assert.assertEquals("my://127.0.0.1:9090", transport.getEndpoint().getEndpoint()); - Assert.assertEquals("127.0.0.1", ((IpPort) transport.parseAddress("my://127.0.0.1:9090")).getHostOrIp()); + Assertions.assertEquals("my", transport.getName()); + Assertions.assertEquals("my://127.0.0.1:9090", transport.getEndpoint().getEndpoint()); + Assertions.assertEquals("127.0.0.1", ((IpPort) transport.parseAddress("my://127.0.0.1:9090")).getHostOrIp()); transport.setListenAddressWithoutSchema("0.0.0.0:9090"); - Assert.assertNotEquals("my://127.0.0.1:9090", transport.getEndpoint().getEndpoint()); + Assertions.assertNotEquals("my://127.0.0.1:9090", transport.getEndpoint().getEndpoint()); transport.setListenAddressWithoutSchema(null); - Assert.assertNull(transport.getEndpoint().getEndpoint()); - Assert.assertNull(transport.parseAddress(null)); - Assert.assertEquals(30000, AbstractTransport.getReqTimeout("sayHi", "hello", "test")); + Assertions.assertNull(transport.getEndpoint().getEndpoint()); + Assertions.assertNull(transport.parseAddress(null)); } - @Test(expected = NumberFormatException.class) - public void testMyAbstractTransportException(@Mocked TransportManager manager) throws Exception { - MyAbstractTransport transport = new MyAbstractTransport(); - - transport.setListenAddressWithoutSchema(":127.0.0.1:9090"); - } - - /** - * Tests the request call timeout for service level timeout value - */ - @Test - public void testRequestCfgService() throws Exception { - System.setProperty("servicecomb.request.hello1.timeout", "3000"); - //check for service level timeout value - Assert.assertEquals(3000, AbstractTransport.getReqTimeout("sayHello1", "sayHelloSchema1", "hello1")); - System.getProperties().remove("servicecomb.request.hello1.timeout"); - } - - /** - * Tests the request call timeout for schema level timeout value - */ - @Test - public void testRequestCfgSchema() throws Exception { - System.setProperty("servicecomb.request.hello2.sayHelloSchema2.timeout", "2000"); - - Assert.assertEquals(2000, AbstractTransport.getReqTimeout("sayHello2", "sayHelloSchema2", "hello2")); - System.getProperties().remove("servicecomb.request.hello2.sayHelloSchema2.timeout"); - } - - /** - * Tests the request call timeout for operatation level timeout value - */ @Test - public void testRequestCfgOperation() throws Exception { - System.setProperty("servicecomb.request.hello3.sayHelloSchema3.sayHello3.timeout", "1000"); - - Assert.assertEquals(1000, AbstractTransport.getReqTimeout("sayHello3", "sayHelloSchema3", "hello3")); - System.getProperties().remove("servicecomb.request.hello3.sayHelloSchema3.sayHello3.timeout"); - } - - /** - * Tests the request call timeout with configuration change event for operation level config. - */ - @Test - public void testRequestTimeoutCfgEvent() { - System.setProperty("servicecomb.request.hello4.sayHelloSchema4.sayHello4.timeout", "1000"); - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello4"); - Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("hello4"); - Assert.assertEquals(1000, AbstractTransport.getReqTimeout("sayHello4", "sayHelloSchema4", "hello4")); - - updateProperty("servicecomb.request.hello4.sayHelloSchema4.sayHello4.timeout", 2000); - - Assert.assertEquals(2000, AbstractTransport.getReqTimeout("sayHello4", "sayHelloSchema4", "hello4")); - System.getProperties().remove("servicecomb.request.hello4.sayHelloSchema4.sayHello4.timeout"); + public void testMyAbstractTransportException() { + MyAbstractTransport transport = new MyAbstractTransport(); + transport.setEnvironment(environment); + Assertions.assertThrows(IllegalArgumentException.class, () -> + transport.setListenAddressWithoutSchema(":127.0.0.1:9090")); } } diff --git a/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportManager.java b/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportManager.java index 27d4b95275f..89b591beecb 100644 --- a/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportManager.java +++ b/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportManager.java @@ -22,125 +22,92 @@ import java.util.Map; import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestTransportManager { @Test - public void testTransportManagerInitFail(@Injectable Transport transport) throws Exception { - new Expectations() { - { - transport.getName(); - result = "test"; - transport.init(); - result = false; - transport.canInit(); - result = true; - } - }; + public void testTransportManagerInitFail() + throws Exception { + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Transport transport = Mockito.mock(Transport.class); + Mockito.when(transport.getName()).thenReturn("test"); + Mockito.when(transport.init()).thenReturn(false); + Mockito.when(transport.canInit()).thenReturn(true); List transports = Arrays.asList(transport); - TransportManager manager = new TransportManager(); - manager.setTransports(transports); + manager.addTransportsBeforeInit(transports); - manager.init(); - Assert.assertEquals(manager.findTransport("test"), transport); + manager.init(scbEngine); + Assertions.assertEquals(manager.findTransport("test"), transport); } @Test - public void testTransportManagerInitSucc(@Injectable Transport transport, @Injectable Endpoint endpoint, - @Mocked RegistryUtils util, @Injectable MicroserviceInstance instance) throws Exception { - new Expectations() { - { - transport.getName(); - result = "test"; - transport.canInit(); - result = true; - transport.init(); - result = true; - transport.getPublishEndpoint(); - result = endpoint; - } - }; + public void testTransportManagerInitSuccess() throws Exception { + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Transport transport = Mockito.mock(Transport.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); + Mockito.when(transport.getName()).thenReturn("test"); + Mockito.when(transport.init()).thenReturn(true); + Mockito.when(transport.canInit()).thenReturn(true); + Mockito.when(transport.getPublishEndpoint()).thenReturn(endpoint); List transports = Arrays.asList(transport); TransportManager manager = new TransportManager(); - manager.setTransports(transports); + manager.addTransportsBeforeInit(transports); - manager.init(); - Assert.assertEquals(manager.findTransport("test"), transport); + manager.init(scbEngine); + Assertions.assertEquals(manager.findTransport("test"), transport); } @Test - public void testGroupByName(@Mocked Transport t1, @Mocked Transport t2_1, @Mocked Transport t2_2) { - new Expectations() { - { - t1.getName(); - result = "t1"; - - t2_1.getName(); - result = "t2"; - t2_2.getName(); - result = "t2"; - } - }; - + public void testGroupByName() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getName()).thenReturn("t1"); + Transport t21 = Mockito.mock(Transport.class); + Mockito.when(t21.getName()).thenReturn("t2"); + Transport t22 = Mockito.mock(Transport.class); + Mockito.when(t22.getName()).thenReturn("t2"); TransportManager manager = new TransportManager(); - manager.setTransports(Arrays.asList(t1, t2_1, t2_2)); + manager.addTransportsBeforeInit(Arrays.asList(t1, t21, t22)); Map> groups = manager.groupByName(); - Assert.assertEquals(2, groups.size()); - Assert.assertEquals(1, groups.get("t1").size()); - Assert.assertEquals(t1, groups.get("t1").get(0)); - Assert.assertEquals(2, groups.get("t2").size()); - Assert.assertEquals(t2_1, groups.get("t2").get(0)); - Assert.assertEquals(t2_2, groups.get("t2").get(1)); + Assertions.assertEquals(2, groups.size()); + Assertions.assertEquals(1, groups.get("t1").size()); + Assertions.assertEquals(t1, groups.get("t1").get(0)); + Assertions.assertEquals(2, groups.get("t2").size()); + Assertions.assertEquals(t21, groups.get("t2").get(0)); + Assertions.assertEquals(t22, groups.get("t2").get(1)); } @Test - public void testCheckTransportGroupInvalid(@Mocked Transport t1, @Mocked Transport t2) { - new Expectations() { - { - t1.getOrder(); - result = 1; - - t2.getOrder(); - result = 1; - } - }; + public void testCheckTransportGroupInvalid() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getOrder()).thenReturn(1); + Transport t2 = Mockito.mock(Transport.class); + Mockito.when(t2.getOrder()).thenReturn(1); TransportManager manager = new TransportManager(); List group = Arrays.asList(t1, t2); try { manager.checkTransportGroup(group); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals( - "org.apache.servicecomb.core.$Impl_Transport and org.apache.servicecomb.core.$Impl_Transport have the same order 1", - e.getMessage()); + Assertions.assertTrue(e.getMessage().contains("have the same order")); } } @Test - public void testCheckTransportGroupValid(@Mocked Transport t1, @Mocked Transport t2) { - new Expectations() { - { - t1.getOrder(); - result = 1; - - t2.getOrder(); - result = 2; - } - }; + public void testCheckTransportGroupValid() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getOrder()).thenReturn(1); + Transport t2 = Mockito.mock(Transport.class); + Mockito.when(t2.getOrder()).thenReturn(2); TransportManager manager = new TransportManager(); List group = Arrays.asList(t1, t2); @@ -148,78 +115,56 @@ public void testCheckTransportGroupValid(@Mocked Transport t1, @Mocked Transport try { manager.checkTransportGroup(group); } catch (ServiceCombException e) { - Assert.fail("must not throw exception: " + e.getMessage()); + Assertions.fail("must not throw exception: " + e.getMessage()); } } @Test - public void testChooseOneTransportFirst(@Mocked Transport t1, @Mocked Transport t2) { - new Expectations() { - { - t1.getOrder(); - result = 1; - t1.canInit(); - result = true; - - t2.getOrder(); - result = 2; - } - }; + public void testChooseOneTransportFirst() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getOrder()).thenReturn(1); + Mockito.when(t1.canInit()).thenReturn(true); + Transport t2 = Mockito.mock(Transport.class); + Mockito.when(t2.getOrder()).thenReturn(2); TransportManager manager = new TransportManager(); List group = Arrays.asList(t1, t2); - Assert.assertEquals(t1, manager.chooseOneTransport(group)); + Assertions.assertEquals(t1, manager.chooseOneTransport(group)); } @Test - public void testChooseOneTransportSecond(@Mocked Transport t1, @Mocked Transport t2) { - new Expectations() { - { - t1.getOrder(); - result = Integer.MAX_VALUE; - t1.canInit(); - result = true; - - t2.getOrder(); - result = -1000; - t2.canInit(); - result = false; - } - }; - + public void testChooseOneTransportSecond() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getOrder()).thenReturn(Integer.MAX_VALUE); + Mockito.when(t1.canInit()).thenReturn(true); + Transport t2 = Mockito.mock(Transport.class); + Mockito.when(t2.getOrder()).thenReturn(-1000); + Mockito.when(t2.canInit()).thenReturn(false); TransportManager manager = new TransportManager(); List group = Arrays.asList(t1, t2); - Assert.assertEquals(t1, manager.chooseOneTransport(group)); + Assertions.assertEquals(t1, manager.chooseOneTransport(group)); } @Test - public void testChooseOneTransportNone(@Mocked Transport t1, @Mocked Transport t2) { - new Expectations() { - { - t1.getName(); - result = "t"; - t1.getOrder(); - result = 1; - t1.canInit(); - result = false; - - t2.getOrder(); - result = 2; - t2.canInit(); - result = false; - } - }; + public void testChooseOneTransportNone() { + Transport t1 = Mockito.mock(Transport.class); + Mockito.when(t1.getName()).thenReturn("t"); + Mockito.when(t1.getOrder()).thenReturn(1); + Mockito.when(t1.canInit()).thenReturn(false); + Transport t2 = Mockito.mock(Transport.class); + Mockito.when(t2.getOrder()).thenReturn(2); + Mockito.when(t2.canInit()).thenReturn(false); TransportManager manager = new TransportManager(); List group = Arrays.asList(t1, t2); try { manager.chooseOneTransport(group); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("all transport named t refused to init.", e.getMessage()); + Assertions.assertEquals("all transport named t refused to init.", e.getMessage()); } } } diff --git a/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportVertxFactory.java b/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportVertxFactory.java deleted file mode 100644 index aec2492b2e2..00000000000 --- a/core/src/test/java/org/apache/servicecomb/core/transport/TestTransportVertxFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.core.transport; - -import org.junit.Assert; -import org.junit.Test; - -public class TestTransportVertxFactory { - @Test - public void getTransportVertx() { - TransportVertxFactory vertxFactory = new TransportVertxFactory(); - - Assert.assertNotNull(vertxFactory.getTransportVertx()); - Assert.assertSame(vertxFactory.getTransportVertx(), vertxFactory.getTransportVertx()); - Assert.assertSame(vertxFactory.getTransportVertx(), vertxFactory.getMetricsFactory().getVertxMetrics().getVertx()); - - vertxFactory.getTransportVertx().close(); - } -} diff --git a/core/src/test/resources/META-INF/spring/cse.bean.xml b/core/src/test/resources/META-INF/spring/cse.bean.xml index 1970e3a4abc..a9774182816 100644 --- a/core/src/test/resources/META-INF/spring/cse.bean.xml +++ b/core/src/test/resources/META-INF/spring/cse.bean.xml @@ -19,13 +19,7 @@ - - - - - - - + diff --git a/core/src/test/resources/config/config.cse.inc.xml b/core/src/test/resources/config/config.cse.inc.xml deleted file mode 100644 index 99780f53a00..00000000000 --- a/core/src/test/resources/config/config.cse.inc.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - classpath*:config/cse.properties - - diff --git a/core/src/test/resources/config/cse.handler.xml b/core/src/test/resources/config/cse.handler.xml deleted file mode 100644 index 89510b4db65..00000000000 --- a/core/src/test/resources/config/cse.handler.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/core/src/test/resources/config/cse.properties b/core/src/test/resources/config/cse.properties deleted file mode 100644 index 33a80653d3b..00000000000 --- a/core/src/test/resources/config/cse.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -cse.demo.client.thread=100 -cse.demo.client.transport=highway -cse.demo.client.mode=reactive -cse.handler.chain.Provider.default=test -cse.handler.chain.Consumer.default=test -cse.handler.chain.Provider.service.test=test -cse.handler.chain.Consumer.service.test=test diff --git a/core/src/test/resources/config/log4j.demo.properties b/core/src/test/resources/config/log4j.demo.properties deleted file mode 100644 index fe3ad5a2591..00000000000 --- a/core/src/test/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=../logs/ -paas.logs.file=cse.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/core/src/test/resources/log4j.properties b/core/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/core/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/core/src/test/resources/log4j2.xml b/core/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/core/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/core/src/test/resources/microservice.yaml b/core/src/test/resources/microservice.yaml index a49e8e39917..b17313cd44c 100644 --- a/core/src/test/resources/microservice.yaml +++ b/core/src/test/resources/microservice.yaml @@ -23,19 +23,11 @@ servicecomb: service: registry: address: http://127.0.0.1:30100 - rest: - client: - thread-count: 10 - connection-pool-per-thread: 1 - server: - thread-count: 10 - highway: - thread-count: 1 - connection-pool-per-thread: 10 handler: chain: Consumer: default: simpleLB - metrics: - cycle: - ms: 1000 +zq: + - tlist: a + - tlist: b + - tlist: 1 diff --git a/core/src/test/resources/test/test/microservice.yaml b/core/src/test/resources/test/test/microservice.yaml index a82dcd3f036..7ec47b07b63 100644 --- a/core/src/test/resources/test/test/microservice.yaml +++ b/core/src/test/resources/test/test/microservice.yaml @@ -18,7 +18,7 @@ service_description: name: default version: 0.0.1 - propertyExtentedClass: org.apache.servicecomb.serviceregistry.MicroServicePropertyExtendedStub + propertyExtendedClass: org.apache.servicecomb.serviceregistry.MicroServicePropertyExtendedStub servicecomb: service: registry: diff --git a/core/src/test/resources/test/test/schema.yaml b/core/src/test/resources/test/test/schema.yaml index b3e6aaa0ba6..1fc4b15f949 100644 --- a/core/src/test/resources/test/test/schema.yaml +++ b/core/src/test/resources/test/test/schema.yaml @@ -37,7 +37,7 @@ paths: schema: $ref: "#/definitions/testintBody" responses: - 200: + "200": description: "response of 200" definitions: testintBody: diff --git a/coverage-reports/pom.xml b/coverage-reports/pom.xml index 341bb06188a..97f795fcbf5 100644 --- a/coverage-reports/pom.xml +++ b/coverage-reports/pom.xml @@ -21,8 +21,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default 4.0.0 @@ -30,45 +30,129 @@ jar + + + + org.apache.servicecomb + config-center-client + + + org.apache.servicecomb + config-clients-common + + + org.apache.servicecomb + config-kie-client + + + org.apache.servicecomb + dashboard-client + + + org.apache.servicecomb + http-client-common + + + org.apache.servicecomb + service-center-client + + + + + org.apache.servicecomb + common-access-log + + + org.apache.servicecomb + common-protobuf + + + org.apache.servicecomb + common-rest + + + + + org.apache.servicecomb + java-chassis-core + + + + + org.apache.servicecomb + config-apollo + + + org.apache.servicecomb + config-cc + + + org.apache.servicecomb + config-kie + + + org.apache.servicecomb + config-nacos + + + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb foundation-common + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-metrics + org.apache.servicecomb foundation-protobuf org.apache.servicecomb - foundation-ssl + foundation-registry org.apache.servicecomb - foundation-config + foundation-spi org.apache.servicecomb - deployment + foundation-ssl org.apache.servicecomb - foundation-vertx + foundation-test-scaffolding org.apache.servicecomb - foundation-metrics + foundation-vertx + + org.apache.servicecomb - metrics-core + servicecomb-governance + + org.apache.servicecomb - java-chassis-core + handler-fault-injection org.apache.servicecomb - handler-bizkeeper + handler-flowcontrol-qps org.apache.servicecomb @@ -80,254 +164,343 @@ org.apache.servicecomb - handler-flowcontrol-qps + handler-router org.apache.servicecomb - handler-fault-injection + handler-tracing-zipkin + + org.apache.servicecomb - common-rest + metrics-core org.apache.servicecomb - transport-rest-client + metrics-prometheus + + org.apache.servicecomb - transport-rest-vertx + provider-jaxrs org.apache.servicecomb - transport-rest-servlet + provider-pojo org.apache.servicecomb - common-protobuf + provider-rest-common org.apache.servicecomb - common-javassist + provider-springmvc + + org.apache.servicecomb - swagger-generator-core + registry-lightweight org.apache.servicecomb - swagger-generator-jaxrs + registry-local org.apache.servicecomb - swagger-generator-springmvc + registry-service-center org.apache.servicecomb - swagger-invocation-core + registry-zero-config + + org.apache.servicecomb - swagger-invocation-jaxrs + solution-basic + + org.apache.servicecomb - swagger-invocation-springmvc + java-chassis-spring-boot-starter-servlet org.apache.servicecomb - service-registry + java-chassis-spring-boot-starter-standalone + + org.apache.servicecomb - provider-pojo + servicestage + org.apache.servicecomb - provider-rest-common + dashboard org.apache.servicecomb - provider-jaxrs + darklaunch + + org.apache.servicecomb - provider-springmvc + swagger-generator-core org.apache.servicecomb - transport-highway + swagger-generator-jaxrs + + + org.apache.servicecomb + swagger-generator-spring-data org.apache.servicecomb - spring-boot-starter-configuration + swagger-generator-springmvc + org.apache.servicecomb - spring-boot-starter-provider + swagger-invocation-core org.apache.servicecomb - spring-boot-starter-transport + swagger-invocation-jaxrs org.apache.servicecomb - spring-boot-starter-discovery + swagger-invocation-springmvc org.apache.servicecomb - spring-boot-starter-registry + swagger-invocation-validator + + org.apache.servicecomb - handler-tracing-zipkin + tracing-common org.apache.servicecomb - config-apollo + tracing-zipkin + + + + + org.apache.servicecomb + transport-common org.apache.servicecomb - config-cc + transport-highway org.apache.servicecomb - edge-core + transport-rest-client + + + org.apache.servicecomb + transport-rest-servlet + + org.apache.servicecomb + transport-rest-vertx + + + + org.apache.servicecomb.demo - pojo-client - 1.2.0-SNAPSHOT + crossapp-client + ${project.version} + test org.apache.servicecomb.demo - pojo-server - 1.2.0-SNAPSHOT + crossapp-server + ${project.version} + test + org.apache.servicecomb.demo - jaxrs-client - 1.2.0-SNAPSHOT + authentication + ${project.version} + test org.apache.servicecomb.demo - jaxrs-server - 1.2.0-SNAPSHOT + business-1-0-0 + ${project.version} + test org.apache.servicecomb.demo - springmvc-client - 1.2.0-SNAPSHOT + business-1-1-0 + ${project.version} + test org.apache.servicecomb.demo - springmvc-server - 1.2.0-SNAPSHOT + business-2-0-0 + ${project.version} + test org.apache.servicecomb.demo - crossapp-client - 1.2.0-SNAPSHOT + consumer + ${project.version} + test org.apache.servicecomb.demo - crossapp-server - 1.2.0-SNAPSHOT + edge-service + ${project.version} + test org.apache.servicecomb.demo - demo-spring-boot-jaxrs-server - 1.2.0-SNAPSHOT + model + ${project.version} + test + org.apache.servicecomb.demo - demo-spring-boot-jaxrs-client - 1.2.0-SNAPSHOT + jaxrs-client + ${project.version} + test org.apache.servicecomb.demo - demo-spring-boot-pojo-client - 1.2.0-SNAPSHOT + jaxrs-server + ${project.version} + test + org.apache.servicecomb.demo - demo-spring-boot-pojo-server - 1.2.0-SNAPSHOT + demo-local-registry-client + ${project.version} + test + + + org.apache.servicecomb.demo + demo-local-registry-server + ${project.version} + test + org.apache.servicecomb.demo - demo-spring-boot-discovery-server - 1.2.0-SNAPSHOT + demo-multi-registries-client + ${project.version} + test org.apache.servicecomb.demo - demo-spring-boot-discovery-client - 1.2.0-SNAPSHOT + demo-multi-registries-server + ${project.version} + test + org.apache.servicecomb.demo - demo-spring-boot-zuul-proxy - 1.2.0-SNAPSHOT + pojo-client + ${project.version} + test - org.apache.servicecomb.tests - jaxrs-tests - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + pojo-server + ${project.version} + test + - org.apache.servicecomb.tests - pojo-test - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-register-url-prefix-client + ${project.version} + test - org.apache.servicecomb.tests - spring-jaxrs-tests - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-register-url-prefix-server + ${project.version} + test + - org.apache.servicecomb.tests - spring-pojo-tests - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-schema + ${project.version} + test + + + + + org.apache.servicecomb.demo + demo-spring-boot-pojo-client + ${project.version} + test - org.apache.servicecomb.tests - spring-pojo-connection-limit-test - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-spring-boot-pojo-server + ${project.version} + test - org.apache.servicecomb.tests - spring-zuul-tracing-tests - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-spring-boot-springmvc-client + ${project.version} + test - org.apache.servicecomb.tests - springmvc-tests-general - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-spring-boot-springmvc-server + ${project.version} + test + - org.apache.servicecomb.tests - springmvc-tests-general-with-springboot - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + springmvc-client + ${project.version} + test - org.apache.servicecomb.tests - springmvc-tests-simplified-mapping - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + springmvc-server + ${project.version} + test + - org.apache.servicecomb.tests - springmvc-tests-connection-limit - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-zeroconfig-registry-client + ${project.version} + test - org.apache.servicecomb.tests - springmvc-tests-simplified-mapping-with-springboot - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-zeroconfig-registry-server + ${project.version} + test - org.apache.servicecomb.tests - tracing-tests - 1.2.0-SNAPSHOT + org.apache.servicecomb.demo + demo-zeroconfig-registry-tests + ${project.version} + test diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 00000000000..18153ce7a57 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,9 @@ +This module contains integrated test cases. Running these test cases, should include profile + +```shell script +-Pdocker +``` + +[java-chassis-samples][java-chassis-samples] project provides a lot of samples. + +[java-chassis-samples]: https://github.com/apache/servicecomb-samples/tree/master/java-chassis-samples diff --git a/demo/assembly/assembly.xml b/demo/assembly/assembly.xml index 4423c961a3a..2683395b554 100644 --- a/demo/assembly/assembly.xml +++ b/demo/assembly/assembly.xml @@ -25,20 +25,22 @@ dir false - - - / - false + + + + /maven + ${project.build.directory} + + **/*.jar + + + + /maven + ${project.build.directory}/classes - ${artifact} + certificates/* - - - /lib - false - - ${artifact} - - - + + + diff --git a/demo/demo-consul/README.md b/demo/demo-consul/README.md new file mode 100644 index 00000000000..872a1d2e93a --- /dev/null +++ b/demo/demo-consul/README.md @@ -0,0 +1,5 @@ +# Notice + +This integration tests is designed for Consul registry and configuration. And extra test cases include: + +* Test cases related to SpringMVC annotations that demo-springmvc can not cover. diff --git a/demo/demo-consul/consumer/pom.xml b/demo/demo-consul/consumer/pom.xml new file mode 100644 index 00000000000..eccc75e41b1 --- /dev/null +++ b/demo/demo-consul/consumer/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-consul + 3.4.0-SNAPSHOT + + + consul-consumer + Java Chassis::Demo::Consul::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-consul + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java new file mode 100644 index 00000000000..f71738a9ed6 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; +import io.vertx.core.http.WebSocket; + +@RestSchema(schemaId = "ClientWebsocketController") +@RequestMapping(path = "/ws") +public class ClientWebsocketController { + interface ProviderService { + WebSocket websocket(); + } + + @RpcReference(schemaId = "WebsocketController", microserviceName = "provider") + private ProviderService providerService; + + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + WebSocket providerWebSocket = providerService.websocket(); + providerWebSocket.closeHandler(v -> serverWebsocket.close()); + providerWebSocket.textMessageHandler(m -> { + serverWebsocket.writeTextMessage(m); + }); + serverWebsocket.textMessageHandler(m -> { + providerWebSocket.writeTextMessage(m); + }); + } +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsulConsumerApplication.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsulConsumerApplication.java new file mode 100644 index 00000000000..da243836198 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsulConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsulConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsulConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..e66fb2cb3d0 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return providerService.getConfig(key); + } + + @PostMapping(path = "/testContentType", consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public User testContentType(@RequestBody User user) { + return providerService.testContentType(user); + } +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java new file mode 100644 index 00000000000..f0e894d6745 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "ConsumerHeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class ConsumerHeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @RpcReference(microserviceName = "provider", schemaId = "HeaderParamWithListSchema") + private IHeaderParamWithListSchemaSpringMvc provider; + + @Override + public String headerListDefault(List headerList) { + return provider.headerListDefault(headerList); + } + + @Override + public String headerListCSV(List headerList) { + return provider.headerListCSV(headerList); + } + + @Override + public String headerListMULTI(List headerList) { + return provider.headerListMULTI(headerList); + } + + @Override + public String headerListSSV(List headerList) { + return provider.headerListSSV(headerList); + } + + @Override + public String headerListPIPES(List headerList) { + return provider.headerListPIPES(headerList); + } +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java new file mode 100644 index 00000000000..aa169801cf7 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +public class ConsumerReactiveStreamController { + interface ProviderReactiveStreamController { + Publisher sseString(); + + Publisher sseModel(); + } + + @RpcReference(microserviceName = "provider", schemaId = "ReactiveStreamController") + ProviderReactiveStreamController controller; + + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseString() { + return controller.sseString(); + } + + @GetMapping("/sseModel") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseModel() { + return controller.sseModel(); + } +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..2899546c752 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); + + String getConfig(String key); + + User testContentType(User user); +} diff --git a/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ff421930ef2 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-consul/consumer/src/main/resources/application.yml b/demo/demo-consul/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..ef0d45c1dcb --- /dev/null +++ b/demo/demo-consul/consumer/src/main/resources/application.yml @@ -0,0 +1,40 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: demo-consul + version: 0.0.1 + name: consumer + properties: + group: green + + registry: + consul: + enabled: true + host: 127.0.0.1 + scheme: http + discovery: + enabled: true + acl-token: '' + watch-seconds: 8 + + rest: + address: 0.0.0.0:9092?websocketEnabled=true + server: + websocket-prefix: /ws diff --git a/demo/demo-consul/consumer/src/main/resources/log4j2.xml b/demo/demo-consul/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-consul/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-consul/gateway/pom.xml b/demo/demo-consul/gateway/pom.xml new file mode 100644 index 00000000000..1dad3860e7f --- /dev/null +++ b/demo/demo-consul/gateway/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-consul + 3.4.0-SNAPSHOT + + + consul-gateway + Java Chassis::Demo::Consul::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb + registry-consul + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-consul/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-consul/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-consul/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-consul/gateway/src/main/resources/application.yml b/demo/demo-consul/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..9855a87a1de --- /dev/null +++ b/demo/demo-consul/gateway/src/main/resources/application.yml @@ -0,0 +1,60 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: demo-consul + version: 0.0.1 + name: gateway + + registry: + consul: + enabled: true + host: 127.0.0.1 + scheme: http + discovery: + enabled: true + acl-token: '' + watch-seconds: 8 + + rest: + address: 0.0.0.0:9090?websocketEnabled=true + server: + websocket-prefix: /ws + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ + websocket: + mappings: + consumer: + prefixSegmentCount: 0 + path: "/ws/.*" + microserviceName: consumer + versionRule: 0.0.0+ diff --git a/demo/demo-consul/gateway/src/main/resources/log4j2.xml b/demo/demo-consul/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-consul/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-consul/pom.xml b/demo/demo-consul/pom.xml new file mode 100644 index 00000000000..aaa8f3b91ce --- /dev/null +++ b/demo/demo-consul/pom.xml @@ -0,0 +1,62 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + + demo-consul + Java Chassis::Demo::Consul + pom + + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + solution-basic + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + + + provider + consumer + gateway + test-client + + diff --git a/demo/demo-consul/provider/pom.xml b/demo/demo-consul/provider/pom.xml new file mode 100644 index 00000000000..0986f9f4342 --- /dev/null +++ b/demo/demo-consul/provider/pom.xml @@ -0,0 +1,114 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-consul + 3.4.0-SNAPSHOT + + + consul-provider + Java Chassis::Demo::Consul::PROVIDER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-consul + + + org.apache.servicecomb + config-consul + + + + io.reactivex.rxjava3 + rxjava + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ConsulProviderApplication.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ConsulProviderApplication.java new file mode 100644 index 00000000000..b84da167943 --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ConsulProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsulProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsulProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java new file mode 100644 index 00000000000..8a773f91c72 --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "HeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class HeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @Override + public String headerListDefault(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListCSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListMULTI(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListSSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListPIPES(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } +} diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..677c20ed106 --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController implements InitializingBean { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { +// return "Hello " + environment.getProperty("servicecomb.rest.address"); + return "Hello " + name; + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @PostMapping(path = "/testContentType", consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public User testContentType(@RequestBody User user) { + return user; + } + + @Override + public void afterPropertiesSet() throws Exception { + } +} diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java new file mode 100644 index 00000000000..8108d15fd46 --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.reactivex.rxjava3.core.Flowable; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +@Transport(name = CoreConst.RESTFUL) +public class ReactiveStreamController { + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + public Publisher sseString() { + return Flowable.fromArray("a", "b", "c"); + } + + @GetMapping("/sseModel") + public Publisher sseModel() { + return Flowable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS) + .map(item -> new Model("jack", item.intValue())); + } +} diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ca12402d672 --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java new file mode 100644 index 00000000000..6381ef1d54c --- /dev/null +++ b/demo/demo-consul/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; + +@RestSchema(schemaId = "WebsocketController") +@RequestMapping(path = "/ws") +public class WebsocketController { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + AtomicInteger receiveCount = new AtomicInteger(0); + CountDownLatch startSend = new CountDownLatch(1); + serverWebsocket.textMessageHandler(s -> { + if ("start".equals(s)) { + startSend.countDown(); + serverWebsocket.writeTextMessage("started"); + return; + } + receiveCount.getAndIncrement(); + }); + serverWebsocket.closeHandler((v) -> System.out.println("closed")); + + new Thread(() -> { + try { + startSend.await(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + serverWebsocket.writeTextMessage("hello"); + + for (int i = 0; i < 5; i++) { + serverWebsocket.writeTextMessage("hello " + i); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + serverWebsocket.writeTextMessage("total " + receiveCount.get()); + serverWebsocket.close(); + }).start(); + } +} diff --git a/demo/demo-consul/provider/src/main/resources/application.yml b/demo/demo-consul/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..31bbfa5d4c7 --- /dev/null +++ b/demo/demo-consul/provider/src/main/resources/application.yml @@ -0,0 +1,67 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# spring boot configurations +servicecomb: + service: + application: demo-consul + version: 0.0.1 + name: provider + properties: + group: green + + registry: + consul: + enabled: true + host: 127.0.0.1 + scheme: http + discovery: + enabled: true + acl-token: '' + watch-seconds: 8 + + config: + consul: + enabled: true + host: 127.0.0.1 + scheme: http + acl-token: '' + watch-seconds: 8 + + rest: + address: 0.0.0.0:9094?websocketEnabled=true + server: + websocket-prefix: /ws + + cors: + enabled: true + origin: "*" + allowCredentials: false + allowedMethod: "*" + maxAge: 3600 + + +key1: 1 +key2: 3 +key3: 5 + +test1: env +test2: applition +test3: service +test4: version +test5: tag diff --git a/demo/demo-consul/provider/src/main/resources/log4j2.xml b/demo/demo-consul/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-consul/provider/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-consul/test-client/pom.xml b/demo/demo-consul/test-client/pom.xml new file mode 100644 index 00000000000..791ac474886 --- /dev/null +++ b/demo/demo-consul/test-client/pom.xml @@ -0,0 +1,220 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-consul + 3.4.0-SNAPSHOT + + + consul-test-client + Java Chassis::Demo::Consul::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-local + + + org.kiwiproject + consul-client + + + com.google.code.gson + gson + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + hashicorp/consul:1.21 + consul + + alias + + consulServer + + + 8500 + + + + + + 8500:8500 + + + yes + + + + + consul-provider:${project.version} + consul-provider + + alias + + + -Dservicecomb.registry.consul.enabled=true + -Dservicecomb.registry.consul.scheme=http + -Dservicecomb.registry.consul.host=consul + -Dservicecomb.registry.consul.port=8500 + -Dservicecomb.config.consul.enabled=true + -Dservicecomb.config.consul.scheme=http + -Dservicecomb.config.consul.host=consul + -Dservicecomb.config.consul.port=8500 + + /maven/maven/consul-provider-${project.version}.jar + + + consul:consul + + + ServiceComb is ready + + + 9094 + + + + + + 9094:9094 + + + + + consul-consumer:${project.version} + consul-consumer + + alias + + + -Dservicecomb.registry.consul.enabled=true + -Dservicecomb.registry.consul.scheme=http + -Dservicecomb.registry.consul.host=consul + -Dservicecomb.registry.consul.port=8500 + + /maven/maven/consul-consumer-${project.version}.jar + + + consul:consul + + + ServiceComb is ready + + + 9092 + + + + + + 9092:9092 + + + + + consul-gateway:${project.version} + consul-gateway + + alias + + + -Dservicecomb.registry.consul.enabled=true + -Dservicecomb.registry.consul.scheme=http + -Dservicecomb.registry.consul.host=consul + -Dservicecomb.registry.consul.port=8500 + + /maven/maven/consul-gateway-${project.version}.jar + + + consul:consul + + + ServiceComb is ready + + + 9090 + + + + + + 9090:9090 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ConsulConfigIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ConsulConfigIT.java new file mode 100644 index 00000000000..1a7be4b874d --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ConsulConfigIT.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import com.google.common.net.HostAndPort; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.ConditionWaiter.SleepUtil; +import org.kiwiproject.consul.Consul; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import java.util.concurrent.TimeUnit; + +@Component +public class ConsulConfigIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulConfigIT.class); + + @Override + public void testRestTransport() throws Exception { + + testEnvironment(); + testApplication(); + testService(); + testVersion(); + testTag(); + testOverride(); + } + + private void testOverride() { + + putValue("/servicecomb/config/environment/production/application2.properties", + "testValue=t1"); + putValue("/servicecomb/config/application/production/demo-consul/application2.properties", + "testValue=t2"); + testGetConfig("testValue", "t2"); + putValue("/servicecomb/config/service/production/demo-consul/provider/application2.properties", + "testValue=t3"); + testGetConfig("testValue", "t3"); + putValue("/servicecomb/config/version/production/demo-consul/provider/0.0.1/application2.properties", + "testValue=t4"); + testGetConfig("testValue", "t4"); + putValue("/servicecomb/config/tag/production/demo-consul/provider/0.0.1/tag1/application2.properties", + "testValue=t5"); + testGetConfig("testValue", "t5"); + } + + private void testEnvironment() { + + putValue("/servicecomb/config/environment/production/application.properties", + "test1=env"); + putValue("/servicecomb/config/environment/production/application.properties", + "test1=env1"); + + testGetConfig("test1", "env1"); + } + + + private void testApplication() { + + putValue("/servicecomb/config/application/production/demo-consul/application.properties", + "test2=applition"); + putValue("/servicecomb/config/application/production/demo-consul/application.properties", + "test2=applition2"); + testGetConfig("test2", "applition2"); + } + + private void testService() { + + putValue("/servicecomb/config/service/production/demo-consul/provider/application.properties", + "test3=service"); + putValue("/servicecomb/config/service/production/demo-consul/provider/application.properties", + "test3=service3"); + testGetConfig("test3", "service3"); + } + + private void testVersion() { + + putValue("/servicecomb/config/version/production/demo-consul/provider/0.0.1/application.properties", + "test3=version"); + putValue("/servicecomb/config/version/production/demo-consul/provider/0.0.1/application.properties", + "test4=version4"); + testGetConfig("test4", "version4"); + } + + private void testTag() { + + putValue("/servicecomb/config/tag/production/demo-consul/provider/0.0.1/tag1/application.properties", + "test5=tag"); + putValue("/servicecomb/config/tag/production/demo-consul/provider/0.0.1/tag1/application.properties", + "test5=tag5"); + testGetConfig("test5", "tag5"); + } + + public void putValue(String key, String value) { + try { + Consul.Builder builder = Consul.builder().withHostAndPort(HostAndPort.fromParts("127.0.0.1", 8500)); + Consul consulClient = builder.build(); + consulClient.keyValueClient().putValue(key, value); + LOGGER.info("Value set successfully:{}", value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void testGetConfig(String key, String expectValue) { + + String result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=" + key, String.class); + + for (int i = 0; i < 4; i++) { + if (StringUtils.equals(expectValue, result)) { + TestMgr.check(expectValue, result); + break; + } + SleepUtil.sleep(500, TimeUnit.MILLISECONDS); + } + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java new file mode 100644 index 00000000000..1b129acc2c6 --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HeaderParamWithListSchemaIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHeaderListDefault(); + testHeaderListMulti(); + testHeaderListCSV(); + testHeaderListSSV(); + testHeaderListPipes(); + } + + // default to multi + private void testHeaderListDefault() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListDefault", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListPipes() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a|b|c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListPIPES", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListSSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a b c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListSSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListCSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a,b,c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + + headers.add("headerList", "a, b, c"); + entity = new HttpEntity<>(headers); + result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListMulti() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListMULTI", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..97e883fb45f --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorld(); + testGetConfig(); + } + + private void testGetConfig() { + String result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key1", String.class); + TestMgr.check("1", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key2", String.class); + TestMgr.check("3", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key3", String.class); + TestMgr.check("5", result); + } + + private void testHelloWorld() { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + TestMgr.check("Hello World", result); + + // test trace id added + MultiValueMap headers = new HttpHeaders(); + headers.add("X-B3-TraceId", "81de2eb7691c2bbb"); + HttpEntity entity = new HttpEntity(headers); + ResponseEntity response = + template.exchange(Config.GATEWAY_URL + "/sayHello?name=World", HttpMethod.GET, entity, String.class); + TestMgr.check(1, response.getHeaders().get("X-B3-TraceId").size()); + TestMgr.check("81de2eb7691c2bbb", response.getHeaders().getFirst("X-B3-TraceId")); + TestMgr.check("Hello World", response.getBody()); + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java new file mode 100644 index 00000000000..2bdd0ca42ca --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class ProviderIT implements CategorizedTestCase { + + RestOperations template = new RestTemplate(); + + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderIT.class); + + @Override + public void testRestTransport() throws Exception { + + User user = getUser("Application/json"); + TestMgr.check(1L, user.getId()); + TestMgr.check("czd", user.getName()); + + User user2 = getUser("application/json"); + TestMgr.check(1L, user2.getId()); + TestMgr.check("czd", user2.getName()); + + User user3 = getUser("APPLICATION/JSON"); + TestMgr.check(1L, user3.getId()); + TestMgr.check("czd", user3.getName()); + } + + private User getUser(String contentType) throws IOException { + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", contentType); + + String requestBody = """ + { + "id": 1, + "name": "czd" + } + """; + + HttpEntity entity = new HttpEntity<>(requestBody, headers); + + String url = Config.GATEWAY_URL + "/testContentType"; + ResponseEntity response = template.exchange( + url, HttpMethod.POST, entity, String.class); + + User user = JsonUtils.readValue(response.getBody().getBytes(StandardCharsets.UTF_8), User.class); + return user; + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java new file mode 100644 index 00000000000..488a6cf712a --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient.Model; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +public class ReactiveStreamIT implements CategorizedTestCase { + @Autowired + @Qualifier("reactiveStreamProvider") + ReactiveStreamClient reactiveStreamProvider; + + @Autowired + @Qualifier("reactiveStreamGateway") + ReactiveStreamClient reactiveStreamGateway; + + @Override + public void testRestTransport() throws Exception { + testSseString(reactiveStreamProvider); + testSseModel(reactiveStreamProvider); + testSseString(reactiveStreamGateway); + testSseModel(reactiveStreamGateway); + } + + private void testSseModel(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseModel(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(Model s) { + buffer.append(s.getName()).append(s.getAge()); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("jack0jack1jack2jack3jack4", buffer.toString()); + } + + private void testSseString(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseString(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(String s) { + buffer.append(s); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("abc", buffer.toString()); + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..26a2a491bbe --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java new file mode 100644 index 00000000000..abe96a4f10b --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.apache.servicecomb.provider.pojo.Invoker; +import org.reactivestreams.Publisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.WebSocket; + +@Configuration +public class ThirdSvcConfiguration { + @RequestMapping(path = "/ws") + public interface WebsocketClient { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + WebSocket websocket(); + } + + @RequestMapping(path = "/") + public interface ReactiveStreamClient { + class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + Publisher sseString(); + + @GetMapping("/sseModel") + Publisher sseModel(); + } + + @Bean + public RegistryBean providerServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .setAppId("demo-consul") + .setServiceName("provider") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9094"))))); + } + + @Bean + public RegistryBean gatewayServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .addSchemaInterface("WebsocketController", WebsocketClient.class) + .setAppId("demo-consul") + .setServiceName("gateway") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9090?websocketEnabled=true"))))); + } + + @Bean("reactiveStreamProvider") + public ReactiveStreamClient reactiveStreamProvider() { + return Invoker.createProxy("provider", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean("reactiveStreamGateway") + public ReactiveStreamClient reactiveStreamGateway() { + return Invoker.createProxy("gateway", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean + public WebsocketClient gatewayWebsocketClient() { + return Invoker.createProxy("gateway", "WebsocketController", WebsocketClient.class); + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ff421930ef2 --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java new file mode 100644 index 00000000000..c36f2d16d28 --- /dev/null +++ b/demo/demo-consul/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.WebsocketClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import io.vertx.core.http.WebSocket; + +@Component +public class WebsocketIT implements CategorizedTestCase { + @Autowired + private WebsocketClient websocketClient; + + @Override + public void testRestTransport() throws Exception { + StringBuffer sb = new StringBuffer(); + AtomicBoolean closed = new AtomicBoolean(false); + CountDownLatch latchStarted = new CountDownLatch(1); + CountDownLatch latch = new CountDownLatch(1); + + WebSocket webSocket = websocketClient.websocket(); + webSocket.textMessageHandler(s -> { + if ("started".equals(s)) { + latchStarted.countDown(); + return; + } + sb.append(s); + sb.append(" "); + webSocket.writeTextMessage(s); + }); + webSocket.closeHandler(v -> { + closed.set(true); + latch.countDown(); + }); + + webSocket.writeTextMessage("start"); + int i = 0; + for (; i < 10; i++) { + if (!latchStarted.await(3, TimeUnit.SECONDS)) { + webSocket.writeTextMessage("start"); + continue; + } + break; + } + TestMgr.check(i < 10, true); + latch.await(30, TimeUnit.SECONDS); + TestMgr.check(sb.toString(), "hello hello 0 hello 1 hello 2 hello 3 hello 4 total 6 "); + TestMgr.check(closed.get(), true); + } +} diff --git a/demo/demo-consul/test-client/src/main/resources/application.yml b/demo/demo-consul/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..718fbd9cc84 --- /dev/null +++ b/demo/demo-consul/test-client/src/main/resources/application.yml @@ -0,0 +1,40 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: demo-consul + name: test-client + version: 0.0.1 + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container + + config: + consul: + enabled: true + host: 127.0.0.1 + scheme: http + acl-token: '' + instance-tag: tag1 + +test1: env +test2: applition +test3: service +test4: version +test5: tag diff --git a/demo/demo-consul/test-client/src/main/resources/log4j2.xml b/demo/demo-consul/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-consul/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-consul/test-client/src/test/java/org/apache/servicecomb/samples/ConsulIT.java b/demo/demo-consul/test-client/src/test/java/org/apache/servicecomb/samples/ConsulIT.java new file mode 100644 index 00000000000..62862743e27 --- /dev/null +++ b/demo/demo-consul/test-client/src/test/java/org/apache/servicecomb/samples/ConsulIT.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = TestClientApplication.class) +public class ConsulIT { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulIT.class); + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() { + try { + TestClientApplication.run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-crossapp/crossapp-client/pom.xml b/demo/demo-crossapp/crossapp-client/pom.xml index e1395920cd9..fa2e051cd0f 100644 --- a/demo/demo-crossapp/crossapp-client/pom.xml +++ b/demo/demo-crossapp/crossapp-client/pom.xml @@ -23,59 +23,102 @@ org.apache.servicecomb.demo demo-crossapp - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT crossapp-client Java Chassis::Demo::CrossApp::Client - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-springmvc - org.apache.servicecomb.demo.crossapp.CrossappClient - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - 1.2.0-SNAPSHOT - - - - - - docker crossapp-server - -Dcse.rest.address=0.0.0.0:8080 + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + io.fabric8 diff --git a/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java b/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java index 9df1546f750..7d78648963a 100644 --- a/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java +++ b/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java @@ -22,64 +22,125 @@ import org.apache.servicecomb.core.provider.consumer.InvokerUtils; import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; import org.apache.servicecomb.provider.pojo.RpcReference; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; -@Component +@SpringBootApplication public class CrossappClient { @RpcReference(microserviceName = "appServer:appService", schemaId = "helloworld") private static HelloWorld helloWorld; public static void main(String[] args) throws Exception { - System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(CrossappClient.class).web(WebApplicationType.NONE).run(args); run(); - - TestMgr.summary(); - System.setProperty("sun.net.http.allowRestrictedHeaders", "false"); } public static void run() { - Object result = InvokerUtils.syncInvoke("appServer:appService", "helloworld", "sayHello", null); + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + + String result = InvokerUtils.syncInvoke("appServer:appService", "helloworld", + "sayHello", null, String.class); TestMgr.check("hello world", result); - RestTemplate restTemplate = RestTemplateBuilder.create(); + RestOperations restTemplate = RestTemplateBuilder.create(); result = restTemplate.getForObject("cse://appServer:appService/helloworld/hello", String.class); TestMgr.check("hello world", result); + result = restTemplate.getForObject("servicecomb://appServer:appService/helloworld/hello", String.class); + TestMgr.check("hello world", result); result = helloWorld.sayHello(); TestMgr.check("hello world", result); - testCorsHandler(); + testCorsHandlerOptions(); + testCorsHandlerGet(); + + TestMgr.summary(); + System.setProperty("sun.net.http.allowRestrictedHeaders", "false"); } - private static void testCorsHandler() { - RestTemplate springRestTemplate = new RestTemplate(); + private static void testCorsHandlerOptions() { + // first domain + RestOperations springRestTemplate = new RestTemplate(); MultiValueMap requestHeaders = new LinkedMultiValueMap<>(); - requestHeaders.put("Origin", Collections.singletonList("http://localhost:8080")); + requestHeaders.put("Origin", Collections.singletonList("http://test.domain:8080")); requestHeaders.put("Access-Control-Request-Method", Collections.singletonList("PUT")); - HttpEntity requestEntity = new HttpEntity<>(requestHeaders); ResponseEntity responseEntity = springRestTemplate .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.OPTIONS, requestEntity, String.class); - - TestMgr.check("200", responseEntity.getStatusCodeValue()); + TestMgr.check("204", responseEntity.getStatusCode().value()); TreeSet sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Methods")); TestMgr.check("[DELETE,POST,GET,PUT]", sortedSet); sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Headers")); TestMgr.check("[abc,def]", sortedSet); - TestMgr.check("*", responseEntity.getHeaders().getFirst("Access-Control-Allow-Origin")); + TestMgr.check("http://test.domain:8080", + responseEntity.getHeaders().getFirst("Access-Control-Allow-Origin")); + + // second domain + requestHeaders = new LinkedMultiValueMap<>(); + requestHeaders.put("Origin", Collections.singletonList("http://test.domain:9090")); + requestHeaders.put("Access-Control-Request-Method", Collections.singletonList("PUT")); + requestEntity = new HttpEntity<>(requestHeaders); + responseEntity = springRestTemplate + .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.OPTIONS, requestEntity, + String.class); + TestMgr.check("204", responseEntity.getStatusCode().value()); + sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Methods")); + TestMgr.check("[DELETE,POST,GET,PUT]", sortedSet); + sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Headers")); + TestMgr.check("[abc,def]", sortedSet); + TestMgr.check("http://test.domain:9090", + responseEntity.getHeaders().getFirst("Access-Control-Allow-Origin")); + } + + private static void testCorsHandlerGet() { + // allowed origin + RestOperations springRestTemplate = new RestTemplate(); + MultiValueMap requestHeaders = new LinkedMultiValueMap<>(); + requestHeaders.put("Origin", Collections.singletonList("http://test.domain:8080")); + HttpEntity requestEntity = new HttpEntity<>(requestHeaders); + ResponseEntity responseEntity = springRestTemplate + .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.GET, requestEntity, + String.class); + + TestMgr.check("200", responseEntity.getStatusCode().value()); + TestMgr.check("hello world", responseEntity.getBody()); + + // allowed origin + requestHeaders = new LinkedMultiValueMap<>(); + requestHeaders.put("Origin", Collections.singletonList("http://test.domain:9090")); + requestEntity = new HttpEntity<>(requestHeaders); + responseEntity = springRestTemplate + .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.GET, requestEntity, + String.class); + + TestMgr.check("200", responseEntity.getStatusCode().value()); + TestMgr.check("hello world", responseEntity.getBody()); + + // not allowed origin + try { + requestHeaders = new LinkedMultiValueMap<>(); + requestHeaders.put("Origin", Collections.singletonList("http://test.domain:7070")); + requestEntity = new HttpEntity<>(requestHeaders); + springRestTemplate + .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.GET, requestEntity, + String.class); + TestMgr.fail("must throw"); + } catch (HttpServerErrorException e) { + TestMgr.check(500, e.getStatusCode().value()); + TestMgr.check(true, e.getMessage().contains("500 CORS Rejected")); + } } } diff --git a/demo/demo-crossapp/crossapp-client/src/main/resources/log4j2.xml b/demo/demo-crossapp/crossapp-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-crossapp/crossapp-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-crossapp/crossapp-client/src/main/resources/microservice.yaml b/demo/demo-crossapp/crossapp-client/src/main/resources/microservice.yaml index 4590f8f8791..1728b196574 100644 --- a/demo/demo-crossapp/crossapp-client/src/main/resources/microservice.yaml +++ b/demo/demo-crossapp/crossapp-client/src/main/resources/microservice.yaml @@ -14,14 +14,13 @@ ## See the License for the specific language governing permissions and ## limitations under the License. ## --------------------------------------------------------------------------- - -APPLICATION_ID: appClient -service_description: - name: appClientService - version: 0.0.1 servicecomb: service: - registry: + application: appClient + name: appClientService + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 handler: chain: diff --git a/demo/demo-crossapp/crossapp-client/src/main/resources/schemas/helloworld.yaml b/demo/demo-crossapp/crossapp-client/src/main/resources/schemas/helloworld.yaml deleted file mode 100644 index a00b21c765f..00000000000 --- a/demo/demo-crossapp/crossapp-client/src/main/resources/schemas/helloworld.yaml +++ /dev/null @@ -1,36 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello service - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.crossapp.HelloWorld - -basePath: /helloworld -produces: - - application/json - -paths: - /hello: - get: - operationId: sayHello - responses: - 200: - description: say hello - schema: - type: string diff --git a/demo/demo-crossapp/crossapp-client/src/test/java/org/apache/servicecomb/demo/crossapp/CrossAppIT.java b/demo/demo-crossapp/crossapp-client/src/test/java/org/apache/servicecomb/demo/crossapp/CrossAppIT.java index 71c7af1d324..54b02c90ae9 100644 --- a/demo/demo-crossapp/crossapp-client/src/test/java/org/apache/servicecomb/demo/crossapp/CrossAppIT.java +++ b/demo/demo-crossapp/crossapp-client/src/test/java/org/apache/servicecomb/demo/crossapp/CrossAppIT.java @@ -17,24 +17,27 @@ package org.apache.servicecomb.demo.crossapp; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - import org.apache.servicecomb.demo.TestMgr; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = CrossappClient.class) public class CrossAppIT { - @Before + @BeforeEach public void setUp() throws Exception { TestMgr.errors().clear(); } @Test public void clientGetsNoError() throws Exception { - CrossappClient.main(new String[0]); + CrossappClient.run(); - assertThat(TestMgr.errors().isEmpty(), is(true)); + Assertions.assertTrue(TestMgr.errors().isEmpty()); } } diff --git a/demo/demo-crossapp/crossapp-server/pom.xml b/demo/demo-crossapp/crossapp-server/pom.xml index f557583ea4e..0207bdb7b20 100644 --- a/demo/demo-crossapp/crossapp-server/pom.xml +++ b/demo/demo-crossapp/crossapp-server/pom.xml @@ -23,20 +23,12 @@ org.apache.servicecomb.demo demo-crossapp - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT crossapp-server Java Chassis::Demo::CrossApp::Server - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-pojo - @@ -45,21 +37,8 @@ - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - 1.2.0-SNAPSHOT - - - + org.springframework.boot + spring-boot-maven-plugin @@ -68,15 +47,50 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappBootListener.java b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappBootListener.java deleted file mode 100644 index 8c8aa82f880..00000000000 --- a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappBootListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.crossapp; - -import org.apache.servicecomb.core.BootListener; -import org.springframework.stereotype.Component; - -@Component -public class CrossappBootListener implements BootListener { - @SuppressWarnings("deprecation") - @Override - public void onBootEvent(BootEvent event) { - if (EventType.BEFORE_PRODUCER_PROVIDER.equals(event.getEventType())) { - // 动态注册schemas目录下面的契约到当前服务 - org.apache.servicecomb.core.definition.loader.DynamicSchemaLoader.INSTANCE - .registerSchemas("classpath*:schemas/*.yaml"); - } - } -} diff --git a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappServer.java b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappServer.java index d64cdf569f3..63678f2e9d6 100644 --- a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappServer.java +++ b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappServer.java @@ -17,13 +17,13 @@ package org.apache.servicecomb.demo.crossapp; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class CrossappServer { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(CrossappServer.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorld.java b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorld.java deleted file mode 100644 index 14347cb3846..00000000000 --- a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorld.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.crossapp; - -public interface HelloWorld { - String sayHello(); -} diff --git a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorldImpl.java b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorldImpl.java index aedfb70c77f..b8ede3eba7e 100644 --- a/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorldImpl.java +++ b/demo/demo-crossapp/crossapp-server/src/main/java/org/apache/servicecomb/demo/crossapp/HelloWorldImpl.java @@ -17,12 +17,16 @@ package org.apache.servicecomb.demo.crossapp; -import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.apache.servicecomb.provider.rest.common.RestSchema; -@RpcSchema(schemaId = "helloworld") -public class HelloWorldImpl implements HelloWorld { +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; - @Override +@RestSchema(schemaId = "helloworld") +@Path("helloworld") +public class HelloWorldImpl { + @GET + @Path("hello") public String sayHello() { return "hello world"; } diff --git a/demo/demo-crossapp/crossapp-server/src/main/resources/log4j2.xml b/demo/demo-crossapp/crossapp-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-crossapp/crossapp-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml b/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml index bd0158a17ed..0f1bbdc8853 100644 --- a/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml +++ b/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml @@ -15,25 +15,22 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: appServer -service_description: - name: appService - version: 0.0.1 - properties: - allowCrossApp: true -instance_description: - properties: - tag0: value0 - servicecomb: service: - registry: + application: appServer + name: appService + version: 0.0.1 + properties: + allowCrossApp: true + tag0: value0 + registry: + sc: address: http://127.0.0.1:30100 rest: - address: 127.0.0.1:8080 + address: 0.0.0.0:8080 cors: enabled: true - origin: "*" + origin: "http://test.domain:8080,http://test.domain:9090" allowedHeader: abc,def allowedMethod: GET,PUT,POST,DELETE exposedHeader: abc,def diff --git a/demo/demo-crossapp/crossapp-server/src/main/resources/schemas/helloworld.yaml b/demo/demo-crossapp/crossapp-server/src/main/resources/schemas/helloworld.yaml deleted file mode 100644 index a00b21c765f..00000000000 --- a/demo/demo-crossapp/crossapp-server/src/main/resources/schemas/helloworld.yaml +++ /dev/null @@ -1,36 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello service - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.crossapp.HelloWorld - -basePath: /helloworld -produces: - - application/json - -paths: - /hello: - get: - operationId: sayHello - responses: - 200: - description: say hello - schema: - type: string diff --git a/demo/demo-crossapp/pom.xml b/demo/demo-crossapp/pom.xml index acb407ac710..08c2055d357 100644 --- a/demo/demo-crossapp/pom.xml +++ b/demo/demo-crossapp/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-crossapp Java Chassis::Demo::CrossApp @@ -33,4 +33,30 @@ crossapp-client + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + diff --git a/demo/demo-cse-v1/README.md b/demo/demo-cse-v1/README.md new file mode 100644 index 00000000000..965592efcf8 --- /dev/null +++ b/demo/demo-cse-v1/README.md @@ -0,0 +1,22 @@ +# 使用微服务引擎专业版的测试用例 + +* 首先登陆华为云华南区,获取 AK/SK。 测试机器设置环境变量: CREDENTIALS_AK、CREDENTIALS_SK。 +* 在配置中心增加如下配置: + * consumer.yaml + +```yaml +cse: + v1: + test: + foo: foo + dynamicString: a,b + dynamicArray: + - m + - n +``` + +* 依次启动 provider、provider-canary、consumer、gateway +* 在配置中心增加如下配置: + * cse.v1.test.bar: bar + +* 执行 tests-client 里面的集成测试用例 diff --git a/demo/demo-cse-v1/consumer/pom.xml b/demo/demo-cse-v1/consumer/pom.xml new file mode 100644 index 00000000000..78a7bf75a23 --- /dev/null +++ b/demo/demo-cse-v1/consumer/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v1 + 3.4.0-SNAPSHOT + + + cse-v1-consumer + Java Chassis::Demo::CSE-V1::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java new file mode 100644 index 00000000000..3e7a2a0e285 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java new file mode 100644 index 00000000000..f86c5a29492 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerConfigController") +@RequestMapping(path = "/") +public class ConsumerConfigController { + private Environment environment; + + private ConsumerConfigurationProperties consumerConfigurationProperties; + + @Autowired + public ConsumerConfigController(Environment environment, + ConsumerConfigurationProperties consumerConfigurationProperties) { + this.environment = environment; + this.consumerConfigurationProperties = consumerConfigurationProperties; + } + + @GetMapping("/config") + public String config(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @GetMapping("/foo") + public String foo() { + return consumerConfigurationProperties.getFoo(); + } + + @GetMapping("/bar") + public String bar() { + return consumerConfigurationProperties.getBar(); + } + + @GetMapping("/dynamicString") + public String dynamicString(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @GetMapping("/dynamicArray") + @SuppressWarnings("unchecked") + public List dynamicArray() { + return consumerConfigurationProperties.getDynamicArray(); + } +} diff --git a/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java new file mode 100644 index 00000000000..6f9592425d9 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties("cse.v1.test") +@Component +public class ConsumerConfigurationProperties { + private String foo; + + private String bar; + + private List dynamicArray; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + public String getBar() { + return bar; + } + + public void setBar(String bar) { + this.bar = bar; + } + + public List getDynamicArray() { + return dynamicArray; + } + + public void setDynamicArray(List dynamicArray) { + this.dynamicArray = dynamicArray; + } +} diff --git a/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..dc3ead65da2 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } + + @GetMapping("/sayHelloCanary") + public String sayHelloCanary(@RequestParam("name") String name) { + return providerService.sayHelloCanary(name); + } +} diff --git a/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..176bcee9932 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); + + String sayHelloCanary(String name); +} diff --git a/demo/demo-cse-v1/consumer/src/main/resources/application.yml b/demo/demo-cse-v1/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..11f739de444 --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/resources/application.yml @@ -0,0 +1,137 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v1 + name: consumer + version: 0.0.1 + registry: + sc: + address: https://cse.cn-south-1.myhuaweicloud.com + watch: false + config: + client: + serverUri: https://cse.cn-south-1.myhuaweicloud.com + fileSource: consumer.yaml + + rest: + address: 0.0.0.0:9092 # should be same with server.port to use web container + + routeRule: + provider: | + - precedence: 1 + match: + headers: + canary: + exact: new + route: + - weight: 20 + tags: + version: 0.0.1 + - weight: 80 + tags: + version: 0.0.2 + - precedence: 2 + match: + headers: + canary: + exact: old + route: + - weight: 100 + tags: + version: 0.0.1 + - precedence: 3 + match: + headers: + canary: + exact: fallback + route: + - weight: 100 + tags: + version: 0.0.3 + fallback: + - weight: 20 + tags: + version: 0.0.1 + - weight: 80 + tags: + version: 0.0.2 + - precedence: 4 + emptyProtection: false + match: + headers: + canary: + exact: emptyProtectionClose100 + route: + - weight: 100 + tags: + version: 0.0.3 + - precedence: 5 + emptyProtection: false + match: + headers: + canary: + exact: emptyProtectionCloseLess100 + route: + - weight: 50 + tags: + version: 0.0.3 + - precedence: 6 + emptyProtection: false + match: + headers: + canary: + exact: emptyProtectionCloseFallback + route: + - weight: 100 + tags: + version: 0.0.3 + fallback: + - weight: 100 + tags: + version: 0.0.1 + - precedence: 7 + emptyProtection: false + match: + headers: + canary: + exact: emptyProtectionClose100-2 + route: + - weight: 50 + tags: + version: 0.0.1 + - weight: 50 + tags: + version: 0.0.3 + + + router: + type: router + header: canary + + # Configure AK/SK credentials if needed. Default not enabled. + credentials: + akskEnabled: true + accessKey: ${CREDENTIALS_AK} + secretKey: ${CREDENTIALS_SK} + akskCustomCipher: default + project: cn-south-1 diff --git a/demo/demo-cse-v1/consumer/src/main/resources/log4j2.xml b/demo/demo-cse-v1/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..4e54783856a --- /dev/null +++ b/demo/demo-cse-v1/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./file/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v1/gateway/pom.xml b/demo/demo-cse-v1/gateway/pom.xml new file mode 100644 index 00000000000..49241e669cf --- /dev/null +++ b/demo/demo-cse-v1/gateway/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v1 + 3.4.0-SNAPSHOT + + + cse-v1-gateway + Java Chassis::Demo::CSE-V1::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v1/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-cse-v1/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-cse-v1/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v1/gateway/src/main/resources/application.yml b/demo/demo-cse-v1/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..52f065c4f62 --- /dev/null +++ b/demo/demo-cse-v1/gateway/src/main/resources/application.yml @@ -0,0 +1,70 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# override common configurations in common module +servicecomb-config-order: 100 + +servicecomb: + service: + application: demo-java-chassis-cse-v1 + name: gateway + version: 0.0.1 + registry: + sc: + address: https://cse.cn-south-1.myhuaweicloud.com + watch: false + config: + client: + serverUri: https://cse.cn-south-1.myhuaweicloud.com + + rest: + address: 0.0.0.0:9090?sslEnabled=false + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ + + matchGroup: + canary-header: | + matches: + - headers: + canary: + prefix: "" + mapper: + canary-header: | + target: + canary: $H{canary} + + # Configure AK/SK credentials if needed. Default not enabled. + credentials: + akskEnabled: true + accessKey: ${CREDENTIALS_AK} + secretKey: ${CREDENTIALS_SK} + akskCustomCipher: default + project: cn-south-1 diff --git a/demo/demo-cse-v1/gateway/src/main/resources/log4j2.xml b/demo/demo-cse-v1/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..165cdf7e0a3 --- /dev/null +++ b/demo/demo-cse-v1/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./gateway/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v1/pom.xml b/demo/demo-cse-v1/pom.xml new file mode 100644 index 00000000000..72e70e58c15 --- /dev/null +++ b/demo/demo-cse-v1/pom.xml @@ -0,0 +1,78 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-cse-v1 + Java Chassis::Demo::CSE-V1 + pom + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + dashboard + + + org.apache.servicecomb + darklaunch + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + config-cc + + + org.apache.servicecomb + servicestage + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + + + provider + provider-canary + consumer + gateway + test-client + + + diff --git a/demo/demo-cse-v1/provider-canary/pom.xml b/demo/demo-cse-v1/provider-canary/pom.xml new file mode 100644 index 00000000000..34c393b9e8d --- /dev/null +++ b/demo/demo-cse-v1/provider-canary/pom.xml @@ -0,0 +1,51 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v1 + 3.4.0-SNAPSHOT + + + cse-v1-provider-canary + Java Chassis::Demo::CSE-V1::PROVIDER CANARY + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java b/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java new file mode 100644 index 00000000000..fde6f36b2e3 --- /dev/null +++ b/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..d5b8e1384a9 --- /dev/null +++ b/demo/demo-cse-v1/provider-canary/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController { + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return "Hello in canary " + name; + } + + @GetMapping("/sayHelloCanary") + public String sayHelloCanary(@RequestParam("name") String name) { + return "Hello Canary in canary " + name; + } +} diff --git a/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml new file mode 100644 index 00000000000..29e8e8f3879 --- /dev/null +++ b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml @@ -0,0 +1,43 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v1 + name: provider + version: 0.0.2 + registry: + sc: + address: https://cse.cn-south-1.myhuaweicloud.com + watch: false + config: + client: + serverUri: https://cse.cn-south-1.myhuaweicloud.com + + rest: + address: 0.0.0.0:9095 + +# Configure AK/SK credentials if needed. Default not enabled. + credentials: + akskEnabled: true + accessKey: ${CREDENTIALS_AK} + secretKey: ${CREDENTIALS_SK} + akskCustomCipher: default + project: cn-south-1 diff --git a/demo/demo-cse-v1/provider-canary/src/main/resources/log4j2.xml b/demo/demo-cse-v1/provider-canary/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..9ac74305e0c --- /dev/null +++ b/demo/demo-cse-v1/provider-canary/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./user/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v1/provider/pom.xml b/demo/demo-cse-v1/provider/pom.xml new file mode 100644 index 00000000000..12015bd6b7a --- /dev/null +++ b/demo/demo-cse-v1/provider/pom.xml @@ -0,0 +1,51 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v1 + 3.4.0-SNAPSHOT + + + cse-v1-provider + Java Chassis::Demo::CSE-V1::PROVIDER + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java b/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java new file mode 100644 index 00000000000..fde6f36b2e3 --- /dev/null +++ b/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..9e1c8f96541 --- /dev/null +++ b/demo/demo-cse-v1/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController { + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return "Hello " + name; + } + + @GetMapping("/sayHelloCanary") + public String sayHelloCanary(@RequestParam("name") String name) { + return "Hello Canary " + name; + } +} diff --git a/demo/demo-cse-v1/provider/src/main/resources/application.yml b/demo/demo-cse-v1/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..097e2e9cc85 --- /dev/null +++ b/demo/demo-cse-v1/provider/src/main/resources/application.yml @@ -0,0 +1,43 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v1 + name: provider + version: 0.0.1 + registry: + sc: + address: https://cse.cn-south-1.myhuaweicloud.com + watch: false + config: + client: + serverUri: https://cse.cn-south-1.myhuaweicloud.com + + rest: + address: 0.0.0.0:9093 # should be same with server.port to use web container + +# Configure AK/SK credentials if needed. Default not enabled. + credentials: + akskEnabled: true + accessKey: ${CREDENTIALS_AK} + secretKey: ${CREDENTIALS_SK} + akskCustomCipher: default + project: cn-south-1 diff --git a/demo/demo-cse-v1/provider/src/main/resources/log4j2.xml b/demo/demo-cse-v1/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..9ac74305e0c --- /dev/null +++ b/demo/demo-cse-v1/provider/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./user/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v1/test-client/pom.xml b/demo/demo-cse-v1/test-client/pom.xml new file mode 100644 index 00000000000..697c28fb64e --- /dev/null +++ b/demo/demo-cse-v1/test-client/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v1 + 3.4.0-SNAPSHOT + + + cse-v1-test-client + Java Chassis::Demo::CSE-V1::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java new file mode 100644 index 00000000000..2aff8c25966 --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class ConsumerConfigIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testConfig(); + testFooBar(); + } + + @SuppressWarnings("unchecked") + private void testConfig() { + String result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v1.test.foo", String.class); + TestMgr.check("foo", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v1.test.bar", String.class); + TestMgr.check("bar", result); + result = template.getForObject(Config.GATEWAY_URL + "/dynamicString?key=cse.v1.test.dynamicString", String.class); + TestMgr.check("a,b", result); + + List listResult = template + .getForObject(Config.GATEWAY_URL + "/dynamicArray", List.class); + TestMgr.check(2, listResult.size()); + TestMgr.check("m", listResult.get(0)); + TestMgr.check("n", listResult.get(1)); + } + + private void testFooBar() { + String result = template.getForObject(Config.GATEWAY_URL + "/foo", String.class); + TestMgr.check("foo", result); + result = template.getForObject(Config.GATEWAY_URL + "/bar", String.class); + TestMgr.check("bar", result); + } +} diff --git a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..691ee47a162 --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorldFallback(); + testHelloWorldNoHeader(); + testHelloWorld(); + testHelloWorldCanary(); + testHelloWorldEmptyProtectionCloseWeight100(); + testHelloWorldeEmptyProtectionCloseWeightLess100(); + testHelloWorldEmptyProtectionCloseFallback(); + testHelloWorldEmptyProtectionCloseWeight100Two(); + } + + private void testHelloWorld() { + for (int i = 0; i < 10; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "old"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/sayHello?name=World", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("Hello World", result); + } + } + + private void testHelloWorldCanary() { + int oldCount = 0; + int newCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "new"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, entity, String.class).getBody(); + if (result.equals("Hello Canary World")) { + oldCount++; + } else if (result.equals("Hello Canary in canary World")) { + newCount++; + } else { + TestMgr.fail("not expected result testHelloWorldCanary"); + return; + } + } + + double ratio = oldCount / (float) (oldCount + newCount); + TestMgr.check(ratio > 0.1 && ratio < 0.3, true); + } + + private void testHelloWorldFallback() { + int oldCount = 0; + int newCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "fallback"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, entity, String.class).getBody(); + if (result.equals("\"Hello Canary World\"")) { + oldCount++; + } else if (result.equals("\"Hello Canary in canary World\"")) { + newCount++; + } else { + TestMgr.fail("not expected result testHelloWorldCanary"); + return; + } + } + + double ratio = oldCount / (float) (oldCount + newCount); + TestMgr.check(Math.abs(ratio - 0.2) <= 0.1, true); + } + + private void testHelloWorldNoHeader() { + int oldCount = 0; + int newCount = 0; + + for (int i = 0; i < 20; i++) { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHelloCanary?name=World", String.class); + if (result.equals("\"Hello Canary World\"")) { + oldCount++; + } else if (result.equals("\"Hello Canary in canary World\"")) { + newCount++; + } else { + TestMgr.fail("not expected result testHelloWorldCanary"); + return; + } + } + + double ratio = oldCount / (float) (oldCount + newCount); + TestMgr.check(Double.compare(ratio, 0.5) == 0, true); + } + + private void testHelloWorldEmptyProtectionCloseWeight100() { + int failCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "emptyProtectionClose100"); + HttpEntity entity = new HttpEntity<>(headers); + try { + template.exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, + entity, String.class); + } catch (Exception e) { + failCount++; + } + } + + TestMgr.check(failCount == 20, true); + } + + private void testHelloWorldeEmptyProtectionCloseWeightLess100() { + int failCount = 0; + int succCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "emptyProtectionCloseLess100"); + HttpEntity entity = new HttpEntity<>(headers); + try { + template.exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, + entity, String.class); + succCount++; + } catch (Exception e) { + failCount++; + } + } + + TestMgr.check(succCount == 20, true); + } + + private void testHelloWorldEmptyProtectionCloseFallback() { + int failCount = 0; + int succCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "emptyProtectionCloseFallback"); + HttpEntity entity = new HttpEntity<>(headers); + try { + template.exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, + entity, String.class); + succCount++; + } catch (Exception e) { + failCount++; + } + } + + TestMgr.check(succCount == 20, true); + } + + private void testHelloWorldEmptyProtectionCloseWeight100Two() { + int failCount = 0; + int succCount = 0; + + for (int i = 0; i < 20; i++) { + MultiValueMap headers = new HttpHeaders(); + headers.add("canary", "emptyProtectionClose100-2"); + HttpEntity entity = new HttpEntity<>(headers); + try { + template.exchange(Config.GATEWAY_URL + "/sayHelloCanary?name=World", HttpMethod.GET, + entity, String.class); + succCount++; + } catch (Exception e) { + failCount++; + } + } + + TestMgr.check(failCount == succCount, true); + } +} diff --git a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..10d62c6bba4 --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } +} diff --git a/demo/demo-cse-v1/test-client/src/main/resources/application.yml b/demo/demo-cse-v1/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..13ffddc60b8 --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/resources/application.yml @@ -0,0 +1,43 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v1 + name: test-client + version: 0.0.1 + registry: + sc: + address: https://cse.cn-south-1.myhuaweicloud.com + watch: false + config: + client: + serverUri: https://cse.cn-south-1.myhuaweicloud.com + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container + + # Configure AK/SK credentials if needed. Default not enabled. + credentials: + akskEnabled: true + accessKey: ${CREDENTIALS_AK} + secretKey: ${CREDENTIALS_SK} + akskCustomCipher: default + project: cn-south-1 diff --git a/demo/demo-cse-v1/test-client/src/main/resources/log4j2.xml b/demo/demo-cse-v1/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..9ac74305e0c --- /dev/null +++ b/demo/demo-cse-v1/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./user/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v2/README.md b/demo/demo-cse-v2/README.md new file mode 100644 index 00000000000..dda7dee702e --- /dev/null +++ b/demo/demo-cse-v2/README.md @@ -0,0 +1,137 @@ +# 使用微服务引擎2.0的测试用例 + +* 参考:https://support.huaweicloud.com/devg-cse/cse_devg_0036.html 安装微服务引擎2.0 + +* 设置环境变量: + * PAAS_CSE_SC_ENDPOINT: 注册中心的地址 + * PAAS_CSE_CC_ENDPOINT: 配置中心的地址 + +* 依次启动 provider、consumer、gateway + +* 在配置中心增加如下配置: +* 应用级配置:consumer.yaml。类型为 yaml。 + +```yaml +cse: + v2: + test: + foo: foo +``` + + * 自定义配置:priority1.yaml。label信息: public=default 。类型为 yaml。 +```yaml +cse: + v2: + test: + priority: v1 + common: common +``` + + * 自定义配置:priority1.yaml。label信息: public=default,extra=default 。类型为 yaml。 +```yaml +cse: + v2: + test: + priority: v1 + extra: common +``` + + * 应用级配置:priority2.yaml。类型为 yaml。 +```yaml +cse: + v2: + test: + priority: v2 +``` + + * 服务级配置:priority3.yaml,微服务性选择consumer。类型为 yaml。 +```yaml +cse: + v2: + test: + priority: v3 +``` + +* 应用级配置:consumerApp.yaml,应用选择demo-java-chassis-cse-v2。类型为 yaml。 +```yaml +cse: + v2: + test: + priority1: v1 +``` + +* 服务级配置:consumerService.yaml,微服务性选择consumer。类型为 yaml。 +```yaml +cse: + v2: + test: + priority1: v2 +``` + + * 应用级配置: cse.v2.test.bar: bar 。 类型为 text。 + +* 执行 tests-client 里面的集成测试用例 (成功) + +* 修改 + * priority1.yaml。label信息: public=default 。类型为 yaml。 +```yaml +cse: + v2: + test: + priority: v4 +``` + +* 执行 tests-client 里面的集成测试用例 (成功) + +* 修改 + * 应用级priority3.yaml。 +```yaml +cse: + v2: + test: + priority: v5 +``` + +* 执行 tests-client 里面的集成测试用例 (失败) + +* 修改 + * 应用级priority3.yaml。label信息: +```yaml +cse: + v2: + test: + priority: v3 +``` + +* 执行 tests-client 里面的集成测试用例 (成功) +* 修改 + * 应用级consumerApp.yaml。 +```yaml +cse: + v2: + test: + priority1: v10 +``` + +* 执行 tests-client 里面的集成测试用例 (成功) +* 修改 + * 服务级配置:consumerService.yaml。 +```yaml +cse: + v2: + test: + priority1: v20 +``` + +* 执行 tests-client 里面的集成测试用例 (成功) + +* 修改 + * 版本级配置:consumerIns.yaml。 +```yaml +cse: + v2: + test: + priority1: v30 +``` + +* 执行 tests-client 里面的集成测试用例 (失败) diff --git a/demo/demo-cse-v2/consumer/pom.xml b/demo/demo-cse-v2/consumer/pom.xml new file mode 100644 index 00000000000..0fe6e05f4d0 --- /dev/null +++ b/demo/demo-cse-v2/consumer/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v2 + 3.4.0-SNAPSHOT + + + cse-v2-consumer + Java Chassis::Demo::CSE-V2::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java new file mode 100644 index 00000000000..3e7a2a0e285 --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java new file mode 100644 index 00000000000..8c3c45d24a3 --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigController.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerConfigController") +@RequestMapping(path = "/") +public class ConsumerConfigController { + private Environment environment; + + private ConsumerConfigurationProperties consumerConfigurationProperties; + + @Autowired + public ConsumerConfigController(Environment environment, ConsumerConfigurationProperties consumerConfigurationProperties) { + this.environment = environment; + this.consumerConfigurationProperties = consumerConfigurationProperties; + } + + @GetMapping("/config") + public String config(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @GetMapping("/foo") + public String foo() { + return consumerConfigurationProperties.getFoo(); + } + + @GetMapping("/bar") + public String bar() { + return consumerConfigurationProperties.getBar(); + } + + @GetMapping("/priority") + public String priority() { + return consumerConfigurationProperties.getPriority(); + } + + @GetMapping("/common") + public String common() { + return consumerConfigurationProperties.getCommon(); + } + + @GetMapping("/extra") + public String extra() { + return consumerConfigurationProperties.getExtra(); + } +} diff --git a/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java new file mode 100644 index 00000000000..e87d9ebb915 --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerConfigurationProperties.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties("cse.v2.test") +@Component +public class ConsumerConfigurationProperties { + private String foo; + + private String bar; + + private String priority; + + private String common; + + private String extra; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + public String getBar() { + return bar; + } + + public void setBar(String bar) { + this.bar = bar; + } + + public String getPriority() { + return priority; + } + + public void setPriority(String priority) { + this.priority = priority; + } + + public String getCommon() { + return common; + } + + public void setCommon(String common) { + this.common = common; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } +} diff --git a/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..4ed0ecd85fe --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } +} diff --git a/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..f327412b759 --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); +} diff --git a/demo/demo-cse-v2/consumer/src/main/resources/application.yml b/demo/demo-cse-v2/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..5982bb668b5 --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/resources/application.yml @@ -0,0 +1,37 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v2 + name: consumer + version: 0.0.1 + registry: + sc: + address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} + watch: false + kie: + serverUri: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} + customLabel: public + customLabelValue: default + + rest: + address: 0.0.0.0:9092 # should be same with server.port to use web container diff --git a/demo/demo-cse-v2/consumer/src/main/resources/log4j2.xml b/demo/demo-cse-v2/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..4e54783856a --- /dev/null +++ b/demo/demo-cse-v2/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./file/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v2/gateway/pom.xml b/demo/demo-cse-v2/gateway/pom.xml new file mode 100644 index 00000000000..1d04a248410 --- /dev/null +++ b/demo/demo-cse-v2/gateway/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v2 + 3.4.0-SNAPSHOT + + + cse-v2-gateway + Java Chassis::Demo::CSE-V2::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v2/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-cse-v2/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-cse-v2/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v2/gateway/src/main/resources/application.yml b/demo/demo-cse-v2/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..32d2a728d76 --- /dev/null +++ b/demo/demo-cse-v2/gateway/src/main/resources/application.yml @@ -0,0 +1,52 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# override common configurations in common module +servicecomb-config-order: 100 + +servicecomb: + service: + application: demo-java-chassis-cse-v2 + name: gateway + version: 0.0.1 + registry: + sc: + address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} + watch: false + + kie: + serverUri: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} + customLabel: public + + rest: + address: 0.0.0.0:9090?sslEnabled=false + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ diff --git a/demo/demo-cse-v2/gateway/src/main/resources/log4j2.xml b/demo/demo-cse-v2/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..165cdf7e0a3 --- /dev/null +++ b/demo/demo-cse-v2/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./gateway/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v2/pom.xml b/demo/demo-cse-v2/pom.xml new file mode 100644 index 00000000000..35a623930da --- /dev/null +++ b/demo/demo-cse-v2/pom.xml @@ -0,0 +1,65 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-cse-v2 + Java Chassis::Demo::CSE-V2 + pom + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + config-kie + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + + + provider + consumer + gateway + test-client + + + diff --git a/demo/demo-cse-v2/provider/pom.xml b/demo/demo-cse-v2/provider/pom.xml new file mode 100644 index 00000000000..4308b1169d9 --- /dev/null +++ b/demo/demo-cse-v2/provider/pom.xml @@ -0,0 +1,51 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v2 + 3.4.0-SNAPSHOT + + + cse-v2-provider + Java Chassis::Demo::CSE-V2::PROVIDER + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java b/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java new file mode 100644 index 00000000000..fde6f36b2e3 --- /dev/null +++ b/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..6eea7776a6b --- /dev/null +++ b/demo/demo-cse-v2/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController { + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return "Hello " + name; + } +} diff --git a/demo/demo-cse-v2/provider/src/main/resources/application.yml b/demo/demo-cse-v2/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..bb55de45abc --- /dev/null +++ b/demo/demo-cse-v2/provider/src/main/resources/application.yml @@ -0,0 +1,39 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +server: + port: 9093 # should be same with servicecomb.rest.address to use web container + +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v2 + name: provider + version: 0.0.1 + registry: + sc: + address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} + watch: false + kie: + serverUri: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} + customLabel: public + + rest: + address: 0.0.0.0:9093 # should be same with server.port to use web container diff --git a/demo/demo-cse-v2/provider/src/main/resources/log4j2.xml b/demo/demo-cse-v2/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..9ac74305e0c --- /dev/null +++ b/demo/demo-cse-v2/provider/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./user/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-cse-v2/test-client/pom.xml b/demo/demo-cse-v2/test-client/pom.xml new file mode 100644 index 00000000000..78917aa7e5c --- /dev/null +++ b/demo/demo-cse-v2/test-client/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-cse-v2 + 3.4.0-SNAPSHOT + + + cse-v2-test-client + Java Chassis::Demo::CSE-V2::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java new file mode 100644 index 00000000000..16b1388641a --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/ConsumerConfigIT.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class ConsumerConfigIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testConfig(); + testFooBar(); + } + + private void testConfig() { + String result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.foo", String.class); + TestMgr.check("foo", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.bar", String.class); + TestMgr.check("bar", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.priority", String.class); + TestMgr.check("v1", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.common", String.class); + TestMgr.check("common", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.extra", String.class); + TestMgr.check("common", result); + result = template.getForObject(Config.GATEWAY_URL + "/config?key=cse.v2.test.priority1", String.class); + TestMgr.check("v2", result); + } + + private void testFooBar() { + String result = template.getForObject(Config.GATEWAY_URL + "/bar", String.class); + TestMgr.check("bar", result); + result = template.getForObject(Config.GATEWAY_URL + "/foo", String.class); + TestMgr.check("foo", result); + result = template.getForObject(Config.GATEWAY_URL + "/priority", String.class); + TestMgr.check("v1", result); + result = template.getForObject(Config.GATEWAY_URL + "/common", String.class); + TestMgr.check("common", result); + result = template.getForObject(Config.GATEWAY_URL + "/extra", String.class); + TestMgr.check("common", result); + } +} diff --git a/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..59d06bb1e01 --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorld(); + } + + private void testHelloWorld() { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + TestMgr.check("Hello World", result); + } +} diff --git a/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..10d62c6bba4 --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } +} diff --git a/demo/demo-cse-v2/test-client/src/main/resources/application.yml b/demo/demo-cse-v2/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..046fa53ee6b --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/resources/application.yml @@ -0,0 +1,39 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +server: + port: 9093 # should be same with servicecomb.rest.address to use web container + +# override common configurations in common module +servicecomb-config-order: 10 + +servicecomb: + service: + application: demo-java-chassis-cse-v2 + name: test-client + version: 0.0.1 + registry: + sc: + address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} + watch: false + kie: + serverUri: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} + customLabel: public + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container diff --git a/demo/demo-cse-v2/test-client/src/main/resources/log4j2.xml b/demo/demo-cse-v2/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..9ac74305e0c --- /dev/null +++ b/demo/demo-cse-v2/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + + + + ./user/log/ + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/demo-edge/README.md b/demo/demo-edge/README.md new file mode 100644 index 00000000000..b5a552e0668 --- /dev/null +++ b/demo/demo-edge/README.md @@ -0,0 +1,17 @@ +# About edge service API compatibility + +* Edge service use the latest version of the microservice meta. e.g. For business 1.0.0, 1.1.0, 2.0.0 have the following APIs: + + * 1.0.0: /business/v1/add + * 1.1.0: /business/v1/add, /business/v1/dec + * 2.0.0: /business/v2/add, /business/v2/dec + + If users invoke /business/v1/add, edge service will give NOT FOUND, because 2.0.0 microservice meta do not have this API. Even using router to route all /business/v1/* requests to 1.1.0, path locating happens before load balance. + +* It's very important to keep your API compatibility cross versions if these versions need work together. e.g. + + * 1.0.0: /business/v1/add + * 1.1.0: /business/v1/add, /business/v1/dec + * 2.0.0: /business/v1/add, /business/v1/dec, /business/v2/add, /business/v2/dec + + Together with router, /business/v1/add will go correctly to 1.0.0 or 1.1.0, and /business/v2/add will go correctly to 2.0.0. Without router, /business/v2/add may route to 1.0.0 or 1.1.0 and NOT FOUND is reported. diff --git a/demo/demo-edge/authentication/pom.xml b/demo/demo-edge/authentication/pom.xml index 156eedd083c..4849faf28fe 100644 --- a/demo/demo-edge/authentication/pom.xml +++ b/demo/demo-edge/authentication/pom.xml @@ -21,18 +21,74 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT authentication Java Chassis::Demo::Edge::Authentication - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-rest-vertx - + + org.apache.servicecomb.demo.edge.authentication.AuthMain + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/authentication/src/main/java/org/apache/servicecomb/demo/edge/authentication/AuthMain.java b/demo/demo-edge/authentication/src/main/java/org/apache/servicecomb/demo/edge/authentication/AuthMain.java index 734db1e273d..4928706edcd 100644 --- a/demo/demo-edge/authentication/src/main/java/org/apache/servicecomb/demo/edge/authentication/AuthMain.java +++ b/demo/demo-edge/authentication/src/main/java/org/apache/servicecomb/demo/edge/authentication/AuthMain.java @@ -17,12 +17,13 @@ package org.apache.servicecomb.demo.edge.authentication; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class AuthMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(AuthMain.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-edge/authentication/src/main/resources/log4j2.xml b/demo/demo-edge/authentication/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/authentication/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/authentication/src/main/resources/microservice.yaml b/demo/demo-edge/authentication/src/main/resources/microservice.yaml index d532582bea1..038b64eb1ec 100644 --- a/demo/demo-edge/authentication/src/main/resources/microservice.yaml +++ b/demo/demo-edge/authentication/src/main/resources/microservice.yaml @@ -15,15 +15,18 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: auth - version: 0.0.1 servicecomb: service: - registry: + application: edge + name: auth + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 rest: - address: 127.0.0.1:7070 + address: 0.0.0.0:7070?protocol=http2 server: - thread-count: 10 + http2: + useAlpnEnabled: false + # for test case run in one core machine + verticle-count: 1 diff --git a/demo/demo-edge/business-1-1-0/pom.xml b/demo/demo-edge/business-1-1-0/pom.xml index cc4539d0b5f..1cef9b01cab 100644 --- a/demo/demo-edge/business-1-1-0/pom.xml +++ b/demo/demo-edge/business-1-1-0/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT business-1-1-0 Java Chassis::Demo::Edge::Business 1.1.0 @@ -30,22 +30,71 @@ - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-rest-servlet - org.apache.servicecomb.demo model - 1.2.0-SNAPSHOT + ${project.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_1_0.java b/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_1_0.java index 2e92e7b9ba0..f725fa24e0e 100644 --- a/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_1_0.java +++ b/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_1_0.java @@ -17,12 +17,13 @@ package org.apache.servicecomb.demo.edge.business; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class BusinessMain_V1_1_0 { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(BusinessMain_V1_1_0.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java b/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java index 3ff5cd1bf9e..38420d285d6 100644 --- a/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java +++ b/demo/demo-edge/business-1-1-0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java @@ -17,11 +17,12 @@ package org.apache.servicecomb.demo.edge.business; -import org.apache.commons.lang.StringUtils; import org.apache.servicecomb.demo.edge.model.AppClientDataRsp; import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; import org.apache.servicecomb.demo.edge.model.ResultWithInstance; import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -29,21 +30,28 @@ @RestSchema(schemaId = "news-v1") @RequestMapping(path = "/business/v1") public class Impl { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + @RequestMapping(path = "/channel/news/subscribe", method = RequestMethod.POST) public AppClientDataRsp subscribeNewsColumn(@RequestBody ChannelRequestBase request) { AppClientDataRsp response = new AppClientDataRsp(); - String rsp = StringUtils.rightPad("edge test", 1024, "*"); + String rsp = "result from 1.1.0"; response.setRsp(rsp); return response; } @RequestMapping(path = "/add", method = RequestMethod.GET) public ResultWithInstance add(int x, int y) { - return ResultWithInstance.create(x + y); + return ResultWithInstance.create(x + y, environment); } @RequestMapping(path = "/dec", method = RequestMethod.GET) public ResultWithInstance dec(int x, int y) { - return ResultWithInstance.create(x - y); + return ResultWithInstance.create(x - y, environment); } } diff --git a/demo/demo-edge/business-1-1-0/src/main/resources/log4j2.xml b/demo/demo-edge/business-1-1-0/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/business-1-1-0/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/business-1-1-0/src/main/resources/microservice.yaml b/demo/demo-edge/business-1-1-0/src/main/resources/microservice.yaml index 11206233cf6..0fa3a1764e4 100644 --- a/demo/demo-edge/business-1-1-0/src/main/resources/microservice.yaml +++ b/demo/demo-edge/business-1-1-0/src/main/resources/microservice.yaml @@ -15,15 +15,15 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: business - version: 1.1.0 servicecomb: service: - registry: + application: edge + name: business + version: 1.1.0 + registry: + sc: address: http://127.0.0.1:30100 rest: - address: 127.0.0.1:8090 + address: 0.0.0.0:8090 server: - thread-count: 1 + verticle-count: 1 diff --git a/demo/demo-edge/business-1.0.0/pom.xml b/demo/demo-edge/business-1.0.0/pom.xml index 1d937ec25ad..d7e35748fef 100644 --- a/demo/demo-edge/business-1.0.0/pom.xml +++ b/demo/demo-edge/business-1.0.0/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT business-1-0-0 Java Chassis::Demo::Edge::Business 1.0.0 @@ -32,22 +32,71 @@ - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-rest-servlet - org.apache.servicecomb.demo model ${project.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_0_0.java b/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_0_0.java index 83ef6309ec7..e1a57c7e8b1 100644 --- a/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_0_0.java +++ b/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V1_0_0.java @@ -17,12 +17,13 @@ package org.apache.servicecomb.demo.edge.business; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class BusinessMain_V1_0_0 { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(BusinessMain_V1_0_0.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java b/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java index 1322db087e0..1e0d1b84bb8 100644 --- a/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java +++ b/demo/demo-edge/business-1.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java @@ -17,11 +17,12 @@ package org.apache.servicecomb.demo.edge.business; -import org.apache.commons.lang.StringUtils; import org.apache.servicecomb.demo.edge.model.AppClientDataRsp; import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; import org.apache.servicecomb.demo.edge.model.ResultWithInstance; import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -29,16 +30,23 @@ @RestSchema(schemaId = "news-v1") @RequestMapping(path = "/business/v1") public class Impl { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + @RequestMapping(path = "/channel/news/subscribe", method = RequestMethod.POST) public AppClientDataRsp subscribeNewsColumn(@RequestBody ChannelRequestBase request) { AppClientDataRsp response = new AppClientDataRsp(); - String rsp = StringUtils.rightPad("edge test", 1024, "*"); + String rsp = "result from 1.0.0"; response.setRsp(rsp); return response; } @RequestMapping(path = "/add", method = RequestMethod.GET) public ResultWithInstance add(int x, int y) { - return ResultWithInstance.create(x + y); + return ResultWithInstance.create(x + y, environment); } } diff --git a/demo/demo-edge/business-1.0.0/src/main/resources/log4j2.xml b/demo/demo-edge/business-1.0.0/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/business-1.0.0/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/business-1.0.0/src/main/resources/microservice.yaml b/demo/demo-edge/business-1.0.0/src/main/resources/microservice.yaml index 296bf393a2f..cc3c45ed92c 100644 --- a/demo/demo-edge/business-1.0.0/src/main/resources/microservice.yaml +++ b/demo/demo-edge/business-1.0.0/src/main/resources/microservice.yaml @@ -15,15 +15,15 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: business - version: 1.0.0 servicecomb: service: - registry: + application: edge + name: business + version: 1.0.0 + registry: + sc: address: http://127.0.0.1:30100 rest: - address: 127.0.0.1:8080 + address: 0.0.0.0:8080 server: - thread-count: 1 + verticle-count: 1 diff --git a/demo/demo-edge/business-2.0.0/pom.xml b/demo/demo-edge/business-2.0.0/pom.xml index 045381995a8..3500be47d75 100644 --- a/demo/demo-edge/business-2.0.0/pom.xml +++ b/demo/demo-edge/business-2.0.0/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT business-2-0-0 Java Chassis::Demo::Edge::Business 2.0.0 @@ -32,22 +32,71 @@ - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-rest-servlet - org.apache.servicecomb.demo model - 1.2.0-SNAPSHOT + ${project.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V2_0_0.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V2_0_0.java index 04646157e56..81559ce431f 100644 --- a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V2_0_0.java +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/BusinessMain_V2_0_0.java @@ -17,12 +17,13 @@ package org.apache.servicecomb.demo.edge.business; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class BusinessMain_V2_0_0 { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(BusinessMain_V2_0_0.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/EdgeServiceGovernanceService.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/EdgeServiceGovernanceService.java new file mode 100644 index 00000000000..f8d951cd226 --- /dev/null +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/EdgeServiceGovernanceService.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.edge.business; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +@RestSchema(schemaId = "EdgeServiceGovernanceService") +@RequestMapping(path = "/business/v2") +public class EdgeServiceGovernanceService { + private static final Logger LOGGER = LoggerFactory.getLogger(EdgeServiceGovernanceService.class); + + private Map retryTimes = new HashMap<>(); + + private AtomicInteger instanceIsolationIndex = new AtomicInteger(); + + @GetMapping("/testEdgeServiceRetry") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)), description = ""), + @ApiResponse(responseCode = "502", content = @Content(schema = @Schema(implementation = String.class)), description = "")}) + public String testEdgeServiceRetry(@RequestParam(name = "invocationID") String invocationID) { + LOGGER.info("invoke service: {}", invocationID); + retryTimes.putIfAbsent(invocationID, 0); + retryTimes.put(invocationID, retryTimes.get(invocationID) + 1); + + int retry = retryTimes.get(invocationID); + + if (retry == 3) { + return "try times: " + retry; + } + throw new InvocationException(502, "retry", "retry"); + } + + @GetMapping("/testEdgeServiceInstanceIsolation") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)), description = ""), + @ApiResponse(responseCode = "502", content = @Content(schema = @Schema(implementation = String.class)), description = "")}) + public String testEdgeServiceInstanceIsolation(@RequestParam(name = "name") String name) { + if (instanceIsolationIndex.getAndIncrement() % 3 != 0) { + throw new InvocationException(502, "InstanceIsolation", "InstanceIsolation"); + } + return name; + } + + @GetMapping("/testEdgeServiceInstanceBulkhead") + public String testEdgeServiceInstanceBulkhead(@RequestParam(name = "name") String name) { + return name; + } +} diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java index 335d36857b0..fde945e50bf 100644 --- a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/Impl.java @@ -17,99 +17,41 @@ package org.apache.servicecomb.demo.edge.business; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.nio.charset.StandardCharsets; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; import org.apache.servicecomb.demo.edge.model.AppClientDataRsp; import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; -import org.apache.servicecomb.demo.edge.model.DependTypeA; -import org.apache.servicecomb.demo.edge.model.RecursiveSelfType; import org.apache.servicecomb.demo.edge.model.ResultWithInstance; -import org.apache.servicecomb.demo.edge.model.User; import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@RestSchema(schemaId = "news-v2") -@RequestMapping(path = "/business/v2") +@RestSchema(schemaId = "news-v1") +@RequestMapping(path = "/business/v1") public class Impl { - File tempDir = new File("target/downloadTemp"); + private Environment environment; - public Impl() throws IOException { - FileUtils.forceMkdir(tempDir); + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; } @RequestMapping(path = "/channel/news/subscribe", method = RequestMethod.POST) public AppClientDataRsp subscribeNewsColumn(@RequestBody ChannelRequestBase request) { AppClientDataRsp response = new AppClientDataRsp(); - String rsp = StringUtils.rightPad("edge test", 1024, "*"); + String rsp = "result from 2.0.0"; response.setRsp(rsp); return response; } @RequestMapping(path = "/add", method = RequestMethod.GET) public ResultWithInstance add(int x, int y) { - return ResultWithInstance.create(x + y); + return ResultWithInstance.create(x + y, environment); } @RequestMapping(path = "/dec", method = RequestMethod.GET) public ResultWithInstance dec(int x, int y) { - return ResultWithInstance.create(x - y); - } - - @GetMapping(path = "/download") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public ResponseEntity download() throws IOException { - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=download.txt") - .body(new ByteArrayInputStream("download".getBytes(StandardCharsets.UTF_8))); - } - - protected File createBigFile() throws IOException { - File file = new File(tempDir, "bigFile.txt"); - file.delete(); - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); - randomAccessFile.setLength(10 * 1024 * 1024); - randomAccessFile.close(); - return file; - } - - @GetMapping(path = "/bigFile") - public File bigFile() throws IOException { - return createBigFile(); - } - - @PostMapping(path = "recursiveSelf") - public RecursiveSelfType recursiveSelf(@RequestBody RecursiveSelfType value) { - return value; - } - - @PostMapping(path = "dependType") - public DependTypeA dependType(@RequestBody DependTypeA value) { - return value; - } - - @PostMapping(path = "encrypt") - public User encrypt(@RequestBody User value) { - return value; + return ResultWithInstance.create(x - y, environment); } } diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/ImplV2.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/ImplV2.java new file mode 100644 index 00000000000..0e5eabf290f --- /dev/null +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/ImplV2.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.edge.business; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.demo.edge.model.AppClientDataRsp; +import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; +import org.apache.servicecomb.demo.edge.model.DependTypeA; +import org.apache.servicecomb.demo.edge.model.RecursiveSelfType; +import org.apache.servicecomb.demo.edge.model.ResultWithInstance; +import org.apache.servicecomb.demo.edge.model.User; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +@RestSchema(schemaId = "news-v2") +@RequestMapping(path = "/business/v2") +public class ImplV2 { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + File tempDir = new File("target/downloadTemp"); + + public ImplV2() throws IOException { + FileUtils.forceMkdir(tempDir); + } + + @RequestMapping(path = "/channel/news/subscribe", method = RequestMethod.POST) + public AppClientDataRsp subscribeNewsColumn(@RequestBody ChannelRequestBase request) { + AppClientDataRsp response = new AppClientDataRsp(); + String rsp = "result from 2.0.0"; + response.setRsp(rsp); + return response; + } + + @RequestMapping(path = "/add", method = RequestMethod.GET) + public ResultWithInstance add(int x, int y) { + return ResultWithInstance.create(x + y, environment); + } + + @RequestMapping(path = "/dec", method = RequestMethod.GET) + public ResultWithInstance dec(int x, int y) { + return ResultWithInstance.create(x - y, environment); + } + + @GetMapping(path = "/download") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = File.class)), description = ""), + }) + public ResponseEntity download() throws IOException { + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=download.txt") + .body(new ByteArrayInputStream("download".getBytes(StandardCharsets.UTF_8))); + } + + protected File createBigFile() throws IOException { + File file = new File(tempDir, "bigFile.txt"); + file.delete(); + RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); + randomAccessFile.setLength(10 * 1024 * 1024); + randomAccessFile.close(); + return file; + } + + @GetMapping(path = "/bigFile") + public File bigFile() throws IOException { + return createBigFile(); + } + + @PostMapping(path = "recursiveSelf") + public RecursiveSelfType recursiveSelf(@RequestBody RecursiveSelfType value) { + return value; + } + + @PostMapping(path = "dependType") + public DependTypeA dependType(@RequestBody DependTypeA value) { + return value; + } + + @PostMapping(path = "encrypt") + public User encrypt(@RequestBody User value) { + return value; + } +} diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToProducerResponseConverter.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToProducerResponseConverter.java index 9894b6d37b7..9fd5aeec777 100644 --- a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToProducerResponseConverter.java +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToProducerResponseConverter.java @@ -17,18 +17,18 @@ package org.apache.servicecomb.demo.edge.business.error; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; + public class CustomExceptionToProducerResponseConverter implements - ExceptionToProducerResponseConverter { + ExceptionConverter { @Override - public Class getExceptionClass() { - return IllegalStateException.class; + public boolean canConvert(Throwable throwable) { + return throwable instanceof IllegalStateException; } @Override @@ -37,12 +37,12 @@ public int getOrder() { } @Override - public Response convert(SwaggerInvocation swaggerInvocation, IllegalStateException e) { + public InvocationException convert(Invocation invocation, IllegalStateException e, + StatusType genericStatus) { IllegalStateErrorData data = new IllegalStateErrorData(); data.setId(500); data.setMessage(e.getMessage()); data.setState(e.getMessage()); - InvocationException state = new InvocationException(Status.INTERNAL_SERVER_ERROR, data); - return Response.failResp(state); + return new InvocationException(Status.INTERNAL_SERVER_ERROR, data); } } diff --git a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java index 8bdba9c2bc3..f4b56e58782 100644 --- a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java +++ b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.demo.edge.business.error; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; diff --git a/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter b/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter new file mode 100644 index 00000000000..2675a9b60dd --- /dev/null +++ b/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.demo.edge.business.error.CustomExceptionToProducerResponseConverter diff --git a/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter deleted file mode 100644 index 1633f696818..00000000000 --- a/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.demo.edge.business.error.CustomExceptionToProducerResponseConverter \ No newline at end of file diff --git a/demo/demo-edge/business-2.0.0/src/main/resources/log4j2.xml b/demo/demo-edge/business-2.0.0/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/business-2.0.0/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/business-2.0.0/src/main/resources/microservice.yaml b/demo/demo-edge/business-2.0.0/src/main/resources/microservice.yaml index 18982e96965..45a9f2ff743 100644 --- a/demo/demo-edge/business-2.0.0/src/main/resources/microservice.yaml +++ b/demo/demo-edge/business-2.0.0/src/main/resources/microservice.yaml @@ -15,15 +15,15 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: business - version: 2.0.0 servicecomb: service: - registry: + application: edge + name: business + version: 2.0.0 + registry: + sc: address: http://127.0.0.1:30100 rest: - address: 127.0.0.1:8091 + address: 0.0.0.0:8091 server: - thread-count: 1 + verticle-count: 1 diff --git a/demo/demo-edge/consumer/pom.xml b/demo/demo-edge/consumer/pom.xml index 1ada10ea1f1..c26ca048528 100644 --- a/demo/demo-edge/consumer/pom.xml +++ b/demo/demo-edge/consumer/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT consumer Java Chassis::Demo::Edge::Consumer @@ -33,25 +33,228 @@ - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-rest-servlet + org.apache.servicecomb.demo + demo-schema org.apache.servicecomb.demo model - 1.2.0-SNAPSHOT + ${project.version} + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + authentication:${project.version} + authentication + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/authentication-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 7070 + + + + + + 7070:7070 + + + service-center + + + + + business-1-0-0:${project.version} + business-1-0-0 + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/business-1-0-0-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 8080:8080 + + + service-center + + + + + business-1-1-0:${project.version} + business-1-1-0 + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/business-1-1-0-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8090 + + + + + + 8090:8090 + + + service-center + + + + + business-2-0-0:${project.version} + business-2-0-0 + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/business-2-0-0-${project.version}.jar + + + service-center:sc.servicecomb.io + + + Register microservice instance success + + + 8091 + + + + + + 8091:8091 + + + service-center + + + + + edge-service:${project.version} + edge-service + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/edge-service-${project.version}.jar + + + service-center:sc.servicecomb.io + + + Register microservice instance success + + + + 18090 + + + + + + 18090:18090 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java index 7117f076157..ab10a7c3713 100644 --- a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java +++ b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java @@ -26,6 +26,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.demo.edge.model.AppClientDataRsp; import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; import org.apache.servicecomb.demo.edge.model.DependTypeA; @@ -33,11 +34,11 @@ import org.apache.servicecomb.demo.edge.model.RecursiveSelfType; import org.apache.servicecomb.demo.edge.model.ResultWithInstance; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.springframework.core.env.Environment; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -48,10 +49,10 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; public class Consumer { - RestTemplate template = RestTemplateBuilder.create(); + RestOperations template = RestTemplateBuilder.create(); ChannelRequestBase request = new ChannelRequestBase(); @@ -65,6 +66,10 @@ public class Consumer { List decV2Result = new ArrayList<>(); + DiscoveryManager discoveryManager = BeanUtils.getBean(DiscoveryManager.class); + + Environment environment = BeanUtils.getBean(Environment.class); + public Consumer() { request.setDeviceId("2a5cc42ff60006ac"); request.setServiceToken( @@ -140,7 +145,7 @@ public void testEncrypt() { String expected = "{name=userName, age=10, userId=serviceTokenTest-userId, body1=b1, body2=b2, body3=b3}"; Assert.isTrue(expected.equalsIgnoreCase(result.toString()), - String.format("expected: %s\nreal : %s", expected, result.toString())); + String.format("expected: %s\nreal : %s", expected, result)); } protected void testRecursiveSelf() { @@ -168,21 +173,25 @@ protected void testErrorCode() { int response = template.getForObject(url + "?x=2&y=3", Integer.class); Assert.isTrue(response == 5, "not get 5."); - Map raw = template.getForObject(url + "?x=99&y=3", Map.class); - Assert.isTrue(raw.get("message").equals("Cse Internal Server Error"), "x99"); + try { + Map raw = template.getForObject(url + "?x=99&y=3", Map.class); + } catch (HttpServerErrorException e) { + Assert.isTrue(e.getStatusCode().value() == 500, "x99"); + Assert.isTrue(e.getResponseBodyAsString().contains("un expected NPE test."), "x99"); + } try { template.getForObject(url + "?x=88&y=3", Map.class); Assert.isTrue(false, "x88"); } catch (HttpClientErrorException e) { - Assert.isTrue(e.getRawStatusCode() == 403, "x88"); + Assert.isTrue(e.getStatusCode().value() == 403, "x88"); Assert.isTrue(e.getResponseBodyAsString().equals("{\"id\":12,\"message\":\"not allowed id.\"}"), "x88"); } try { template.getForObject(url + "?x=77&y=3", Map.class); Assert.isTrue(false, "x77"); } catch (HttpServerErrorException e) { - Assert.isTrue(e.getRawStatusCode() == 500, "x77"); + Assert.isTrue(e.getStatusCode().value() == 500, "x77"); Assert.isTrue(e.getResponseBodyAsString().equals("{\"id\":500,\"message\":\"77\",\"state\":\"77\"}"), "x77"); } } @@ -222,7 +231,7 @@ protected void testDownloadBigFile() { } return null; }); - Assert.isTrue(size.get() == 10 * 1024 * 1024, "size is : " + String.valueOf(size.get()) + " not 10 * 1024 * 1024"); + Assert.isTrue(size.get() == 10 * 1024 * 1024, "size is : " + size.get() + " not 10 * 1024 * 1024"); System.out.println("test download bigFile finished"); } @@ -263,32 +272,31 @@ protected void invoke(String appendUrl, int x, int y, List r } private URIEndpointObject prepareEdge(String prefix) { - Microservice microservice = RegistryUtils.getMicroservice(); - MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry() - .getAppManager() - .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "edge", DefinitionConst.VERSION_RULE_ALL) - .getVersionedCache() - .mapData() - .values() + DiscoveryInstance instance = discoveryManager.findServiceInstances( + BootStrapProperties.readApplication(environment), "edge") .stream() .findFirst() .get(); - URIEndpointObject edgeAddress = new URIEndpointObject(microserviceInstance.getEndpoints().get(0)); + URIEndpointObject edgeAddress = new URIEndpointObject(instance.getEndpoints().get(0)); edgePrefix = String.format("http://%s:%d/%s/business", edgeAddress.getHostOrIp(), edgeAddress.getPort(), prefix); return edgeAddress; } protected void invokeBusiness(String urlPrefix, ChannelRequestBase request) { - String url = urlPrefix + "/channel/news/subscribe"; + List result = new ArrayList<>(6); + for (int i = 0; i < 6; i++) { + String url = urlPrefix + "/channel/news/subscribe"; - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = new HttpEntity<>(request, headers); + HttpEntity entity = new HttpEntity<>(request, headers); - ResponseEntity response = template.postForEntity(url, entity, AppClientDataRsp.class); - System.out.println("urlPrefix: " + urlPrefix); - System.out.println(response.getHeaders()); - System.out.println(response.getBody().toString()); + ResponseEntity response = template.postForEntity(url, entity, AppClientDataRsp.class); + result.add(response.getBody().getRsp()); + } + Assert.isTrue(result.contains("result from 2.0.0"), "invokeBusiness not balance"); + Assert.isTrue(result.contains("result from 1.1.0"), "invokeBusiness not balance"); + Assert.isTrue(result.contains("result from 1.0.0"), "invokeBusiness not balance"); } } diff --git a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/ConsumerMain.java b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/ConsumerMain.java index b4378b52469..ae462eb6fd1 100644 --- a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/ConsumerMain.java +++ b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/ConsumerMain.java @@ -17,15 +17,24 @@ package org.apache.servicecomb.demo.edge.consumer; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.edge.model.ChannelRequestBase; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +@SpringBootApplication public class ConsumerMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(ConsumerMain.class).web(WebApplicationType.NONE).run(args); + runTest(); + } + + public static void runTest() throws Exception { new Consumer().testEncrypt(); + new Consumer().invokeBusiness("cse://business/business/v1", new ChannelRequestBase()); System.out.println("Running api dispatcher."); new Consumer().run("api"); @@ -33,7 +42,22 @@ public static void main(String[] args) throws Exception { new Consumer().run("rest"); System.out.println("Running url dispatcher."); new Consumer().run("url"); +// Common Http Dispatcher do not have OperationMeta, can not use router. +// System.out.println("Running http dispatcher."); +// new Consumer().run("http"); System.out.println("All test case finished."); + + runCategorizedTest(); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + throw new IllegalStateException("tests failed"); + } + } + + private static void runCategorizedTest() throws Exception { + CategorizedTestCaseRunner + .runCategorizedTestCase("edge"); } } diff --git a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/EdgeServiceGovernanceTest.java b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/EdgeServiceGovernanceTest.java new file mode 100644 index 00000000000..ad774433957 --- /dev/null +++ b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/EdgeServiceGovernanceTest.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.edge.consumer; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestOperations; + +@Component +public class EdgeServiceGovernanceTest implements CategorizedTestCase { + RestOperations template = RestTemplateBuilder.create(); + + String edgePrefix; + + @Autowired + Environment environment; + + @Autowired + DiscoveryManager discoveryManager; + + @Override + public void testRestTransport() throws Exception { + prepareEdge("url"); + // edge service do not support retry +// testEdgeServiceRetry(); + testEdgeServiceInstanceBulkhead(); + testEdgeServiceInstanceIsolation(); // may isolate instance for 5 seconds. + Thread.sleep(6000); // ensure isolation is open for new requests + } + + private void testEdgeServiceInstanceBulkhead() throws Exception { + String url = edgePrefix + "/business/v2/testEdgeServiceInstanceBulkhead"; + + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed503 = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + String result = template.getForObject(url + "?name={1}", String.class, "hello"); + if (!"hello".equals(result)) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (!(e instanceof HttpServerErrorException)) { + notExpectedFailed.set(true); + } else { + if (((HttpServerErrorException) e).getStatusCode().value() == 503) { + expectedFailed503.set(true); + } + } + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(true, expectedFailed503.get()); + TestMgr.check(false, notExpectedFailed.get()); + } + + private void testEdgeServiceInstanceIsolation() throws Exception { + String url = edgePrefix + "/business/v2/testEdgeServiceInstanceIsolation"; + + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed404 = new AtomicBoolean(false); + AtomicBoolean expectedFailed502 = new AtomicBoolean(false); + AtomicBoolean expectedFailed503 = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + String result = template.getForObject(url + "?name={1}", String.class, "hello"); + if (!"hello".equals(result)) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (e instanceof HttpClientErrorException) { + // isolate 2.0.0 and other instance will give 404 + if (((HttpClientErrorException) e).getStatusCode().value() == 404) { + expectedFailed404.set(true); + } else { + notExpectedFailed.set(true); + } + } else if (e instanceof HttpServerErrorException) { + // instance isolated and return 503 + if (((HttpServerErrorException) e).getStatusCode().value() == 503) { + expectedFailed503.set(true); + } + // provider throw 502 exception to trigger instance isolation + if (((HttpServerErrorException) e).getStatusCode().value() == 502) { + expectedFailed502.set(true); + } + } else { + notExpectedFailed.set(true); + } + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(true, expectedFailed404.get()); + TestMgr.check(true, expectedFailed502.get()); + TestMgr.check(true, expectedFailed503.get()); + TestMgr.check(false, notExpectedFailed.get()); + } + + private URIEndpointObject prepareEdge(String prefix) { + DiscoveryInstance microserviceInstance = discoveryManager.findServiceInstances( + BootStrapProperties.readApplication(environment), "edge") + .stream() + .findFirst() + .get(); + URIEndpointObject edgeAddress = new URIEndpointObject(microserviceInstance.getEndpoints().get(0)); + edgePrefix = String.format("http://%s:%d/%s", edgeAddress.getHostOrIp(), edgeAddress.getPort(), prefix); + return edgeAddress; + } +} diff --git a/demo/demo-edge/consumer/src/main/resources/log4j2.xml b/demo/demo-edge/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/consumer/src/main/resources/microservice.yaml b/demo/demo-edge/consumer/src/main/resources/microservice.yaml index 6fdaaf9c9a7..953b1e567e4 100644 --- a/demo/demo-edge/consumer/src/main/resources/microservice.yaml +++ b/demo/demo-edge/consumer/src/main/resources/microservice.yaml @@ -15,11 +15,17 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: consumer - version: 0.0.1 servicecomb: service: - registry: + application: edge + name: consumer + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 + rest: + client.http2.useAlpnEnabled: false + handler: + chain: + Consumer: + default: loadbalance diff --git a/demo/demo-edge/consumer/src/test/java/org/apache/servicecomb/demo/edge/consumer/EdgeDemoIT.java b/demo/demo-edge/consumer/src/test/java/org/apache/servicecomb/demo/edge/consumer/EdgeDemoIT.java new file mode 100644 index 00000000000..0ef1f0c9ba3 --- /dev/null +++ b/demo/demo-edge/consumer/src/test/java/org/apache/servicecomb/demo/edge/consumer/EdgeDemoIT.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.edge.consumer; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = ConsumerMain.class) +public class EdgeDemoIT { + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + ConsumerMain.runTest(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-edge/edge-service/pom.xml b/demo/demo-edge/edge-service/pom.xml index 9d4f3aa596d..31fdcff3874 100644 --- a/demo/demo-edge/edge-service/pom.xml +++ b/demo/demo-edge/edge-service/pom.xml @@ -21,13 +21,13 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT edge-service Java Chassis::Demo::Edge::Service - org.apache.servicecomb.demo.edge.service.EdgeMain + org.apache.servicecomb.demo.edge.EdgeMain @@ -35,13 +35,66 @@ org.apache.servicecomb edge-core - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - provider-pojo - + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/EdgeMain.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/EdgeMain.java new file mode 100644 index 00000000000..b1c17a93cab --- /dev/null +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/EdgeMain.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.edge; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class EdgeMain { + public static void main(String[] args) throws Exception { + new SpringApplicationBuilder(EdgeMain.class).web(WebApplicationType.NONE).run(args); + } +} diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java index c3eaa51102b..7aa294c83ed 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java @@ -20,18 +20,16 @@ import java.util.HashMap; import java.util.Map; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; import org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.SimpleType; public class CustomResponseMetaMapper implements ResponseMetaMapper { - private final static Map CODES = new HashMap<>(1); + private static final Map CODES = new HashMap<>(1); static { - ResponseMeta meta = new ResponseMeta(); - meta.setJavaType(SimpleType.constructUnsafe(IllegalStateErrorData.class)); - CODES.put(500, meta); + CODES.put(500, SimpleType.constructUnsafe(IllegalStateErrorData.class)); } @Override @@ -40,7 +38,7 @@ public int getOrder() { } @Override - public Map getMapper() { + public Map getMapper() { return CODES; } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeConst.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeConst.java index dc5b3f2d437..7439ec60d44 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeConst.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeConst.java @@ -1,4 +1,4 @@ -package org.apache.servicecomb.demo.edge.service;/* +/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -15,6 +15,8 @@ * limitations under the License. */ +package org.apache.servicecomb.demo.edge.service; + public interface EdgeConst { String ENCRYPT_CONTEXT = "encryptContext"; } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeDispatcher.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeDispatcher.java index d5643d3fda4..b900a427409 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeDispatcher.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeDispatcher.java @@ -19,17 +19,19 @@ import java.util.Map; +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.core.invocation.InvocationCreator; import org.apache.servicecomb.edge.core.AbstractEdgeDispatcher; -import org.apache.servicecomb.edge.core.CompatiblePathVersionMapper; -import org.apache.servicecomb.edge.core.EdgeInvocation; +import org.apache.servicecomb.edge.core.EdgeInvocationCreator; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; +import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; public class EdgeDispatcher extends AbstractEdgeDispatcher { - private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); - @Override public int getOrder() { return 10000; @@ -38,7 +40,7 @@ public int getOrder() { @Override public void init(Router router) { String regex = "/api/([^\\\\/]+)/([^\\\\/]+)/(.*)"; - router.routeWithRegex(regex).handler(CookieHandler.create()); + // cookies handler are enabled by default start from 3.8.3 router.routeWithRegex(regex).handler(createBodyHandler()); router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); } @@ -46,13 +48,17 @@ public void init(Router router) { protected void onRequest(RoutingContext context) { Map pathParams = context.pathParams(); String microserviceName = pathParams.get("param0"); - String pathVersion = pathParams.get("param1"); String path = context.request().path().substring(4); - EdgeInvocation edgeInvocation = new EdgeInvocation(); - edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); + requestByFilter(context, microserviceName, path); + } - edgeInvocation.init(microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); + protected void requestByFilter(RoutingContext context, String microserviceName, String path) { + HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); + HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); + InvocationCreator creator = new EdgeInvocationCreator(context, requestEx, responseEx, + microserviceName, path); + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeMain.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeMain.java deleted file mode 100644 index 1c5aebb61fa..00000000000 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/EdgeMain.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.edge.service; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class EdgeMain { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeDispatcher.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeDispatcher.java index 5c8a9a5b8bd..76ea1840402 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeDispatcher.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeDispatcher.java @@ -20,9 +20,17 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.invocation.InvocationCreator; import org.apache.servicecomb.demo.edge.authentication.encrypt.Hcr; +import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.edge.core.AbstractEdgeDispatcher; -import org.apache.servicecomb.edge.core.CompatiblePathVersionMapper; +import org.apache.servicecomb.edge.core.EdgeInvocationCreator; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; +import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse; import org.apache.servicecomb.provider.pojo.Invoker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,13 +38,10 @@ import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; public class EncryptEdgeDispatcher extends AbstractEdgeDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(EncryptEdgeDispatcher.class); - private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); - private Encrypt encrypt = Invoker.createProxy("auth", "encrypt", Encrypt.class); private String prefix = "encryptApi"; @@ -48,12 +53,10 @@ public int getOrder() { @Override public void init(Router router) { - { - String regex = "/" + prefix + "/([^\\\\/]+)/([^\\\\/]+)/(.*)"; - router.routeWithRegex(regex).handler(CookieHandler.create()); - router.routeWithRegex(regex).handler(createBodyHandler()); - router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); - } + String regex = "/" + prefix + "/([^\\\\/]+)/(.*)"; + // cookies handler are enabled by default start from 3.8.3 + router.routeWithRegex(regex).handler(createBodyHandler()); + router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); } protected void onRequest(RoutingContext context) { @@ -102,13 +105,30 @@ private CompletableFuture queryHcr(HttpServerRequest httpServerRequest) { private void routeToBackend(RoutingContext context, Hcr hcr, String userId) { Map pathParams = context.pathParams(); String microserviceName = pathParams.get("param0"); - String pathVersion = pathParams.get("param1"); String path = context.request().path().substring(prefix.length() + 1); - EncryptEdgeInvocation edgeInvocation = new EncryptEdgeInvocation(new EncryptContext(hcr, userId)); - edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); + requestByFilter(context, microserviceName, path, + new EncryptContext(hcr, userId)); + } - edgeInvocation.init(microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); + protected void requestByFilter(RoutingContext context, String microserviceName, String path + , EncryptContext encryptContext) { + HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); + HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); + InvocationCreator creator = new EdgeInvocationCreator(context, requestEx, responseEx, + microserviceName, path) { + @Override + public CompletableFuture createAsync() { + CompletableFuture result = super.createAsync(); + return result.whenComplete((invocation, throwable) + -> { + if (throwable == null) { + invocation.getHandlerContext().put(EdgeConst.ENCRYPT_CONTEXT, encryptContext); + } + }); + } + }; + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeInvocation.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeInvocation.java deleted file mode 100644 index cdeb3355e70..00000000000 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/EncryptEdgeInvocation.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.edge.service.encrypt; - -import org.apache.servicecomb.edge.core.EdgeInvocation; - -public class EncryptEdgeInvocation extends EdgeInvocation { - private EncryptContext encryptContext; - - public EncryptEdgeInvocation(EncryptContext encryptContext) { - this.encryptContext = encryptContext; - } - - @Override - protected void createInvocation() { - super.createInvocation(); - - invocation.getHandlerContext().put("encryptContext", encryptContext); - } -} diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/DecodeBodyFilter.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/DecodeBodyFilter.java index 73c533e678c..d9e0f332318 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/DecodeBodyFilter.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/DecodeBodyFilter.java @@ -17,38 +17,48 @@ package org.apache.servicecomb.demo.edge.service.encrypt.filter; import java.util.Map; +import java.util.concurrent.CompletableFuture; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; import org.apache.servicecomb.demo.edge.authentication.encrypt.Hcr; import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.demo.edge.service.encrypt.EncryptContext; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -public class DecodeBodyFilter implements HttpServerFilter { +@Component +public class DecodeBodyFilter extends AbstractFilter implements EdgeFilter { private JavaType bodyType = TypeFactory.defaultInstance().constructMapType(Map.class, String.class, String[].class); @Override public int getOrder() { - return -9000; + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1790; } @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { + public String getName() { + return "test-edge-decode-body"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); if (encryptContext == null) { - return null; + return nextNode.onFilter(invocation); } Hcr hcr = encryptContext.getHcr(); - String encodedBody = requestEx.getParameter("body"); + String encodedBody = invocation.getRequestEx().getParameter("body"); if (encodedBody == null) { - return null; + return nextNode.onFilter(invocation); } encodedBody = encodedBody.substring(hcr.getBodyKey().length()); @@ -56,11 +66,11 @@ public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx try { Map decodedBody = RestObjectMapperFactory.getRestObjectMapper() .readValue(encodedBody, bodyType); - requestEx.getParameterMap().putAll(decodedBody); + invocation.getRequestEx().getParameterMap().putAll(decodedBody); } catch (Throwable e) { // should be a meaning exception response - return Response.producerFailResp(e); + return CompletableFuture.failedFuture(e); } - return null; + return nextNode.onFilter(invocation); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureRequestFilter.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureRequestFilter.java index 0eae860c273..42443b555b4 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureRequestFilter.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureRequestFilter.java @@ -20,48 +20,58 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; import org.apache.servicecomb.demo.edge.authentication.encrypt.Hcr; import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.demo.edge.service.encrypt.EncryptContext; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.swagger.invocation.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; -public class EdgeSignatureRequestFilter implements HttpServerFilter { +@Component +public class EdgeSignatureRequestFilter extends AbstractFilter implements EdgeFilter { private static final Logger LOGGER = LoggerFactory.getLogger(EdgeSignatureRequestFilter.class); @Override public int getOrder() { - return -10000; + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1800; } @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { + public String getName() { + return "test-edge-signature-request"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); if (encryptContext == null) { - return null; + return nextNode.onFilter(invocation); } Hcr hcr = encryptContext.getHcr(); // signature for query and form - List names = Collections.list(requestEx.getParameterNames()); + List names = Collections.list(invocation.getRequestEx().getParameterNames()); names.sort(Comparator.naturalOrder()); Hasher hasher = Hashing.sha256().newHasher(); hasher.putString(hcr.getSignatureKey(), StandardCharsets.UTF_8); for (String name : names) { hasher.putString(name, StandardCharsets.UTF_8); - hasher.putString(requestEx.getParameter(name), StandardCharsets.UTF_8); + hasher.putString(invocation.getRequestEx().getParameter(name), StandardCharsets.UTF_8); } - LOGGER.info("afterReceiveRequest signature: {}", hasher.hash().toString()); + LOGGER.info("afterReceiveRequest signature: {}", hasher.hash()); - return null; + return nextNode.onFilter(invocation); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java index 4d9a3805b5b..a3909d75540 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/EdgeSignatureResponseFilter.java @@ -17,60 +17,65 @@ package org.apache.servicecomb.demo.edge.service.encrypt.filter; import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; import org.apache.servicecomb.demo.edge.authentication.encrypt.Hcr; import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.demo.edge.service.encrypt.EncryptContext; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; import org.apache.servicecomb.swagger.invocation.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import io.vertx.core.buffer.Buffer; -public class EdgeSignatureResponseFilter implements HttpServerFilter { +@Component +public class EdgeSignatureResponseFilter extends AbstractFilter implements EdgeFilter { private static final Logger LOGGER = LoggerFactory.getLogger(EdgeSignatureResponseFilter.class); @Override public int getOrder() { - return 10000; + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1991; } @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - return null; + public String getName() { + return "test-edge-signature-response"; } @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - if (invocation == null) { - return; - } + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + return nextNode.onFilter(invocation).whenComplete((response, throwable) -> { + if (throwable != null) { + return; + } + EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); + if (encryptContext == null) { + return; + } + Hcr hcr = encryptContext.getHcr(); - EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); - if (encryptContext == null) { - return; - } - Hcr hcr = encryptContext.getHcr(); + // bad practice: it's better to set signature in response header + Buffer bodyBuffer = response.getResult(); + String body = bodyBuffer.toString(); + if (body.endsWith("}")) { + Hasher hasher = Hashing.sha256().newHasher(); + hasher.putString(hcr.getSignatureKey(), StandardCharsets.UTF_8); + hasher.putString(body, StandardCharsets.UTF_8); + String signature = hasher.hash().toString(); + LOGGER.info("beforeSendResponse signature: {}", signature); - // bad practice: it's better to set signature in response header - Buffer bodyBuffer = responseEx.getBodyBuffer(); - String body = bodyBuffer.toString(); - if (body.endsWith("}")) { - Hasher hasher = Hashing.sha256().newHasher(); - hasher.putString(hcr.getSignatureKey(), StandardCharsets.UTF_8); - hasher.putString(body, StandardCharsets.UTF_8); - String signature = hasher.hash().toString(); - LOGGER.info("beforeSendResponse signature: {}", signature); - - body = body.substring(0, body.length() - 1) + ",\"signature\":\"" + signature + "\"}"; - responseEx.setBodyBuffer(Buffer.buffer(body)); - } + body = body.substring(0, body.length() - 1) + ",\"signature\":\"" + signature + "\"}"; + response.setResult(Buffer.buffer(body)); + } + }); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/UserIdFilter.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/UserIdFilter.java index 2212042ef7c..fd20c0e6d7e 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/UserIdFilter.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/encrypt/filter/UserIdFilter.java @@ -16,31 +16,42 @@ */ package org.apache.servicecomb.demo.edge.service.encrypt.filter; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; +import java.util.concurrent.CompletableFuture; + import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.demo.edge.service.encrypt.EncryptContext; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.stereotype.Component; -public class UserIdFilter implements HttpServerFilter { +@Component +public class UserIdFilter extends AbstractFilter implements EdgeFilter { @Override public int getOrder() { - return -8000; + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1790; + } + + @Override + public String getName() { + return "test-edge-user-id"; } @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); if (encryptContext == null) { - return null; + return nextNode.onFilter(invocation); } String userId = encryptContext.getUserId(); if (userId != null) { - requestEx.setParameter("userId", userId); + invocation.getRequestEx().setParameter("userId", userId); } - return null; + return nextNode.onFilter(invocation); } } diff --git a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/handler/AuthHandler.java b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/handler/AuthHandler.java index 183ba3da893..4aeb44be08a 100644 --- a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/handler/AuthHandler.java +++ b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/handler/AuthHandler.java @@ -17,20 +17,25 @@ package org.apache.servicecomb.demo.edge.service.handler; -import javax.ws.rs.core.Response.Status; +import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.core.Handler; import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; import org.apache.servicecomb.demo.edge.service.EdgeConst; import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.InvocationType; +import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; -public class AuthHandler implements Handler { +import jakarta.ws.rs.core.Response.Status; + +@Component +public class AuthHandler extends AbstractFilter implements EdgeFilter { private static Logger LOGGER = LoggerFactory.getLogger(AuthHandler.class); private static Auth auth; @@ -40,34 +45,36 @@ public class AuthHandler implements Handler { } @Override - public void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) { + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1980; } @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - if (invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT) != null) { - invocation.next(asyncResp); - return; - } + public boolean enabledForMicroservice(String application, String serviceName) { + // Do not enable for service auth and not enable for internal management access(myself) + return !"auth".equals(serviceName) && !"edge".equals(serviceName); + } - auth.auth("").whenComplete((succ, e) -> doHandle(invocation, asyncResp, succ, e)); + @Override + public String getName() { + return "test-auth"; } - protected void doHandle(Invocation invocation, AsyncResponse asyncResp, Boolean authSucc, Throwable authException) { - if (authException != null) { - asyncResp.consumerFail(new InvocationException(Status.UNAUTHORIZED, (Object) authException.getMessage())); - return; + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT) != null) { + return nextNode.onFilter(invocation); } + return auth.auth("").thenCompose(result -> doHandle(invocation, nextNode, result)); + } + + protected CompletableFuture doHandle(Invocation invocation, FilterNode nextNode, Boolean authSucc) { if (!authSucc) { - asyncResp.consumerFail(new InvocationException(Status.UNAUTHORIZED, (Object) "auth failed")); + return CompletableFuture.failedFuture(new InvocationException(Status.UNAUTHORIZED, (Object) "auth failed")); } LOGGER.debug("auth success."); - try { - invocation.next(asyncResp); - } catch (Throwable e) { - asyncResp.consumerFail(e); - } + return nextNode.onFilter(invocation); } } diff --git a/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter deleted file mode 100644 index eb91526f3d5..00000000000 --- a/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.demo.edge.service.encrypt.filter.EdgeSignatureRequestFilter -org.apache.servicecomb.demo.edge.service.encrypt.filter.DecodeBodyFilter -org.apache.servicecomb.demo.edge.service.encrypt.filter.UserIdFilter -org.apache.servicecomb.demo.edge.service.encrypt.filter.EdgeSignatureResponseFilter \ No newline at end of file diff --git a/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper b/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper index d8a88a70544..dcc25e0a838 100644 --- a/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper +++ b/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.demo.edge.service.CustomResponseMetaMapper \ No newline at end of file +org.apache.servicecomb.demo.edge.service.CustomResponseMetaMapper diff --git a/demo/demo-edge/edge-service/src/main/resources/config/cse.handler.xml b/demo/demo-edge/edge-service/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 3a27cb37339..00000000000 --- a/demo/demo-edge/edge-service/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/demo/demo-edge/edge-service/src/main/resources/config/log4j.properties b/demo/demo-edge/edge-service/src/main/resources/config/log4j.properties deleted file mode 100644 index efd6a27d95f..00000000000 --- a/demo/demo-edge/edge-service/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO,stdout -log4j.appender.stdout.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS/zzz}][%t][%p]%m %l%n \ No newline at end of file diff --git a/demo/demo-edge/edge-service/src/main/resources/log4j2.xml b/demo/demo-edge/edge-service/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-edge/edge-service/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml index fefa992318b..56403677e38 100644 --- a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml +++ b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml @@ -15,26 +15,33 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: edge -service_description: - name: edge - version: 0.0.1 servicecomb: service: - registry: + application: edge + name: edge + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 + edge: + filter: + addHeader: + enabled: true + allowedHeaders: xxx rest: - address: 127.0.0.1:18080 + address: 0.0.0.0:18090 server: - thread-count: 8 + # for test case run in one core machine + verticle-count: 1 client: - thread-count: 8 + verticle-count: 1 + http2.useAlpnEnabled: false handler: chain: Consumer: - default: auth,loadbalance + default: auth,loadbalance,instance-isolation-consumer,instance-bulkhead-consumer service: - auth: loadbalance + auth: loadbalance,instance-isolation-consumer,instance-bulkhead-consumer http: dispatcher: edge: @@ -50,9 +57,81 @@ servicecomb: prefixSegmentCount: 1 path: "/url/business/v1/.*" microserviceName: business - versionRule: 1.0.0-2.0.0 businessV2: prefixSegmentCount: 1 path: "/url/business/v2/.*" microserviceName: business - versionRule: 2.0.0-3.0.0 + http: + enabled: true + mappings: + businessV2: + prefixSegmentCount: 1 + path: "/http/business/v2/.*" + microserviceName: business + businessV1: + prefixSegmentCount: 1 + path: "/http/business/v1/add.*" + microserviceName: business + businessV1_1: + prefixSegmentCount: 1 + path: "/http/business/v1/dec.*" + microserviceName: business + + # 服务治理配置 + matchGroup: + testEdgeServiceRetry: | + matches: + - apiPath: + exact: "/business/v2/testEdgeServiceRetry" + testEdgeServiceInstanceIsolation: | + matches: + - apiPath: + exact: "/business/v2/testEdgeServiceInstanceIsolation" + testEdgeServiceInstanceBulkhead: | + matches: + - apiPath: + exact: "/business/v2/testEdgeServiceInstanceBulkhead" + # retry not supported now + # retry: + # testEdgeServiceRetry: | + # maxAttempts: 2 + # retryOnSame: 0 + instanceIsolation: + testEdgeServiceInstanceIsolation: | + minimumNumberOfCalls: 10 + slidingWindowSize: 20 + slidingWindowType: COUNT_BASED + failureRateThreshold: 50 + slowCallRateThreshold: 100 + slowCallDurationThreshold: 3000 + waitDurationInOpenState: 3000 + permittedNumberOfCallsInHalfOpenState: 10 + instanceBulkhead: + testEdgeServiceInstanceBulkhead: | + maxConcurrentCalls: 1 + maxWaitDuration: 1 + + # enable router for edge service + router: + type: router + routeRule: + business: | + - precedence: 2 + match: + apiPath: + prefix: "/business/v2" + route: + - weight: 100 + tags: + version: 2.0.0 + - precedence: 1 + match: + apiPath: + prefix: "/business/v1/dec" + route: + - weight: 50 + tags: + version: 1.1.0 + - weight: 50 + tags: + version: 2.0.0 diff --git a/demo/demo-edge/model/pom.xml b/demo/demo-edge/model/pom.xml index cd3b99dc90d..3adda2c13e4 100644 --- a/demo/demo-edge/model/pom.xml +++ b/demo/demo-edge/model/pom.xml @@ -22,14 +22,14 @@ org.apache.servicecomb.demo demo-edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT model Java Chassis::Demo::Edge::Model org.apache.servicecomb - service-registry + registry-service-center diff --git a/demo/demo-edge/model/src/main/java/org/apache/servicecomb/demo/edge/model/ResultWithInstance.java b/demo/demo-edge/model/src/main/java/org/apache/servicecomb/demo/edge/model/ResultWithInstance.java index d4ca73cba92..c225f7fee34 100644 --- a/demo/demo-edge/model/src/main/java/org/apache/servicecomb/demo/edge/model/ResultWithInstance.java +++ b/demo/demo-edge/model/src/main/java/org/apache/servicecomb/demo/edge/model/ResultWithInstance.java @@ -17,7 +17,8 @@ package org.apache.servicecomb.demo.edge.model; -import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.springframework.core.env.Environment; public class ResultWithInstance { private int result; @@ -28,12 +29,10 @@ public class ResultWithInstance { private String version; - public static ResultWithInstance create(int value) { + public static ResultWithInstance create(int value, Environment environment) { ResultWithInstance result = new ResultWithInstance(); result.setResult(value); - result.setInstanceId(RegistryUtils.getMicroserviceInstance().getInstanceId()); - result.setServiceId(RegistryUtils.getMicroservice().getServiceId()); - result.setVersion(RegistryUtils.getMicroservice().getVersion()); + result.setVersion(BootStrapProperties.readServiceVersion(environment)); return result; } diff --git a/demo/demo-edge/pom.xml b/demo/demo-edge/pom.xml index 771a29fd4a0..34cdcd1fccc 100644 --- a/demo/demo-edge/pom.xml +++ b/demo/demo-edge/pom.xml @@ -22,29 +22,47 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-edge Java Chassis::Demo::Edge pom - - edge-service + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + model - consumer + edge-service business-1.0.0 business-1-1-0 business-2.0.0 authentication + consumer - - - - org.apache.maven.plugins - maven-dependency-plugin - - - diff --git a/demo/demo-etcd/README.md b/demo/demo-etcd/README.md new file mode 100644 index 00000000000..046bec6c968 --- /dev/null +++ b/demo/demo-etcd/README.md @@ -0,0 +1,5 @@ +# Notice + +This integration tests is designed for Etcd registry and configuration. And extra test cases include: + +* Test cases related to SpringMVC annotations that demo-springmvc can not cover. diff --git a/demo/demo-etcd/consumer/pom.xml b/demo/demo-etcd/consumer/pom.xml new file mode 100644 index 00000000000..20a03319d43 --- /dev/null +++ b/demo/demo-etcd/consumer/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-etcd + 3.4.0-SNAPSHOT + + + etcd-consumer + Java Chassis::Demo::Etcd::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + com.google.protobuf + protobuf-java + 3.25.5 + runtime + + + org.apache.servicecomb + registry-etcd + + + org.apache.servicecomb + config-etcd + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java new file mode 100644 index 00000000000..f71738a9ed6 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; +import io.vertx.core.http.WebSocket; + +@RestSchema(schemaId = "ClientWebsocketController") +@RequestMapping(path = "/ws") +public class ClientWebsocketController { + interface ProviderService { + WebSocket websocket(); + } + + @RpcReference(schemaId = "WebsocketController", microserviceName = "provider") + private ProviderService providerService; + + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + WebSocket providerWebSocket = providerService.websocket(); + providerWebSocket.closeHandler(v -> serverWebsocket.close()); + providerWebSocket.textMessageHandler(m -> { + serverWebsocket.writeTextMessage(m); + }); + serverWebsocket.textMessageHandler(m -> { + providerWebSocket.writeTextMessage(m); + }); + } +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..e66fb2cb3d0 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return providerService.getConfig(key); + } + + @PostMapping(path = "/testContentType", consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public User testContentType(@RequestBody User user) { + return providerService.testContentType(user); + } +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java new file mode 100644 index 00000000000..f0e894d6745 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "ConsumerHeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class ConsumerHeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @RpcReference(microserviceName = "provider", schemaId = "HeaderParamWithListSchema") + private IHeaderParamWithListSchemaSpringMvc provider; + + @Override + public String headerListDefault(List headerList) { + return provider.headerListDefault(headerList); + } + + @Override + public String headerListCSV(List headerList) { + return provider.headerListCSV(headerList); + } + + @Override + public String headerListMULTI(List headerList) { + return provider.headerListMULTI(headerList); + } + + @Override + public String headerListSSV(List headerList) { + return provider.headerListSSV(headerList); + } + + @Override + public String headerListPIPES(List headerList) { + return provider.headerListPIPES(headerList); + } +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java new file mode 100644 index 00000000000..aa169801cf7 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +public class ConsumerReactiveStreamController { + interface ProviderReactiveStreamController { + Publisher sseString(); + + Publisher sseModel(); + } + + @RpcReference(microserviceName = "provider", schemaId = "ReactiveStreamController") + ProviderReactiveStreamController controller; + + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseString() { + return controller.sseString(); + } + + @GetMapping("/sseModel") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseModel() { + return controller.sseModel(); + } +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/EtcdConsumerApplication.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/EtcdConsumerApplication.java new file mode 100644 index 00000000000..2101e6512f8 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/EtcdConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class EtcdConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(EtcdConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..2899546c752 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); + + String getConfig(String key); + + User testContentType(User user); +} diff --git a/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ff421930ef2 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-etcd/consumer/src/main/resources/application.yml b/demo/demo-etcd/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..e0db5f1434e --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/resources/application.yml @@ -0,0 +1,35 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-etcd + version: 0.0.1 + name: consumer + properties: + group: red + registry: + etcd: + connectString: http://127.0.0.1:2379 + config: + etcd: + connectString: http://127.0.0.1:2379 + + rest: + address: 0.0.0.0:9092?websocketEnabled=true + server: + websocket-prefix: /ws diff --git a/demo/demo-etcd/consumer/src/main/resources/log4j2.xml b/demo/demo-etcd/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-etcd/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-etcd/gateway/pom.xml b/demo/demo-etcd/gateway/pom.xml new file mode 100644 index 00000000000..0b52381a492 --- /dev/null +++ b/demo/demo-etcd/gateway/pom.xml @@ -0,0 +1,113 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-etcd + 3.4.0-SNAPSHOT + + + etcd-gateway + Java Chassis::Demo::Etcd::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + com.google.protobuf + protobuf-java + 3.25.5 + runtime + + + org.apache.servicecomb + registry-etcd + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-etcd/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-etcd/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-etcd/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-etcd/gateway/src/main/resources/application.yml b/demo/demo-etcd/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..f526eb3de70 --- /dev/null +++ b/demo/demo-etcd/gateway/src/main/resources/application.yml @@ -0,0 +1,53 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-etcd + version: 0.0.1 + name: gateway + registry: + etcd: + enabled: true + connectString: http://127.0.0.1:2379 + + rest: + address: 0.0.0.0:9090?websocketEnabled=true + server: + websocket-prefix: /ws + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ + websocket: + mappings: + consumer: + prefixSegmentCount: 0 + path: "/ws/.*" + microserviceName: consumer + versionRule: 0.0.0+ diff --git a/demo/demo-etcd/gateway/src/main/resources/log4j2.xml b/demo/demo-etcd/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-etcd/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-etcd/pom.xml b/demo/demo-etcd/pom.xml new file mode 100644 index 00000000000..c615edd88b1 --- /dev/null +++ b/demo/demo-etcd/pom.xml @@ -0,0 +1,61 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-etcd + Java Chassis::Demo::Etcd + pom + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + solution-basic + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + + + provider + consumer + gateway + test-client + + + diff --git a/demo/demo-etcd/provider/pom.xml b/demo/demo-etcd/provider/pom.xml new file mode 100644 index 00000000000..8d8c005a1e1 --- /dev/null +++ b/demo/demo-etcd/provider/pom.xml @@ -0,0 +1,123 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-etcd + 3.4.0-SNAPSHOT + + + etcd-provider + Java Chassis::Demo::Etcd::PROVIDER + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + com.google.protobuf + protobuf-java + 3.25.5 + runtime + + + org.apache.servicecomb + registry-etcd + + + org.apache.servicecomb + config-etcd + + + + io.reactivex.rxjava3 + rxjava + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/EtcdProviderApplication.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/EtcdProviderApplication.java new file mode 100644 index 00000000000..388b962dc61 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/EtcdProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class EtcdProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(EtcdProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java new file mode 100644 index 00000000000..8a773f91c72 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "HeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class HeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @Override + public String headerListDefault(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListCSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListMULTI(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListSSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListPIPES(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } +} diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..677c20ed106 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController implements InitializingBean { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { +// return "Hello " + environment.getProperty("servicecomb.rest.address"); + return "Hello " + name; + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @PostMapping(path = "/testContentType", consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public User testContentType(@RequestBody User user) { + return user; + } + + @Override + public void afterPropertiesSet() throws Exception { + } +} diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java new file mode 100644 index 00000000000..8108d15fd46 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.reactivex.rxjava3.core.Flowable; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +@Transport(name = CoreConst.RESTFUL) +public class ReactiveStreamController { + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + public Publisher sseString() { + return Flowable.fromArray("a", "b", "c"); + } + + @GetMapping("/sseModel") + public Publisher sseModel() { + return Flowable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS) + .map(item -> new Model("jack", item.intValue())); + } +} diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ca12402d672 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java new file mode 100644 index 00000000000..3bc88c64ac5 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; + +@RestSchema(schemaId = "WebsocketController") +@RequestMapping(path = "/ws") +public class WebsocketController { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + // Client may have not registered message handler, and messages sent may get lost. + // So we sleep for a while to send message. + AtomicInteger receiveCount = new AtomicInteger(0); + serverWebsocket.textMessageHandler(s -> { + receiveCount.getAndIncrement(); + }); + serverWebsocket.closeHandler((v) -> System.out.println("closed")); + + new Thread(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + serverWebsocket.writeTextMessage("hello"); + + for (int i = 0; i < 5; i++) { + serverWebsocket.writeTextMessage("hello " + i); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + serverWebsocket.writeTextMessage("total " + receiveCount.get()); + serverWebsocket.close(); + }).start(); + } +} diff --git a/demo/demo-etcd/provider/src/main/resources/application.yml b/demo/demo-etcd/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..da2051cd77e --- /dev/null +++ b/demo/demo-etcd/provider/src/main/resources/application.yml @@ -0,0 +1,55 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +servicecomb: + service: + application: demo-etcd + version: 0.0.1 + name: provider + properties: + group: green + registry: + etcd: + connectString: http://127.0.0.1:2379 + config: + etcd: + connectString: http://127.0.0.1:2379 + instance-tag: tag1 + + rest: + address: 0.0.0.0:9094?websocketEnabled=true + server: + websocket-prefix: /ws + + cors: + enabled: true + origin: "*" + allowCredentials: false + allowedMethod: "*" + maxAge: 3600 + + +key1: 1 +key2: 3 +key3: 5 + +test1: env +test2: applition +test3: service +test4: version +test5: tag diff --git a/demo/demo-etcd/provider/src/main/resources/log4j2.xml b/demo/demo-etcd/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-etcd/provider/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-etcd/test-client/pom.xml b/demo/demo-etcd/test-client/pom.xml new file mode 100644 index 00000000000..ab839d762f5 --- /dev/null +++ b/demo/demo-etcd/test-client/pom.xml @@ -0,0 +1,211 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-etcd + 3.4.0-SNAPSHOT + + + etcd-test-client + Java Chassis::Demo::Etcd::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-local + + + io.etcd + jetcd-core + + + com.google.protobuf + protobuf-java + 3.25.5 + runtime + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + bitnami/etcd:3.5.16 + etcd + + alias + + etcdserver + + + 2379 + + + + + + 2379:2379 + + + yes + + + + + etcd-provider:${project.version} + etcd-provider + + alias + + + -Dservicecomb.registry.etcd.connectString=http://etcd:2379 + -Dservicecomb.config.etcd.connectString=http://etcd:2379 + + /maven/maven/etcd-provider-${project.version}.jar + + + etcd:etcd + + + ServiceComb is ready + + + 9094 + + + + + + 9094:9094 + + + + + etcd-consumer:${project.version} + etcd-consumer + + alias + + + -Dservicecomb.registry.etcd.connectString=http://etcd:2379 + -Dservicecomb.config.etcd.connectString=http://etcd:2379 + + /maven/maven/etcd-consumer-${project.version}.jar + + + etcd:etcd + + + ServiceComb is ready + + + 9092 + + + + + + 9092:9092 + + + + + etcd-gateway:${project.version} + etcd-gateway + + alias + + + -Dservicecomb.registry.etcd.connectString=http://etcd:2379 + + /maven/maven/etcd-gateway-${project.version}.jar + + + etcd:etcd + + + ServiceComb is ready + + + 9090 + + + + + + 9090:9090 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/EtcdConfigIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/EtcdConfigIT.java new file mode 100644 index 00000000000..92432e01f5f --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/EtcdConfigIT.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.ConditionWaiter.SleepUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; + +@Component +public class EtcdConfigIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdConfigIT.class); + + @Override + public void testRestTransport() throws Exception { + + testEnvironment(); + testApplication(); + testService(); + testVersion(); + testTag(); + testOverride(); + } + + private void testOverride() { + + putValue("/servicecomb/config/environment/production/application2.properties", + "testValue=t1"); + putValue("/servicecomb/config/application/production/demo-etcd/application2.properties", + "testValue=t2"); + testGetConfig("testValue", "t2"); + putValue("/servicecomb/config/service/production/demo-etcd/provider/application2.properties", + "testValue=t3"); + testGetConfig("testValue", "t3"); + putValue("/servicecomb/config/version/production/demo-etcd/provider/0.0.1/application2.properties", + "testValue=t4"); + testGetConfig("testValue", "t4"); + putValue("/servicecomb/config/tag/production/demo-etcd/provider/0.0.1/tag1/application2.properties", + "testValue=t5"); + testGetConfig("testValue", "t5"); + } + + private void testEnvironment() { + + putValue("/servicecomb/config/environment/production/application.properties", + "test1=env"); + putValue("/servicecomb/config/environment/production/application.properties", + "test1=env1"); + + testGetConfig("test1", "env1"); + } + + + private void testApplication() { + + putValue("/servicecomb/config/application/production/demo-etcd/application.properties", + "test2=applition"); + putValue("/servicecomb/config/application/production/demo-etcd/application.properties", + "test2=applition2"); + testGetConfig("test2", "applition2"); + } + + private void testService() { + + putValue("/servicecomb/config/service/production/demo-etcd/provider/application.properties", + "test3=service"); + putValue("/servicecomb/config/service/production/demo-etcd/provider/application.properties", + "test3=service3"); + testGetConfig("test3", "service3"); + } + + private void testVersion() { + + putValue("/servicecomb/config/version/production/demo-etcd/provider/0.0.1/application.properties", + "test3=version"); + putValue("/servicecomb/config/version/production/demo-etcd/provider/0.0.1/application.properties", + "test4=version4"); + testGetConfig("test4", "version4"); + } + + private void testTag() { + + putValue("/servicecomb/config/tag/production/demo-etcd/provider/0.0.1/tag1/application.properties", + "test5=tag"); + putValue("/servicecomb/config/tag/production/demo-etcd/provider/0.0.1/tag1/application.properties", + "test5=tag5"); + testGetConfig("test5", "tag5"); + } + + + public void putValue(String key, String value) { + try (Client client = Client.builder().endpoints("http://localhost:2379").build()) { + + client.getKVClient().put( + ByteSequence.from(key, StandardCharsets.UTF_8), + ByteSequence.from(value, StandardCharsets.UTF_8) + ).get(); + + LOGGER.info("Value set successfully:{}", value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void testGetConfig(String key, String expectValue) { + + String result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=" + key, String.class); + + for (int i = 0; i < 4; i++) { + if (StringUtils.equals(expectValue, result)) { + TestMgr.check(expectValue, result); + break; + } + SleepUtil.sleep(500, TimeUnit.MILLISECONDS); + } + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java new file mode 100644 index 00000000000..1b129acc2c6 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HeaderParamWithListSchemaIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHeaderListDefault(); + testHeaderListMulti(); + testHeaderListCSV(); + testHeaderListSSV(); + testHeaderListPipes(); + } + + // default to multi + private void testHeaderListDefault() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListDefault", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListPipes() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a|b|c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListPIPES", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListSSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a b c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListSSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListCSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a,b,c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + + headers.add("headerList", "a, b, c"); + entity = new HttpEntity<>(headers); + result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListMulti() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListMULTI", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..97e883fb45f --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorld(); + testGetConfig(); + } + + private void testGetConfig() { + String result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key1", String.class); + TestMgr.check("1", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key2", String.class); + TestMgr.check("3", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key3", String.class); + TestMgr.check("5", result); + } + + private void testHelloWorld() { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + TestMgr.check("Hello World", result); + + // test trace id added + MultiValueMap headers = new HttpHeaders(); + headers.add("X-B3-TraceId", "81de2eb7691c2bbb"); + HttpEntity entity = new HttpEntity(headers); + ResponseEntity response = + template.exchange(Config.GATEWAY_URL + "/sayHello?name=World", HttpMethod.GET, entity, String.class); + TestMgr.check(1, response.getHeaders().get("X-B3-TraceId").size()); + TestMgr.check("81de2eb7691c2bbb", response.getHeaders().getFirst("X-B3-TraceId")); + TestMgr.check("Hello World", response.getBody()); + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java new file mode 100644 index 00000000000..2bdd0ca42ca --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ProviderIT.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class ProviderIT implements CategorizedTestCase { + + RestOperations template = new RestTemplate(); + + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderIT.class); + + @Override + public void testRestTransport() throws Exception { + + User user = getUser("Application/json"); + TestMgr.check(1L, user.getId()); + TestMgr.check("czd", user.getName()); + + User user2 = getUser("application/json"); + TestMgr.check(1L, user2.getId()); + TestMgr.check("czd", user2.getName()); + + User user3 = getUser("APPLICATION/JSON"); + TestMgr.check(1L, user3.getId()); + TestMgr.check("czd", user3.getName()); + } + + private User getUser(String contentType) throws IOException { + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", contentType); + + String requestBody = """ + { + "id": 1, + "name": "czd" + } + """; + + HttpEntity entity = new HttpEntity<>(requestBody, headers); + + String url = Config.GATEWAY_URL + "/testContentType"; + ResponseEntity response = template.exchange( + url, HttpMethod.POST, entity, String.class); + + User user = JsonUtils.readValue(response.getBody().getBytes(StandardCharsets.UTF_8), User.class); + return user; + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java new file mode 100644 index 00000000000..488a6cf712a --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient.Model; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +public class ReactiveStreamIT implements CategorizedTestCase { + @Autowired + @Qualifier("reactiveStreamProvider") + ReactiveStreamClient reactiveStreamProvider; + + @Autowired + @Qualifier("reactiveStreamGateway") + ReactiveStreamClient reactiveStreamGateway; + + @Override + public void testRestTransport() throws Exception { + testSseString(reactiveStreamProvider); + testSseModel(reactiveStreamProvider); + testSseString(reactiveStreamGateway); + testSseModel(reactiveStreamGateway); + } + + private void testSseModel(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseModel(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(Model s) { + buffer.append(s.getName()).append(s.getAge()); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("jack0jack1jack2jack3jack4", buffer.toString()); + } + + private void testSseString(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseString(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(String s) { + buffer.append(s); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("abc", buffer.toString()); + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..26a2a491bbe --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java new file mode 100644 index 00000000000..3ee5db8c346 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.apache.servicecomb.provider.pojo.Invoker; +import org.reactivestreams.Publisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.WebSocket; + +@Configuration +public class ThirdSvcConfiguration { + @RequestMapping(path = "/ws") + public interface WebsocketClient { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + WebSocket websocket(); + } + + @RequestMapping(path = "/") + public interface ReactiveStreamClient { + class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + Publisher sseString(); + + @GetMapping("/sseModel") + Publisher sseModel(); + } + + @Bean + public RegistryBean providerServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .setAppId("demo-etcd") + .setServiceName("provider") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9094"))))); + } + + @Bean + public RegistryBean gatewayServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .addSchemaInterface("WebsocketController", WebsocketClient.class) + .setAppId("demo-etcd") + .setServiceName("gateway") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9090?websocketEnabled=true"))))); + } + + @Bean("reactiveStreamProvider") + public ReactiveStreamClient reactiveStreamProvider() { + return Invoker.createProxy("provider", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean("reactiveStreamGateway") + public ReactiveStreamClient reactiveStreamGateway() { + return Invoker.createProxy("gateway", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean + public WebsocketClient gatewayWebsocketClient() { + return Invoker.createProxy("gateway", "WebsocketController", WebsocketClient.class); + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/User.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/User.java new file mode 100644 index 00000000000..ff421930ef2 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/User.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +public class User { + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java new file mode 100644 index 00000000000..ea7a7f45b15 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.WebsocketClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import io.vertx.core.http.WebSocket; + +@Component +public class WebsocketIT implements CategorizedTestCase { + @Autowired + private WebsocketClient websocketClient; + + @Override + public void testRestTransport() throws Exception { + StringBuffer sb = new StringBuffer(); + AtomicBoolean closed = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); + + WebSocket webSocket = websocketClient.websocket(); + webSocket.textMessageHandler(s -> { + sb.append(s); + sb.append(" "); + webSocket.writeTextMessage(s); + }); + webSocket.closeHandler(v -> { + closed.set(true); + latch.countDown(); + }); + latch.await(30, TimeUnit.SECONDS); + TestMgr.check(sb.toString(), "hello hello 0 hello 1 hello 2 hello 3 hello 4 total 6 "); + TestMgr.check(closed.get(), true); + } +} diff --git a/demo/demo-etcd/test-client/src/main/resources/application.yml b/demo/demo-etcd/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..adcf259e984 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/resources/application.yml @@ -0,0 +1,35 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-etcd + name: test-client + version: 0.0.1 + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container + + config: + etcd: + instance-tag: tag1 + +test1: env +test2: applition +test3: service +test4: version +test5: tag diff --git a/demo/demo-etcd/test-client/src/main/resources/log4j2.xml b/demo/demo-etcd/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-etcd/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-etcd/test-client/src/test/java/org/apache/servicecomb/samples/EtcdIT.java b/demo/demo-etcd/test-client/src/test/java/org/apache/servicecomb/samples/EtcdIT.java new file mode 100644 index 00000000000..833feff87c0 --- /dev/null +++ b/demo/demo-etcd/test-client/src/test/java/org/apache/servicecomb/samples/EtcdIT.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = TestClientApplication.class) +public class EtcdIT { + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdIT.class); + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() { + try { + TestClientApplication.run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-filter/filter-client/pom.xml b/demo/demo-filter/filter-client/pom.xml new file mode 100644 index 00000000000..6c39fb4f5ad --- /dev/null +++ b/demo/demo-filter/filter-client/pom.xml @@ -0,0 +1,108 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-filter + 3.4.0-SNAPSHOT + + filter-client + Java Chassis::Demo::Filter::Client + + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + foundation-test-scaffolding + + + + + org.apache.servicecomb.demo.filter.FilterClient + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + + diff --git a/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/FilterClient.java b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/FilterClient.java new file mode 100644 index 00000000000..ab454f7c9e2 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/FilterClient.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.filter; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class FilterClient { + private static final Logger LOGGER = LoggerFactory.getLogger(FilterClient.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder(FilterClient.class).web(WebApplicationType.NONE).run(args); + + run(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("com.servicecomb.filterServer"); + } +} diff --git a/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/ClientExceptionSchema.java b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/ClientExceptionSchema.java new file mode 100644 index 00000000000..3d64b25b426 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/ClientExceptionSchema.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.client; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.client.RestOperations; + +@RestSchema(schemaId = "ClientExceptionSchema") +@RequestMapping(path = "/exception", produces = MediaType.APPLICATION_JSON_VALUE) +public class ClientExceptionSchema { + interface IExceptionSchema { + boolean blockingException(); + + CompletableFuture reactiveException(); + } + + private IExceptionSchema exceptionSchema; + + private RestOperations restTemplate = RestTemplateBuilder.create(); + + @RpcReference(microserviceName = "com.servicecomb.filterServer", schemaId = "ExceptionSchema") + public void setExceptionSchema(IExceptionSchema exceptionSchema) { + this.exceptionSchema = exceptionSchema; + } + + @GetMapping(path = "/blockingExceptionRestTemplate") + public boolean blockingExceptionRestTemplate() { + return restTemplate.getForObject( + "servicecomb://com.servicecomb.filterServer/exception/blockingException", boolean.class); + } + + @GetMapping(path = "/blockingExceptionReference") + public boolean blockingExceptionReference() { + return exceptionSchema.blockingException(); + } + + @GetMapping(path = "/blockingExceptionInvoker") + public boolean blockingExceptionInvoker() { + return InvokerUtils.syncInvoke("com.servicecomb.filterServer", + "ExceptionSchema", "blockingException", null, boolean.class); + } + + @GetMapping(path = "/reactiveExceptionReference") + public CompletableFuture reactiveExceptionReference() { + return exceptionSchema.reactiveException(); + } +} diff --git a/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/GovernanceConsumerSchema.java b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/GovernanceConsumerSchema.java new file mode 100644 index 00000000000..733d3ab1f54 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/GovernanceConsumerSchema.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.client; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "GovernanceConsumerSchema") +@RequestMapping(path = "/govern", produces = MediaType.APPLICATION_JSON_VALUE) +public class GovernanceConsumerSchema { + interface GovernanceProviderSchemaInf { + boolean providerFlowControl(); + } + + @RpcReference(microserviceName = "com.servicecomb.filterServer", schemaId = "GovernanceProviderSchema") + private GovernanceProviderSchemaInf retrySchemaInf; + + + @GetMapping(path = "/edgeFlowControl") + public boolean edgeFlowControl() { + return true; + } + + @GetMapping(path = "/providerFlowControl") + public boolean providerFlowControl() { + return retrySchemaInf.providerFlowControl(); + } +} diff --git a/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/RetryClientSchema.java b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/RetryClientSchema.java new file mode 100644 index 00000000000..159c52fe340 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/java/org/apache/servicecomb/demo/filter/client/RetryClientSchema.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.client; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.Response.Status; + +@RestSchema(schemaId = "RetryClientSchema") +@RequestMapping(path = "/retry", produces = MediaType.APPLICATION_JSON_VALUE) +public class RetryClientSchema { + interface RetrySchemaInf { + CompletableFuture successWhenRetryAsync(); + } + + @RpcReference(microserviceName = "com.servicecomb.filterServer", schemaId = "RetrySchema") + private RetrySchemaInf retrySchemaInf; + + RestOperations restTemplate = RestTemplateBuilder.create(); + + private AtomicLong counter = new AtomicLong(0); + + @GetMapping(path = "/governance/edgeSuccessWhenRetry") + public boolean edgeSuccessWhenRetry() { + if (counter.getAndIncrement() % 3 != 0) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later."); + } + return true; + } + + @GetMapping(path = "/governance/edgeSuccessWhenRetryAsync") + public CompletableFuture edgeSuccessWhenRetryAsync() { + CompletableFuture result = new CompletableFuture<>(); + if (counter.getAndIncrement() % 2 == 0) { + result.completeExceptionally(new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later.")); + } else { + result.complete(true); + } + return result; + } + + @GetMapping(path = "/governance/successWhenRetry") + public boolean successWhenRetry() { + return restTemplate.getForObject("servicecomb://com.servicecomb.filterServer/retry/governance/successWhenRetry", + Boolean.class); + } + + @GetMapping(path = "/governance/successWhenRetryAsync") + public CompletableFuture successWhenRetryAsync() { + return retrySchemaInf.successWhenRetryAsync(); + } +} diff --git a/demo/demo-filter/filter-client/src/main/resources/log4j2.xml b/demo/demo-filter/filter-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-filter/filter-client/src/main/resources/microservice.yaml b/demo/demo-filter/filter-client/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..72f90936c83 --- /dev/null +++ b/demo/demo-filter/filter-client/src/main/resources/microservice.yaml @@ -0,0 +1,48 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: filtertest + # test service name with dot + name: com.servicecomb.filterClient + version: 0.0.1 + + registry: + sc: + address: http://127.0.0.1:30100 + rest: + address: 0.0.0.0:8082 + server: + compression: true + highway: + address: 0.0.0.0:7072 + + invocation: + exception: + print-stack-trace: true + # test governance retry + matchGroup: + retry-governance: | + matches: + - apiPath: + prefix: "/retry/governance/" + + retry: + retry-governance: | + maxAttempts: 2 + retryOnResponseStatus: [500] diff --git a/demo/demo-filter/filter-edge/pom.xml b/demo/demo-filter/filter-edge/pom.xml new file mode 100644 index 00000000000..798f7b7697e --- /dev/null +++ b/demo/demo-filter/filter-edge/pom.xml @@ -0,0 +1,112 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-filter + 3.4.0-SNAPSHOT + + filter-edge + Java Chassis::Demo::Filter::Edge + + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb + foundation-test-scaffolding + + + + + org.apache.servicecomb.demo.filter.FilterEdge + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + + diff --git a/demo/demo-filter/filter-edge/src/main/java/org/apache/servicecomb/demo/filter/FilterEdge.java b/demo/demo-filter/filter-edge/src/main/java/org/apache/servicecomb/demo/filter/FilterEdge.java new file mode 100644 index 00000000000..8ea4b7cb22d --- /dev/null +++ b/demo/demo-filter/filter-edge/src/main/java/org/apache/servicecomb/demo/filter/FilterEdge.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.filter; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class FilterEdge { + private static final Logger LOGGER = LoggerFactory.getLogger(FilterEdge.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder(FilterEdge.class).web(WebApplicationType.NONE).run(args); + + run(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("filterEdge"); + } +} diff --git a/demo/demo-filter/filter-edge/src/main/resources/log4j2.xml b/demo/demo-filter/filter-edge/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-filter/filter-edge/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-filter/filter-edge/src/main/resources/microservice.yaml b/demo/demo-filter/filter-edge/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..128a825e6d6 --- /dev/null +++ b/demo/demo-filter/filter-edge/src/main/resources/microservice.yaml @@ -0,0 +1,79 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: filtertest + # test service name with dot + name: com.servicecomb.filterEdge + version: 0.0.1 + + registry: + sc: + address: http://127.0.0.1:30100 + + rest: + address: 0.0.0.0:9090 + server: + compression: true + + edge: + filter: + addHeader: + allowedHeaders: X-B3-TraceId + + invocation: + exception: + print-stack-trace: true + + http: + dispatcher: + edge: + default: + enabled: true + prefix: service + withVersion: false + prefixSegmentCount: 2 + url: + enabled: true + mappings: + filterClient: + prefixSegmentCount: 0 + path: "/retry/.*" + microserviceName: com.servicecomb.filterClient + filterClient2: + prefixSegmentCount: 0 + path: "/govern/.*" + microserviceName: com.servicecomb.filterClient + matchGroup: + edgeFlowControl: | + matches: + - apiPath: + exact: "/govern/edgeFlowControl" + retry-governance: | + matches: + - apiPath: + prefix: "/retry/governance/" + rateLimiting: + edgeFlowControl: | + timeoutDuration: 0 + limitRefreshPeriod: 1000 + rate: 1 + retry: + retry-governance: | + maxAttempts: 2 + retryOnResponseStatus: [500] diff --git a/demo/demo-filter/filter-server/pom.xml b/demo/demo-filter/filter-server/pom.xml new file mode 100644 index 00000000000..b3f257fd875 --- /dev/null +++ b/demo/demo-filter/filter-server/pom.xml @@ -0,0 +1,102 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-filter + 3.4.0-SNAPSHOT + + filter-server + Java Chassis::Demo::Filter::Server + + + + org.apache.servicecomb.demo + demo-schema + + + + + org.apache.servicecomb.demo.filter.FilterServer + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/FilterServer.java b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/FilterServer.java new file mode 100644 index 00000000000..c947b0e7d0b --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/FilterServer.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.filter; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class FilterServer { + private static final Logger LOGGER = LoggerFactory.getLogger(FilterServer.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder(FilterServer.class).web(WebApplicationType.NONE).run(args); + + run(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("filterServer"); + } +} diff --git a/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/ExceptionSchema.java b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/ExceptionSchema.java new file mode 100644 index 00000000000..980681b6b96 --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/ExceptionSchema.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.server; + +import java.util.concurrent.CompletableFuture; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "ExceptionSchema") +@RequestMapping(path = "/exception", produces = MediaType.APPLICATION_JSON_VALUE) +public class ExceptionSchema { + @GetMapping(path = "/blockingException") + public boolean blockingException() { + throw new InvocationException(Status.SERVICE_UNAVAILABLE, new CommonExceptionData("Blocking Exception")); + } + + @GetMapping(path = "/reactiveException") + public CompletableFuture reactiveException() { + throw new InvocationException(Status.SERVICE_UNAVAILABLE, new CommonExceptionData("Reactive Exception")); + } +} diff --git a/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/GovernanceProviderSchema.java b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/GovernanceProviderSchema.java new file mode 100644 index 00000000000..c2b5f37cadf --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/GovernanceProviderSchema.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "GovernanceProviderSchema") +@RequestMapping(path = "/govern", produces = MediaType.APPLICATION_JSON_VALUE) +public class GovernanceProviderSchema { + @GetMapping(path = "/providerFlowControl") + public boolean providerFlowControl() { + return true; + } +} diff --git a/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/RetrySchema.java b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/RetrySchema.java new file mode 100644 index 00000000000..603f2a79e55 --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/java/org/apache/servicecomb/demo/filter/server/RetrySchema.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.server; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +// test cases for retry +@RestSchema(schemaId = "RetrySchema") +@RequestMapping(path = "/retry", produces = MediaType.APPLICATION_JSON_VALUE) +public class RetrySchema { + private AtomicLong counter = new AtomicLong(0); + + @GetMapping(path = "/governance/successWhenRetry") + public boolean successWhenRetry() { + if (counter.getAndIncrement() % 3 != 0) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later."); + } + return true; + } + + @GetMapping(path = "/governance/successWhenRetryAsync") + public CompletableFuture successWhenRetryAsync() { + CompletableFuture result = new CompletableFuture<>(); + if (counter.getAndIncrement() % 2 == 0) { + result.completeExceptionally(new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later.")); + } else { + result.complete(true); + } + return result; + } +} diff --git a/demo/demo-filter/filter-server/src/main/resources/log4j2.xml b/demo/demo-filter/filter-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-filter/filter-server/src/main/resources/microservice.yaml b/demo/demo-filter/filter-server/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..bb96cf5f576 --- /dev/null +++ b/demo/demo-filter/filter-server/src/main/resources/microservice.yaml @@ -0,0 +1,62 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: filtertest + # test service name with dot + name: com.servicecomb.filterServer + version: 0.0.1 + + registry: + sc: + address: http://127.0.0.1:30100 + + rest: + address: 0.0.0.0:8080 + server: + compression: true + highway: + address: 0.0.0.0:7070 + + matchGroup: + providerFlowControl: | + matches: + - apiPath: + exact: "/govern/providerFlowControl" + rateLimiting: + providerFlowControl: | + timeoutDuration: 0 + limitRefreshPeriod: 1000 + rate: 1 + +#########SSL options +ssl.protocols: TLSv1.2 +ssl.authPeer: true +ssl.checkCN.host: true + +#########certificates config +ssl.trustStore: trust.jks +ssl.trustStoreType: JKS +ssl.trustStoreValue: Changeme_123 +ssl.keyStore: server.p12 +ssl.keyStoreType: PKCS12 +ssl.keyStoreValue: Changeme_123 +ssl.crl: revoke.crl +ssl.sslCustomClass: org.apache.servicecomb.demo.DemoSSLCustom + +vertx.disableFileCPResolving: false # false: create the .vertx directory, true: do not create diff --git a/demo/demo-filter/filter-tests/pom.xml b/demo/demo-filter/filter-tests/pom.xml new file mode 100644 index 00000000000..3936a85f517 --- /dev/null +++ b/demo/demo-filter/filter-tests/pom.xml @@ -0,0 +1,192 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-filter + 3.4.0-SNAPSHOT + + filter-tests + Java Chassis::Demo::Filter::Tests + + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-local + + + + + org.apache.servicecomb.demo.filter.FilterTests + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service30100 + + alias + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + filter-server:${project.version} + filter-server + + alias + + + -Dservicecomb.registry.sc.address=http://service30100:30100 + + /maven/maven/filter-server-${project.version}.jar + + + service30100:service30100 + + + ServiceComb is ready + + + 8080 + + + + + + 8080:8080 + + + + + filter-client:${project.version} + filter-client + + alias + + + -Dservicecomb.registry.sc.address=http://service30100:30100 + + /maven/maven/filter-client-${project.version}.jar + + + service30100:service30100 + + + ServiceComb is ready + + + 8082 + + + + + + 8082:8082 + + + + + filter-edge:${project.version} + filter-edge + + alias + + + -Dservicecomb.registry.sc.address=http://service30100:30100 + + /maven/maven/filter-edge-${project.version}.jar + + + service30100:service30100 + + + ServiceComb is ready + + + 9090 + + + + + + 9090:9090 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + + diff --git a/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/FilterTests.java b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/FilterTests.java new file mode 100644 index 00000000000..0c7551b685d --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/FilterTests.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.filter; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class FilterTests { + private static final Logger LOGGER = LoggerFactory.getLogger(FilterTests.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder(FilterTests.class).web(WebApplicationType.NONE).run(args); + + run(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("filterTests"); + } +} diff --git a/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestExceptionSchemaFromClient.java b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestExceptionSchemaFromClient.java new file mode 100644 index 00000000000..e404b38b8a9 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestExceptionSchemaFromClient.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.tests; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestExceptionSchemaFromClient implements CategorizedTestCase { + + RestOperations restTemplate = RestTemplateBuilder.create(); + + private static final String SERVER = "servicecomb://com.servicecomb.filterClient"; + + @Override + public String getMicroserviceName() { + return "filterEdge"; + } + + @Override + public void testAllTransport() throws Exception { + testBlockingExceptionRestTemplate(); + testBlockingExceptionReference(); + testBlockingExceptionInvoker(); + testReactiveExceptionReference(); + } + + private void testBlockingExceptionRestTemplate() { + try { + restTemplate.getForObject(SERVER + "/exception/blockingExceptionRestTemplate", + boolean.class); + } catch (InvocationException e) { + TestMgr.check(503, e.getStatus().getStatusCode()); + TestMgr.check("Blocking Exception", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testBlockingExceptionReference() { + try { + restTemplate.getForObject(SERVER + "/exception/blockingExceptionReference", + boolean.class); + } catch (InvocationException e) { + TestMgr.check(503, e.getStatus().getStatusCode()); + TestMgr.check("Blocking Exception", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testBlockingExceptionInvoker() { + try { + restTemplate.getForObject(SERVER + "/exception/blockingExceptionInvoker", + boolean.class); + } catch (InvocationException e) { + TestMgr.check(503, e.getStatus().getStatusCode()); + TestMgr.check("Blocking Exception", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testReactiveExceptionReference() { + try { + restTemplate.getForObject(SERVER + "/exception/reactiveExceptionReference", + boolean.class); + } catch (InvocationException e) { + TestMgr.check(503, e.getStatus().getStatusCode()); + TestMgr.check("Reactive Exception", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } +} diff --git a/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestGovernanceSchemaFromEdge.java b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestGovernanceSchemaFromEdge.java new file mode 100644 index 00000000000..cd9958b7624 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestGovernanceSchemaFromEdge.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.tests; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestGovernanceSchemaFromEdge implements CategorizedTestCase { + interface GovernanceEdgeSchemaInf { + boolean edgeFlowControl(); + + boolean providerFlowControl(); + } + + @RpcReference(microserviceName = "com.servicecomb.filterEdge", schemaId = "GovernanceConsumerSchema") + private GovernanceEdgeSchemaInf retrySchemaInf; + + @Override + public String getMicroserviceName() { + return "com.servicecomb.filterEdge"; + } + + @Override + public void testRestTransport() throws Exception { + testEdgeFlowControl(); + testConsumerFlowControl(); + } + + private void testConsumerFlowControl() throws Exception { + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + boolean result = retrySchemaInf.providerFlowControl(); + if (!result) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (!e.getMessage().contains("rate limited")) { + notExpectedFailed.set(true); + } + expectedFailed.set(true); + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(expectedFailed.get(), true); + TestMgr.check(notExpectedFailed.get(), false); + } + + private void testEdgeFlowControl() throws Exception { + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + boolean result = retrySchemaInf.edgeFlowControl(); + if (!result) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (!e.getMessage().contains("rate limited")) { + notExpectedFailed.set(true); + } + expectedFailed.set(true); + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(expectedFailed.get(), true); + TestMgr.check(notExpectedFailed.get(), false); + } +} diff --git a/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromClient.java b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromClient.java new file mode 100644 index 00000000000..944f7831910 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromClient.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.tests; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestRetrySchemaFromClient implements CategorizedTestCase { + interface RetrySchemaInf { + boolean successWhenRetry(); + + CompletableFuture successWhenRetryAsync(); + } + + @RpcReference(microserviceName = "com.servicecomb.filterClient", schemaId = "RetryClientSchema") + private RetrySchemaInf retrySchemaInf; + + RestOperations restTemplate = RestTemplateBuilder.create(); + + private static final String SERVER = "servicecomb://com.servicecomb.filterClient"; + + @Override + public String getMicroserviceName() { + return "com.servicecomb.filterClient"; + } + + @Override + public void testAllTransport() throws Exception { + testRetryGovernanceRestTemplate(); + testRetryGovernanceRpc(); + } + + private void testRetryGovernanceRpc() throws Exception { + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + } + + private void testRetryGovernanceRestTemplate() { + TestMgr.check(restTemplate.getForObject(SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + TestMgr.check(restTemplate.getForObject(SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + } +} diff --git a/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromEdge.java b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromEdge.java new file mode 100644 index 00000000000..b28eaff3cbc --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/java/org/apache/servicecomb/demo/filter/tests/TestRetrySchemaFromEdge.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.filter.tests; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class TestRetrySchemaFromEdge implements CategorizedTestCase { + interface RetrySchemaInf { + boolean edgeSuccessWhenRetry(); + + boolean successWhenRetry(); + + CompletableFuture edgeSuccessWhenRetryAsync(); + + CompletableFuture successWhenRetryAsync(); + } + + @RpcReference(microserviceName = "com.servicecomb.filterEdge", schemaId = "RetryClientSchema") + private RetrySchemaInf retrySchemaInf; + + RestOperations restTemplate = RestTemplateBuilder.create(); + + RestTemplate springRestTemplate = new RestTemplate(); + + private static final String SERVER = "servicecomb://com.servicecomb.filterEdge"; + + private static final String EDGE_SERVER = "http://127.0.0.1:9090"; + + @Override + public String getMicroserviceName() { + return "com.servicecomb.filterEdge"; + } + + @Override + public void testRestTransport() throws Exception { + testRetryGovernanceFromEdgeDefaultDispatcher(); + testRetryGovernanceRestTemplate(); + testRetryGovernanceRpc(); + testEdgeRetryGovernanceRpc(); + } + + private void testRetryGovernanceRpc() throws Exception { + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + } + + private void testEdgeRetryGovernanceRpc() throws Exception { + TestMgr.check(retrySchemaInf.edgeSuccessWhenRetry(), true); + TestMgr.check(retrySchemaInf.edgeSuccessWhenRetry(), true); + + TestMgr.check(retrySchemaInf.edgeSuccessWhenRetryAsync().get(), true); + TestMgr.check(retrySchemaInf.edgeSuccessWhenRetryAsync().get(), true); + } + + private void testRetryGovernanceRestTemplate() { + TestMgr.check(restTemplate.getForObject( + SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + TestMgr.check(restTemplate.getForObject( + SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + } + + private void testRetryGovernanceFromEdgeDefaultDispatcher() { + TestMgr.check(springRestTemplate.getForObject( + EDGE_SERVER + "/service/com.servicecomb.filterClient/retry/governance/successWhenRetry", boolean.class), true); + TestMgr.check(springRestTemplate.getForObject( + EDGE_SERVER + "/service/com.servicecomb.filterClient/retry/governance/successWhenRetry", boolean.class), true); + } +} diff --git a/demo/demo-filter/filter-tests/src/main/resources/log4j2.xml b/demo/demo-filter/filter-tests/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-filter/filter-tests/src/main/resources/microservice.yaml b/demo/demo-filter/filter-tests/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..5694d54ac56 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/resources/microservice.yaml @@ -0,0 +1,31 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: filtertest + # test service name with dot + name: com.servicecomb.filterTests + version: 0.0.1 + + registry: + sc: + address: http://127.0.0.1:30100 + + invocation: + exception: + print-stack-trace: true diff --git a/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/GovernanceConsumerSchema.yaml b/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/GovernanceConsumerSchema.yaml new file mode 100644 index 00000000000..b29502270ab --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/GovernanceConsumerSchema.yaml @@ -0,0 +1,45 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.filter.client.GovernanceConsumerSchema + version: 1.0.0 +servers: +- url: /govern +paths: + /edgeFlowControl: + get: + operationId: edgeFlowControl + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean + /providerFlowControl: + get: + operationId: providerFlowControl + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean +components: {} diff --git a/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/RetryClientSchema.yaml b/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/RetryClientSchema.yaml new file mode 100644 index 00000000000..77517becf68 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/resources/microservices/com.servicecomb.filterEdge/RetryClientSchema.yaml @@ -0,0 +1,65 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.filter.client.RetryClientSchema + version: 1.0.0 +servers: +- url: /retry +paths: + /governance/edgeSuccessWhenRetry: + get: + operationId: edgeSuccessWhenRetry + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean + /governance/edgeSuccessWhenRetryAsync: + get: + operationId: edgeSuccessWhenRetryAsync + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean + /governance/successWhenRetry: + get: + operationId: successWhenRetry + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean + /governance/successWhenRetryAsync: + get: + operationId: successWhenRetryAsync + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean +components: {} diff --git a/demo/demo-filter/filter-tests/src/main/resources/registry.yaml b/demo/demo-filter/filter-tests/src/main/resources/registry.yaml new file mode 100644 index 00000000000..1e09e18eea2 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/main/resources/registry.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +com.servicecomb.filterEdge: + - id: "001" + version: "1.0" + appid: filtertest + instances: + - endpoints: + - rest://127.0.0.1:9090 diff --git a/demo/demo-filter/filter-tests/src/test/java/org/apache/servicecomb/demo/filter/retry/FilterTestsIT.java b/demo/demo-filter/filter-tests/src/test/java/org/apache/servicecomb/demo/filter/retry/FilterTestsIT.java new file mode 100644 index 00000000000..d09de401c20 --- /dev/null +++ b/demo/demo-filter/filter-tests/src/test/java/org/apache/servicecomb/demo/filter/retry/FilterTestsIT.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.filter.retry; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.filter.FilterTests; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = FilterTests.class) +public class FilterTestsIT { + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + FilterTests.run(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-filter/pom.xml b/demo/demo-filter/pom.xml new file mode 100644 index 00000000000..45e0206faf1 --- /dev/null +++ b/demo/demo-filter/pom.xml @@ -0,0 +1,62 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-filter + Java Chassis::Demo::Filter + pom + + filter-server + filter-client + filter-edge + filter-tests + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + diff --git a/demo/demo-jaxrs/jaxrs-client/pom.xml b/demo/demo-jaxrs/jaxrs-client/pom.xml index db1c7632546..d25a3cdecca 100644 --- a/demo/demo-jaxrs/jaxrs-client/pom.xml +++ b/demo/demo-jaxrs/jaxrs-client/pom.xml @@ -23,7 +23,7 @@ org.apache.servicecomb.demo demo-jaxrs - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT jaxrs-client Java Chassis::Demo::JAXRS::Client @@ -33,30 +33,103 @@ org.apache.servicecomb.demo demo-schema - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-pojo - - org.apache.servicecomb.demo.jaxrs.client.JaxrsClient + org.apache.servicecomb.demo.jaxrs.JaxrsClient - - - - org.apache.maven.plugins - maven-dependency-plugin - - - + + + docker + + jaxrs-server + + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsClient.java new file mode 100644 index 00000000000..2428e654774 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsClient.java @@ -0,0 +1,555 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.CodeFirstRestTemplate; +import org.apache.servicecomb.demo.DemoConst; +import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; +import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.compute.Person; +import org.apache.servicecomb.demo.jaxrs.client.CodeFirstRestTemplateJaxrs; +import org.apache.servicecomb.demo.jaxrs.client.pojoDefault.DefaultModelServiceClient; +import org.apache.servicecomb.demo.jaxrs.client.validation.ValidationServiceClient; +import org.apache.servicecomb.demo.validator.Student; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; + +@SpringBootApplication +public class JaxrsClient { + private static final Logger LOGGER = LoggerFactory.getLogger(JaxrsClient.class); + + private static RestOperations templateNew = RestTemplateBuilder.create(); + + public static void main(String[] args) throws Exception { + new SpringApplicationBuilder(JaxrsClient.class).web(WebApplicationType.NONE).run(args); + + init(); + + try { + run(); + } catch (Exception e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + + TestMgr.summary(); + LOGGER.info("-------------- last time updated checks(maybe more/less): 540 -------------"); + } + + public static void init() throws Exception { + RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); + RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("jaxrs"); + + CodeFirstRestTemplate codeFirstClient = BeanUtils.getBean(CodeFirstRestTemplateJaxrs.class); + codeFirstClient.testCodeFirst(templateNew, "jaxrs", "/codeFirstJaxrs/"); + testCompute(templateNew); + testValidator(templateNew); + testJaxRSDefaultValuesAllTransport(templateNew); + testSpringMvcDefaultValuesJavaPrimitiveAllTransport(templateNew); + + DefaultModelServiceClient.run(); + ValidationServiceClient.run(); + + testOnlyRest(templateNew); + } + + private static void testOnlyRest(RestOperations template) { + String microserviceName = "jaxrs"; + String cseUrlPrefix = "cse://" + microserviceName; + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, "rest"); + + testGetRest(template, cseUrlPrefix); + testSpringMvcDefaultValuesJavaPrimitiveRest(templateNew); + } + + private static void testCompute(RestOperations template) throws Exception { + String microserviceName = "jaxrs"; + for (String transport : DemoConst.transports) { + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); + TestMgr.setMsg(microserviceName, transport); + + String cseUrlPrefix = "cse://" + microserviceName; + + testGetAllTransport(template, cseUrlPrefix); + testPost(template, cseUrlPrefix); + testPut(template, cseUrlPrefix); + testDelete(template, cseUrlPrefix); + testExchange(template, cseUrlPrefix); + testRawJsonParam(template, cseUrlPrefix); + } + } + + private static void testValidator(RestOperations template) { + String microserviceName = "jaxrs"; + for (String transport : DemoConst.transports) { + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); + TestMgr.setMsg(microserviceName, transport); + + String cseUrlPrefix = "cse://" + microserviceName + "/validator/"; + + testValidatorAddSuccess(template, cseUrlPrefix); + if ("rest".equals(transport)) { + testValidatorAddFail(template, cseUrlPrefix); + testValidatorSayHiFail(template, cseUrlPrefix); + testValidatorExchangeFail(template, cseUrlPrefix); + testJaxRSDefaultValuesRest(template); + } else if ("highway".equals(transport)) { + testValidatorAddFail(template, cseUrlPrefix); + testValidatorSayHiFail(template, cseUrlPrefix); + testValidatorExchangeFail(template, cseUrlPrefix); + } + testValidatorSayHiSuccess(template, cseUrlPrefix); + testValidatorExchangeSuccess(template, cseUrlPrefix); + } + } + + private static void testJaxRSDefaultValuesRest(RestOperations template) { + String result; + String microserviceName = "jaxrs"; + String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; + boolean failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + + result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); + TestMgr.check("Hello 20bobo40302", result); + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + } + + private static void testJaxRSDefaultValuesAllTransport(RestOperations template) { + String microserviceName = "jaxrs"; + for (String transport : DemoConst.transports) { + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); + TestMgr.setMsg(microserviceName, transport); + + String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; + + //default values + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap map = new LinkedMultiValueMap<>(); + HttpEntity> request = new HttpEntity<>(map, headers); + String result = template.postForObject(cseUrlPrefix + "/form", request, String.class); + // TODO: do not support form parameters default value + // TestMgr.check("Hello 20bobo", result); + TestMgr.check("Hello 0null", result); + + headers = new HttpHeaders(); + HttpEntity entity = new HttpEntity<>(null, headers); + result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); + TestMgr.check("Hello 20bobo30", result); + + result = template.getForObject(cseUrlPrefix + "/query?d=10", String.class); + TestMgr.check("Hello 20bobo4010", result); + boolean failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + + result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); + TestMgr.check("Hello 20bobo40302", result); + + failed = false; + try { + result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(failed, true); + + result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", String.class); + TestMgr.check("Hello 302", result); + + result = template.getForObject(cseUrlPrefix + "/query3?a=30", String.class); + TestMgr.check("Hello 30null", result); + + //input values + headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); + Map params = new HashMap<>(); + params.put("a", "30"); + params.put("b", "sam"); + HttpEntity> requestPara = new HttpEntity<>(params, headers); + result = template.postForObject(cseUrlPrefix + "/form", requestPara, String.class); + TestMgr.check("Hello 30sam", result); + + headers = new HttpHeaders(); + headers.add("a", "30"); + headers.add("b", "sam"); + headers.add("c", "40"); + entity = new HttpEntity<>(null, headers); + result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); + TestMgr.check("Hello 30sam40", result); + + result = template.getForObject(cseUrlPrefix + "/query?a=3&b=sam&c=5&d=30", String.class); + TestMgr.check("Hello 3sam530", result); + + result = template.getForObject(cseUrlPrefix + "/query2?a=3&b=4&c=5&d=30&e=2", String.class); + TestMgr.check("Hello 345302", result); + } + } + + private static void testGetRest(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "3"); + int result = + template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, params); + TestMgr.check(2, result); + + result = template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, 5, 4); + TestMgr.check(1, result); + + result = template.getForObject(cseUrlPrefix + "/compute/reduce?a=5&b=6", + Integer.class); + TestMgr.check(-1, result); + } + + private static void testGetAllTransport(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "3"); + int result = + template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, params); + TestMgr.check(2, result); + + result = template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, 5, 4); + TestMgr.check(1, result); + + result = template.getForObject(cseUrlPrefix + "/compute/reduce?a=5&b=6", + Integer.class); + TestMgr.check(-1, result); + } + + private static void testPost(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "3"); + int result = + template.postForObject(cseUrlPrefix + "/compute/add", params, Integer.class); + TestMgr.check(8, result); + + Person person = new Person(); + person.setName("world"); + Person resultPerson = + template.postForObject(cseUrlPrefix + "/compute/sayhello", person, Person.class); + TestMgr.check("hello world", resultPerson.getName()); + + HttpHeaders headers = new HttpHeaders(); + headers.add("prefix", "haha"); + HttpEntity reqEntity = new HttpEntity<>(person, headers); + TestMgr.check("haha world", + template.postForObject(cseUrlPrefix + "/compute/saysomething", reqEntity, String.class)); + } + + private static void testPut(RestOperations template, String cseUrlPrefix) { + template.put(cseUrlPrefix + "/compute/sayhi/{name}", null, "world"); + } + + private static void testDelete(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("name", "world"); + template.delete(cseUrlPrefix + "/compute/sayhei/?name={name}", params); + } + + private static void testExchange(RestOperations template, String cseUrlPrefix) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Accept", MediaType.APPLICATION_JSON); + Person person = new Person(); + person.setName("world"); + HttpEntity requestEntity = new HttpEntity<>(person, headers); + ResponseEntity resEntity = template.exchange(cseUrlPrefix + "/compute/sayhello", + HttpMethod.POST, + requestEntity, + Person.class); + TestMgr.check("hello world", resEntity.getBody()); + + ResponseEntity resEntity2 = + template.exchange(cseUrlPrefix + "/compute/addstring?s=abc&s=def", HttpMethod.DELETE, null, String.class); + TestMgr.check("abcdef", resEntity2.getBody()); + } + + private static void testRawJsonParam(RestOperations template, String cseUrlPrefix) throws Exception { + Map person = new HashMap<>(); + person.put("name", "Tom"); + String jsonPerson = RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(person); + TestMgr.check("hello Tom", + template.postForObject(cseUrlPrefix + "/compute/testrawjson", jsonPerson, String.class)); + } + + @SuppressWarnings({"rawtypes"}) + private static void testValidatorAddFail(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "3"); + boolean isExcep = false; + try { + template.postForObject(cseUrlPrefix + "add", params, Integer.class); + } catch (InvocationException e) { + isExcep = true; + TestMgr.check(400, e.getStatus().getStatusCode()); + TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); + // Message depended on locale, so just check the short part. + // 'must be greater than or equal to 20', propertyPath=add.arg1, rootBeanClass=class org.apache.servicecomb.demo.jaxrs.server.Validator, messageTemplate='{jakarta.validation.constraints.Min.message}'}]] + // ignored + if (e.getErrorData() instanceof CommonExceptionData) { + // highway decode/encode 'Object' with special type information, got runtime type + CommonExceptionData data = (CommonExceptionData) e.getErrorData(); + TestMgr.check("invalid parameters.", data.getMessage()); + TestMgr.check("add.b", + ((Map) ((List) data.getDynamic("validateDetail")).get(0)).get("propertyPath").toString()); + } else { + // rest decode/encode 'Object' using json without type information, got map. Users can got runtime type by adding @JsonTypeInfo to the model. + Map data = (Map) e.getErrorData(); + TestMgr.check("invalid parameters.", data.get("message").toString()); + TestMgr.check("add.b", + ((Map) ((List) data.get("validateDetail")).get(0)).get("propertyPath").toString()); + } + } + + TestMgr.check(true, isExcep); + } + + private static void testValidatorAddSuccess(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "20"); + int result = template.postForObject(cseUrlPrefix + "add", params, Integer.class); + TestMgr.check(25, result); + } + + @SuppressWarnings({"rawtypes"}) + private static void testValidatorSayHiFail(RestOperations template, String cseUrlPrefix) { + boolean isExcep = false; + try { + template.exchange(cseUrlPrefix + "sayhi/{name}", HttpMethod.PUT, null, String.class, "te"); + } catch (InvocationException e) { + isExcep = true; + TestMgr.check(400, e.getStatus().getStatusCode()); + TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); + // Message depended on locale, so just check the short part. + if (e.getErrorData() instanceof CommonExceptionData) { + // highway decode/encode 'Object' with special type information, got runtime type + CommonExceptionData data = (CommonExceptionData) e.getErrorData(); + TestMgr.check("invalid parameters.", data.getMessage()); + TestMgr.check("sayHi.name", + ((Map) ((List) data.getDynamic("validateDetail")).get(0)).get("propertyPath").toString()); + } else { + Map data = (Map) e.getErrorData(); + TestMgr.check("invalid parameters.", data.get("message").toString()); + TestMgr.check("sayHi.name", + ((Map) ((List) data.get("validateDetail")).get(0)).get("propertyPath").toString()); + } + } + TestMgr.check(true, isExcep); + } + + private static void testValidatorSayHiSuccess(RestOperations template, String cseUrlPrefix) { + ResponseEntity responseEntity = + template.exchange(cseUrlPrefix + "sayhi/{name}", HttpMethod.PUT, null, String.class, "world"); + TestMgr.check(202, responseEntity.getStatusCode().value()); + TestMgr.check("world sayhi", responseEntity.getBody()); + } + + @SuppressWarnings({"rawtypes"}) + private static void testValidatorExchangeFail(RestOperations template, String cseUrlPrefix) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Accept", MediaType.APPLICATION_JSON); + Student student = new Student(); + student.setName(""); + student.setAge(25); + boolean isExcep = false; + try { + HttpEntity requestEntity = new HttpEntity<>(student, headers); + template.exchange(cseUrlPrefix + "/sayhello", + HttpMethod.POST, + requestEntity, + Student.class); + } catch (InvocationException e) { + isExcep = true; + TestMgr.check(400, e.getStatus().getStatusCode()); + TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); + // Message depended on locale, so just check the short part. + if (e.getErrorData() instanceof CommonExceptionData) { + // highway decode/encode 'Object' with special type information, got runtime type + CommonExceptionData data = (CommonExceptionData) e.getErrorData(); + TestMgr.check("invalid parameters.", data.getMessage()); + TestMgr.check("sayHello.student.age", + ((Map) ((List) data.getDynamic("validateDetail")).get(0)).get("propertyPath").toString()); + } else { + Map data = (Map) e.getErrorData(); + TestMgr.check("invalid parameters.", data.get("message").toString()); + TestMgr.check("sayHello.student.age", + ((Map) ((List) data.get("validateDetail")).get(0)).get("propertyPath").toString()); + } + } + TestMgr.check(true, isExcep); + } + + private static void testValidatorExchangeSuccess(RestOperations template, String cseUrlPrefix) { + Student student = new Student(); + student.setName("test"); + student.setAge(15); + Student result = template.postForObject(cseUrlPrefix + "sayhello", student, Student.class); + TestMgr.check("hello test 15", result); + } + + private static void testSpringMvcDefaultValuesJavaPrimitiveRest(RestOperations template) { + String microserviceName = "jaxrs"; + String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap map = new LinkedMultiValueMap<>(); + HttpEntity> request = new HttpEntity<>(map, headers); + + //default values with primitive + String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", request, String.class); + // TODO: form default values support +// TestMgr.check("Hello 0bobo", result); + TestMgr.check("Hello 0null", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", request, String.class); + TestMgr.check("Hello 0.0false", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", request, String.class); + TestMgr.check("Hello", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", request, String.class); + TestMgr.check("Hello nullnull", result); + + result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); + TestMgr.check("Hello false,\0,0,0,0,0,0.0,0.0,null", result); + } + + private static void testSpringMvcDefaultValuesJavaPrimitiveAllTransport(RestOperations template) { + String microserviceName = "jaxrs"; + for (String transport : DemoConst.transports) { + CategorizedTestCaseRunner.changeTransport(microserviceName, transport); + + String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap map = new LinkedMultiValueMap<>(); + HttpEntity> request = new HttpEntity<>(map, headers); + + //default values with primitive + String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", request, String.class); + // TODO: form default values support +// TestMgr.check("Hello 0bobo", result); + TestMgr.check("Hello 0null", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", request, String.class); + TestMgr.check("Hello 0.0false", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", request, String.class); + TestMgr.check("Hello", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", request, String.class); + TestMgr.check("Hello nullnull", result); + + result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); + TestMgr.check("Hello false,\0,0,0,0,0,0.0,0.0,null", result); + } + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java index 38ae6e963fd..66c5ab958b4 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CodeFirstRestTemplateJaxrs.java @@ -17,106 +17,46 @@ package org.apache.servicecomb.demo.jaxrs.client; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.MediaType; - -import org.apache.commons.io.FileUtils; import org.apache.servicecomb.demo.CodeFirstRestTemplate; import org.apache.servicecomb.demo.TestMgr; -import org.springframework.core.io.FileSystemResource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; +@Component public class CodeFirstRestTemplateJaxrs extends CodeFirstRestTemplate { @Override - protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) { + protected void testAllTransport(String microserviceName, RestOperations template, String cseUrlPrefix) { testDefaultPath(template, cseUrlPrefix); test404(template); super.testAllTransport(microserviceName, template, cseUrlPrefix); } - private void testDefaultPath(RestTemplate template, String cseUrlPrefix) { + private void testDefaultPath(RestOperations template, String cseUrlPrefix) { int result = template.getForObject(cseUrlPrefix.substring(0, cseUrlPrefix.length() - 1), Integer.class); TestMgr.check(100, result); } @Override - protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) { - try { - testUpload(template, cseUrlPrefix); - } catch (IOException e) { - throw new IllegalStateException(e); - } - super.testOnlyRest(template, cseUrlPrefix); - } - - private void testUpload(RestTemplate template, String cseUrlPrefix) throws IOException { - String file1Content = "Hello World"; - File file1 = File.createTempFile("jaxrstest1", ".txt"); - FileUtils.writeStringToFile(file1, file1Content); - - testFileUpload(template, cseUrlPrefix, file1, file1Content); - testFileAndStringUpload(template, cseUrlPrefix, file1, file1Content); - } - - private void testFileUpload(RestTemplate template, String cseUrlPrefix, File file1, String file1Content) - throws IOException { - Map map = new HashMap<>(); - map.put("file1", new FileSystemResource(file1)); - String file2Content = "Hello EveryOne"; - File file2 = File.createTempFile("测试2", ".txt"); - FileUtils.writeStringToFile(file2, file2Content); - map.put("file2", new FileSystemResource(file2)); - - String result1 = template.postForObject(cseUrlPrefix + "/upload1", new HttpEntity<>(new HashMap<>()), String.class); - TestMgr.check("null file", result1); - - String expect = String.format("%s:%s:%s\n" + "%s:%s:%s", - file1.getName(), - MediaType.TEXT_PLAIN, - file1Content, - file2.getName(), - MediaType.TEXT_PLAIN, - file2Content); - String result2 = template.postForObject(cseUrlPrefix + "/upload1", new HttpEntity<>(map), String.class); - TestMgr.check(expect, result2); + protected void testOnlyRest(String microserviceName, RestOperations template, String cseUrlPrefix) { + super.testOnlyRest(microserviceName, template, cseUrlPrefix); } - private void testFileAndStringUpload(RestTemplate template, String cseUrlPrefix, File file1, String file1Content) { - Map map = new HashMap<>(); - String message = "hi"; - map.put("file1", new FileSystemResource(file1)); - map.put("message", message); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); - String expect = String.format("%s:%s:%s:%s", - file1.getName(), - MediaType.TEXT_PLAIN, - file1Content, - message); - String result = template.postForObject(cseUrlPrefix + "/upload2", new HttpEntity<>(map, headers), String.class); - TestMgr.check(expect, result); - } - private void test404(RestTemplate template) { + private void test404(RestOperations template) { HttpClientErrorException exception = null; try { template.getForEntity("http://127.0.0.1:8080/aPathNotExist", String.class); + TestMgr.check("expect throw but not", ""); } catch (RestClientException e) { if (e instanceof HttpClientErrorException) { exception = (HttpClientErrorException) e; } } - TestMgr.check(404, exception.getRawStatusCode()); - TestMgr.check("404 Not Found", exception.getMessage()); + TestMgr.check(404, exception.getStatusCode().value()); + TestMgr.check(true, exception.getMessage().contains("404 Not Found")); } } diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CustomLoadbalanceExtensionsFactory.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CustomLoadbalanceExtensionsFactory.java index 5b2c0ec1968..9614164a05f 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CustomLoadbalanceExtensionsFactory.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/CustomLoadbalanceExtensionsFactory.java @@ -22,46 +22,21 @@ import org.apache.servicecomb.loadbalance.RuleExt; import org.springframework.stereotype.Component; -import com.netflix.client.DefaultLoadBalancerRetryHandler; -import com.netflix.client.RetryHandler; -import com.netflix.client.Utils; - @Component public class CustomLoadbalanceExtensionsFactory implements ExtensionsFactory { - class MyCustomRule extends RoundRobinRuleExt { - - } - - class MyCustomHandler extends DefaultLoadBalancerRetryHandler { - @Override - public boolean isRetriableException(Throwable e, boolean sameServer) { - if (retryEnabled) { - return Utils.isPresentAsCause(e, getRetriableExceptions()); - } - return false; - } + static class MyCustomRule extends RoundRobinRuleExt { - public MyCustomHandler(int retrySameServer, int retryNextServer, boolean retryEnabled) { - super(retrySameServer, retryNextServer, retryEnabled); - } } @Override public boolean isSupport(String key, String value) { - return (Configuration.PROP_RULE_STRATEGY_NAME.equals(key) && - "mycustomrule".equals(value)) - || (Configuration.PROP_RETRY_HANDLER.equals(key) && - "mycustomhandler".equals(value)); + return (Configuration.RULE_STRATEGY_NAME.equals(key) && + "mycustomrule".equals(value)); } @Override public RuleExt createLoadBalancerRule(String ruleName) { return new MyCustomRule(); } - - @Override - public RetryHandler createRetryHandler(String retryName, String microservice) { - return new MyCustomHandler(1, 1, true); - } } diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java deleted file mode 100644 index cd4f7837762..00000000000 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.client; - -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; - -import org.apache.http.HttpStatus; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.demo.CodeFirstRestTemplate; -import org.apache.servicecomb.demo.DemoConst; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.jaxrs.client.beanParam.BeanParamPojoClient; -import org.apache.servicecomb.demo.jaxrs.client.beanParam.BeanParamRestTemplateClient; -import org.apache.servicecomb.demo.jaxrs.client.pojoDefault.DefaultModelServiceClient; -import org.apache.servicecomb.demo.jaxrs.client.validation.ValidationServiceClient; -import org.apache.servicecomb.demo.validator.Student; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -public class JaxrsClient { - private static RestTemplate templateNew = RestTemplateBuilder.create(); - - public static void main(String[] args) throws Exception { - init(); - - run(); - - TestMgr.summary(); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); - RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); - } - - public static void run() throws Exception { - CodeFirstRestTemplate codeFirstClient = new CodeFirstRestTemplateJaxrs(); - codeFirstClient.testCodeFirst(templateNew, "jaxrs", "/codeFirstJaxrs/"); - testCompute(templateNew); - testValidator(templateNew); - testClientTimeOut(templateNew); - testJaxRSDefaultValues(templateNew); - testSpringMvcDefaultValuesJavaPrimitive(templateNew); - MultiErrorCodeServiceClient.runTest(); - - BeanParamPojoClient beanParamPojoClient = new BeanParamPojoClient(); - beanParamPojoClient.testAll(); - BeanParamRestTemplateClient beanParamRestTemplateClient = new BeanParamRestTemplateClient(); - beanParamRestTemplateClient.testAll(); - DefaultModelServiceClient.run(); - ValidationServiceClient.run(); - } - - private static void testCompute(RestTemplate template) throws Exception { - String microserviceName = "jaxrs"; - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); - - String cseUrlPrefix = "cse://" + microserviceName; - - testGet(template, cseUrlPrefix); - testPost(template, cseUrlPrefix); - testPut(template, cseUrlPrefix); - testDelete(template, cseUrlPrefix); - testExchange(template, cseUrlPrefix); - testRawJsonParam(template, cseUrlPrefix); - } - } - - private static void testValidator(RestTemplate template) { - String microserviceName = "jaxrs"; - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); - - String cseUrlPrefix = "cse://" + microserviceName + "/validator/"; - - testValidatorAddSuccess(template, cseUrlPrefix); - testValidatorAddFail(template, cseUrlPrefix); - testValidatorSayHiSuccess(template, cseUrlPrefix); - testValidatorSayHiFail(template, cseUrlPrefix); - testValidatorExchangeSuccess(template, cseUrlPrefix); - testValidatorExchangeFail(template, cseUrlPrefix); - } - } - - - private static void testJaxRSDefaultValues(RestTemplate template) { - String microserviceName = "jaxrs"; - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); - - String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; - - //default values - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); - MultiValueMap map = new LinkedMultiValueMap<>(); - HttpEntity> request = new HttpEntity<>(map, headers); - String result = template.postForObject(cseUrlPrefix + "/form", request, String.class); - TestMgr.check("Hello 20bobo", result); - - headers = new HttpHeaders(); - HttpEntity entity = new HttpEntity<>(null, headers); - result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); - TestMgr.check("Hello 20bobo30", result); - - result = template.getForObject(cseUrlPrefix + "/query?d=10", String.class); - TestMgr.check("Hello 20bobo4010", result); - boolean failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); - TestMgr.check("Hello 20bobo40302", result); - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", String.class); - TestMgr.check("Hello 302", result); - - result = template.getForObject(cseUrlPrefix + "/query3?a=30", String.class); - TestMgr.check("Hello 30null", result); - - //input values - headers = new HttpHeaders(); - headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); - Map params = new HashMap<>(); - params.put("a", "30"); - params.put("b", "sam"); - HttpEntity> requestPara = new HttpEntity<>(params, headers); - result = template.postForObject(cseUrlPrefix + "/form", requestPara, String.class); - TestMgr.check("Hello 30sam", result); - - headers = new HttpHeaders(); - headers.add("a", "30"); - headers.add("b", "sam"); - headers.add("c", "40"); - entity = new HttpEntity<>(null, headers); - result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); - TestMgr.check("Hello 30sam40", result); - - result = template.getForObject(cseUrlPrefix + "/query?a=3&b=sam&c=5&d=30", String.class); - TestMgr.check("Hello 3sam530", result); - - result = template.getForObject(cseUrlPrefix + "/query2?a=3&b=4&c=5&d=30&e=2", String.class); - TestMgr.check("Hello 345302", result); - } - } - - - private static void testGet(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "3"); - int result = - template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, params); - TestMgr.check(2, result); - - result = template.getForObject(cseUrlPrefix + "/compute/reduce?a={a}&b={b}", Integer.class, 5, 4); - TestMgr.check(1, result); - - result = template.getForObject(cseUrlPrefix + "/compute/reduce?a=5&b=6", - Integer.class); - TestMgr.check(-1, result); - } - - private static void testPost(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "3"); - int result = - template.postForObject(cseUrlPrefix + "/compute/add", params, Integer.class); - TestMgr.check(8, result); - - Person person = new Person(); - person.setName("world"); - Person resultPerson = - template.postForObject(cseUrlPrefix + "/compute/sayhello", person, Person.class); - TestMgr.check("hello world", resultPerson.getName()); - - HttpHeaders headers = new HttpHeaders(); - headers.add("prefix", "haha"); - HttpEntity reqEntity = new HttpEntity<>(person, headers); - TestMgr.check("haha world", - template.postForObject(cseUrlPrefix + "/compute/saysomething", reqEntity, String.class)); - } - - private static void testPut(RestTemplate template, String cseUrlPrefix) { - template.put(cseUrlPrefix + "/compute/sayhi/{name}", null, "world"); - } - - private static void testDelete(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("name", "world"); - template.delete(cseUrlPrefix + "/compute/sayhei/?name={name}", params); - } - - private static void testExchange(RestTemplate template, String cseUrlPrefix) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Accept", MediaType.APPLICATION_JSON); - Person person = new Person(); - person.setName("world"); - HttpEntity requestEntity = new HttpEntity<>(person, headers); - ResponseEntity resEntity = template.exchange(cseUrlPrefix + "/compute/sayhello", - HttpMethod.POST, - requestEntity, - Person.class); - TestMgr.check("hello world", resEntity.getBody()); - - ResponseEntity resEntity2 = - template.exchange(cseUrlPrefix + "/compute/addstring?s=abc&s=def", HttpMethod.DELETE, null, String.class); - TestMgr.check("abcdef", resEntity2.getBody()); - } - - private static void testRawJsonParam(RestTemplate template, String cseUrlPrefix) throws Exception { - Map person = new HashMap<>(); - person.put("name", "Tom"); - String jsonPerson = RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(person); - TestMgr.check("hello Tom", - template.postForObject(cseUrlPrefix + "/compute/testrawjson", jsonPerson, String.class)); - } - - @SuppressWarnings({"rawtypes"}) - private static void testValidatorAddFail(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "3"); - boolean isExcep = false; - try { - template.postForObject(cseUrlPrefix + "add", params, Integer.class); - } catch (InvocationException e) { - isExcep = true; - TestMgr.check(400, e.getStatus().getStatusCode()); - TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); - // Message dependends on locale, so just check the short part. - // 'must be greater than or equal to 20', propertyPath=add.arg1, rootBeanClass=class org.apache.servicecomb.demo.jaxrs.server.Validator, messageTemplate='{javax.validation.constraints.Min.message}'}]] - // ignored - Map data = (Map) e.getErrorData(); - TestMgr.check( - true, data.get("message").toString().contains("propertyPath=add.b")); - } - - TestMgr.check(true, isExcep); - } - - private static void testValidatorAddSuccess(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "20"); - int result = template.postForObject(cseUrlPrefix + "add", params, Integer.class); - TestMgr.check(25, result); - } - - @SuppressWarnings({"rawtypes"}) - private static void testValidatorSayHiFail(RestTemplate template, String cseUrlPrefix) { - boolean isExcep = false; - try { - template.exchange(cseUrlPrefix + "sayhi/{name}", HttpMethod.PUT, null, String.class, "te"); - } catch (InvocationException e) { - isExcep = true; - TestMgr.check(400, e.getStatus().getStatusCode()); - TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); - // Message dependends on locale, so just check the short part. - Map data = (Map) e.getErrorData(); - TestMgr.check( - true, data.get("message").toString().contains("propertyPath=sayHi.name")); - } - TestMgr.check(true, isExcep); - } - - private static void testValidatorSayHiSuccess(RestTemplate template, String cseUrlPrefix) { - ResponseEntity responseEntity = - template.exchange(cseUrlPrefix + "sayhi/{name}", HttpMethod.PUT, null, String.class, "world"); - TestMgr.check(202, responseEntity.getStatusCode()); - TestMgr.check("world sayhi", responseEntity.getBody()); - } - - @SuppressWarnings({"rawtypes"}) - private static void testValidatorExchangeFail(RestTemplate template, String cseUrlPrefix) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Accept", MediaType.APPLICATION_JSON); - Student student = new Student(); - student.setName(""); - student.setAge(25); - boolean isExcep = false; - try { - HttpEntity requestEntity = new HttpEntity<>(student, headers); - template.exchange(cseUrlPrefix + "/sayhello", - HttpMethod.POST, - requestEntity, - Student.class); - } catch (InvocationException e) { - isExcep = true; - TestMgr.check(400, e.getStatus().getStatusCode()); - TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); - // Message dependends on locale, so just check the short part. - Map data = (Map) e.getErrorData(); - TestMgr.check( - true, data.get("message").toString().contains("propertyPath=sayHello.student.age")); - } - TestMgr.check(true, isExcep); - } - - private static void testValidatorExchangeSuccess(RestTemplate template, String cseUrlPrefix) { - Student student = new Student(); - student.setName("test"); - student.setAge(15); - Student result = template.postForObject(cseUrlPrefix + "sayhello", student, Student.class); - TestMgr.check("hello test 15", result); - } - - private static void testClientTimeOut(RestTemplate template) { - String microserviceName = "jaxrs"; - for (String transport : DemoConst.transports) { - if (transport.equals(Const.ANY_TRANSPORT)) { - continue; - } - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); - - String cseUrlPrefix = "cse://" + microserviceName + "/clientreqtimeout/"; - - testClientTimeoutSayHi(template, cseUrlPrefix); - testClientTimeoutAdd(template, cseUrlPrefix); - } - } - - private static void testClientTimeoutSayHi(RestTemplate template, String cseUrlPrefix) { - Student student = new Student(); - student.setName("timeout"); - student.setAge(30); - Student result = template.postForObject(cseUrlPrefix + "sayhello", student, Student.class); - TestMgr.check("hello timeout 30", result); - } - - private static void testClientTimeoutAdd(RestTemplate template, String cseUrlPrefix) { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "20"); - boolean isExcep = false; - try { - template.postForObject(cseUrlPrefix + "add", params, Integer.class); - } catch (InvocationException e) { - isExcep = true; - TestMgr.check(490, e.getStatus().getStatusCode()); - TestMgr.check( - "CommonExceptionData [message=Cse Internal Bad Request]", - e.getErrorData()); - } - - TestMgr.check(true, isExcep); - } - - private static void testSpringMvcDefaultValuesJavaPrimitive(RestTemplate template) { - String microserviceName = "jaxrs"; - String cseUrlPrefix = "cse://" + microserviceName + "/JaxRSDefaultValues/"; - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); - MultiValueMap map = new LinkedMultiValueMap<>(); - HttpEntity> request = new HttpEntity<>(map, headers); - - //default values with primitive - String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", request, String.class); - TestMgr.check("Hello 0bobo", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", request, String.class); - TestMgr.check("Hello 0.0false", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", request, String.class); - TestMgr.check("Hello", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", request, String.class); - TestMgr.check("Hello nullnull", result); - - result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); - TestMgr.check("Hello false,0,0,0,0,0,0.0,0.0,null", result); - } -} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java index 8dd67e6f543..5eba5b94c95 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java @@ -19,95 +19,84 @@ import java.util.List; import java.util.Map; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.demo.DemoConst; +import org.apache.servicecomb.demo.CategorizedTestCase; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.multiErrorCode.MultiRequest; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse200; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse400; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse500; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; +import jakarta.ws.rs.core.Response.Status; -public class MultiErrorCodeServiceClient { +@Component +public class MultiErrorCodeServiceClient implements CategorizedTestCase { private static final String SERVER = "cse://jaxrs"; - private static String serverDirectURL; - - private static RestTemplate template = RestTemplateBuilder.create(); + private static RestOperations template = RestTemplateBuilder.create(); - public static void runTest() { - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport("jaxrs", transport); - - testErrorCode(); - testErrorCodeWithHeader(); - testErrorCodeWithHeaderJAXRS(); - testErrorCodeWithHeaderJAXRSUsingRowType(); - testNoClientErrorCode(); - } + @Override + public void testAllTransport() throws Exception { + testErrorCode(); + testErrorCodeWithHeader(); + testErrorCodeWithHeaderJAXRS(); + testErrorCodeWithHeaderJAXRSUsingRowType(); + testNoClientErrorCode(); + } - prepareServerDirectURL(); + @Override + public void testRestTransport() throws Exception { testErrorCodeWrongType(); } - private static void prepareServerDirectURL() { - Microservice microservice = RegistryUtils.getMicroservice(); - MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry() - .getAppManager() - .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "jaxrs", DefinitionConst.VERSION_RULE_ALL) - .getVersionedCache() - .mapData() - .values() - .stream() - .findFirst() - .get(); - URIEndpointObject edgeAddress = new URIEndpointObject(microserviceInstance.getEndpoints().get(0)); - serverDirectURL = String.format("http://%s:%d/", edgeAddress.getHostOrIp(), edgeAddress.getPort()); + @Override + public void testHighwayTransport() throws Exception { + } + private static void testErrorCodeWrongType() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); String body = "{\"message\":\"hello\",\"code\":\"wrongType\""; HttpEntity entity = new HttpEntity<>(body, headers); - ResponseEntity result; try { template - .postForEntity(serverDirectURL + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); - } catch (HttpClientErrorException e) { + .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); + TestMgr.fail("expect failed."); + } catch (InvocationException e) { TestMgr.check(e.getStatusCode(), 400); - TestMgr.check(e.getMessage(), "400 Bad Request"); } entity = new HttpEntity<>(null, headers); - result = template - .postForEntity(serverDirectURL + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); - TestMgr.check(result.getStatusCodeValue(), 590); + try { + template + .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); + TestMgr.fail("expect failed."); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 400); + } + // wrong type body = "{\"message\":\"hello\",\"code\":\"200\"}"; entity = new HttpEntity<>(body, headers); - result = template - .postForEntity(serverDirectURL + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); - TestMgr.check(result.getBody().getMessage(), "success result"); + try { + template + .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", entity, MultiResponse200.class); + TestMgr.fail("expect failed."); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 400); + } } private static void testErrorCode() { @@ -116,7 +105,7 @@ private static void testErrorCode() { request.setCode(200); ResponseEntity result = template .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); + TestMgr.check(result.getStatusCode().value(), 200); TestMgr.check(result.getBody().getMessage(), "success result"); request.setCode(400); @@ -146,7 +135,7 @@ private static void testErrorCodeWithHeader() { request.setCode(200); ResponseEntity result = template .postForEntity(SERVER + "/MultiErrorCodeService/errorCodeWithHeader", request, MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); + TestMgr.check(result.getStatusCode().value(), 200); TestMgr.check(result.getBody().getMessage(), "success result"); TestMgr.check(result.getBody().getCode(), 200); TestMgr.check(result.getHeaders().getFirst("x-code"), 200); @@ -181,7 +170,7 @@ private static void testErrorCodeWithHeaderJAXRS() { request.setMessage("success result"); ResponseEntity result = template .postForEntity(SERVER + "/MultiErrorCodeService/errorCodeWithHeaderJAXRS", request, MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); + TestMgr.check(result.getStatusCode().value(), 200); TestMgr.check(result.getBody().getMessage(), "success result"); TestMgr.check(result.getBody().getCode(), 200); TestMgr.check(result.getHeaders().getFirst("x-code"), 200); @@ -220,7 +209,7 @@ private static void testErrorCodeWithHeaderJAXRSUsingRowType() { ResponseEntity result = template .postForEntity(SERVER + "/MultiErrorCodeService/errorCodeWithHeaderJAXRS", requestJson, MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); + TestMgr.check(result.getStatusCode().value(), 200); TestMgr.check(result.getBody().getMessage(), "test message"); TestMgr.check(result.getBody().getCode(), 200); TestMgr.check(result.getHeaders().getFirst("x-code"), 200); @@ -233,16 +222,7 @@ private static void testErrorCodeWithHeaderJAXRSUsingRowType() { result = template .postForEntity(SERVER + "/MultiErrorCodeService/errorCodeWithHeaderJAXRS", new JsonObject(stringRequest), MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); - TestMgr.check(result.getBody().getMessage(), "test message"); - TestMgr.check(result.getBody().getCode(), 200); - TestMgr.check(result.getHeaders().getFirst("x-code"), 200); - - // using string - result = template - .postForEntity(SERVER + "/MultiErrorCodeService/errorCodeWithHeaderJAXRS", stringRequest, - MultiResponse200.class); - TestMgr.check(result.getStatusCode(), 200); + TestMgr.check(result.getStatusCode().value(), 200); TestMgr.check(result.getBody().getMessage(), "test message"); TestMgr.check(result.getBody().getCode(), 200); TestMgr.check(result.getHeaders().getFirst("x-code"), 200); @@ -256,7 +236,7 @@ private static void testNoClientErrorCode() { @SuppressWarnings("rawtypes") ResponseEntity listResult = template .postForEntity(SERVER + "/MultiErrorCodeService/noClientErrorCode", requestJson, List.class); - TestMgr.check(listResult.getStatusCode(), 200); + TestMgr.check(listResult.getStatusCode().value(), 200); Map mapResult = RestObjectMapperFactory.getRestObjectMapper().convertValue(listResult.getBody().get(0), Map.class); TestMgr.check(mapResult.get("message"), "test message"); diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/SchemeInterfaceJaxrs.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/SchemeInterfaceJaxrs.java new file mode 100644 index 00000000000..a074ad90423 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/SchemeInterfaceJaxrs.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import org.springframework.data.domain.Page; + +public interface SchemeInterfaceJaxrs { + int add(int a, int b); + + int reduce(int a, int b); + + Page interfaceModel(Page model); +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestClientTimeout.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestClientTimeout.java new file mode 100644 index 00000000000..7d8017eb38d --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestClientTimeout.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.validator.Student; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestClientTimeout implements CategorizedTestCase { + private static RestOperations template = RestTemplateBuilder.create(); + + public void testAllTransport() throws Exception { + testClientTimeOut(template); + } + + private static void testClientTimeOut(RestOperations template) { + String microserviceName = "jaxrs"; + + String cseUrlPrefix = "cse://" + microserviceName + "/clientreqtimeout/"; + + testClientTimeoutSayHi(template, cseUrlPrefix); + testClientTimeoutAdd(template, cseUrlPrefix); + } + + private static void testClientTimeoutSayHi(RestOperations template, String cseUrlPrefix) { + Student student = new Student(); + student.setName("timeout"); + student.setAge(30); + Student result = template.postForObject(cseUrlPrefix + "sayhello", student, Student.class); + TestMgr.check("hello timeout 30", result); + } + + private static void testClientTimeoutAdd(RestOperations template, String cseUrlPrefix) { + Map params = new HashMap<>(); + params.put("a", "5"); + params.put("b", "20"); + boolean failed = false; +// long failures = 0; +// ServiceCombServerStats serviceCombServerStats = null; + try { +// serviceCombServerStats = getServiceCombServerStats(); +// failures = serviceCombServerStats.getContinuousFailureCount(); + template.postForObject(cseUrlPrefix + "add", params, Integer.class); + } catch (InvocationException e) { + failed = true; + // implement timeout with same error code and message for rest and highway + TestMgr.check(408, e.getStatus().getStatusCode()); + // Request Timeout or Invocation Timeout + TestMgr.check(true, + e.getErrorData().toString().contains("Timeout.")); + } + + TestMgr.check(true, failed); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrs.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrs.java new file mode 100644 index 00000000000..4e6cbd97deb --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrs.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.server.User; +import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +@Component +public class TestCodeFirstJaxrs implements CategorizedTestCase { + interface DownloadInf { + ReadStreamPart testDeleteAfterFinished(String name, String content); + } + + private static final String SERVICE_NAME = "jaxrs"; + + private static final String SCHEMA_ID = "codeFirst"; + + @RpcReference(microserviceName = SERVICE_NAME, schemaId = SCHEMA_ID) + private DownloadInf downloadInf; + + @Override + public void testAllTransport() throws Exception { + testCodeFirstJaxrs(); + testResponseLong(); + } + + @Override + public void testHighwayTransport() throws Exception { + // test only once + testInstanceIsolation(); + } + + private void testInstanceIsolation() { + AtomicInteger e503Business = new AtomicInteger(0); + AtomicInteger e503CircuitBreaker = new AtomicInteger(0); + + for (int i = 0; i < 30; i++) { + try { + InvokerUtils.syncInvoke(SERVICE_NAME, SCHEMA_ID, "instanceIsolationTest", null, + String.class); + } catch (InvocationException e) { + if (e.getStatusCode() == 503) { + if ("CommonExceptionData [message=business]".equals(e.getErrorData().toString())) { + e503Business.getAndIncrement(); + } else if ("CommonExceptionData [message=instance isolation circuitBreaker is open.]".equals( + e.getErrorData().toString())) { + e503CircuitBreaker.getAndIncrement(); + } else { + TestMgr.fail("not expected message"); + } + } else { + TestMgr.fail("not expected code"); + } + } + } + TestMgr.check(true, e503Business.get() >= 10); + TestMgr.check(true, e503CircuitBreaker.get() >= 10); + } + + @Override + public void testRestTransport() throws Exception { + testDeleteAfterFinished(); + } + + private void testDeleteAfterFinished() throws Exception { + ReadStreamPart part = downloadInf.testDeleteAfterFinished("hello", "hello content"); + TestMgr.check(part.saveAsString().get(), "hello content"); + File systemTempFile = new File(System.getProperty("java.io.tmpdir")); + File file = new File(systemTempFile, "hello"); + TestMgr.check(file.exists(), false); + } + + private void testResponseLong() { + Object result = InvokerUtils.syncInvoke(SERVICE_NAME, SCHEMA_ID, "responseLong", null, + Object.class); + TestMgr.check(result, Long.MAX_VALUE); + } + + // invoke CodeFirstJaxrs + private void testCodeFirstJaxrs() { + Map swaggerArguments = new HashMap<>(); + Map userMap = new HashMap<>(); + User user = new User(); + user.setName("hello"); + userMap.put("user", user); + swaggerArguments.put("userMap", userMap); + TypeReference> type = new TypeReference>() { + }; + Map result = InvokerUtils.syncInvoke(SERVICE_NAME, SCHEMA_ID, "testUserMap", swaggerArguments, + type.getType()); + TestMgr.check(result.get("user").getName(), userMap.get("user").getName()); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrsReactive.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrsReactive.java new file mode 100644 index 00000000000..2fdaffe3edb --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestCodeFirstJaxrsReactive.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestCodeFirstJaxrsReactive implements CategorizedTestCase { + interface AddOperation { + CompletableFuture add(int a, int b); + } + + @RpcReference(microserviceName = "jaxrs", schemaId = "codeFirst") + AddOperation addOperation; + + @Override + public void testAllTransport() throws Exception { + final int count = 10; + CountDownLatch latch = new CountDownLatch(count); + AtomicInteger result = new AtomicInteger(0); + + for (int i = 0; i < count; i++) { + new Thread(() -> addOperation.add(1, 2) + .whenComplete((r, e) -> addOperation.add(r, r).whenComplete((r1, e1) -> { + result.addAndGet(r1); + latch.countDown(); + }))).start(); + } + + latch.await(3, TimeUnit.SECONDS); + TestMgr.check(count * 6, result.get()); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestDynamicConfig.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestDynamicConfig.java new file mode 100644 index 00000000000..9dfa234a923 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestDynamicConfig.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.util.Arrays; + +import org.apache.servicecomb.config.inject.InjectProperties; +import org.apache.servicecomb.config.inject.InjectProperty; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; + +@Component +public class TestDynamicConfig implements BootListener { + @InjectProperties(prefix = "jaxrstest.jaxrsclient") + public static class Configuration { + /* + * 方法的 prefix 属性值 "override" 会覆盖标注在类定义的 @InjectProperties + * 注解的 prefix 属性值。 + * + * keys属性可以为一个字符串数组,下标越小优先级越高。 + * + * 这里会按照如下顺序的属性名称查找配置属性,直到找到已被配置的配置属性,则停止查找: + * 1) jaxrstest.jaxrsclient.override.high + * 2) jaxrstest.jaxrsclient.override.low + * + * 测试用例: + * jaxrstest.jaxrsclient.override.high: hello high + * jaxrstest.jaxrsclient.override.low: hello low + * 预期: + * hello high + */ + @InjectProperty(prefix = "jaxrstest.jaxrsclient.override", keys = {"high", "low"}) + public String strValue; + + /** + * keys支持通配符,并在可以在将配置属性注入的时候指定通配符的代入对象。 + * + * 测试用例: + * jaxrstest.jaxrsclient.k.value: 3 + * 预期: + * 3 + */ + @InjectProperty(keys = "${key}.value") + public int intValue; + + /** + * 通配符的代入对象可以是一个字符串List,优先级遵循数组元素下标越小优先级越高策略。 + * + * 测试用例: + * jaxrstest.jaxrsclient.l1-1: 3.0 + * jaxrstest.jaxrsclient.l1-2: 2.0 + * + * 预期: + * 3.0 + */ + @InjectProperty(keys = "${full-list}") + public float floatValue; + + /** + * keys属性也支持多个通配符,优先级如下:首先通配符的优先级从左到右递减, + * 然后如果通配符被代入List,遵循List中元素index越小优先级越高策略。 + * + * 测试用例: + * jaxrstest.jaxrsclient.low-1.a.high-1.b: 1 + * jaxrstest.jaxrsclient.low-1.a.high-2.b: 2 + * jaxrstest.jaxrsclient.low-2.a.high-1.b: 3 + * jaxrstest.jaxrsclient.low-2.a.high-2.b: 4 + * 预期: + * 1 + */ + @InjectProperty(keys = "${low-list}.a.${high-list}.b") + public long longValue; + + /** + * 可以通过注解的defaultValue属性指定默认值。如果字段未关联任何配置属性, + * 定义的默认值会生效,否则默认值会被覆盖。 + * + * 测试用例: + * 预期: + * abc + */ + @InjectProperty(defaultValue = "abc") + public String strDef; + } + + @Override + public void onAfterRegistry(BootEvent event) { + Configuration configuration = SCBEngine.getInstance().getPriorityPropertyManager() + .createConfigObject(Configuration.class, + "key", "k", + "low-list", Arrays.asList("low-1", "low-2"), + "high-list", Arrays.asList("high-1", "high-2"), + "full-list", Arrays.asList("l1-1", "l1-2") + ); + TestMgr.check(configuration.strValue, "hello high"); + TestMgr.check(configuration.intValue, 3); + TestMgr.check(configuration.floatValue, 3.0); + TestMgr.check(configuration.longValue, 1); + TestMgr.check(configuration.strDef, "abc"); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFileUploadSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFileUploadSchema.java new file mode 100644 index 00000000000..049da2e47f9 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFileUploadSchema.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.jaxrs.client; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.MediaType; + +@Component +public class TestFileUploadSchema implements CategorizedTestCase { + @Override + public void testRestTransport() throws Exception { + testUpload(RestTemplateBuilder.create(), "servicecomb://jaxrs/fileUpload"); + } + + private void testUpload(RestOperations template, String cseUrlPrefix) throws IOException { + String file1Content = "Hello World"; + File file1 = File.createTempFile("jaxrstest1", ".txt"); + FileUtils.writeStringToFile(file1, file1Content, StandardCharsets.UTF_8, false); + + testFileUpload(template, cseUrlPrefix, file1, file1Content); + testFileAndStringUpload(template, cseUrlPrefix, file1, file1Content); + } + + private void testFileUpload(RestOperations template, String cseUrlPrefix, File file1, String file1Content) + throws IOException { + String result1 = template.postForObject(cseUrlPrefix + "/upload1", new HttpEntity<>(new HashMap<>()), String.class); + TestMgr.check("null file", result1); + + Map map = new HashMap<>(); + map.put("file1", new FileSystemResource(file1)); + String file2Content = "Hello EveryOne"; + File file2 = File.createTempFile("测试2", ".txt"); + FileUtils.writeStringToFile(file2, file2Content, StandardCharsets.UTF_8, false); + map.put("file2", new FileSystemResource(file2)); + String expect = String.format("%s:%s:%s\n" + "%s:%s:%s", + file1.getName(), + MediaType.TEXT_PLAIN, + file1Content, + file2.getName(), + MediaType.TEXT_PLAIN, + file2Content); + String result2 = template.postForObject(cseUrlPrefix + "/upload1", new HttpEntity<>(map), String.class); + TestMgr.check(expect, result2); + } + + private void testFileAndStringUpload(RestOperations template, String cseUrlPrefix, File file1, String file1Content) { + Map map = new HashMap<>(); + String message = "hi"; + map.put("file1", new FileSystemResource(file1)); + map.put("message", message); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + String expect = String.format("%s:%s:%s:%s", + file1.getName(), + MediaType.TEXT_PLAIN, + file1Content, + message); + String result = template.postForObject(cseUrlPrefix + "/upload2", new HttpEntity<>(map, headers), String.class); + TestMgr.check(expect, result); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFormRequestSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFormRequestSchema.java new file mode 100644 index 00000000000..591302058de --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestFormRequestSchema.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; + + +@Component +public class TestFormRequestSchema implements CategorizedTestCase { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestFormRequestSchema.class); + + private final RestOperations restTemplate = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testFormRequestFail(); + // testFormRequestFail会关闭连接,防止下个测试用例失败,睡眠2s + Thread.sleep(2000); + testFormRequestSuccess(); + testFormRequestBufferSize(); + } + + // formSize is less than default maxFormAttributeSize , success + private void testFormRequestSuccess() { + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("formData", "a".repeat(512)); + HttpEntity> requestEntity = new HttpEntity<>(formData, headers); + ResponseEntity responseEntity = restTemplate + .postForEntity("cse://jaxrs/form/formRequest", requestEntity, String.class); + TestMgr.check(responseEntity.getBody(), "formRequest success : 512"); + } catch (Throwable e) { + LOGGER.error("testFormRequestSuccess-->", e); + TestMgr.failed("", e); + } + } + + // formSize is greater than default maxFormAttributeSize , throw exception + private void testFormRequestFail() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("formData", "a".repeat(1688)); + HttpEntity> requestEntity = new HttpEntity<>(formData, headers); + try { + restTemplate.postForEntity("cse://jaxrs/form/formRequest", requestEntity, String.class); + TestMgr.fail("Size exceed allowed maximum capacity"); + } catch (Throwable e) { + TestMgr.check(e.getMessage().contains("Internal Server Error"), true); + } + } + + private void testFormRequestBufferSize() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap formData = new LinkedMultiValueMap<>(); + // we can not test a situation for form exceed max buffer size, because the netty buffer is very + // big and the trunc can always be decoded and cached buffer size is always 0. + formData.add("F0123456789001234567890012345678900123456789001234567890" + + "0123456789001234567890012345678900123456789001234567890", "a".repeat(1020) + // we can not test a situation for form exceed max buffer size, because the netty buffer is very + // big and the trunc can always be decoded and cached buffer size is always 0. + ); + HttpEntity> requestEntity = new HttpEntity<>(formData, headers); + try { + ResponseEntity responseEntity = + restTemplate.postForEntity("cse://jaxrs/form/formLongName", requestEntity, String.class); + TestMgr.check(responseEntity.getBody(), "formRequest success : 1020"); + } catch (Throwable e) { + LOGGER.error("testFormRequestBufferSize-->", e); + TestMgr.failed("", e); + } + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamSchema.java new file mode 100644 index 00000000000..8c0933172a6 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamSchema.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestQueryParamSchema implements CategorizedTestCase { + public interface QueryParamService { + String testQueryEncode(String param); + } + + private final RestOperations restTemplate = RestTemplateBuilder.create(); + + @RpcReference(microserviceName = "jaxrs", schemaId = "QueryParamSchema") + private QueryParamService queryParamService; + + @Override + public void testAllTransport() throws Exception { + testQueryParamEncodingPlus(); + } + + private void testQueryParamEncodingPlus() { + // should encode + + TestMgr.check("a+b", + restTemplate.getForObject("servicecomb://jaxrs/queryParam/testQueryEncode?param={1}", String.class, "a+b")); + // if not encoded, + should be blank + TestMgr.check("a b", + restTemplate.getForObject("servicecomb://jaxrs/queryParam/testQueryEncode?param=a+b", String.class)); + + // rpc should encode + TestMgr.check("a+b", queryParamService.testQueryEncode("a+b")); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamWithListSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamWithListSchema.java new file mode 100644 index 00000000000..19aa1c66ee8 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestQueryParamWithListSchema.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestQueryParamWithListSchema implements CategorizedTestCase { + private RestOperations restTemplate = RestTemplateBuilder.create(); + + @Override + public void testAllTransport() throws Exception { + testMulti(); + testCSV(); + testSSV(); + testPipes(); + } + + @Override + public void testRestTransport() throws Exception { + testMultiRest(); + testCSVRest(); + testSSVRest(); + testPipesRest(); + } + + @Override + // highway do not handle empty/default/null + public void testHighwayTransport() throws Exception { + testMultiHighway(); + testCSVHighway(); + testSSVHighway(); + testPipesHighway(); + } + + private void testCSVHighway() { + TestMgr.check("null", + restTemplate.getForObject("cse://jaxrs/queryList/queryListCSV?", String.class)); + } + + private void testCSVRest() { + TestMgr.check("0:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListCSV?", String.class)); + } + + private void testSSV() { + TestMgr.check("1:[1%202]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList=1%202", String.class)); + TestMgr.check("1:[%20]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList=%20", String.class)); + TestMgr.check("1:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList=", String.class)); + + TestMgr.check("2:[1, 2]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList={1}", String.class, "1 2")); + TestMgr.check("2:[, ]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList={1}", String.class, " ")); + TestMgr.check("1:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?queryList=", String.class)); + } + + private void testPipesHighway() { + TestMgr.check("null", + restTemplate.getForObject("cse://jaxrs/queryList/queryListPIPES?", String.class)); + } + + private void testPipesRest() { + TestMgr.check("0:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListPIPES?", String.class)); + } + + private void testPipes() { + TestMgr.check("2:[1, 2]", + restTemplate + .getForObject("cse://jaxrs/queryList/queryListPIPES?queryList={1}", String.class, "1|2")); + TestMgr.check("2:[, ]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListPIPES?queryList={1}", String.class, "|")); + TestMgr.check("1:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListPIPES?queryList=", String.class)); + } + + private void testSSVHighway() { + TestMgr.check("null", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?", String.class)); + } + + private void testSSVRest() { + TestMgr.check("0:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListSSV?", String.class)); + } + + private void testCSV() { + TestMgr.check("2:[1, 2]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListCSV?queryList=1,2", String.class)); + TestMgr.check("2:[, ]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListCSV?queryList=,", String.class)); + TestMgr.check("1:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListCSV?queryList=", String.class)); + } + + private void testMultiHighway() { + TestMgr.check("null", + restTemplate.getForObject("cse://jaxrs/queryList/queryListMULTI?", String.class)); + } + + private void testMultiRest() { + TestMgr.check("0:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListMULTI?", String.class)); + } + + private void testMulti() { + TestMgr.check("2:[1, 2]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListMULTI?queryList=1&queryList=2", String.class)); + TestMgr.check("2:[, ]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListMULTI?queryList=&queryList=", String.class)); + TestMgr.check("1:[]", + restTemplate.getForObject("cse://jaxrs/queryList/queryListMULTI?queryList=", String.class)); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestReactiveSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestReactiveSchema.java new file mode 100644 index 00000000000..6126c053ad3 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestReactiveSchema.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.util.Map; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestReactiveSchema implements CategorizedTestCase { + @SuppressWarnings("rawtypes") + public void testRestTransport() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + try { + restTemplate.getForObject("cse://jaxrs/reactive/testSyncInvokeInEventLoop?a=1&b=2", int.class); + TestMgr.check(true, false); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 500); + TestMgr.check(((Map) e.getErrorData()).get("message"), + "Unexpected exception when processing jaxrs.ReactiveSchema.testSyncInvokeInEventLoop. " + + "Can not execute sync logic in event loop."); + } + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestSchemeInterfaceJaxrs.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestSchemeInterfaceJaxrs.java new file mode 100644 index 00000000000..dd53006df29 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/TestSchemeInterfaceJaxrs.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; + +@Component +public class TestSchemeInterfaceJaxrs implements CategorizedTestCase { + @RpcReference(schemaId = "SchemeInterfaceJaxrs", microserviceName = "jaxrs") + private SchemeInterfaceJaxrs jaxrs; + + public void testRestTransport() throws Exception { + List contents = new ArrayList<>(); + contents.add("hello"); + Sort sort = Sort.by(new String[0]); + Pageable pageable = PageRequest.of(1, 10, sort); + Page pages = new PageImpl<>(contents, pageable, 1); + Page result = jaxrs.interfaceModel(pages); + TestMgr.check("hello", result.stream().findFirst().get()); + } + + public void testAllTransport() throws Exception { + TestMgr.check(3, jaxrs.add(1, 2)); + TestMgr.check(0, jaxrs.add(-1, 1)); + + try { + jaxrs.reduce(1, 3); + TestMgr.failed("should throw exception", new Exception()); + } catch (InvocationException e) { + TestMgr.check( + "Consumer method org.apache.servicecomb.demo.jaxrs.client.SchemeInterfaceJaxrs:reduce " + + "not exist in contract, microserviceName=jaxrs, schemaId=SchemeInterfaceJaxrs.", + ((CommonExceptionData) e.getError()).getMessage()); + } + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamPojoClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamPojoClient.java index cf70f8e4060..5f34487335a 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamPojoClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamPojoClient.java @@ -19,22 +19,37 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import org.apache.servicecomb.demo.CategorizedTestCase; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.provider.pojo.Invoker; +import org.springframework.stereotype.Component; -public class BeanParamPojoClient { +@Component +public class BeanParamPojoClient implements CategorizedTestCase { private BeanParamTestServiceIntf beanParamTestServiceIntf; public BeanParamPojoClient() { beanParamTestServiceIntf = Invoker.createProxy("jaxrs", "beanParamTest", BeanParamTestServiceIntf.class); } - public void testAll() { + @Override + public void testRestTransport() throws Exception { testBeanParam(); testUpload(); } + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + testBeanParam(); + } + private void testBeanParam() { String result = beanParamTestServiceIntf.beanParameterTest("querySwaggerValue", 2, "pathSwaggerValue", 10, "extra"); TestMgr.check( @@ -44,9 +59,9 @@ private void testBeanParam() { } private void testUpload() { - BufferedInputStream bufferedInputStream0 = new BufferedInputStream(new ByteArrayInputStream("up0".getBytes())); - BufferedInputStream bufferedInputStream1 = new BufferedInputStream(new ByteArrayInputStream("up1".getBytes())); - BufferedInputStream bufferedInputStream2 = new BufferedInputStream(new ByteArrayInputStream("up2".getBytes())); + BufferedInputStream bufferedInputStream0 = new BufferedInputStream(new ByteArrayInputStream("up0".getBytes(StandardCharsets.UTF_8))); + BufferedInputStream bufferedInputStream1 = new BufferedInputStream(new ByteArrayInputStream("up1".getBytes(StandardCharsets.UTF_8))); + BufferedInputStream bufferedInputStream2 = new BufferedInputStream(new ByteArrayInputStream("up2".getBytes(StandardCharsets.UTF_8))); String result = beanParamTestServiceIntf.beanParameterTestUpload( bufferedInputStream0, "queryTest", bufferedInputStream1, bufferedInputStream2, "ex"); diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamRestTemplateClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamRestTemplateClient.java index 82422d99f49..decb4a4207f 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamRestTemplateClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/beanParam/BeanParamRestTemplateClient.java @@ -19,9 +19,11 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import org.apache.servicecomb.demo.CategorizedTestCase; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; @@ -30,22 +32,35 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; -public class BeanParamRestTemplateClient { - RestTemplate restTemplate; +@Component +public class BeanParamRestTemplateClient implements CategorizedTestCase { + RestOperations restTemplate; public BeanParamRestTemplateClient() { restTemplate = RestTemplateBuilder.create(); } - public void testAll() { + @Override + public void testRestTransport() throws Exception { testBeanParam(); testUpload(); } - public void testBeanParam() { + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + testBeanParam(); + } + + private void testBeanParam() { HttpHeaders headers = new HttpHeaders(); headers.add("Cookie", "cookieSwaggerLong=11"); headers.add("headerSwaggerInt", "2"); @@ -61,10 +76,13 @@ public void testBeanParam() { result.getBody()); } - public void testUpload() { - BufferedInputStream bufferedInputStream0 = new BufferedInputStream(new ByteArrayInputStream("up0".getBytes())); - BufferedInputStream bufferedInputStream1 = new BufferedInputStream(new ByteArrayInputStream("up1".getBytes())); - BufferedInputStream bufferedInputStream2 = new BufferedInputStream(new ByteArrayInputStream("up2".getBytes())); + private void testUpload() { + BufferedInputStream bufferedInputStream0 = new BufferedInputStream( + new ByteArrayInputStream("up0".getBytes(StandardCharsets.UTF_8))); + BufferedInputStream bufferedInputStream1 = new BufferedInputStream( + new ByteArrayInputStream("up1".getBytes(StandardCharsets.UTF_8))); + BufferedInputStream bufferedInputStream2 = new BufferedInputStream( + new ByteArrayInputStream("up2".getBytes(StandardCharsets.UTF_8))); HashMap formData = new HashMap<>(); formData.put("up0", bufferedInputStream0); diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/injectBean/TestInjectBeanSchema.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/injectBean/TestInjectBeanSchema.java new file mode 100644 index 00000000000..02d1ee1d97e --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/injectBean/TestInjectBeanSchema.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.client.injectBean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestInjectBeanSchema implements CategorizedTestCase { + RestOperations restTemplate = RestTemplateBuilder.create(); + + @Override + public void testAllTransport() throws Exception { + boolean result = restTemplate.getForObject("cse://jaxrs/injectSet", boolean.class); + TestMgr.check(true, result); + } +} diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java index f6dedf1ef5d..a221853b6a8 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java @@ -17,20 +17,20 @@ package org.apache.servicecomb.demo.jaxrs.client.pojoDefault; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.jaxrs.server.pojoDefault.DefaultResponseModel; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; public class DefaultModelServiceClient { - private static RestTemplate template = RestTemplateBuilder.create(); + private static RestOperations template = RestTemplateBuilder.create(); private static String urlPrefix = "cse://jaxrs/DefaultModelService"; public static void run() { // highway do not support this feature - CseContext.getInstance().getConsumerProviderManager().setTransport("jaxrs", "rest"); + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport.jaxrs", "rest"); testDefaultModelService(); } diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java index 5600ddaaad3..4b99fff0359 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java @@ -19,23 +19,25 @@ import java.util.ArrayList; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.jaxrs.server.validation.ValidationModel; +import org.apache.servicecomb.demo.validator.Teacher; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.Response.Status; public class ValidationServiceClient { - private static RestTemplate template = RestTemplateBuilder.create(); + private static RestOperations template = RestTemplateBuilder.create(); private static String urlPrefix = "cse://jaxrs/ValidationService"; public static void run() { // highway do not support this feature - CseContext.getInstance().getConsumerProviderManager().setTransport("jaxrs", "rest"); + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport.jaxrs", "rest"); testValidation(); } @@ -70,8 +72,17 @@ private static void testValidation() { TestMgr.check(e.getErrorData().toString().contains("propertyPath=errorCode.request.members"), true); } - String strResult = template.getForObject(urlPrefix + "/validateQuery?name=", String.class); - TestMgr.check(strResult, ""); + try { + template.postForObject(urlPrefix + "/validate", null, ValidationModel.class); + TestMgr.check(false, true); + } catch (InvocationException e) { + TestMgr.check(400, e.getStatus().getStatusCode()); + TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); + TestMgr.check(e.getErrorData().toString().contains("propertyPath=errorCode.request"), true); + } + + String strResult = template.getForObject(urlPrefix + "/validateQuery?name=a", String.class); + TestMgr.check(strResult, "a"); try { template.getForObject(urlPrefix + "/validateQuery", String.class); @@ -79,7 +90,27 @@ private static void testValidation() { } catch (InvocationException e) { TestMgr.check(400, e.getStatus().getStatusCode()); TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase()); - TestMgr.check(e.getErrorData().toString().contains("propertyPath=queryValidate.name"), true); + TestMgr.check(((CommonExceptionData) e.getErrorData()).getMessage().contains("Parameter is not valid"), true); + } + + Teacher teacher = new Teacher(); + teacher.setName("teacher"); + teacher.setAge("20"); + Teacher response = template.postForObject(urlPrefix + "/sayTeacherInfo", teacher, Teacher.class); + TestMgr.check(response.getName(), "teacher"); + + try { + teacher = new Teacher(); + teacher.setAge("20"); + template.postForObject(urlPrefix + "/sayTeacherInfo", teacher, Teacher.class); + TestMgr.fail("Name should not empty"); + } catch (InvocationException e) { + TestMgr.check(400, e.getStatus().getStatusCode()); + TestMgr.check(e.getErrorData().toString().contains("must not be blank"), true); } + + // jax-rs body default required = false + response = template.postForObject(urlPrefix + "/sayTeacherInfo", null, Teacher.class); + TestMgr.check(null, response); } } diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java index 6c4350a07f4..ea5c2072ff5 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java @@ -17,9 +17,9 @@ package org.apache.servicecomb.demo.jaxrs.server.pojoDefault; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.Null; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Null; public class DefaultResponseModel { @Min(20) diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/resources/log4j2.xml b/demo/demo-jaxrs/jaxrs-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml b/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml index 1559f535833..07493f07ef8 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml +++ b/demo/demo-jaxrs/jaxrs-client/src/main/resources/microservice.yaml @@ -15,23 +15,31 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: jaxrstest -service_description: - name: jaxrsClient - version: 0.0.1 servicecomb: service: - registry: + application: jaxrstest + name: jaxrsClient + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance - loadbalance: - strategy: - name: mycustomrule - retryEnabled: true - retryHandler: mycustomhandler + enableSwaggerRegistration: true + + matchGroup: + instanceIsolationTest: | + matches: + - apiPath: + prefix: "/codeFirstJaxrs/instanceIsolationTest" + instanceIsolation: + instanceIsolationTest: | + minimumNumberOfCalls: 10 + slidingWindowSize: 20 + slidingWindowType: COUNT_BASED + failureRateThreshold: 50 + slowCallRateThreshold: 100 + slowCallDurationThreshold: 3000 + waitDurationInOpenState: 200 + permittedNumberOfCallsInHalfOpenState: 10 request: timeout: 30000 @@ -42,4 +50,45 @@ servicecomb: sayHello: timeout: 30000 add: - timeout: 1000 \ No newline at end of file + timeout: 1000 + + invocation: + timeout: + check: + enabled: false + + # use service center to find schema info + openAPI: + registry: + # enable service center OpenAPI registry, and need set enableSwaggerRegistration: true + registry: + enabled: true + # disable instance OpenAPI registry + instance: + enabled: false + + # test configurations. you can choose any implementation. default using local. + + # using nacos configuration + # nacos: + # serverAddr: http://127.0.0.1:8848 + # group: jaxrstest + # dataId: jaxrsclient + # namespace: public + # contentType: properties # can be properties, yaml, raw. If using raw, property [group].[dataId]=value. + # addPrefix: false # if true [group].[dataId] will added as properties/yaml items prefix. Will not influence raw. + + # for integration test not install any config server +jaxrstest: + jaxrsclient: + override.high: hello high + override.low: hello low + k.value: 3 + l1-1: 3.0 + l1-2: 2.0 + low-1.a.high-1.b: 1 + low-1.a.high-2.b: 2 + low-2.a.high-1.b: 3 + low-2.a.high-2.b: 4 + +# test configurations. diff --git a/demo/demo-jaxrs/jaxrs-client/src/test/java/org/apache/servicecomb/demo/jaxrs/JaxrsIT.java b/demo/demo-jaxrs/jaxrs-client/src/test/java/org/apache/servicecomb/demo/jaxrs/JaxrsIT.java new file mode 100644 index 00000000000..c1bb351ba5d --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-client/src/test/java/org/apache/servicecomb/demo/jaxrs/JaxrsIT.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = JaxrsClient.class) +public class JaxrsIT { + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + JaxrsClient.run(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/pom.xml b/demo/demo-jaxrs/jaxrs-server/pom.xml index b55f930480b..cc80ad1521c 100644 --- a/demo/demo-jaxrs/jaxrs-server/pom.xml +++ b/demo/demo-jaxrs/jaxrs-server/pom.xml @@ -23,7 +23,7 @@ org.apache.servicecomb.demo demo-jaxrs - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT jaxrs-server Java Chassis::Demo::JAXRS::Server @@ -32,41 +32,28 @@ org.apache.servicecomb.demo demo-schema - - org.apache.servicecomb - provider-jaxrs - org.glassfish.jersey.core jersey-client + + org.glassfish.jersey.core + jersey-common + org.apache.servicecomb swagger-invocation-validator - org.apache.servicecomb.demo.jaxrs.server.JaxrsServer + org.apache.servicecomb.demo.jaxrs.JaxrsServer - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - ${project.version} - - - + org.springframework.boot + spring-boot-maven-plugin @@ -74,15 +61,50 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsServer.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsServer.java new file mode 100644 index 00000000000..4cd136d0fbc --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/JaxrsServer.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; +import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class JaxrsServer { + public static void main(String[] args) throws Exception { + new SpringApplicationBuilder(JaxrsServer.class).web(WebApplicationType.NONE).run(args); + + RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); + RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/CodeFirstJaxrs.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/CodeFirstJaxrs.java index 63fc02488b0..8626f86087a 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/CodeFirstJaxrs.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/CodeFirstJaxrs.java @@ -17,70 +17,68 @@ package org.apache.servicecomb.demo.jaxrs.server; +import java.io.File; import java.io.IOException; -import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; -import javax.ws.rs.Consumes; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; - -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.FileUtils; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.demo.ignore.InputModelForTestIgnore; import org.apache.servicecomb.demo.ignore.OutputModelForTestIgnore; -import org.apache.servicecomb.demo.jaxbbean.JAXBPerson; import org.apache.servicecomb.demo.server.User; +import org.apache.servicecomb.foundation.common.part.FilePart; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.response.Headers; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.vertx.core.json.JsonObject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; @RestSchema(schemaId = "codeFirst") @Path("/codeFirstJaxrs") @Produces(MediaType.APPLICATION_JSON) public class CodeFirstJaxrs { - // public Response getUserResponse() { - // - // } - @ApiResponse(code = 200, response = User.class, message = "") - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = User.class)), description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) @Path("/cseResponse") @GET public Response cseResponse(InvocationContext c1) { Response response = Response.createSuccess(Status.ACCEPTED, new User()); - Headers headers = response.getHeaders(); - headers.addHeader("h1", "h1v " + c1.getContext().get(Const.SRC_MICROSERVICE).toString()); + response.setHeader("h1", "h1v " + c1.getContext().get(CoreConst.SRC_MICROSERVICE)); InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.addHeader("h2", "h2v " + c2.getContext().get(Const.SRC_MICROSERVICE).toString()); + response.setHeader("h2", "h2v " + c2.getContext().get(CoreConst.SRC_MICROSERVICE)); return response; } @@ -98,14 +96,6 @@ public String textPlain(String body) { return body; } - @Path("/appXml") - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_XML) - public JAXBPerson appXml(JAXBPerson body) { - return body; - } - @Path("/bytes") @POST public byte[] bytes(byte[] input) { @@ -132,7 +122,7 @@ public int add(@FormParam("a") int a, @FormParam("b") int b) { @Path("/reduce") @GET - @ApiImplicitParams({@ApiImplicitParam(name = "a", dataType = "integer", format = "int32", paramType = "query")}) + @Parameters({@Parameter(name = "a", schema = @Schema(implementation = int.class), in = ParameterIn.QUERY)}) public int reduce(HttpServletRequest request, @CookieParam("b") int b) { int a = Integer.parseInt(request.getParameter("a")); return a - b; @@ -151,7 +141,8 @@ public Person sayHello(Person user) { public String testRawJsonString(String jsonInput) { Map person; try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); + person = RestObjectMapperFactory.getRestObjectMapper() + .readValue(jsonInput.getBytes(StandardCharsets.UTF_8), Map.class); } catch (Exception e) { e.printStackTrace(); return null; @@ -188,11 +179,11 @@ public boolean isTrue() { @DELETE @Produces(MediaType.TEXT_PLAIN) public String addString(@QueryParam("s") List s) { - String result = ""; + StringBuilder result = new StringBuilder(); for (String x : s) { - result += x; + result.append(x); } - return result; + return result.toString(); } @Path("/ignore") @@ -210,7 +201,8 @@ public OutputModelForTestIgnore testModelWithIgnoreField(InputModelForTestIgnore public String testRawJsonAnnotation(@RawJsonRequestBody String jsonInput) { Map person; try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); + person = RestObjectMapperFactory.getRestObjectMapper() + .readValue(jsonInput.getBytes(StandardCharsets.UTF_8), Map.class); } catch (Exception e) { e.printStackTrace(); return null; @@ -221,40 +213,37 @@ public String testRawJsonAnnotation(@RawJsonRequestBody String jsonInput) { @Path("/traceId") @GET public String getTraceId() { - return ContextUtils.getInvocationContext().getContext(Const.TRACE_ID_NAME); + return ContextUtils.getInvocationContext().getContext(CoreConst.TRACE_ID_NAME); } - @Path("/upload1") - @POST - @Produces(MediaType.TEXT_PLAIN) - public String fileUpload1(@FormParam("file1") Part file1, @FormParam("file2") Part file2) throws IOException { - if (file1 == null || file2 == null) { - return "null file"; - } - try (InputStream is1 = file1.getInputStream(); InputStream is2 = file2.getInputStream()) { - String content1 = IOUtils.toString(is1); - String content2 = IOUtils.toString(is2); - return String.format("%s:%s:%s\n" + "%s:%s:%s", - file1.getSubmittedFileName(), - file1.getContentType(), - content1, - file2.getSubmittedFileName(), - file2.getContentType(), - content2); - } + @GET + @Path("/responseLong") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Object.class)), description = "") + public Response responseLong() { + return Response.createSuccess(Long.MAX_VALUE); } - @Path("/upload2") - @POST - @Produces(MediaType.TEXT_PLAIN) - public String fileUpload2(@FormParam("file1") Part file1, @FormParam("message") String message) throws IOException { - try (InputStream is1 = file1.getInputStream()) { - String content1 = IOUtils.toString(is1); - return String.format("%s:%s:%s:%s", - file1.getSubmittedFileName(), - file1.getContentType(), - content1, - message); - } + @Path("/download/testDeleteAfterFinished") + @GET + public Part testDeleteAfterFinished(@QueryParam("name") String name, @QueryParam("content") String content) + throws IOException { + File file = createTempFile(name, content); + + return new FilePart(null, file) + .setDeleteAfterFinished(true) + .setSubmittedFileName(name); + } + + @Path("/instanceIsolationTest") + @GET + public String instanceIsolationTest() { + throw new InvocationException(503, "", "business"); + } + + private File createTempFile(String name, String content) throws IOException { + File systemTempFile = new File(System.getProperty("java.io.tmpdir")); + File file = new File(systemTempFile, name); + FileUtils.write(file, content, StandardCharsets.UTF_8, false); + return file; } } diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ComputeImpl.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ComputeImpl.java index 9797901b0f1..e5735de44fe 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ComputeImpl.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ComputeImpl.java @@ -17,22 +17,9 @@ package org.apache.servicecomb.demo.jaxrs.server; +import java.nio.charset.StandardCharsets; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; - import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.provider.rest.common.RestSchema; @@ -40,6 +27,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; + @RestSchema(schemaId = "compute") @Path("/compute") @Produces(MediaType.APPLICATION_JSON) @@ -54,6 +59,8 @@ public int add(@FormParam("a") int a, @FormParam("b") int b) { @Path("/reduce") @GET + @Parameters(value = {@Parameter(in = ParameterIn.QUERY, name = "a", schema = @Schema(implementation = int.class)), + @Parameter(in = ParameterIn.QUERY, name = "b", schema = @Schema(implementation = int.class))}) public int reduce(@Context HttpServletRequest request) { int a = Integer.parseInt(request.getParameter("a")); int b = Integer.parseInt(request.getParameter("b")); @@ -73,7 +80,8 @@ public Person sayHello(Person user) { public String testRawJsonString(String jsonInput) { Map person; try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); + person = RestObjectMapperFactory.getRestObjectMapper() + .readValue(jsonInput.getBytes(StandardCharsets.UTF_8), Map.class); } catch (Exception e) { e.printStackTrace(); return null; @@ -116,10 +124,10 @@ public boolean isTrue() { @DELETE @Produces(MediaType.TEXT_PLAIN) public String addString(@QueryParam("s") String[] s) { - String result = ""; + StringBuilder result = new StringBuilder(); for (String x : s) { - result += x; + result.append(x); } - return result; + return result.toString(); } } diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FileUploadSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FileUploadSchema.java new file mode 100644 index 00000000000..dfaac37fa2d --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FileUploadSchema.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.jaxrs.server; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +/** + * Test and illustrate JaxRS uploads. + * + * Use @FormParam to annotate a multipart/form-data item. + */ +@RestSchema(schemaId = "FileUploadSchema") +@Path("/fileUpload") +public class FileUploadSchema { + @Path("/upload1") + @POST + @Produces(MediaType.TEXT_PLAIN) + public String fileUpload1(@FormParam("file1") Part file1, @FormParam("file2") Part file2) throws IOException { + if (file1 == null || file2 == null) { + return "null file"; + } + try (InputStream is1 = file1.getInputStream(); InputStream is2 = file2.getInputStream()) { + String content1 = IOUtils.toString(is1, StandardCharsets.UTF_8); + String content2 = IOUtils.toString(is2, StandardCharsets.UTF_8); + return String.format("%s:%s:%s\n" + "%s:%s:%s", + file1.getSubmittedFileName(), + file1.getContentType(), + content1, + file2.getSubmittedFileName(), + file2.getContentType(), + content2); + } + } + + @Path("/upload2") + @POST + @Produces(MediaType.TEXT_PLAIN) + public String fileUpload2(@FormParam("file1") Part file1, @FormParam("message") String message) throws IOException { + try (InputStream is1 = file1.getInputStream()) { + String content1 = IOUtils.toString(is1, StandardCharsets.UTF_8); + return String.format("%s:%s:%s:%s", + file1.getSubmittedFileName(), + file1.getContentType(), + content1, + message); + } + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FormRequestSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FormRequestSchema.java new file mode 100644 index 00000000000..2670681217a --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/FormRequestSchema.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "FormRequestSchema") +@Path("/form") +@Produces(MediaType.APPLICATION_JSON) +public class FormRequestSchema { + + @Path("/formRequest") + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String formRequestSuccess(@FormParam("formData") String formData) throws Exception { + return "formRequest success : " + formData.length(); + } + + @Path("/formLongName") + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String formLongName(@FormParam("F0123456789001234567890012345678900123456789001234567890" + + "0123456789001234567890012345678900123456789001234567890") String formData) throws Exception { + return "formRequest success : " + formData.length(); + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java index 5a2788e648b..17769d3c291 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java @@ -16,21 +16,21 @@ */ package org.apache.servicecomb.demo.jaxrs.server; -import javax.servlet.http.HttpServletRequest; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import javax.ws.rs.Consumes; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.provider.rest.common.RestSchema; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java deleted file mode 100644 index 02584744559..00000000000 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsDemoHttpServerFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.server; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JaxrsDemoHttpServerFilter implements HttpServerFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(JaxrsDemoHttpServerFilter.class); - - @Override - public int getOrder() { - return 0; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - return null; - } - - @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - // in 404 situation, invocation is null and a NPE is thrown - LOGGER.info("JaxrsDemoHttpServerFilter is called, operation=[{}]", invocation.getOperationName()); - } -} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java deleted file mode 100644 index 3b2d952a378..00000000000 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.server; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class JaxrsServer { - public static void main(String[] args) throws Exception { - RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); - RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); - - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamSchema.java new file mode 100644 index 00000000000..80985d68541 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamSchema.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "QueryParamSchema") +@Path("/queryParam") +public class QueryParamSchema { + @Path("testQueryEncode") + @GET + public String testQueryEncode(@QueryParam("param") String param) { + return param; + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamWithListSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamWithListSchema.java new file mode 100644 index 00000000000..d15849423ac --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/QueryParamWithListSchema.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import java.util.List; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.ParameterStyle; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +@RestSchema(schemaId = "QueryParamWithListSchema") +@Path("/queryList") +public class QueryParamWithListSchema { + @Path("queryListCSV") + @GET + public String queryListCSV( + @Parameter(name = "queryList", in = ParameterIn.QUERY, style = ParameterStyle.FORM, explode = Explode.FALSE) + @QueryParam("queryList") List queryList) { + return queryList == null ? "null" : queryList.size() + ":" + queryList; + } + + @Path("queryListSSV") + @GET + public String queryListSSV( + @Parameter(name = "queryList", in = ParameterIn.QUERY, style = ParameterStyle.SPACEDELIMITED, explode = Explode.FALSE) + @QueryParam("queryList") List queryList) { + return queryList == null ? "null" : queryList.size() + ":" + queryList; + } + + @Path("queryListPIPES") + @GET + public String queryListPIPES( + @Parameter(name = "queryList", in = ParameterIn.QUERY, style = ParameterStyle.PIPEDELIMITED, explode = Explode.FALSE) + @QueryParam("queryList") List queryList) { + return queryList == null ? "null" : queryList.size() + ":" + queryList; + } + + @Path("queryListMULTI") + @GET + public String queryListMULTI( + @Parameter(name = "queryList", in = ParameterIn.QUERY, style = ParameterStyle.FORM, explode = Explode.TRUE) + @QueryParam("queryList") List queryList) { + return queryList == null ? "null" : queryList.size() + ":" + queryList; + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ReactiveSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ReactiveSchema.java new file mode 100644 index 00000000000..2143d27a04c --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/ReactiveSchema.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ReactiveSchema") +@Path("/reactive") +@Produces(MediaType.APPLICATION_JSON) +public class ReactiveSchema { + // reactive is configured to run in event-loop thread pool + @Path("/testSyncInvokeInEventLoop") + @GET + public int testSyncInvokeInEventLoop(@QueryParam("a") int a, @QueryParam("b") int b) { + RestOperations client = RestTemplateBuilder.create(); + return client.getForObject("cse://jaxrs/compute/reduce?a=1&b=2", int.class); + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/RequestClientTimeOut.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/RequestClientTimeOut.java index 387165123d6..2f17c2fc6f8 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/RequestClientTimeOut.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/RequestClientTimeOut.java @@ -17,11 +17,11 @@ package org.apache.servicecomb.demo.jaxrs.server; -import javax.ws.rs.FormParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.demo.validator.Student; import org.apache.servicecomb.provider.rest.common.RestSchema; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrs.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrs.java new file mode 100644 index 00000000000..c9c9b311535 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrs.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.RequestParam; + +@Path("/jaxrs/schemaInterface") +@Produces(MediaType.APPLICATION_JSON) +public interface SchemeInterfaceJaxrs { + @Path("/add") + @GET + int add(@Min(-100) @RequestParam("a") int a, @Min(1) @RequestParam("b") int b); + + @Path("/interfaceModel") + @GET + Page interfaceModel(Page model); +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrsImpl.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrsImpl.java new file mode 100644 index 00000000000..a551644834e --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/SchemeInterfaceJaxrsImpl.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.data.domain.Page; + +@RestSchema(schemaId = "SchemeInterfaceJaxrs", schemaInterface = SchemeInterfaceJaxrs.class) +public class SchemeInterfaceJaxrsImpl implements SchemeInterfaceJaxrs { + @Override + public int add(int a, int b) { + return a + b; + } + + public int reduce(int a, int b) { + return a - b; + } + + public int add(String a, String b) { + return Integer.parseInt(a) + Integer.parseInt(b); + } + + @Override + public Page interfaceModel(Page model) { + return model; + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/Validator.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/Validator.java index 9f5bef60ae6..a5c5f9b8332 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/Validator.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/Validator.java @@ -17,15 +17,15 @@ package org.apache.servicecomb.demo.jaxrs.server; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.ws.rs.FormParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.demo.validator.Student; import org.apache.servicecomb.provider.rest.common.RestSchema; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/BeanParamTestService.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/BeanParamTestService.java index 1e2a040bc62..8f037cff595 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/BeanParamTestService.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/BeanParamTestService.java @@ -20,15 +20,15 @@ import java.io.IOException; import java.util.Scanner; -import javax.servlet.http.Part; -import javax.ws.rs.BeanParam; -import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameter.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameter.java index 489b29c567d..3ccff412a5e 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameter.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameter.java @@ -17,11 +17,11 @@ package org.apache.servicecomb.demo.jaxrs.server.beanParam; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameterWithUpload.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameterWithUpload.java index 80530aba63d..b6e3685ef47 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameterWithUpload.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/beanParam/TestBeanParameterWithUpload.java @@ -17,9 +17,9 @@ package org.apache.servicecomb.demo.jaxrs.server.beanParam; -import javax.servlet.http.Part; -import javax.ws.rs.FormParam; -import javax.ws.rs.QueryParam; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.QueryParam; public class TestBeanParameterWithUpload { @QueryParam("query") diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBean.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBean.java new file mode 100644 index 00000000000..60ef5241e9a --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBean.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server.injectBean; + +import org.springframework.stereotype.Component; + +@Component +public class InjectBean { + private boolean set = true; + + public boolean isSet() { + return set; + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanSchema.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanSchema.java new file mode 100644 index 00000000000..59395b02687 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanSchema.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server.injectBean; + +import java.util.List; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher; + +@RestSchema(schemaId = "InjectBeanSchema") +@Path("/") +public class InjectBeanSchema { + @Path("/injectSet") + @GET + public boolean injectSet() { + List services = SPIServiceUtils.getOrLoadSortedService(VertxHttpDispatcher.class); + for (VertxHttpDispatcher service : services) { + if (service instanceof InjectBeanVertxHttpDispatcher) { + return ((InjectBeanVertxHttpDispatcher) service).isSet(); + } + } + return false; + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanVertxHttpDispatcher.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanVertxHttpDispatcher.java new file mode 100644 index 00000000000..347ba9473ab --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/injectBean/InjectBeanVertxHttpDispatcher.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.jaxrs.server.injectBean; + +import org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher; +import org.springframework.beans.factory.annotation.Autowired; + +import io.vertx.ext.web.Router; + +public class InjectBeanVertxHttpDispatcher implements VertxHttpDispatcher { + private InjectBean injectBean; + + @Autowired + public void setInjectBean(InjectBean injectBean) { + this.injectBean = injectBean; + } + + @Override + public void init(Router router) { + + } + + public boolean isSet() { + return injectBean.isSet(); + } +} diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/multiErrorCode/MultiErrorCodeService.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/multiErrorCode/MultiErrorCodeService.java index 5535c53b647..9a5c6be64b0 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/multiErrorCode/MultiErrorCodeService.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/multiErrorCode/MultiErrorCodeService.java @@ -20,22 +20,22 @@ import java.util.ArrayList; import java.util.List; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.demo.multiErrorCode.MultiRequest; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse200; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse400; import org.apache.servicecomb.demo.multiErrorCode.MultiResponse500; import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response.Status; @RestSchema(schemaId = "MultiErrorCodeService") @Path("MultiErrorCodeService") @@ -43,20 +43,20 @@ public class MultiErrorCodeService { @Path("/errorCode") @POST @ApiResponses({ - @ApiResponse(code = 200, response = MultiResponse200.class, message = ""), - @ApiResponse(code = 400, response = MultiResponse400.class, message = ""), - @ApiResponse(code = 500, response = MultiResponse500.class, message = "")}) + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = MultiResponse200.class)), description = ""), + @ApiResponse(responseCode = "400", content = @Content(schema = @Schema(implementation = MultiResponse400.class)), description = ""), + @ApiResponse(responseCode = "500", content = @Content(schema = @Schema(implementation = MultiResponse500.class)), description = "")}) public MultiResponse200 errorCode(MultiRequest request) { if (request.getCode() == 400) { MultiResponse400 r = new MultiResponse400(); r.setCode(400); r.setMessage("bad request"); - throw new InvocationException(javax.ws.rs.core.Response.Status.BAD_REQUEST, r); + throw new InvocationException(jakarta.ws.rs.core.Response.Status.BAD_REQUEST, r); } else if (request.getCode() == 500) { MultiResponse500 r = new MultiResponse500(); r.setCode(500); r.setMessage("internal error"); - throw new InvocationException(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR, r); + throw new InvocationException(jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR, r); } else { MultiResponse200 r = new MultiResponse200(); r.setCode(200); @@ -68,10 +68,15 @@ public MultiResponse200 errorCode(MultiRequest request) { @Path("/errorCodeWithHeader") @POST @ApiResponses({ - @ApiResponse(code = 200, response = MultiResponse200.class, message = ""), - @ApiResponse(code = 400, response = MultiResponse400.class, message = ""), - @ApiResponse(code = 500, response = MultiResponse500.class, message = "")}) - @ResponseHeaders({@ResponseHeader(name = "x-code", response = String.class)}) + @ApiResponse(responseCode = "200", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse200.class)), description = ""), + @ApiResponse(responseCode = "400", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse400.class)), description = ""), + @ApiResponse(responseCode = "500", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse500.class)), description = "")}) public Response errorCodeWithHeader(MultiRequest request) { Response response = new Response(); if (request.getCode() == 400) { @@ -82,14 +87,14 @@ public Response errorCodeWithHeader(MultiRequest request) { // If got many types for different status code, we can only using InvocationException for failed error code like 400-500. // The result for Failed Family(e.g. 400-500), can not set return value as target type directly or will give exception. response.setResult(new InvocationException(Status.BAD_REQUEST, r)); - response.getHeaders().addHeader("x-code", "400"); + response.setHeader("x-code", "400"); } else if (request.getCode() == 500) { MultiResponse500 r = new MultiResponse500(); r.setCode(500); r.setMessage("internal error"); response.setStatus(Status.INTERNAL_SERVER_ERROR); response.setResult(new InvocationException(Status.INTERNAL_SERVER_ERROR, r)); - response.getHeaders().addHeader("x-code", "500"); + response.setHeader("x-code", "500"); } else { MultiResponse200 r = new MultiResponse200(); r.setCode(200); @@ -97,7 +102,7 @@ public Response errorCodeWithHeader(MultiRequest request) { response.setStatus(Status.OK); // If error code is OK family(like 200), we can use the target type. response.setResult(r); - response.getHeaders().addHeader("x-code", "200"); + response.setHeader("x-code", "200"); } return response; } @@ -106,19 +111,24 @@ public Response errorCodeWithHeader(MultiRequest request) { @Path("/errorCodeWithHeaderJAXRS") @POST @ApiResponses({ - @ApiResponse(code = 200, response = MultiResponse200.class, message = ""), - @ApiResponse(code = 400, response = MultiResponse400.class, message = ""), - @ApiResponse(code = 500, response = MultiResponse500.class, message = "")}) - @ResponseHeaders({@ResponseHeader(name = "x-code", response = String.class)}) - public javax.ws.rs.core.Response errorCodeWithHeaderJAXRS(MultiRequest request) { - javax.ws.rs.core.Response response; + @ApiResponse(responseCode = "200", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse200.class)), description = ""), + @ApiResponse(responseCode = "400", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse400.class)), description = ""), + @ApiResponse(responseCode = "500", headers = { + @Header(name = "x-code", schema = @Schema(implementation = String.class))}, + content = @Content(schema = @Schema(implementation = MultiResponse500.class)), description = "")}) + public jakarta.ws.rs.core.Response errorCodeWithHeaderJAXRS(MultiRequest request) { + jakarta.ws.rs.core.Response response; if (request.getCode() == 400) { MultiResponse400 r = new MultiResponse400(); r.setCode(request.getCode()); r.setMessage(request.getMessage()); // If got many types for different status code, we can only using InvocationException for failed error code like 400-500. // The result for Failed Family(e.g. 400-500), can not set return value as target type directly or will give exception. - response = javax.ws.rs.core.Response.status(Status.BAD_REQUEST) + response = jakarta.ws.rs.core.Response.status(Status.BAD_REQUEST) .entity(new InvocationException(Status.BAD_REQUEST, r)) .header("x-code", "400") .build(); @@ -126,7 +136,7 @@ public javax.ws.rs.core.Response errorCodeWithHeaderJAXRS(MultiRequest request) MultiResponse500 r = new MultiResponse500(); r.setCode(request.getCode()); r.setMessage(request.getMessage()); - response = javax.ws.rs.core.Response.status(Status.INTERNAL_SERVER_ERROR) + response = jakarta.ws.rs.core.Response.status(Status.INTERNAL_SERVER_ERROR) .entity(new InvocationException(Status.INTERNAL_SERVER_ERROR, r)) .header("x-code", "500") .build(); @@ -135,7 +145,7 @@ public javax.ws.rs.core.Response errorCodeWithHeaderJAXRS(MultiRequest request) r.setCode(request.getCode()); r.setMessage(request.getMessage()); // If error code is OK family(like 200), we can use the target type. - response = javax.ws.rs.core.Response.status(Status.OK) + response = jakarta.ws.rs.core.Response.status(Status.OK) .entity(r) .header("x-code", "200") .build(); @@ -146,7 +156,7 @@ public javax.ws.rs.core.Response errorCodeWithHeaderJAXRS(MultiRequest request) @Path("/noClientErrorCode") @POST @ApiResponses({ - @ApiResponse(code = 400, response = NoClientErrorCode400.class, message = "")}) + @ApiResponse(responseCode = "400", content = @Content(schema = @Schema(implementation = NoClientErrorCode400.class)), description = "")}) public List noClientErrorCode(MultiRequest request) { if (request.getCode() == 400) { NoClientErrorCode400 r = new NoClientErrorCode400(); diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java index 7296a0970e1..36020868cbd 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.demo.jaxrs.server.pojoDefault; -import javax.ws.rs.POST; -import javax.ws.rs.Path; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; import org.apache.servicecomb.provider.rest.common.RestSchema; diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java index 0cc535703df..b8053ca8086 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java @@ -17,9 +17,9 @@ package org.apache.servicecomb.demo.jaxrs.server.pojoDefault; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.Null; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Null; public class DefaultRequestModel { @Min(20) diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java index bf4288a2869..9c505699866 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java @@ -17,9 +17,9 @@ package org.apache.servicecomb.demo.jaxrs.server.pojoDefault; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.Null; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Null; public class DefaultResponseModel { @Min(20) diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java index 732466957f4..7b18a4f7322 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java +++ b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java @@ -17,13 +17,15 @@ package org.apache.servicecomb.demo.jaxrs.server.validation; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import org.apache.servicecomb.demo.validator.Teacher; import org.apache.servicecomb.provider.rest.common.RestSchema; @RestSchema(schemaId = "ValidationService") @@ -31,13 +33,19 @@ public class ValidationService { @Path("/validate") @POST - public ValidationModel errorCode(@Valid ValidationModel request) { + public ValidationModel errorCode(@NotNull @Valid ValidationModel request) { return request; } @Path("/validateQuery") @GET - public String queryValidate(@NotNull @QueryParam("name") String name) { + public String queryValidate(@NotEmpty @QueryParam("name") String name) { return name; } + + @Path("/sayTeacherInfo") + @POST + public Teacher sayTeacherInfo(@Valid Teacher teacher) { + return teacher; + } } diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter deleted file mode 100644 index 5e737d86d70..00000000000 --- a/demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.demo.jaxrs.server.JaxrsDemoHttpServerFilter \ No newline at end of file diff --git a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher similarity index 88% rename from integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher rename to demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher index 66f422f32b5..a3a19c72aa3 100644 --- a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher +++ b/demo/demo-jaxrs/jaxrs-server/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher @@ -15,5 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.it.edge.EdgeDispatcher -org.apache.servicecomb.it.edge.encrypt.EncryptEdgeDispatcher +org.apache.servicecomb.demo.jaxrs.server.injectBean.InjectBeanVertxHttpDispatcher diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/resources/log4j2.xml b/demo/demo-jaxrs/jaxrs-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-jaxrs/jaxrs-server/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml b/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml index 89f324c368b..475708a55b1 100644 --- a/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml +++ b/demo/demo-jaxrs/jaxrs-server/src/main/resources/microservice.yaml @@ -15,21 +15,41 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: jaxrstest -service_description: - name: jaxrs - version: 0.0.2 servicecomb: service: - registry: + application: jaxrstest + name: jaxrs + version: 0.0.2 + registry: + sc: address: http://127.0.0.1:30100 + enableSwaggerRegistration: true rest: address: 0.0.0.0:8080 + server: + maxFormAttributeSize: 1024 # for testing, and bigger than netty buffer allocator + maxFormBufferedBytes: 100 highway: address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider uploads: - directory: target \ No newline at end of file + directory: target + + codec: + printErrorMessage: true + + executors.Provider.ReactiveSchema: servicecomb.executor.reactive + + invocation: + timeout: + check: + enabled: false + + # use service center to find schema info + openAPI: + registry: + # enable service center OpenAPI registry, and need set enableSwaggerRegistration: true + registry: + enabled: true + # disable instance OpenAPI registry + instance: + enabled: false diff --git a/demo/demo-jaxrs/pom.xml b/demo/demo-jaxrs/pom.xml index f7a808fa29f..014baac0318 100644 --- a/demo/demo-jaxrs/pom.xml +++ b/demo/demo-jaxrs/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-jaxrs Java Chassis::Demo::JAXRS @@ -31,5 +31,38 @@ jaxrs-server jaxrs-client - + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + swagger-generator-spring-data + + + org.springframework.data + spring-data-commons + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + diff --git a/demo/demo-local-registry/README.md b/demo/demo-local-registry/README.md new file mode 100644 index 00000000000..a585a17b7ce --- /dev/null +++ b/demo/demo-local-registry/README.md @@ -0,0 +1,5 @@ +This demo is an integration test for testing local registration an discovery. + + +Local registration and discovery is a mechanism that do not using Service Center, +`Microservice` and `MicroserviceInstance` are constructed from configuration file. diff --git a/demo/demo-local-registry/demo-local-registry-client/pom.xml b/demo/demo-local-registry/demo-local-registry-client/pom.xml new file mode 100644 index 00000000000..352e0cf26aa --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/pom.xml @@ -0,0 +1,106 @@ + + + + + 4.0.0 + demo-local-registry-client + Java Chassis::Demo::Local Registry client + + org.apache.servicecomb.demo + demo-local-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.localRegistryClient.LocalRegistryClientApplication + + + + org.apache.servicecomb.demo + demo-schema + + + + + + docker + + demo-local-registry-server + + + + + + io.fabric8 + docker-maven-plugin + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + /maven/maven/${demo.service.name}-${project.version}.jar + + + ServiceComb is ready + + + 8080 + + + + + + 8080:8080 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/CodeFirstService.java b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/CodeFirstService.java new file mode 100644 index 00000000000..05973bd18de --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/CodeFirstService.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryClient; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; + +@Path("/register/url/codeFirst") +@Produces("application/json") +public interface CodeFirstService { + @GET + @Path("getName") + String getName(@QueryParam("name") String name); +} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryClientApplication.java b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryClientApplication.java new file mode 100644 index 00000000000..76f1f2d570f --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryClientApplication.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryClient; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class LocalRegistryClientApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(LocalRegistryClientApplication.class) + .web(WebApplicationType.SERVLET).build() + .run(args); + + registerSchema(); + + runTest(); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + throw new IllegalStateException("tests failed"); + } + } + + private static void registerSchema() { + SCBEngine.getInstance().getOpenAPIRegistryManager().registerOpenAPI("demo-local-registry", + "demo-local-registry-server", + "CodeFirstEndpoint", CodeFirstService.class); + SCBEngine.getInstance().getOpenAPIRegistryManager().registerOpenAPI("demo-local-registry", + "demo-local-registry-server-bean", + "CodeFirstEndpoint", CodeFirstService.class); + } + + private static void runTest() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("demo-local-registry-server"); + } +} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryServerTest.java b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryServerTest.java new file mode 100644 index 00000000000..06a24601e03 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryServerTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryClient; + +import java.util.List; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class LocalRegistryServerTest implements CategorizedTestCase { + // demo-local-registry-server-bean use yaml to register service, and register schema by + // local file loading + @RpcReference(microserviceName = "demo-local-registry-server", schemaId = "CodeFirstEndpoint") + private CodeFirstService codeFirstService; + + @RpcReference(microserviceName = "demo-local-registry-server", schemaId = "ServerEndpoint") + private ServerService serverService; + + // demo-local-registry-server-bean use bean to register service, and register schema part by + // local file loading, part by bean class + @RpcReference(microserviceName = "demo-local-registry-server-bean", schemaId = "CodeFirstEndpoint") + private CodeFirstService codeFirstServiceBean; + + @RpcReference(microserviceName = "demo-local-registry-server-bean", schemaId = "ServerEndpoint") + private ServerService serverServiceBean; + + // demo-local-registry-server-bean2 use bean to register service and schema + @RpcReference(microserviceName = "demo-local-registry-server-bean2", schemaId = "CodeFirstEndpoint2") + private CodeFirstService codeFirstServiceBean2; + + @RpcReference(microserviceName = "demo-local-registry-server-bean2", schemaId = "ServerEndpoint") + private ServerService serverServiceBean2; + + private DiscoveryManager discoveryManager; + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Override + public void testRestTransport() throws Exception { + testServerGetName(); + testCodeFirstGetName(); + testGetAllMicroservice(); + } + + private void testGetAllMicroservice() { + List microserviceList = discoveryManager + .findServiceInstances("demo-local-registry", "demo-local-registry-client"); + TestMgr.check(1, microserviceList.size()); + microserviceList = discoveryManager + .findServiceInstances("demo-local-registry", "demo-local-registry-server"); + TestMgr.check(1, microserviceList.size()); + microserviceList = discoveryManager + .findServiceInstances("demo-local-registry", "demo-local-registry-server-bean"); + TestMgr.check(1, microserviceList.size()); + microserviceList = discoveryManager + .findServiceInstances("demo-local-registry", "demo-local-registry-server-bean2"); + TestMgr.check(1, microserviceList.size()); + } + + private void testCodeFirstGetName() { + TestMgr.check("2", codeFirstService.getName("2")); + TestMgr.check("2", codeFirstServiceBean.getName("2")); + TestMgr.check("2", codeFirstServiceBean2.getName("2")); + } + + private void testServerGetName() { + RestOperations template = RestTemplateBuilder.create(); + TestMgr.check("2", template + .getForObject("cse://demo-local-registry-server/register/url/prefix/getName?name=2", + String.class)); + TestMgr.check("2", template + .getForObject("cse://demo-local-registry-server-bean/register/url/prefix/getName?name=2", + String.class)); + TestMgr.check("2", template + .getForObject("cse://demo-local-registry-server-bean2/register/url/prefix/getName?name=2", + String.class)); + TestMgr.check("2", serverService.getName("2")); + TestMgr.check("2", serverServiceBean.getName("2")); + TestMgr.check("2", serverServiceBean2.getName("2")); + } +} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/RegistryBeansConfiguration.java b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/RegistryBeansConfiguration.java new file mode 100644 index 00000000000..28c5d3a1f25 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/RegistryBeansConfiguration.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryClient; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@SuppressWarnings("unused") +public class RegistryBeansConfiguration { + @Bean + public RegistryBean demoLocalRegistryServerBean() { + List endpoints = new ArrayList<>(); + endpoints.add("rest://localhost:8080"); + List instances = new ArrayList<>(); + instances.add(new Instance().setEndpoints(endpoints)); + + return new RegistryBean() + .setServiceName("demo-local-registry-server-bean") + .setId("002") + .setVersion("0.0.3") + .setAppId("demo-local-registry") + .addSchemaId("ServerEndpoint") + .addSchemaInterface("CodeFirstEndpoint", CodeFirstService.class) + .setInstances(new Instances().setInstances(instances)); + } + + @Bean + public RegistryBean demoLocalRegistryServerBean2() { + List endpoints = new ArrayList<>(); + endpoints.add("rest://localhost:8080"); + List instances = new ArrayList<>(); + instances.add(new Instance().setEndpoints(endpoints)); + + return new RegistryBean() + .setServiceName("demo-local-registry-server-bean2") + .setId("003") + .setVersion("0.0.3") + .setAppId("demo-local-registry") + .addSchemaId("ServerEndpoint") + .addSchemaInterface("CodeFirstEndpoint2", CodeFirstService.class) + .setInstances(new Instances().setInstances(instances)); + } +} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/ServerService.java b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/ServerService.java new file mode 100644 index 00000000000..f8211fd9a36 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/java/org/apache/servicecomb/demo/localRegistryClient/ServerService.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.localRegistryClient; + +public interface ServerService { + String getName(String name); +} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/application.yml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/application.yml new file mode 100644 index 00000000000..fcf4bb18309 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/application.yml @@ -0,0 +1,25 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: demo-local-registry + name: demo-local-registry-client + version: 0.0.1 diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/log4j2.xml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean/ServerEndpoint.yaml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean/ServerEndpoint.yaml new file mode 100644 index 00000000000..2adeb24781c --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean/ServerEndpoint.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.localRegistryServer.ServerEndpoint + version: 1.0.0 +servers: +- url: /register/url/prefix +paths: + /getName: + get: + operationId: getName + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean2/ServerEndpoint.yaml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean2/ServerEndpoint.yaml new file mode 100644 index 00000000000..2adeb24781c --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server-bean2/ServerEndpoint.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.localRegistryServer.ServerEndpoint + version: 1.0.0 +servers: +- url: /register/url/prefix +paths: + /getName: + get: + operationId: getName + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server/ServerEndpoint.yaml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server/ServerEndpoint.yaml new file mode 100644 index 00000000000..2adeb24781c --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/microservices/demo-local-registry-server/ServerEndpoint.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.localRegistryServer.ServerEndpoint + version: 1.0.0 +servers: +- url: /register/url/prefix +paths: + /getName: + get: + operationId: getName + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-local-registry/demo-local-registry-client/src/main/resources/registry.yaml b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/registry.yaml new file mode 100644 index 00000000000..cb5a3bcd4d9 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/main/resources/registry.yaml @@ -0,0 +1,27 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +demo-local-registry-server: + - id: "001" + version: "1.0" + appid: demo-local-registry + schemaIds: + - ServerEndpoint + - CodeFirstEndpoint + instances: + - endpoints: + - rest://localhost:8080 diff --git a/demo/demo-local-registry/demo-local-registry-client/src/test/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryIT.java b/demo/demo-local-registry/demo-local-registry-client/src/test/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryIT.java new file mode 100644 index 00000000000..f8f12fd9cfa --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-client/src/test/java/org/apache/servicecomb/demo/localRegistryClient/LocalRegistryIT.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryClient; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class LocalRegistryIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + LocalRegistryClientApplication.main(new String[0]); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-local-registry/demo-local-registry-server/pom.xml b/demo/demo-local-registry/demo-local-registry-server/pom.xml new file mode 100644 index 00000000000..8832ac2dc8a --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/pom.xml @@ -0,0 +1,106 @@ + + + + + 4.0.0 + demo-local-registry-server + Java Chassis::Demo::Local Registry Server + + org.apache.servicecomb.demo + demo-local-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.localRegistryServer.LocalRegistryServerApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/CodeFirstEndpoint.java b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/CodeFirstEndpoint.java new file mode 100644 index 00000000000..06fdf6b7939 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/CodeFirstEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryServer; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "CodeFirstEndpoint") +@RequestMapping(path = "/register/url/codeFirst", produces = MediaType.APPLICATION_JSON) +public class CodeFirstEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/LocalRegistryServerApplication.java b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/LocalRegistryServerApplication.java new file mode 100644 index 00000000000..e574177a982 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/LocalRegistryServerApplication.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryServer; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class LocalRegistryServerApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(LocalRegistryServerApplication.class).web(WebApplicationType.SERVLET).build() + .run(args); + + SelfServiceInvoker invoker = BeanUtils.getBean("SelfServiceInvoker"); + invoker.latch.await(10, TimeUnit.SECONDS); + TestMgr.check(invoker.result, "hello"); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + System.exit(1); + } + } +} diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/SelfServiceInvoker.java b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/SelfServiceInvoker.java new file mode 100644 index 00000000000..0790cfeec7c --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/SelfServiceInvoker.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryServer; + +import java.util.concurrent.CountDownLatch; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component("SelfServiceInvoker") +public class SelfServiceInvoker implements BootListener { + interface IServerEndpoint { + String getName(String name); + } + + @RpcReference(microserviceName = "demo-local-registry-server", schemaId = "ServerEndpoint") + IServerEndpoint endpoint; + + public CountDownLatch latch = new CountDownLatch(1); + + public String result = ""; + + public void onAfterRegistry(BootEvent event) { + result = endpoint.getName("hello"); + latch.countDown(); + } +} diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/ServerEndpoint.java b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/ServerEndpoint.java new file mode 100644 index 00000000000..2db9d87dd05 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/java/org/apache/servicecomb/demo/localRegistryServer/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.localRegistryServer; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/resources/application.yml b/demo/demo-local-registry/demo-local-registry-server/src/main/resources/application.yml new file mode 100644 index 00000000000..1478383598e --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/resources/application.yml @@ -0,0 +1,28 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8080 + +# java-chassis configurations +servicecomb: + service: + application: demo-local-registry + name: demo-local-registry-server + version: 0.0.1 + rest: + address: 0.0.0.0:8080 diff --git a/demo/demo-local-registry/demo-local-registry-server/src/main/resources/log4j2.xml b/demo/demo-local-registry/demo-local-registry-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-local-registry/demo-local-registry-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-local-registry/pom.xml b/demo/demo-local-registry/pom.xml new file mode 100644 index 00000000000..c33eebf22e7 --- /dev/null +++ b/demo/demo-local-registry/pom.xml @@ -0,0 +1,66 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-local-registry + Java Chassis::Demo::Local Registry + pom + + demo-local-registry-server + demo-local-registry-client + + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb + foundation-test-scaffolding + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + diff --git a/demo/demo-local/pom.xml b/demo/demo-local/pom.xml deleted file mode 100644 index e9260c3dce0..00000000000 --- a/demo/demo-local/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - demo-local - Java Chassis::Demo::Local - - - org.apache.servicecomb.demo - pojo-server - - - org.apache.servicecomb.demo - pojo-client - - - - - org.apache.servicecomb.demo.local.DemoLocal - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - diff --git a/demo/demo-local/src/main/java/org/apache/servicecomb/demo/local/DemoLocal.java b/demo/demo-local/src/main/java/org/apache/servicecomb/demo/local/DemoLocal.java deleted file mode 100644 index 05f5c82f9d1..00000000000 --- a/demo/demo-local/src/main/java/org/apache/servicecomb/demo/local/DemoLocal.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.local; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class DemoLocal { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - - // TODO:当前未实现本地调用 - // DemoClient.runTest(); - } -} diff --git a/demo/demo-multi-registries/README.md b/demo/demo-multi-registries/README.md new file mode 100644 index 00000000000..762bd27eba3 --- /dev/null +++ b/demo/demo-multi-registries/README.md @@ -0,0 +1,4 @@ +# About + +* This demo enables both local-registry and sc-registry. +* This demo using local-registry to call service center api. diff --git a/demo/demo-multi-registries/demo-multi-registries-client/pom.xml b/demo/demo-multi-registries/demo-multi-registries-client/pom.xml new file mode 100644 index 00000000000..3577950317f --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/pom.xml @@ -0,0 +1,134 @@ + + + + + 4.0.0 + demo-multi-registries-client + Java Chassis::Demo::Multi Registries client + + org.apache.servicecomb.demo + demo-multi-registries + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.registry.MultiRegistriesClientApplication + + + + org.apache.servicecomb.demo + demo-schema + + + + + + docker + + demo-multi-registries-server + + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServerEndpoint.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServerEndpoint.java new file mode 100644 index 00000000000..b4ac30465d0 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServerEndpoint.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +public interface IServerEndpoint { + String getName(String name); +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServiceCenterEndpoint.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServiceCenterEndpoint.java new file mode 100644 index 00000000000..42878945bc2 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/IServiceCenterEndpoint.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +public interface IServiceCenterEndpoint { + // java name can not be `x-domain-name`, so interfaces define all parameters. + @GetMapping(path = "/instances") + Object getInstances(@RequestParam(name = "appId") String appId, + @RequestParam(name = "serviceName") String serviceName, + @RequestParam(name = "global") String global, + @RequestParam(name = "version") String version, + @RequestHeader(name = "x-domain-name") String domain); +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesClientApplication.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesClientApplication.java new file mode 100644 index 00000000000..87efbff570a --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesClientApplication.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.stereotype.Component; + +@SpringBootApplication +@Component +public class MultiRegistriesClientApplication { + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(MultiRegistriesClientApplication.class) + .web(WebApplicationType.SERVLET).build().run(args); + + runTest(); + } + + public static void runTest() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("demo-multi-registries-server"); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + throw new IllegalStateException("tests failed"); + } + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerTestCase.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerTestCase.java new file mode 100644 index 00000000000..abbd66a3d1b --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerTestCase.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import java.util.List; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class MultiRegistriesServerTestCase implements CategorizedTestCase { + RestOperations template = RestTemplateBuilder.create(); + + private DiscoveryManager discoveryManager; + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Override + public void testRestTransport() throws Exception { + testServerGetName(); + testGetAllMicroservice(); + } + + private void testGetAllMicroservice() { + List microserviceList = discoveryManager + .findServiceInstances("demo-multi-registries", "demo-multi-registries-client"); + TestMgr.check(2, microserviceList.size()); // both local and sc has one. + microserviceList = discoveryManager + .findServiceInstances("demo-multi-registries", "demo-multi-registries-server"); + TestMgr.check(1, microserviceList.size()); + microserviceList = discoveryManager + .findServiceInstances("demo-multi-registries", "thirdParty-service-center"); + TestMgr.check(1, microserviceList.size()); + microserviceList = discoveryManager + .findServiceInstances("demo-multi-registries", "thirdParty-no-schema-server"); + TestMgr.check(1, microserviceList.size()); + } + + private void testServerGetName() { + // invoke demo-multi-registries-server + TestMgr.check("2", template + .getForObject("cse://demo-multi-registries-server/register/url/prefix/getName?name=2", + String.class)); + } + + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/SchemaDiscoveryTestCase.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/SchemaDiscoveryTestCase.java new file mode 100644 index 00000000000..0bf58aa7c3f --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/SchemaDiscoveryTestCase.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.springframework.stereotype.Component; + +@Component +public class SchemaDiscoveryTestCase implements CategorizedTestCase { + // Do not support this feature any more since 3.0.0 +// @RpcReference(microserviceName = "thirdParty-no-schema-server", schemaId = "ServerEndpoint") +// IServerEndpoint serverEndpoint; + + @Override + public void testRestTransport() throws Exception { + // invoke thirdParty-no-schema-server(mocked by demo-multi-registries-server) + // TestMgr.check("hello", serverEndpoint.getName("hello")); + } + + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + + } + + @Override + public String getMicroserviceName() { + return "thirdParty-service-center"; + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterEndpoint.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterEndpoint.java new file mode 100644 index 00000000000..491732f92bc --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterEndpoint.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import jakarta.ws.rs.core.MediaType; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +// do not know how to write schemas? code first and generate it. +@RestSchema(schemaId = "ServiceCenterEndpoint") +@RequestMapping(path = "/v4/default/registry", produces = MediaType.APPLICATION_JSON) +public class ServiceCenterEndpoint implements IServiceCenterEndpoint { + @GetMapping(path = "/instances") + public Object getInstances(@RequestParam(name = "appId") String appId, + @RequestParam(name = "serviceName") String serviceName, + @RequestParam(name = "global") String global, + @RequestParam(name = "version") String version, + @RequestHeader(name = "x-domain-name") String domain) { + return null; + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterTestCase.java b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterTestCase.java new file mode 100644 index 00000000000..c84bdc2fe0e --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/java/org/apache/servicecomb/demo/registry/ServiceCenterTestCase.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class ServiceCenterTestCase implements CategorizedTestCase { + @RpcReference(microserviceName = "thirdParty-service-center", schemaId = "ServiceCenterEndpoint") + IServiceCenterEndpoint serviceCenterEndpoint; + + @Override + public void testRestTransport() throws Exception { + // invoke service-center(3rd-parties) + @SuppressWarnings("unchecked") + Map> result = (Map>) serviceCenterEndpoint.getInstances( + "demo-multi-registries", + "demo-multi-registries-server", + "true", + "0.0.2", + "default"); + TestMgr.check(result.get("instances").size(), 1); + } + + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + + } + + @Override + public String getMicroserviceName() { + return "thirdParty-service-center"; + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/application.yml b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/application.yml new file mode 100644 index 00000000000..e440ff6c897 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/application.yml @@ -0,0 +1,35 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: demo-multi-registries + name: demo-multi-registries-client + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 + demo-multi-registries: + thirdParty-service-center: + enabled: false + local: + demo-multi-registries: + demo-multi-registries-server: + enabled: false diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/log4j2.xml b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/microservices/thirdParty-service-center/ServiceCenterEndpoint.yaml b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/microservices/thirdParty-service-center/ServiceCenterEndpoint.yaml new file mode 100644 index 00000000000..88332e3259a --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/microservices/thirdParty-service-center/ServiceCenterEndpoint.yaml @@ -0,0 +1,62 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the License); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an AS IS BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.localRegistryServer.ServerEndpoint + version: 1.0.0 +servers: + - url: /v4/default/registry +paths: + /instances: + get: + operationId: getInstances + parameters: + - name: appId + in: query + required: true + schema: + type: string + - name: serviceName + in: query + required: true + schema: + type: string + - name: global + in: query + required: true + schema: + type: string + - name: version + in: query + required: true + schema: + type: string + - name: x-domain-name + in: header + required: true + schema: + type: string + responses: + 200: + description: response of 200 + content: + application/json: + schema: + type: object +components: + schemas: {} diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/registry.yaml b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/registry.yaml new file mode 100644 index 00000000000..9d39b1b8bd1 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/main/resources/registry.yaml @@ -0,0 +1,35 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +thirdParty-service-center: + - id: "001" + version: "4.0.0" + appid: demo-multi-registries + schemaIds: + - ServiceCenterEndpoint + instances: + - endpoints: + - rest://localhost:30100 +thirdParty-no-schema-server: + - id: "002" + version: "4.0.0" + appid: demo-multi-registries + schemaIds: + - ServerEndpoint # not in local , discovery from demo-multi-registries-server. Not supported since 3.0.0 + instances: + - endpoints: + - rest://localhost:8080 # actually will invoke to demo-multi-registries-server diff --git a/demo/demo-multi-registries/demo-multi-registries-client/src/test/java/org/apache/servicecomb/demo/registry/MultiRegistriesIT.java b/demo/demo-multi-registries/demo-multi-registries-client/src/test/java/org/apache/servicecomb/demo/registry/MultiRegistriesIT.java new file mode 100644 index 00000000000..1c716783c2d --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-client/src/test/java/org/apache/servicecomb/demo/registry/MultiRegistriesIT.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MultiRegistriesIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + MultiRegistriesClientApplication.main(new String[0]); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-server/pom.xml b/demo/demo-multi-registries/demo-multi-registries-server/pom.xml new file mode 100644 index 00000000000..4a0b37f4433 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/pom.xml @@ -0,0 +1,106 @@ + + + + + 4.0.0 + demo-multi-registries-server + Java Chassis::Demo::Multi Registries Server + + org.apache.servicecomb.demo + demo-multi-registries + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.registry.MultiRegistriesServerApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerApplication.java b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerApplication.java new file mode 100644 index 00000000000..afacef1155c --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/MultiRegistriesServerApplication.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class MultiRegistriesServerApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(MultiRegistriesServerApplication.class) + .web(WebApplicationType.SERVLET).build().run(args); + + SelfServiceInvoker invoker = BeanUtils.getBean("SelfServiceInvoker"); + invoker.latch.await(10, TimeUnit.SECONDS); + TestMgr.check(invoker.result, "hello"); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + System.exit(1); + } + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/SelfServiceInvoker.java b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/SelfServiceInvoker.java new file mode 100644 index 00000000000..b15bb7c0df9 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/SelfServiceInvoker.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import java.util.concurrent.CountDownLatch; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component("SelfServiceInvoker") +public class SelfServiceInvoker implements BootListener { + interface IServerEndpoint { + String getName(String name); + } + + @RpcReference(microserviceName = "demo-multi-registries-server", schemaId = "ServerEndpoint") + IServerEndpoint endpoint; + + public CountDownLatch latch = new CountDownLatch(1); + + public String result = ""; + + public void onAfterRegistry(BootEvent event) { + result = endpoint.getName("hello"); + latch.countDown(); + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/ServerEndpoint.java b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/ServerEndpoint.java new file mode 100644 index 00000000000..eb594aaba57 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/src/main/java/org/apache/servicecomb/demo/registry/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.registry; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/application.yml b/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/application.yml new file mode 100644 index 00000000000..1104cebdbd7 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/application.yml @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8080 + +servicecomb: + service: + application: demo-multi-registries + name: demo-multi-registries-server + version: 0.0.2 + registry: + sc: + address: http://127.0.0.1:30100 + rest: + address: 0.0.0.0:8080 diff --git a/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/log4j2.xml b/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multi-registries/demo-multi-registries-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multi-registries/pom.xml b/demo/demo-multi-registries/pom.xml new file mode 100644 index 00000000000..13f34c9c7af --- /dev/null +++ b/demo/demo-multi-registries/pom.xml @@ -0,0 +1,70 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-multi-registries + Java Chassis::Demo::Multi Registry + pom + + demo-multi-registries-server + demo-multi-registries-client + + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + foundation-test-scaffolding + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/pom.xml b/demo/demo-multi-service-center/demo-multi-service-center-client/pom.xml new file mode 100644 index 00000000000..2669f28a874 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/pom.xml @@ -0,0 +1,184 @@ + + + + + 4.0.0 + demo-multi-service-center-client + Java Chassis::Demo::Multi Service Centers::Client + + org.apache.servicecomb.demo + demo-multi-service-center + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.multiServiceCenterClient.Application + + + + + org.apache.servicecomb + service-center-client + + + org.apache.servicecomb.demo + demo-schema + + + + + + docker + + demo-multi-registries-server + + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service30100 + + alias + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + servicecomb/service-center + service40100 + + alias + + server is ready + + + 30100 + + + + + + 40100:30100 + + + + + demo-multi-service-center-servera:${project.version} + demo-multi-service-center-servera + + alias + + + -Dservicecomb.registry.sc.address=http://service30100:30100 + + /maven/maven/demo-multi-service-center-servera-${project.version}.jar + + + service30100:service30100 + + + ServiceComb is ready + + + 8080 + + + + + + 8080:8080 + + + + + demo-multi-service-center-serverb:${project.version} + demo-multi-service-center-serverb + + alias + + + -Dservicecomb.registry.sc.address=http://service40100:30100 + + /maven/maven/demo-multi-service-center-serverb-${project.version}.jar + + + service40100:service40100 + + + ServiceComb is ready + + + 8082 + + + + + + 8082:8082 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/Application.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/Application.java new file mode 100644 index 00000000000..4264651164e --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/Application.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.stereotype.Component; + +@SpringBootApplication +@Component +public class Application { + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(Application.class) + .web(WebApplicationType.NONE).build().run(args); + + runTest(); + } + + public static void runTest() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("demo-multi-service-center-serverA"); + testTransportThreads(); + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + throw new IllegalStateException("tests failed"); + } + } + + private static void testTransportThreads() throws Exception { + Set threadSet = Thread.getAllStackTraces().keySet(); + List expectedThread = new ArrayList<>(); + threadSet.forEach(thread -> { + if (thread.getName().startsWith("transport-vert.x-eventloop-thread")) { + expectedThread.add(thread.getName()); + } + }); + // After SSL improvements https://github.com/eclipse-vertx/vert.x/pull/4468 introduced in 4.3.4 + // SSL helper will use `internal-blocking` thread init ssl engine + // transport-vert.x-eventloop-thread-0 + // transport-vert.x-eventloop-thread-1 + // transport-vert.x-eventloop-thread-2 + // transport-vert.x-eventloop-thread-3 + // transport-vert.x-eventloop-thread-4 + // transport-vert.x-eventloop-thread-5 + // transport-vert.x-internal-blocking-0 + // transport-vert.x-internal-blocking-1 + TestMgr.check(6, expectedThread.size()); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IConfigurationEndpoint.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IConfigurationEndpoint.java new file mode 100644 index 00000000000..b237db532ba --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IConfigurationEndpoint.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import java.util.List; + +public interface IConfigurationEndpoint { + String getValue(String key, int type); + + List getValueList(String key, int type); +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IServerEndpoint.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IServerEndpoint.java new file mode 100644 index 00000000000..9d10324777a --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/IServerEndpoint.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +public interface IServerEndpoint { + String getName(String name); +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java new file mode 100644 index 00000000000..3b11e0582d8 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/RegistryClientTest.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.event.SimpleEventBus; +import org.apache.servicecomb.http.client.auth.DefaultRequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.apache.servicecomb.service.center.client.ServiceCenterAddressManager; +import org.apache.servicecomb.service.center.client.RegistrationEvents; +import org.apache.servicecomb.service.center.client.RegistrationEvents.HeartBeatEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.MicroserviceInstanceRegistrationEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.MicroserviceRegistrationEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.SchemaRegistrationEvent; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterDiscovery; +import org.apache.servicecomb.service.center.client.ServiceCenterDiscovery.SubscriptionKey; +import org.apache.servicecomb.service.center.client.ServiceCenterRegistration; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.apache.servicecomb.service.center.client.model.ServiceCenterConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.google.common.base.Charsets; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import com.google.common.hash.Hashing; + +@Component +public class RegistryClientTest implements CategorizedTestCase { + private List events = new ArrayList<>(); + + private CountDownLatch registrationCounter = new CountDownLatch(1); + + // auto test only tests 'hasRegistered=false', can run this client many times to test 'hasRegistered=true' + private boolean hasRegistered = true; + + private final Environment environment; + + @Autowired + public RegistryClientTest(Environment environment) { + this.environment = environment; + } + + @Override + public void testRestTransport() throws Exception { + ServiceCenterAddressManager addressManager = new ServiceCenterAddressManager("default", + Arrays.asList("http://127.0.0.1:30100"), new EventBus(), "", ""); + SSLProperties sslProperties = new SSLProperties(); + sslProperties.setEnabled(false); + ServiceCenterClient serviceCenterClient = new ServiceCenterClient(addressManager, sslProperties, + new DefaultRequestAuthHeaderProvider(), "default", null, environment); + EventBus eventBus = new SimpleEventBus(); + ServiceCenterConfiguration serviceCenterConfiguration = new ServiceCenterConfiguration(); + ServiceCenterRegistration serviceCenterRegistration = new ServiceCenterRegistration(serviceCenterClient, + serviceCenterConfiguration, eventBus); + Microservice microservice = new Microservice(); + microservice.setAppId("app_registry"); + microservice.setServiceName("name_registry"); + microservice.setVersion("1.0.0"); + microservice.setEnvironment("development"); + List schemas = new ArrayList<>(); + schemas.add("SchemaA"); + schemas.add("SchemaB"); + microservice.setSchemas(schemas); + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + microserviceInstance.setHostName("host_registry"); + List endpoints = new ArrayList<>(); + endpoints.add("rest://127.0.0.1/"); + microserviceInstance.setEndpoints(endpoints); + List schemaInfos = new ArrayList<>(); + SchemaInfo schemaA = new SchemaInfo(); + schemaA.setSchemaId("SchemaA"); + schemaA.setSchema("schema contents in any format"); + schemaA.setSummary( + Hashing.sha256().newHasher().putString("schema contents in any format".toString(), Charsets.UTF_8).hash() + .toString()); + schemaInfos.add(schemaA); + SchemaInfo schemaB = new SchemaInfo(); + schemaB.setSchemaId("SchemaA"); + schemaB.setSchema("schema contents in any format"); + schemaB.setSummary( + Hashing.sha256().newHasher().putString("schema contents in any format".toString(), Charsets.UTF_8).hash() + .toString()); + schemaInfos.add(schemaB); + serviceCenterRegistration.setMicroservice(microservice); + serviceCenterRegistration.setMicroserviceInstance(microserviceInstance); + serviceCenterRegistration.setSchemaInfos(schemaInfos); + eventBus.register(this); + + serviceCenterRegistration.startRegistration(); + registrationCounter.await(30000, TimeUnit.MILLISECONDS); + if (hasRegistered) { + TestMgr.check(events.size() >= 3, true); + TestMgr.check(events.get(0).isSuccess(), true); + TestMgr.check(events.get(0) instanceof MicroserviceRegistrationEvent, true); + TestMgr.check(events.get(1).isSuccess(), true); + TestMgr.check(events.get(1) instanceof MicroserviceInstanceRegistrationEvent, true); + TestMgr.check(events.get(2).isSuccess(), true); + TestMgr.check(events.get(2) instanceof HeartBeatEvent, true); + } else { + TestMgr.check(events.size() >= 4, true); + TestMgr.check(events.get(0).isSuccess(), true); + TestMgr.check(events.get(0) instanceof MicroserviceRegistrationEvent, true); + TestMgr.check(events.get(1).isSuccess(), true); + TestMgr.check(events.get(1) instanceof SchemaRegistrationEvent, true); + TestMgr.check(events.get(2).isSuccess(), true); + TestMgr.check(events.get(2) instanceof MicroserviceInstanceRegistrationEvent, true); + TestMgr.check(events.get(3).isSuccess(), true); + TestMgr.check(events.get(3) instanceof HeartBeatEvent, true); + } + + ServiceCenterDiscovery discovery = new ServiceCenterDiscovery(serviceCenterClient, eventBus); + discovery.updateMyselfServiceId(microservice.getServiceId()); + discovery.startDiscovery(); + SubscriptionKey subscriptionKey = new SubscriptionKey(microservice.getAppId(), microservice.getServiceName()); + discovery.registerIfNotPresent(subscriptionKey); + List instances = discovery.getInstanceCache(subscriptionKey); + TestMgr.check(instances != null, true); + TestMgr.check(instances.size(), 1); + discovery.stop(); + serviceCenterRegistration.stop(); + serviceCenterClient.deleteMicroserviceInstance(microservice.getServiceId(), microserviceInstance.getInstanceId()); + } + + @Subscribe + public void onMicroserviceRegistrationEvent(MicroserviceRegistrationEvent event) { + events.add(event); + } + + @Subscribe + public void onSchemaRegistrationEvent(SchemaRegistrationEvent event) { + events.add(event); + hasRegistered = false; + } + + @Subscribe + public void onMicroserviceInstanceRegistrationEvent(MicroserviceInstanceRegistrationEvent event) { + events.add(event); + } + + @Subscribe + public void onHeartBeatEvent(HeartBeatEvent event) { + events.add(event); + registrationCounter.countDown(); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Configuration.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Configuration.java new file mode 100644 index 00000000000..db7fc11df06 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Configuration.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import java.util.List; + +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.registry.sc.SCClientUtils; +import org.apache.servicecomb.registry.sc.SCConfigurationProperties; +import org.apache.servicecomb.registry.sc.SCConst; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterWatch; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class SC2Configuration { + @Bean + @ConfigurationProperties(prefix = SCConst.SC_REGISTRY_PREFIX + "2") + public SCConfigurationProperties scConfigurationProperties2() { + return new SCConfigurationProperties(); + } + + @Bean + public ServiceCenterWatch serviceCenterWatch2( + @Qualifier("scConfigurationProperties2") SCConfigurationProperties scConfigurationProperties2, + List authHeaderProviders, Environment environment) { + return SCClientUtils.serviceCenterWatch(scConfigurationProperties2, authHeaderProviders, environment); + } + + @Bean + public ServiceCenterClient serviceCenterClient2( + @Qualifier("scConfigurationProperties2") SCConfigurationProperties scConfigurationProperties2, + Environment environment) { + return SCClientUtils.serviceCenterClient(scConfigurationProperties2, environment); + } + + @Bean + public SC2Discovery sc2Discovery( + @Qualifier("scConfigurationProperties2") SCConfigurationProperties scConfigurationProperties2, + @Qualifier("serviceCenterClient2") ServiceCenterClient serviceCenterClient2) { + return new SC2Discovery(scConfigurationProperties2, serviceCenterClient2); + } + + @Bean + public SC2Registration sc2Registration( + @Qualifier("scConfigurationProperties2") SCConfigurationProperties scConfigurationProperties2, + @Qualifier("serviceCenterClient2") ServiceCenterClient serviceCenterClient2, + @Qualifier("serviceCenterWatch2") ServiceCenterWatch serviceCenterWatch2) { + return new SC2Registration(scConfigurationProperties2, serviceCenterClient2, serviceCenterWatch2); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Discovery.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Discovery.java new file mode 100644 index 00000000000..e6669d294ea --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Discovery.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import org.apache.servicecomb.registry.sc.SCConfigurationProperties; +import org.apache.servicecomb.registry.sc.SCConst; +import org.apache.servicecomb.registry.sc.SCDiscovery; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; + +public class SC2Discovery extends SCDiscovery { + public SC2Discovery(SCConfigurationProperties configurationProperties, + ServiceCenterClient serviceCenterClient) { + super(configurationProperties, serviceCenterClient); + } + + @Override + public String name() { + return SCConst.SC_REGISTRY_NAME + "2"; + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Registration.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Registration.java new file mode 100644 index 00000000000..7fd22f03616 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/SC2Registration.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import org.apache.servicecomb.registry.sc.SCConfigurationProperties; +import org.apache.servicecomb.registry.sc.SCConst; +import org.apache.servicecomb.registry.sc.SCRegistration; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterWatch; + +public class SC2Registration extends SCRegistration { + public SC2Registration(SCConfigurationProperties configurationProperties, + ServiceCenterClient serviceCenterClient, ServiceCenterWatch serviceCenterWatch) { + super(configurationProperties, serviceCenterClient, serviceCenterWatch); + } + + @Override + public String name() { + return SCConst.SC_REGISTRY_NAME + 2; + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerATest.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerATest.java new file mode 100644 index 00000000000..9ddd4d88f4b --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerATest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class ServerATest implements CategorizedTestCase { + @RpcReference(microserviceName = "demo-multi-service-center-serverA", schemaId = "ServerEndpoint") + private IServerEndpoint serverEndpoint; + + @Override + public void testRestTransport() throws Exception { + TestMgr.check("hello", serverEndpoint.getName("hello")); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerBTest.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerBTest.java new file mode 100644 index 00000000000..f76836d4ef8 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/java/org/apache/servicecomb/demo/multiServiceCenterClient/ServerBTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import java.util.Arrays; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class ServerBTest implements CategorizedTestCase { + @RpcReference(microserviceName = "demo-multi-service-center-serverB", schemaId = "ServerEndpoint") + private IServerEndpoint serverEndpoint; + + @RpcReference(microserviceName = "demo-multi-service-center-serverB", schemaId = "ConfigurationEndpoint") + private IConfigurationEndpoint configurationEndpoint; + + @Override + public void testRestTransport() throws Exception { + TestMgr.check("hello", serverEndpoint.getName("hello")); + + TestMgr.check("key1-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key1", 1)); + TestMgr.check("key1-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key1", 2)); + TestMgr.check("key1-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key1", 3)); + TestMgr.check("key2-override", configurationEndpoint.getValue("demo.multi.service.center.serverB.key2", 1)); + TestMgr.check("key2-override", configurationEndpoint.getValue("demo.multi.service.center.serverB.key2", 2)); + TestMgr.check("key2-override", configurationEndpoint.getValue("demo.multi.service.center.serverB.key2", 3)); + TestMgr.check("key3", configurationEndpoint.getValue("demo.multi.service.center.serverB.key3", 1)); + TestMgr.check("key3", configurationEndpoint.getValue("demo.multi.service.center.serverB.key3", 2)); + TestMgr.check("key3", configurationEndpoint.getValue("demo.multi.service.center.serverB.key3", 3)); + TestMgr.check("key4-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key4", 1)); + TestMgr.check("key4-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key4", 2)); + TestMgr.check("key4-boot", configurationEndpoint.getValue("demo.multi.service.center.serverB.key4", 3)); + TestMgr.check("key5-high", configurationEndpoint.getValue("demo.multi.service.center.serverB.key5", 1)); + TestMgr.check("key5-high", configurationEndpoint.getValue("demo.multi.service.center.serverB.key5", 2)); + TestMgr.check("key5-high", configurationEndpoint.getValue("demo.multi.service.center.serverB.key5", 3)); + TestMgr.check("key6", configurationEndpoint.getValue("demo.multi.service.center.serverB.key6", 1)); + TestMgr.check("key6", configurationEndpoint.getValue("demo.multi.service.center.serverB.key6", 2)); + TestMgr.check("key6", configurationEndpoint.getValue("demo.multi.service.center.serverB.key6", 3)); + TestMgr.check(Arrays.asList("key71", "key72"), + configurationEndpoint.getValueList("demo.multi.service.center.serverB.key7", 1)); + TestMgr.check(Arrays.asList("key71", "key72"), + configurationEndpoint.getValueList("demo.multi.service.center.serverB.key7", 2)); + } + + @Override + public String getMicroserviceName() { + return "demo-multi-service-center-serverB"; + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/application.yml b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/application.yml new file mode 100644 index 00000000000..6daa76e8dee --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/application.yml @@ -0,0 +1,31 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: demo-multi-service-center + name: demo-multi-service-center-client + version: 0.0.2 + registry: + sc: + address: http://127.0.0.1:30100 + sc2: + address: http://127.0.0.1:40100 + + transport: + eventloop: + size: 6 diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/log4j2.xml b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-client/src/test/java/org/apache/servicecomb/demo/multiServiceCenterClient/MultiServiceCenterIT.java b/demo/demo-multi-service-center/demo-multi-service-center-client/src/test/java/org/apache/servicecomb/demo/multiServiceCenterClient/MultiServiceCenterIT.java new file mode 100644 index 00000000000..f7cd5157171 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-client/src/test/java/org/apache/servicecomb/demo/multiServiceCenterClient/MultiServiceCenterIT.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterClient; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MultiServiceCenterIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + Application.main(new String[0]); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverA/pom.xml b/demo/demo-multi-service-center/demo-multi-service-center-serverA/pom.xml new file mode 100644 index 00000000000..ddfd3570a43 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverA/pom.xml @@ -0,0 +1,106 @@ + + + + + 4.0.0 + demo-multi-service-center-servera + Java Chassis::Demo::Multi Service Centers::ServerA + + org.apache.servicecomb.demo + demo-multi-service-center + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.multiServiceCenter.ServerApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerApplication.java b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerApplication.java new file mode 100644 index 00000000000..4515d6c7575 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerApplication.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenter; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ServerApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(ServerApplication.class) + .web(WebApplicationType.SERVLET).build().run(args); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerEndpoint.java b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerEndpoint.java new file mode 100644 index 00000000000..16fdb41bdde --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/java/org/apache/servicecomb/demo/multiServiceCenter/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenter; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/application.yml b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/application.yml new file mode 100644 index 00000000000..03f54c0db15 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/application.yml @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8080 + +servicecomb: + service: + application: demo-multi-service-center + name: demo-multi-service-center-serverA + version: 0.0.2 + registry: + sc: + address: http://127.0.0.1:30100 + rest: + address: 0.0.0.0:8080 diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/log4j2.xml b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverA/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/pom.xml b/demo/demo-multi-service-center/demo-multi-service-center-serverB/pom.xml new file mode 100644 index 00000000000..66dfd58d9b4 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/pom.xml @@ -0,0 +1,106 @@ + + + + + 4.0.0 + demo-multi-service-center-serverb + Java Chassis::Demo::Multi Service Centers::ServerB + + org.apache.servicecomb.demo + demo-multi-service-center + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.multiServiceCenterServerB.ServerApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ConfigurationEndpoint.java b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ConfigurationEndpoint.java new file mode 100644 index 00000000000..edbb116ccca --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ConfigurationEndpoint.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterServerB; + +import java.util.List; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ConfigurationEndpoint") +@RequestMapping(path = "/register/url/config", produces = MediaType.APPLICATION_JSON) +public class ConfigurationEndpoint { + private static final Logger LOGGER + = LoggerFactory.getLogger(ServerEndpoint.class); + + private Environment environment; + + @Autowired + public ConfigurationEndpoint(Environment environment) { + this.environment = environment; + } + + @Value("${demo.multi.service.center.serverB.key1}") + private String key1; + + @Value("${demo.multi.service.center.serverB.key2}") + private String key2; + + @Value("${demo.multi.service.center.serverB.key3}") + private String key3; + + @Value("${demo.multi.service.center.serverB.key4}") + private String key4; + + @Value("${demo.multi.service.center.serverB.key5}") + private String key5; + + @Value("${demo.multi.service.center.serverB.key6}") + private String key6; + + @Value("${demo.multi.service.center.serverB.key7}") + private List key7; + + @GetMapping(path = "/config") + public String getValue(@RequestParam(name = "key") String key, @RequestParam(name = "type") int type) { + if (type == 1) { + return environment.getProperty(key); + } else if (type == 2) { + return environment.getProperty(key); + } else { + switch (key) { + case "demo.multi.service.center.serverB.key1": + return key1; + case "demo.multi.service.center.serverB.key2": + return key2; + case "demo.multi.service.center.serverB.key3": + return key3; + case "demo.multi.service.center.serverB.key4": + return key4; + case "demo.multi.service.center.serverB.key5": + return key5; + case "demo.multi.service.center.serverB.key6": + return key6; + default: + return null; + } + } + } + + @SuppressWarnings("unchecked") + @GetMapping(path = "/configList") + public List getValueList(@RequestParam(name = "key") String key, @RequestParam(name = "type") int type) { + if (type == 1) { + return environment.getProperty(key, List.class); + } else { + switch (key) { + case "demo.multi.service.center.serverB.key7": + return key7; + default: + return null; + } + } + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerApplication.java b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerApplication.java new file mode 100644 index 00000000000..49106b7b8dd --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerApplication.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterServerB; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ServerApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(ServerApplication.class) + .web(WebApplicationType.SERVLET).build().run(args); + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerEndpoint.java b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerEndpoint.java new file mode 100644 index 00000000000..d14c1d4a7b0 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/java/org/apache/servicecomb/demo/multiServiceCenterServerB/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiServiceCenterServerB; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.properties b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.properties new file mode 100644 index 00000000000..121f1aa95c6 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +demo.multi.service.center.serverB.actual.key6=key6 +demo.multi.service.center.serverB.actual.key7.1=key71 +demo.multi.service.center.serverB.actual.key7.2=key72 diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.yml b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.yml new file mode 100644 index 00000000000..e9850bc8c23 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/application.yml @@ -0,0 +1,35 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: demo-multi-service-center + name: demo-multi-service-center-serverB + version: 0.0.2 + registry: + sc: + address: http://127.0.0.1:40100 + rest: + address: 0.0.0.0:8082 + +demo.multi.service.center.serverB: + key1: key1-boot + key4: key4-boot + key5: key5 diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/log4j2.xml b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/mapping.yaml b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/mapping.yaml new file mode 100644 index 00000000000..01642a348f7 --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/mapping.yaml @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +demo.multi.service.center.serverB.actual.key5: + - demo.multi.service.center.serverB.key5 diff --git a/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/microservice.yaml b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..2164cf6ac9f --- /dev/null +++ b/demo/demo-multi-service-center/demo-multi-service-center-serverB/src/main/resources/microservice.yaml @@ -0,0 +1,29 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb-config-order: 1 + +demo.multi.service.center.serverB: + key1: key1-override + key2: key2-override + key5: key5 + actual: + key5: key5-high + key6: ${demo.multi.service.center.serverB.actual.key6} + key7: + - ${demo.multi.service.center.serverB.actual.key7.1} + - ${demo.multi.service.center.serverB.actual.key7.2} diff --git a/demo/demo-multi-service-center/pom.xml b/demo/demo-multi-service-center/pom.xml new file mode 100644 index 00000000000..cf9c101e496 --- /dev/null +++ b/demo/demo-multi-service-center/pom.xml @@ -0,0 +1,67 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-multi-service-center + Java Chassis::Demo::Multi Service Centers + pom + + demo-multi-service-center-serverA + demo-multi-service-center-serverB + demo-multi-service-center-client + + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + foundation-test-scaffolding + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + diff --git a/demo/demo-multiple/a-client/pom.xml b/demo/demo-multiple/a-client/pom.xml index bdfb0c3a7ba..84131a7909c 100644 --- a/demo/demo-multiple/a-client/pom.xml +++ b/demo/demo-multiple/a-client/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT a-client Java Chassis::Demo::Multiple::A client @@ -30,4 +30,5 @@ org.apache.servicecomb.demo.multiple.a.client.AClientMain + diff --git a/demo/demo-multiple/a-client/src/main/java/org/apache/servicecomb/demo/multiple/a/client/AClientMain.java b/demo/demo-multiple/a-client/src/main/java/org/apache/servicecomb/demo/multiple/a/client/AClientMain.java index c41e154cca9..907df46c2c7 100644 --- a/demo/demo-multiple/a-client/src/main/java/org/apache/servicecomb/demo/multiple/a/client/AClientMain.java +++ b/demo/demo-multiple/a-client/src/main/java/org/apache/servicecomb/demo/multiple/a/client/AClientMain.java @@ -19,12 +19,12 @@ import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; public class AClientMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(AClientMain.class).web(WebApplicationType.NONE).run(args); AClient client = BeanUtils.getContext().getBean(AClient.class); client.run(); diff --git a/demo/demo-multiple/a-client/src/main/resources/log4j2.xml b/demo/demo-multiple/a-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/a-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/a-client/src/main/resources/microservice.yaml b/demo/demo-multiple/a-client/src/main/resources/microservice.yaml index 9a8ea2d7fe7..81a782bafc2 100644 --- a/demo/demo-multiple/a-client/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/a-client/src/main/resources/microservice.yaml @@ -16,11 +16,12 @@ ## --------------------------------------------------------------------------- a-server.name: a-server -APPLICATION_ID: multiple -service_description: - name: a-client - version: 0.0.1 + servicecomb: service: - registry: + application: multiple + name: a-client + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 diff --git a/demo/demo-multiple/a-server/pom.xml b/demo/demo-multiple/a-server/pom.xml index 4a5d0894d6d..d38b12d8d62 100644 --- a/demo/demo-multiple/a-server/pom.xml +++ b/demo/demo-multiple/a-server/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT a-server Java Chassis::Demo::Multiple::A server @@ -31,4 +31,5 @@ org.apache.servicecomb.demo.multiple.a.server.AServerMain + diff --git a/demo/demo-multiple/a-server/src/main/java/org/apache/servicecomb/demo/multiple/a/server/AServerMain.java b/demo/demo-multiple/a-server/src/main/java/org/apache/servicecomb/demo/multiple/a/server/AServerMain.java index 8f750c499a5..40c96981c7a 100644 --- a/demo/demo-multiple/a-server/src/main/java/org/apache/servicecomb/demo/multiple/a/server/AServerMain.java +++ b/demo/demo-multiple/a-server/src/main/java/org/apache/servicecomb/demo/multiple/a/server/AServerMain.java @@ -17,12 +17,11 @@ package org.apache.servicecomb.demo.multiple.a.server; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; public class AServerMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(AServerMain.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-multiple/a-server/src/main/resources/log4j2.xml b/demo/demo-multiple/a-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/a-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/a-server/src/main/resources/microservice.yaml b/demo/demo-multiple/a-server/src/main/resources/microservice.yaml index b24d620d4bb..d916c594f79 100644 --- a/demo/demo-multiple/a-server/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/a-server/src/main/resources/microservice.yaml @@ -15,13 +15,13 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: multiple -service_description: - name: a-server - version: 0.0.1 servicecomb: service: - registry: + application: multiple + name: a-server + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 rest: address: 0.0.0.0:8080 diff --git a/demo/demo-multiple/b-client/pom.xml b/demo/demo-multiple/b-client/pom.xml index 08eb318db3e..4ab02a66f1b 100644 --- a/demo/demo-multiple/b-client/pom.xml +++ b/demo/demo-multiple/b-client/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT b-client Java Chassis::Demo::Multiple::B client @@ -30,4 +30,5 @@ org.apache.servicecomb.demo.multiple.b.client.BClientMain + diff --git a/demo/demo-multiple/b-client/src/main/java/org/apache/servicecomb/demo/multiple/b/client/BClientMain.java b/demo/demo-multiple/b-client/src/main/java/org/apache/servicecomb/demo/multiple/b/client/BClientMain.java index 7c9939a843f..a6400d91a4e 100644 --- a/demo/demo-multiple/b-client/src/main/java/org/apache/servicecomb/demo/multiple/b/client/BClientMain.java +++ b/demo/demo-multiple/b-client/src/main/java/org/apache/servicecomb/demo/multiple/b/client/BClientMain.java @@ -19,12 +19,12 @@ import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; public class BClientMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(BClientMain.class).web(WebApplicationType.NONE).run(args); BClient client = BeanUtils.getContext().getBean(BClient.class); client.run(); diff --git a/demo/demo-multiple/b-client/src/main/resources/log4j2.xml b/demo/demo-multiple/b-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/b-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/b-client/src/main/resources/microservice.yaml b/demo/demo-multiple/b-client/src/main/resources/microservice.yaml index ea9f8a88776..8445ed3f4d8 100644 --- a/demo/demo-multiple/b-client/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/b-client/src/main/resources/microservice.yaml @@ -16,11 +16,12 @@ ## --------------------------------------------------------------------------- b-server.name: b-server -APPLICATION_ID: multiple -service_description: - name: b-client - version: 0.0.1 + servicecomb: service: - registry: + application: multiple + name: b-client + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 diff --git a/demo/demo-multiple/b-server/pom.xml b/demo/demo-multiple/b-server/pom.xml index 4aae8e82450..e33e750d8e4 100644 --- a/demo/demo-multiple/b-server/pom.xml +++ b/demo/demo-multiple/b-server/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT b-server diff --git a/demo/demo-multiple/b-server/src/main/java/org/apache/servicecomb/demo/multiple/b/server/BServerMain.java b/demo/demo-multiple/b-server/src/main/java/org/apache/servicecomb/demo/multiple/b/server/BServerMain.java index 28d964df945..267925aceae 100644 --- a/demo/demo-multiple/b-server/src/main/java/org/apache/servicecomb/demo/multiple/b/server/BServerMain.java +++ b/demo/demo-multiple/b-server/src/main/java/org/apache/servicecomb/demo/multiple/b/server/BServerMain.java @@ -17,12 +17,11 @@ package org.apache.servicecomb.demo.multiple.b.server; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; public class BServerMain { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(BServerMain.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-multiple/b-server/src/main/resources/log4j2.xml b/demo/demo-multiple/b-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/b-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/b-server/src/main/resources/microservice.yaml b/demo/demo-multiple/b-server/src/main/resources/microservice.yaml index 814dbfae3b2..695ed8f50a8 100644 --- a/demo/demo-multiple/b-server/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/b-server/src/main/resources/microservice.yaml @@ -15,13 +15,13 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: multiple -service_description: - name: b-server - version: 0.0.1 servicecomb: service: - registry: + application: multiple + name: b-server + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 rest: address: 0.0.0.0:8080 diff --git a/demo/demo-multiple/multiple-client/pom.xml b/demo/demo-multiple/multiple-client/pom.xml index dc31b1501af..7dcbb6f14f2 100644 --- a/demo/demo-multiple/multiple-client/pom.xml +++ b/demo/demo-multiple/multiple-client/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT multiple-client Java Chassis::Demo::Multiple::Client @@ -40,35 +40,91 @@ org.apache.servicecomb.demo.multiple.client.MultipleClient - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - ${project.version} - - - - - - docker multiple-server - - -Dservicecomb.highway.address=0.0.0.0:7070 - -Dservicecomb.rest.address=0.0.0.0:8080 - + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + io.fabric8 diff --git a/demo/demo-multiple/multiple-client/src/main/java/org/apache/servicecomb/demo/multiple/client/MultipleClient.java b/demo/demo-multiple/multiple-client/src/main/java/org/apache/servicecomb/demo/multiple/client/MultipleClient.java index c46a0ee6296..ae804ad8bea 100644 --- a/demo/demo-multiple/multiple-client/src/main/java/org/apache/servicecomb/demo/multiple/client/MultipleClient.java +++ b/demo/demo-multiple/multiple-client/src/main/java/org/apache/servicecomb/demo/multiple/client/MultipleClient.java @@ -20,13 +20,22 @@ import org.apache.servicecomb.demo.multiple.a.client.AClient; import org.apache.servicecomb.demo.multiple.b.client.BClient; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ComponentScan; +@SpringBootApplication +@ComponentScan(basePackages = {"org.apache.servicecomb.demo.multiple.a.client", + "org.apache.servicecomb.demo.multiple.b.client"}) public class MultipleClient { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(MultipleClient.class).web(WebApplicationType.NONE).run(args); + runTest(); + } + + public static void runTest() { AClient aClient = BeanUtils.getContext().getBean(AClient.class); BClient bClient = BeanUtils.getContext().getBean(BClient.class); diff --git a/demo/demo-multiple/multiple-client/src/main/resources/log4j2.xml b/demo/demo-multiple/multiple-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/multiple-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/multiple-client/src/main/resources/microservice.yaml b/demo/demo-multiple/multiple-client/src/main/resources/microservice.yaml index f06dd95db94..1ece43eac98 100644 --- a/demo/demo-multiple/multiple-client/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/multiple-client/src/main/resources/microservice.yaml @@ -18,7 +18,9 @@ servicecomb-config-order: 1000 a-server.name: merged-server b-server.name: merged-server -APPLICATION_ID: multiple -service_description: - name: merged-client - version: 0.0.1 + +servicecomb: + service: + application: multiple + name: merged-client + version: 0.0.1 diff --git a/demo/demo-multiple/multiple-client/src/test/java/org/apache/servicecomb/demo/multiple/client/MultipleIT.java b/demo/demo-multiple/multiple-client/src/test/java/org/apache/servicecomb/demo/multiple/client/MultipleIT.java new file mode 100644 index 00000000000..c5c839ae651 --- /dev/null +++ b/demo/demo-multiple/multiple-client/src/test/java/org/apache/servicecomb/demo/multiple/client/MultipleIT.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.multiple.client; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = MultipleClient.class) +public class MultipleIT { + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + MultipleClient.runTest(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-multiple/multiple-server/pom.xml b/demo/demo-multiple/multiple-server/pom.xml index e4ef0b89cf1..18c7ae19069 100644 --- a/demo/demo-multiple/multiple-server/pom.xml +++ b/demo/demo-multiple/multiple-server/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-multiple - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT multiple-server Java Chassis::Demo::Multiple::Server @@ -40,22 +40,13 @@ org.apache.servicecomb.demo.multiple.server.MultipleServer + - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - ${project.version} - - - + org.springframework.boot + spring-boot-maven-plugin - @@ -63,15 +54,50 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-multiple/multiple-server/src/main/java/org/apache/servicecomb/demo/multiple/server/MultipleServer.java b/demo/demo-multiple/multiple-server/src/main/java/org/apache/servicecomb/demo/multiple/server/MultipleServer.java index 9c1113380a5..5b830e46e83 100644 --- a/demo/demo-multiple/multiple-server/src/main/java/org/apache/servicecomb/demo/multiple/server/MultipleServer.java +++ b/demo/demo-multiple/multiple-server/src/main/java/org/apache/servicecomb/demo/multiple/server/MultipleServer.java @@ -16,12 +16,16 @@ */ package org.apache.servicecomb.demo.multiple.server; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ComponentScan; +@SpringBootApplication +@ComponentScan(basePackages = {"org.apache.servicecomb.demo.multiple.a.server", + "org.apache.servicecomb.demo.multiple.b.server"}) public class MultipleServer { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + new SpringApplicationBuilder(MultipleServer.class).web(WebApplicationType.NONE).run(args); } } diff --git a/demo/demo-multiple/multiple-server/src/main/resources/log4j2.xml b/demo/demo-multiple/multiple-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-multiple/multiple-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-multiple/multiple-server/src/main/resources/microservice.yaml b/demo/demo-multiple/multiple-server/src/main/resources/microservice.yaml index 94fb8d2bc30..b1eeade93d7 100644 --- a/demo/demo-multiple/multiple-server/src/main/resources/microservice.yaml +++ b/demo/demo-multiple/multiple-server/src/main/resources/microservice.yaml @@ -16,7 +16,9 @@ ## --------------------------------------------------------------------------- servicecomb-config-order: 1000 -APPLICATION_ID: multiple -service_description: - name: merged-server - version: 0.0.1 + +servicecomb: + service: + application: multiple + name: merged-server + version: 0.0.1 diff --git a/demo/demo-multiple/pom.xml b/demo/demo-multiple/pom.xml index 4758080c179..7496a2050d7 100644 --- a/demo/demo-multiple/pom.xml +++ b/demo/demo-multiple/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-multiple Java Chassis::Demo::Multiple @@ -62,22 +62,30 @@ + + org.apache.servicecomb + registry-service-center + org.apache.servicecomb.demo demo-schema org.apache.servicecomb - provider-pojo + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core - - - - org.apache.maven.plugins - maven-dependency-plugin - - - diff --git a/demo/demo-nacos/README.md b/demo/demo-nacos/README.md new file mode 100644 index 00000000000..9165cac5687 --- /dev/null +++ b/demo/demo-nacos/README.md @@ -0,0 +1,5 @@ +# Notice + +This integration tests is designed for Nacos registry and configuration. And extra test cases include: + +* Test cases related to JAX-RS annotations that demo-jaxrs can not cover. diff --git a/demo/demo-nacos/consumer/pom.xml b/demo/demo-nacos/consumer/pom.xml new file mode 100644 index 00000000000..6dfe326f6a5 --- /dev/null +++ b/demo/demo-nacos/consumer/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-nacos + 3.4.0-SNAPSHOT + + + nacos-consumer + Java Chassis::Demo::NACOS::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-nacos + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java new file mode 100644 index 00000000000..3e7a2a0e285 --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..437f88bfafd --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } + + @GetMapping("/authIncludePath") + public String authIncludePath() { + return providerService.authIncludePath(); + } +} diff --git a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java new file mode 100644 index 00000000000..aed6894f941 --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchema; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "ConsumerHeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchema.class) +public class ConsumerHeaderParamWithListSchema implements IHeaderParamWithListSchema { + @RpcReference(microserviceName = "provider", schemaId = "HeaderParamWithListSchema") + private IHeaderParamWithListSchema provider; + + @Override + public String headerListDefault(List headerList) { + return provider.headerListDefault(headerList); + } + + @Override + public String headerListCSV(List headerList) { + return provider.headerListCSV(headerList); + } + + @Override + public String headerListMULTI(List headerList) { + return provider.headerListMULTI(headerList); + } + + @Override + public String headerListSSV(List headerList) { + return provider.headerListSSV(headerList); + } + + @Override + public String headerListPIPES(List headerList) { + return provider.headerListPIPES(headerList); + } +} diff --git a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..ee62a110625 --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); + + String authIncludePath(); +} diff --git a/demo/demo-nacos/consumer/src/main/resources/application.yml b/demo/demo-nacos/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..ce6025722a5 --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/resources/application.yml @@ -0,0 +1,35 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-nacos + version: 0.0.1 + name: consumer + registry: + nacos: + serverAddr: ${PAAS_CSE_NACOS_ENDPOINT:http://127.0.0.1:8848} + metadata: + group: red + + rest: + address: 0.0.0.0:9092 + + publicKey: + accessControl: + enabled: true + excludePathPatterns: '/*' diff --git a/demo/demo-nacos/consumer/src/main/resources/log4j2.xml b/demo/demo-nacos/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-nacos/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-nacos/gateway/pom.xml b/demo/demo-nacos/gateway/pom.xml new file mode 100644 index 00000000000..f76d407973a --- /dev/null +++ b/demo/demo-nacos/gateway/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-nacos + 3.4.0-SNAPSHOT + + + nacos-gateway + Java Chassis::Demo::NACOS::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb + registry-nacos + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-nacos/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-nacos/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-nacos/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-nacos/gateway/src/main/resources/application.yml b/demo/demo-nacos/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..3bf90e50b73 --- /dev/null +++ b/demo/demo-nacos/gateway/src/main/resources/application.yml @@ -0,0 +1,44 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-nacos + version: 0.0.1 + name: gateway + registry: + nacos: + enabled: true + serverAddr: ${PAAS_CSE_NACOS_ENDPOINT:http://127.0.0.1:8848} + + rest: + address: 0.0.0.0:9090?sslEnabled=false + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ diff --git a/demo/demo-nacos/gateway/src/main/resources/log4j2.xml b/demo/demo-nacos/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-nacos/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-nacos/pom.xml b/demo/demo-nacos/pom.xml new file mode 100644 index 00000000000..a37e292de1d --- /dev/null +++ b/demo/demo-nacos/pom.xml @@ -0,0 +1,61 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-nacos + Java Chassis::Demo::NACOS + pom + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + solution-basic + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + + + provider + consumer + gateway + test-client + + + diff --git a/demo/demo-nacos/provider/pom.xml b/demo/demo-nacos/provider/pom.xml new file mode 100644 index 00000000000..a23bc1bb06f --- /dev/null +++ b/demo/demo-nacos/provider/pom.xml @@ -0,0 +1,108 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-nacos + 3.4.0-SNAPSHOT + + + nacos-provider + Java Chassis::Demo::NACOS::PROVIDER + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-nacos + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java new file mode 100644 index 00000000000..a4475d80bda --- /dev/null +++ b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchema; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "HeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchema.class) +public class HeaderParamWithListSchema implements IHeaderParamWithListSchema { + @Override + public String headerListDefault(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListCSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListMULTI(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListSSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListPIPES(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } +} diff --git a/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java new file mode 100644 index 00000000000..fde6f36b2e3 --- /dev/null +++ b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..0076440d232 --- /dev/null +++ b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController { + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return "Hello " + name; + } + + @GetMapping("/authIncludePath") + public String authIncludePath() { + return "success."; + } +} diff --git a/demo/demo-nacos/provider/src/main/resources/application.yml b/demo/demo-nacos/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..ae6e029b701 --- /dev/null +++ b/demo/demo-nacos/provider/src/main/resources/application.yml @@ -0,0 +1,42 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +servicecomb: + service: + application: demo-nacos + version: 0.0.1 + name: provider + registry: + nacos: + enabled: true + serverAddr: ${PAAS_CSE_NACOS_ENDPOINT:http://127.0.0.1:8848} + metadata: + group: green + + rest: + address: 0.0.0.0:9094 + + publicKey: + accessControl: + enabled: true + includePathPatterns: '/authIncludePath' + black: + authPath: + category: property + propertyName: serviceName + rule: consumer* diff --git a/demo/demo-nacos/provider/src/main/resources/log4j2.xml b/demo/demo-nacos/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-nacos/provider/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-nacos/test-client/pom.xml b/demo/demo-nacos/test-client/pom.xml new file mode 100644 index 00000000000..103aeb24d94 --- /dev/null +++ b/demo/demo-nacos/test-client/pom.xml @@ -0,0 +1,200 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-nacos + 3.4.0-SNAPSHOT + + + nacos-test-client + Java Chassis::Demo::NACOS::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-local + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + nacos/nacos-server:v2.1.2-slim + nacos-server + + alias + + standalone + hostname + + + Tomcat started on port + + + 8848 + + + + + + nacos-server.port:8848 + + + + + nacos-provider:${project.version} + nacos-provider + + alias + + + -Dservicecomb.registry.nacos.serverAddr=http://nacos-server:8848 + + /maven/maven/nacos-provider-${project.version}.jar + + + nacos-server:nacos-server + + + Nacos is ready + + + 9094 + + + + + + 9094:9094 + + + + + nacos-consumer:${project.version} + nacos-consumer + + alias + + + -Dservicecomb.registry.nacos.serverAddr=http://nacos-server:8848 + + /maven/maven/nacos-consumer-${project.version}.jar + + + nacos-server:nacos-server + + + Nacos is ready + + + 9092 + + + + + + 9092:9092 + + + + + nacos-gateway:${project.version} + nacos-gateway + + alias + + + -Dservicecomb.registry.nacos.serverAddr=http://nacos-server:8848 + + /maven/maven/nacos-gateway-${project.version}.jar + + + nacos-server:nacos-server + + + Nacos is ready + + + 9090 + + + + + + 9090:9090 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java new file mode 100644 index 00000000000..1b129acc2c6 --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HeaderParamWithListSchemaIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHeaderListDefault(); + testHeaderListMulti(); + testHeaderListCSV(); + testHeaderListSSV(); + testHeaderListPipes(); + } + + // default to multi + private void testHeaderListDefault() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListDefault", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListPipes() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a|b|c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListPIPES", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListSSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a b c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListSSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListCSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a,b,c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + + headers.add("headerList", "a, b, c"); + entity = new HttpEntity<>(headers); + result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListMulti() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListMULTI", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } +} diff --git a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..ad9460753a8 --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorld(); + testAuthIncludePath(); + } + + private void testHelloWorld() { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + TestMgr.check("Hello World", result); + } + + private void testAuthIncludePath() { + String result = ""; + try { + result = template.getForObject(Config.GATEWAY_URL + "/authIncludePath", String.class); + } catch (Exception e) { + result = "failed"; + } + TestMgr.check("failed", result); + } +} diff --git a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..26a2a491bbe --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } +} diff --git a/demo/demo-nacos/test-client/src/main/resources/application.yml b/demo/demo-nacos/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..2e8b29356b3 --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/resources/application.yml @@ -0,0 +1,25 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-nacos + name: test-client + version: 0.0.1 + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container diff --git a/demo/demo-nacos/test-client/src/main/resources/log4j2.xml b/demo/demo-nacos/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-nacos/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-nacos/test-client/src/test/java/org/apache/servicecomb/samples/NocasIT.java b/demo/demo-nacos/test-client/src/test/java/org/apache/servicecomb/samples/NocasIT.java new file mode 100644 index 00000000000..bc7b5a6b9ba --- /dev/null +++ b/demo/demo-nacos/test-client/src/test/java/org/apache/servicecomb/samples/NocasIT.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = TestClientApplication.class) +public class NocasIT { + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + TestClientApplication.run(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-pojo/pojo-client/pom.xml b/demo/demo-pojo/pojo-client/pom.xml index 3bdc880c16e..582c8c8f511 100644 --- a/demo/demo-pojo/pojo-client/pom.xml +++ b/demo/demo-pojo/pojo-client/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-pojo - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT pojo-client Java Chassis::Demo::POJO::Client @@ -34,7 +34,7 @@ org.apache.servicecomb - provider-pojo + metrics-core org.apache.servicecomb @@ -46,38 +46,91 @@ org.apache.servicecomb.demo.pojo.client.PojoClient - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - ${project.version} - - - - - - + docker pojo-server - - -Dcse.highway.address=0.0.0.0:7070 - -Dcse.rest.address=0.0.0.0:8080 - + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + io.fabric8 diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/BeanRpcTest.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/BeanRpcTest.java index 69e7f0cbba2..caadd95efe7 100644 --- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/BeanRpcTest.java +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/BeanRpcTest.java @@ -20,7 +20,7 @@ import org.apache.servicecomb.provider.pojo.RpcReference; public class BeanRpcTest { - @RpcReference(microserviceName = "pojo") + @RpcReference(microserviceName = "pojo", schemaId = "server") private Test test; public BeanRpcTest() { @@ -28,27 +28,25 @@ public BeanRpcTest() { } public void init() { - new Thread() { - public void run() { - while (true) { + new Thread(() -> { + while (true) { + try { + System.out.println("XXXXXXXXXXXXXXXXXXXXXXXX" + test.getTestString(null)); + break; + } catch (Exception e) { + e.printStackTrace(); try { - System.out.println("XXXXXXXXXXXXXXXXXXXXXXXX" + test.getTestString(null)); - break; - } catch (Exception e) { - e.printStackTrace(); - try { - Thread.sleep(1000); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - continue; - } catch (Throwable e) { - System.out.println("XXXXXXXXXXXXXXXXXXXXXXXX: teset case error"); - e.printStackTrace(); - System.exit(0); + Thread.sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); } + continue; + } catch (Throwable e) { + System.out.println("XXXXXXXXXXXXXXXXXXXXXXXX: teset case error"); + e.printStackTrace(); + System.exit(0); } } - }.start(); + }).start(); } } diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/ClientInterfaceForServerTest.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/ClientInterfaceForServerTest.java new file mode 100644 index 00000000000..34399d081d1 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/ClientInterfaceForServerTest.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import org.apache.servicecomb.demo.server.TestRequest; +import org.apache.servicecomb.demo.server.User; + +public interface ClientInterfaceForServerTest { + User splitParam(int nameNotIndex, User user); + + User wrapParam(TestRequest nameNotRequest); +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java index 6a775d05e95..601901e5884 100644 --- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClient.java @@ -22,25 +22,28 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import javax.inject.Inject; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.demo.CategorizedTestCase; import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import org.apache.servicecomb.demo.DemoConst; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.compute.Person; +import org.apache.servicecomb.demo.mapnull.ParseRequest; +import org.apache.servicecomb.demo.mapnull.ParseResponse; +import org.apache.servicecomb.demo.server.MapModel; import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.provider.pojo.RpcReference; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.stereotype.Component; import io.vertx.core.Vertx; -public class CodeFirstPojoClient { +@Component +public class CodeFirstPojoClient implements CategorizedTestCase { @RpcReference(microserviceName = "pojo", schemaId = "org.apache.servicecomb.demo.CodeFirstPojoIntf") public CodeFirstPojoClientIntf codeFirstAnnotation; @@ -50,18 +53,26 @@ public class CodeFirstPojoClient { @Inject private CodeFirstPojoIntf codeFirstFromXml; - public void testCodeFirst(String microserviceName) { - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); + @Override + public void testRestTransport() throws Exception { + testOnlyRest(codeFirstAnnotation); + } - testAll(codeFirstAnnotation, transport); - testAll(codeFirstAnnotationEmptySchemaId, transport); - testAll(codeFirstFromXml, transport); - } + @Override + public void testAllTransport() throws Exception { + testAll(codeFirstAnnotation); + testAll(codeFirstAnnotationEmptySchemaId); + testAll(codeFirstFromXml); + } + + private void testOnlyRest(CodeFirstPojoIntf codeFirst) { + testCodeFirstStrings(codeFirst); } - protected void testAll(CodeFirstPojoIntf codeFirst, String transport) { + private void testAll(CodeFirstPojoIntf codeFirst) { + remoteCodeFirstPojo_testParseResponse(codeFirst); + remoteCodeFirstPojo_testMapModel(codeFirst); + remoteCodeFirstPojo_testMap(codeFirst); testCodeFirstUserMap(codeFirst); testCodeFirstUserArray(codeFirst); testCodeFirstStrings(codeFirst); @@ -83,7 +94,7 @@ private void testCodeFirstCompletableFuture(CodeFirstPojoIntf codeFirst) { return; } - Vertx vertx = VertxUtils.getOrCreateVertxByName("transport", null); + Vertx vertx = VertxUtils.getOrCreateVertxByName("transport", null, null); CountDownLatch latch = new CountDownLatch(1); // vertx.runOnContext in normal thread is not a good practice // here just a test, not care for this. @@ -91,18 +102,21 @@ private void testCodeFirstCompletableFuture(CodeFirstPojoIntf codeFirst) { InvocationContext context = new InvocationContext(); context.addContext("k", "v"); ContextUtils.setInvocationContext(context); - CompletableFuture future = ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone"); - future.thenCompose(result -> { - TestMgr.check("someone sayhi, context k: v", result); + ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone") + .thenCompose(result -> { + TestMgr.check("someone sayhi, context k: v", result); - TestMgr.check(true, context == ContextUtils.getInvocationContext()); + // new call need set invocation context implicitly or will not + // inherit parent context + ContextUtils.setInvocationContext(context); - return ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone 1"); - }).whenComplete((r, e) -> { - TestMgr.check("someone 1 sayhi, context k: v", r); - latch.countDown(); - }); + return ((CodeFirstPojoClientIntf) codeFirst).sayHiAsync("someone 1"); + }) + .whenComplete((r, e) -> { + TestMgr.check("someone 1 sayhi, context k: v", r); + latch.countDown(); + }); ContextUtils.removeInvocationContext(); }); @@ -114,6 +128,82 @@ private void testCodeFirstCompletableFuture(CodeFirstPojoIntf codeFirst) { } } + private void remoteCodeFirstPojo_testParseResponse(CodeFirstPojoIntf codeFirst) { + ParseResponse r = codeFirst.parse(new ParseRequest()); + TestMgr.check("", r.getMsgHeader().get("K16")); + TestMgr.check("CMT", r.getMsgHeader().get("K14")); + } + + private void remoteCodeFirstPojo_testMapModel(CodeFirstPojoIntf codeFirst) { + MapModel model = new MapModel(); + model.setName("hello"); + Map userMap = new HashMap<>(); + userMap.put("u1", "u1"); + userMap.put("u2", null); + model.setNames(userMap); + MapModel result = codeFirst.testMapModel(model); + + TestMgr.check(result.getName(), "hello"); + TestMgr.check(result.getNames().get("u1"), "u1"); + TestMgr.check(result.getNames().get("u2"), null); + + model = new MapModel(); + model.setName(null); + userMap = new HashMap<>(); + userMap.put("u1", "u1"); + userMap.put("u2", null); + model.setNames(userMap); + result = codeFirst.testMapModel(model); + + TestMgr.check(result.getName(), null); + TestMgr.check(result.getNames().get("u1"), "u1"); + TestMgr.check(result.getNames().get("u2"), null); + + model = new MapModel(); + model.setName(null); + userMap = new HashMap<>(); + userMap.put("u1", "u1"); + userMap.put("u2", ""); + model.setNames(userMap); + result = codeFirst.testMapModel(model); + + TestMgr.check(result.getName(), null); + TestMgr.check(result.getNames().get("u1"), "u1"); + TestMgr.check(result.getNames().get("u2"), ""); + } + + private void remoteCodeFirstPojo_testMap(CodeFirstPojoIntf codeFirst) { + Map userMap = new HashMap<>(); + userMap.put("u1", "u1"); + userMap.put("u2", null); + Map result = codeFirst.testMap(userMap); + + TestMgr.check(result.get("u1"), "u1"); + TestMgr.check(result.get("u2"), null); + + userMap = new HashMap<>(); + userMap.put("u1", "u1"); + userMap.put("u2", "u2"); + result = codeFirst.testMap(userMap); + + TestMgr.check(result.get("u1"), "u1"); + TestMgr.check(result.get("u2"), "u2"); + + // test large data more than 20M + // can not run the test case in CI , because will cause heap size limit +// char[] data = new char[30 * 1024 * 1024]; +// Arrays.fill(data, 'h'); +// userMap = new HashMap<>(); +// userMap.put("u1", "u1"); +// userMap.put("u2", "u2"); +// userMap.put("u3", new String(data)); +// result = codeFirst.testMap(userMap); +// +// TestMgr.check(result.get("u1"), "u1"); +// TestMgr.check(result.get("u2"), "u2"); +// TestMgr.check(result.get("u3"), new String(data)); + } + private void testCodeFirstUserMap(CodeFirstPojoIntf codeFirst) { User user1 = new User(); user1.setNames(new String[] {"u1", "u2"}); @@ -130,6 +220,15 @@ private void testCodeFirstUserMap(CodeFirstPojoIntf codeFirst) { TestMgr.check("u2", result.get("u1").getNames()[1]); TestMgr.check("u3", result.get("u2").getNames()[0]); TestMgr.check("u4", result.get("u2").getNames()[1]); + + userMap = new HashMap<>(); + userMap.put("u1", user1); + userMap.put("u2", null); + result = codeFirst.testUserMap(userMap); + + TestMgr.check(result.get("u1").getNames()[0], "u1"); + TestMgr.check(result.get("u1").getNames()[1], "u2"); + TestMgr.check(result.get("u2"), null); } private void testCodeFirstUserArray(CodeFirstPojoIntf codeFirst) { @@ -151,6 +250,10 @@ private void testCodeFirstStrings(CodeFirstPojoIntf codeFirst) { String[] result = codeFirst.testStrings(new String[] {"a", "b"}); TestMgr.check("aa0", result[0]); TestMgr.check("b", result[1]); + + result = codeFirst.testStrings(new String[] {"a", ""}); + TestMgr.check("aa0", result[0]); + TestMgr.check("", result[1]); } private void testCodeFirstBytes(CodeFirstPojoIntf codeFirst) { @@ -169,17 +272,17 @@ private void testCodeFirstAddDate(CodeFirstPojoIntf codeFirst) { TestMgr.check(new Date(date.getTime() + seconds * 1000), result); } - protected void testCodeFirstAddString(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstAddString(CodeFirstPojoIntf codeFirst) { String result = codeFirst.addString(Arrays.asList("a", "b")); TestMgr.check("ab", result); } - protected void testCodeFirstIsTrue(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstIsTrue(CodeFirstPojoIntf codeFirst) { boolean result = codeFirst.isTrue(); TestMgr.check(true, result); } - protected void testCodeFirstSayHi2(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstSayHi2(CodeFirstPojoIntf codeFirst) { if (!CodeFirstPojoClientIntf.class.isInstance(codeFirst)) { return; } @@ -188,13 +291,13 @@ protected void testCodeFirstSayHi2(CodeFirstPojoIntf codeFirst) { TestMgr.check("world sayhi 2", result); } - protected void testCodeFirstSayHi(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstSayHi(CodeFirstPojoIntf codeFirst) { String result = codeFirst.sayHi("world"); TestMgr.check("world sayhi, context k: null", result); // TestMgr.check(202, responseEntity.getStatusCode()); } - protected void testCodeFirstSaySomething(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstSaySomething(CodeFirstPojoIntf codeFirst) { Person person = new Person(); person.setName("person name"); @@ -202,15 +305,20 @@ protected void testCodeFirstSaySomething(CodeFirstPojoIntf codeFirst) { TestMgr.check("prefix prefix person name", result); } - protected void testCodeFirstSayHello(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstSayHello(CodeFirstPojoIntf codeFirst) { Person input = new Person(); input.setName("person name"); Person result = codeFirst.sayHello(input); TestMgr.check("hello person name", result.getName()); + + input.setName(""); + + result = codeFirst.sayHello(input); + TestMgr.check("hello ", result.getName()); } - protected void testCodeFirstReduce(CodeFirstPojoIntf codeFirst) { + private void testCodeFirstReduce(CodeFirstPojoIntf codeFirst) { int result = codeFirst.reduce(5, 3); TestMgr.check(2, result); } diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClientIntf.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClientIntf.java index 0d19638f2a1..0f4b6586163 100644 --- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClientIntf.java +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/CodeFirstPojoClientIntf.java @@ -20,10 +20,10 @@ import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; public interface CodeFirstPojoClientIntf extends CodeFirstPojoIntf { - @ApiOperation(nickname = "sayHi", value = "") + @Operation(operationId = "sayHi", summary = "") CompletableFuture sayHiAsync(String name); String sayHi2(String name); diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClient.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClient.java index ccb01ca79b4..03fafced0ae 100644 --- a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClient.java +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClient.java @@ -18,106 +18,99 @@ package org.apache.servicecomb.demo.pojo.client; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ForkJoinPool; import java.util.stream.IntStream; -import javax.inject.Inject; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; import org.apache.servicecomb.demo.DemoConst; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.server.TestRequest; import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.demo.smartcare.Application; import org.apache.servicecomb.demo.smartcare.Group; import org.apache.servicecomb.demo.smartcare.SmartCare; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; import org.apache.servicecomb.provider.pojo.RpcReference; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ImportResource; -@Component +@SpringBootApplication +@ImportResource(value = "classpath*:META-INF/spring/*.bean.xml") public class PojoClient { - public static final byte buffer[] = new byte[1024]; - - public static CodeFirstPojoClient codeFirstPojoClient; + private static final Logger LOGGER = LoggerFactory.getLogger(PojoClient.class); // reference a not exist a microservice, and never use it // this should not cause problems @RpcReference(microserviceName = "notExist") public static Test notExist; - @RpcReference(microserviceName = "pojo") + @RpcReference(microserviceName = "pojo", schemaId = "server") public static Test test; public static Test testFromXml; - private static Logger LOGGER = LoggerFactory.getLogger(PojoClient.class); - private static SmartCare smartcare; - static { - Arrays.fill(buffer, (byte) 1); - } - public static void setTestFromXml(Test testFromXml) { PojoClient.testFromXml = testFromXml; } public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - - run(); + new SpringApplicationBuilder(PojoClient.class).web(WebApplicationType.NONE).run(args); + try { + run(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } TestMgr.summary(); + LOGGER.info("-------------- last time updated checks(maybe more/less): 785 -------------"); } - private static void testContextClassLoaderIsNull() { - IntStream.range(0, 100).parallel().forEach(item -> { - if (Thread.currentThread().getName().equals("main")) { - return; - } - // in web environment, this could be null, here we just mock a null class loader. - Thread.currentThread().setContextClassLoader(null); - TestMgr.check(null, test.postTestStatic(2)); - }); + private static void testContextClassLoaderIsNull() throws Exception { + ForkJoinPool pool = new ForkJoinPool(4); + pool.submit(() -> + IntStream.range(0, 20).parallel().forEach(item -> { + if (Thread.currentThread().getName().equals("main")) { + return; + } + // in web environment, this could be null, here we just mock a null class loader. + Thread.currentThread().setContextClassLoader(null); + TestMgr.check(null, test.postTestStatic(2)); + })).get(); } public static void run() throws Exception { - testContextClassLoaderIsNull(); + testHttpClientsIsOk(); + CategorizedTestCaseRunner.runCategorizedTestCase("pojo"); smartcare = BeanUtils.getBean("smartcare"); - String microserviceName = "pojo"; - codeFirstPojoClient.testCodeFirst(microserviceName); for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); TestMgr.setMsg(microserviceName, transport); LOGGER.info("test {}, transport {}", microserviceName, transport); + testContextClassLoaderIsNull(); testNull(testFromXml); - testNull(test); - testEmpty(test); - - // This test case shows destroy of WeightedResponseTimeRule timer task. after test finished will not print: - // "Weight adjusting job started" and thread "NFLoadBalancer-serverWeightTimer-unknown" destroyed. - ArchaiusUtils.setProperty("servicecomb.loadbalance.strategy.name", "WeightedResponse"); - testStringArray(test); - ArchaiusUtils.setProperty("servicecomb.loadbalance.strategy.name", "RoundRobin"); - testStringArray(test); boolean checkerDestroyed = true; // Timer cancel may not destroy thread very fast so check for 3 times. @@ -133,14 +126,6 @@ public static void run() throws Exception { } TestMgr.check(checkerDestroyed, true); - testChinese(test); - testStringHaveSpace(test); - testWrapParam(test); - testSplitParam(test); - testInputArray(test); - - testException(test); - testSmartCare(smartcare); testCommonInvoke(transport); @@ -148,11 +133,20 @@ public static void run() throws Exception { if ("rest".equals(transport)) { testTraceIdOnNotSetBefore(); } - testTraceIdOnContextContainsTraceId(); } } + private static void testHttpClientsIsOk() { + TestMgr.check(HttpClients.getClient("config-center") != null, false); + TestMgr.check(HttpClients.getClient("http-transport-client") != null, false); + TestMgr.check(HttpClients.getClient("http2-transport-client") != null, true); + + TestMgr.check(HttpClients.getClient("config-center", false) != null, false); + TestMgr.check(HttpClients.getClient("http-transport-client", false) != null, false); + TestMgr.check(HttpClients.getClient("http2-transport-client", false) != null, true); + } + /** * Only in http transport, traceId will be set to invocation if null. * But in highway, nothing done. @@ -164,7 +158,7 @@ private static void testTraceIdOnNotSetBefore() { private static void testTraceIdOnContextContainsTraceId() { InvocationContext context = new InvocationContext(); - context.addContext(Const.TRACE_ID_NAME, String.valueOf(Long.MIN_VALUE)); + context.addContext(CoreConst.TRACE_ID_NAME, String.valueOf(Long.MIN_VALUE)); ContextUtils.setInvocationContext(context); String traceId = test.testTraceId(); TestMgr.check(String.valueOf(Long.MIN_VALUE), traceId); @@ -190,98 +184,34 @@ private static void testSmartCare(SmartCare smartCare) { smartCare.delApplication("app0")); } - private static void testException(Test test) { - try { - test.testException(456); - } catch (InvocationException e) { - TestMgr.check("456 error", e.getErrorData()); - } - - try { - test.testException(556); - } catch (InvocationException e) { - TestMgr.check("[556 error]", e.getErrorData()); - } - - try { - test.testException(557); - } catch (InvocationException e) { - TestMgr.check("[[557 error]]", e.getErrorData()); - } - } - - private static void testInputArray(Test test) { - String result = test.addString(new String[] {"a", "b"}); - LOGGER.info("input array result:{}", result); - TestMgr.check("[a, b]", result); - } - - private static void testSplitParam(Test test) { - User result = test.splitParam(1, new User()); - LOGGER.info("split param result:{}", result); - TestMgr.check("User [name=nameA, users count:0, age=100, index=1]", result); - } - + @SuppressWarnings("rawtypes") private static void testCommonInvoke(String transport) { - Object result = InvokerUtils.syncInvoke("pojo", "server", "splitParam", new Object[] {2, new User()}); + Map arguments = new HashMap<>(); + arguments.put("index", 2); + arguments.put("user", new User()); + Map warpArguments = new HashMap<>(); + warpArguments.put("splitParamBody", arguments); + User result = InvokerUtils.syncInvoke("pojo", "server", + "splitParam", warpArguments, User.class); TestMgr.check("User [name=nameA, users count:0, age=100, index=2]", result); + arguments = new HashMap<>(); + arguments.put("index", 3); + arguments.put("user", new User()); + warpArguments = new HashMap<>(); + warpArguments.put("splitParamBody", arguments); result = InvokerUtils.syncInvoke("pojo", - "0.0.4", transport, "server", "splitParam", - new Object[] {3, new User()}); + warpArguments, User.class); TestMgr.check("User [name=nameA, users count:0, age=100, index=3]", result); } - private static void testEmpty(Test test) { - TestMgr.check("code is ''", test.getTestString("")); - } - private static void testNull(Test test) { TestMgr.check("code is 'null'", test.getTestString(null)); - TestMgr.check(null, test.wrapParam(null)); TestMgr.check(null, test.postTestStatic(2)); TestMgr.check(null, test.patchTestStatic(2)); } - - private static void testChinese(Test test) { - TestMgr.check("code is '测试'", test.getTestString("测试")); - - User user = new User(); - user.setName("名字"); - User result = test.splitParam(1, user); - TestMgr.check("名字, users count:0", result.getName()); - } - - private static void testStringHaveSpace(Test test) { - TestMgr.check("code is 'a b'", test.getTestString("a b")); - } - - private static void testStringArray(Test test) { - // TestMgr.check("arr is '[a, , b]'", test.testStringArray(new String[] {"a", null, "b"})); - TestMgr.check("arr is '[a, b]'", test.testStringArray(new String[] {"a", "b"})); - } - - private static void testWrapParam(Test test) { - User user = new User(); - - TestRequest request = new TestRequest(); - request.setUser(user); - request.setIndex(0); - request.setData(buffer); - request.getUsers().add(user); - - User result = test.wrapParam(request); - LOGGER.info("wrap param result:{}", result); - - TestMgr.check("User [name=nameA, users count:1, age=100, index=0]", result); - } - - @Inject - public void setCodeFirstPojoClient(CodeFirstPojoClient codeFirstPojoClient) { - PojoClient.codeFirstPojoClient = codeFirstPojoClient; - } } diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemaInterface.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemaInterface.java new file mode 100644 index 00000000000..39260f3b4a6 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemaInterface.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +public interface SchemaInterface { + String echo(String content); + + String echoError(String content); +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemeInterfacePojo.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemeInterfacePojo.java new file mode 100644 index 00000000000..f701c9fb1f4 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/SchemeInterfacePojo.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +public interface SchemeInterfacePojo { + int reduce(int a, int b); + + int add(int a, int b); +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestFlowControl.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestFlowControl.java new file mode 100644 index 00000000000..c076c167297 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestFlowControl.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +@Component +public class TestFlowControl implements CategorizedTestCase { + interface Client { + int foo(int num); + + int bar(int num); + } + + @RpcReference(microserviceName = "pojo", schemaId = "FlowControlSchema") + Client client1; + + @RpcReference(microserviceName = "pojo", schemaId = "FlowControlClientSchema") + Client client2; + + @Override + public void testAllTransport() throws Exception { + testFlowControl((num) -> client1.foo(num), "provider", true); + testFlowControl((num) -> client1.bar(num), "provider", false); + testFlowControl((num) -> client2.foo(num), "consumer", true); + testFlowControl((num) -> client2.bar(num), "consumer", false); + } + + private void testFlowControl(Function function, String role, boolean expected) + throws InterruptedException { + AtomicBoolean failed = new AtomicBoolean(false); + CountDownLatch countDownLatch = new CountDownLatch(10); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + for (int i1 = 0; i1 < 10; i1++) { + try { + int result = function.apply(10); + if (result != 10) { + TestMgr.failed("", new Exception("not expected")); + } + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 429); + TestMgr.check(((CommonExceptionData) e.getErrorData()).getMessage(), + role + " request rejected by flow control."); + failed.set(true); + break; + } catch (Throwable e) { + e.printStackTrace(); + TestMgr.fail("not expected error " + e.getMessage()); + } + } + countDownLatch.countDown(); + }).start(); + } + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check(expected, failed.get()); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java new file mode 100644 index 00000000000..59d9a8f92b3 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestNotRecommendedService.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.server.AbstractModel; +import org.apache.servicecomb.demo.server.DefaultAbstractModel; +import org.apache.servicecomb.demo.server.NotRecommendedServiceInf; +import org.apache.servicecomb.demo.server.SecondAbstractModel; +import org.apache.servicecomb.demo.server.WrappedAbstractModel; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestNotRecommendedService implements CategorizedTestCase { + @RpcReference(microserviceName = "pojo", schemaId = "NotRecommendedService") + private NotRecommendedServiceInf pojo; + + @Override + public void testRestTransport() throws Exception { + testLongMap(); + testAbstractModel(); + testListAbstractModel(); + testMapAbstractModel(); + testWrappedModel(); + } + + private void testWrappedModel() { + Map data = new HashMap<>(); + AbstractModel model = new DefaultAbstractModel(); + model.setName("hello"); + data.put(100L, model); + + List data2 = new ArrayList<>(); + + AbstractModel model2 = new DefaultAbstractModel(); + model2.setName("hello"); + data2.add(model2); + + WrappedAbstractModel input = new WrappedAbstractModel(); + input.setMapModel(data); + input.setListModel(data2); + AbstractModel secondModel = new SecondAbstractModel(); + secondModel.setName("second"); + input.setModel(secondModel); + input.setName("wrapped"); + + WrappedAbstractModel result = pojo.wrappedAbstractModel(input); + + TestMgr.check(1, result.getMapModel().size()); + TestMgr.check("hello", result.getMapModel().get(result.getMapModel().keySet().iterator().next()).getName()); + + TestMgr.check(1, result.getListModel().size()); + TestMgr.check("hello", result.getListModel().get(0).getName()); + + TestMgr.check("second", result.getModel().getName()); + TestMgr.check(true, result.getModel() instanceof SecondAbstractModel); + TestMgr.check("wrapped", result.getName()); + } + + private void testMapAbstractModel() { + Map data = new HashMap<>(); + AbstractModel model = new DefaultAbstractModel(); + model.setName("hello"); + data.put(100L, model); + Map result = pojo.mapAbstractModel(data); + TestMgr.check(1, result.size()); + TestMgr.check("hello", result.get(result.keySet().iterator().next()).getName()); + } + + private void testListAbstractModel() { + List data = new ArrayList<>(); + AbstractModel model = new DefaultAbstractModel(); + model.setName("hello"); + data.add(model); + List result = pojo.listAbstractModel(data); + TestMgr.check(1, result.size()); + TestMgr.check("hello", result.get(0).getName()); + } + + private void testAbstractModel() { + AbstractModel model = new DefaultAbstractModel(); + model.setName("hello"); + + AbstractModel result = pojo.abstractModel(model); + TestMgr.check("hello", result.getName()); + } + + private void testLongMap() { + Map data = new HashMap<>(); + data.put(100L, 200L); + Map result = pojo.longMap(data); + TestMgr.check(1, result.size()); + TestMgr.check(200L, result.get(100L)); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestRpcReferenceMethodInjection.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestRpcReferenceMethodInjection.java new file mode 100644 index 00000000000..92308e6b6cd --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestRpcReferenceMethodInjection.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestRpcReferenceMethodInjection implements CategorizedTestCase { + + private SchemeInterfacePojo pojo; + + private SchemeInterfacePojo pojoValue; + + @RpcReference(microserviceName = "pojo", schemaId = "SchemeInterfacePojoImpl") + public void setSchemeInterfacePojo(SchemeInterfacePojo pojo) { + this.pojo = pojo; + } + + @RpcReference(microserviceName = "${servicecomb.provider.name}", schemaId = "SchemeInterfacePojoImpl") + public void setSchemeInterfacePojoValue(SchemeInterfacePojo pojoValue) { + this.pojoValue = pojoValue; + } + + @Override + public void testAllTransport() throws Exception { + TestMgr.check(-1, pojo.reduce(1, 2)); + TestMgr.check(-1, pojoValue.reduce(1, 2)); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSameService.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSameService.java new file mode 100644 index 00000000000..0f735af07c4 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSameService.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; + +@Component +public class TestSameService implements CategorizedTestCase { + @OpenAPIDefinition(servers = {@Server(url = "/SameInterface1")}) + public interface SameInterface1 { + String sayHello(String name); + } + + @OpenAPIDefinition(servers = {@Server(url = "/SameInterface2")}) + public interface SameInterface2 { + String sayHello(String name); + } + + @OpenAPIDefinition(servers = {@Server(url = "/SameService1")}) + public interface SameService1 { + String sayHello(String name); + } + + @OpenAPIDefinition(servers = {@Server(url = "/SameService2")}) + public interface SameService2 { + String sayHello(String name); + } + + @RpcReference(microserviceName = "pojo", schemaId = "SameService1") + SameService1 sameService1; + + @RpcReference(microserviceName = "pojo", schemaId = "SameService2") + SameService2 sameService2; + + @RpcReference(microserviceName = "pojo", schemaId = "SameInterface1") + SameInterface1 sameInterface1; + + @RpcReference(microserviceName = "pojo", schemaId = "SameInterface2") + SameInterface2 sameInterface2; + + @Override + public void testAllTransport() throws Exception { + TestMgr.check("pk1-svc-1", sameService1.sayHello("1")); + TestMgr.check("pk2-svc-1", sameService2.sayHello("1")); + TestMgr.check("pk1-inf-1", sameInterface1.sayHello("1")); + TestMgr.check("pk2-inf-1", sameInterface2.sayHello("1")); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterface.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterface.java new file mode 100644 index 00000000000..7866c3add94 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterface.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +@Component +public class TestSchemeInterface implements CategorizedTestCase { + @RpcReference(microserviceName = "pojo", schemaId = "SchemaInterface") + private SchemaInterface pojo; + + @Override + public void testAllTransport() throws Exception { + TestMgr.check("hello", pojo.echo("hello")); + + try { + pojo.echoError("hello"); + TestMgr.failed("should throw exception", new Exception()); + } catch (InvocationException e) { + TestMgr.check( + "Consumer method org.apache.servicecomb.demo.pojo.client.SchemaInterface:" + + "echoError not exist in contract, microserviceName=pojo, schemaId=SchemaInterface.", + ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterfacePojo.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterfacePojo.java new file mode 100644 index 00000000000..18eb0db47db --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestSchemeInterfacePojo.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +@Component +public class TestSchemeInterfacePojo implements CategorizedTestCase { + @RpcReference(microserviceName = "pojo", schemaId = "SchemeInterfacePojoImpl") + private SchemeInterfacePojo pojo; + + @Override + public void testAllTransport() throws Exception { + TestMgr.check(-1, pojo.reduce(1, 2)); + + try { + pojo.add(1, 2); + TestMgr.failed("should throw exception", new Exception()); + } catch (InvocationException e) { + TestMgr.check( + "Consumer method org.apache.servicecomb.demo.pojo.client.SchemeInterfacePojo:" + + "add not exist in contract, microserviceName=pojo, " + + "schemaId=SchemeInterfacePojoImpl.", + ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestTestImpl.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestTestImpl.java new file mode 100644 index 00000000000..8b8fabde08e --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestTestImpl.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.pojo.client; + +import java.util.Arrays; + +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.server.Test; +import org.apache.servicecomb.demo.server.TestRequest; +import org.apache.servicecomb.demo.server.User; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class TestTestImpl implements CategorizedTestCase { + private static final Logger LOGGER = LoggerFactory.getLogger(TestTestImpl.class); + + private static final byte[] buffer = new byte[1024]; + + static { + Arrays.fill(buffer, (byte) 1); + } + + @RpcReference(microserviceName = "pojo", schemaId = "server") + private Test test; + + @Override + public void testAllTransport() throws Exception { + testNull(test); + + // This test case shows destroy of WeightedResponseTimeRule timer task. after test finished will not print: + // "Weight adjusting job started" and thread "NFLoadBalancer-serverWeightTimer-unknown" destroyed. + InMemoryDynamicPropertiesSource.update("servicecomb.loadbalance.strategy.name", "WeightedResponse"); + testStringArray(test); + InMemoryDynamicPropertiesSource.update("servicecomb.loadbalance.strategy.name", "RoundRobin"); + testStringArray(test); + + testChinese(test); + testStringHaveSpace(test); + testWrapParam(test); + + testSplitParam(test); + testInputArray(test); + + testException(test); + + testIntArray(test); + } + + @Override + public void testRestTransport() throws Exception { + testNullRest(test); + testExceptionRest(test); + testEmptyRest(test); + } + + @Override + public void testHighwayTransport() throws Exception { + testNullHighway(test); + testEmptyHighway(test); + } + + private static void testIntArray(Test test) { + int[] request = new int[] {5, 11, 4}; + int[] result = test.testIntArray(request); + TestMgr.check(request.length, result.length); + TestMgr.check(request[1], result[1]); + } + + private static void testEmptyHighway(Test test) { + TestMgr.check("code is ''", test.getTestString("")); + } + + private static void testEmptyRest(Test test) { + TestMgr.check("code is ''", test.getTestString("")); + } + + private static void testNullRest(Test test) { + TestMgr.check(null, test.wrapParam(null)); + } + + private static void testNullHighway(Test test) { + TestMgr.check("nameA", test.wrapParam(null).getName()); + } + + private static void testNull(Test test) { + TestMgr.check("code is 'null'", test.getTestString(null)); + TestMgr.check(null, test.postTestStatic(2)); + TestMgr.check(null, test.patchTestStatic(2)); + } + + private static void testChinese(Test test) { + TestMgr.check("code is '测试'", test.getTestString("测试")); + + User user = new User(); + user.setName("名字"); + User result = test.splitParam(1, user); + TestMgr.check("名字, users count:0", result.getName()); + } + + private static void testStringHaveSpace(Test test) { + TestMgr.check("code is 'a b'", test.getTestString("a b")); + } + + private static void testStringArray(Test test) { + // TestMgr.check("arr is '[a, , b]'", test.testStringArray(new String[] {"a", null, "b"})); + TestMgr.check("arr is '[a, b]'", test.testStringArray(new String[] {"a", "b"})); + } + + private static void testWrapParam(Test test) { + User user = new User(); + + TestRequest request = new TestRequest(); + request.setUser(user); + request.setIndex(0); + request.setData(buffer); + request.getUsers().add(user); + + User result = test.wrapParam(request); + LOGGER.info("wrap param result:{}", result); + + TestMgr.check("User [name=nameA, users count:1, age=100, index=0]", result); + } + + + private static void testExceptionRest(Test test) { + try { + test.testException(456); + } catch (InvocationException e) { + TestMgr.check("456 error", e.getErrorData()); + } + + try { + test.testException(556); + } catch (InvocationException e) { + TestMgr.check("[556 error]", e.getErrorData()); + } + + try { + test.testException(557); + } catch (InvocationException e) { + TestMgr.check("[[557 error]]", e.getErrorData()); + } + } + + private static void testException(Test test) { + try { + test.testException(456); + } catch (InvocationException e) { + TestMgr.check("456 error", e.getErrorData()); + } + + try { + test.testException(556); + } catch (InvocationException e) { + TestMgr.check("[556 error]", e.getErrorData()); + } + + try { + test.testException(557); + } catch (InvocationException e) { + TestMgr.check("[[557 error]]", e.getErrorData()); + } + } + + private static void testInputArray(Test test) { + String result = test.addString(new String[] {"a", "b"}); + LOGGER.info("input array result:{}", result); + TestMgr.check("[a, b]", result); + } + + private static void testSplitParam(Test test) { + User result = test.splitParam(1, new User()); + LOGGER.info("split param result:{}", result); + TestMgr.check("User [name=nameA, users count:0, age=100, index=1]", result); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java new file mode 100644 index 00000000000..eefc0fd1137 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/TestWeakPojo.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.server.GenericsModel; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/* +This is the provider definition: + + + @GetMapping(path = "/diffNames") + @ApiOperation(value = "differentName", nickname = "differentName") + public int diffNames(@RequestParam("x") int a, @RequestParam("y") int b) + + +and the swagger is: + + + paths: + /diffNames: + get: + summary: "differentName" + operationId: "differentName" + parameters: + - name: "x" + in: "query" + required: true + type: "integer" + format: "int32" + - name: "y" + in: "query" + required: true + type: "integer" + format: "int32" + responses: + "200": + description: "response of 200" + schema: + type: "integer" + format: "int32" + + +In consumer, you can define any prototype that matches generated swagger of provider. + */ + +interface DiffNames { + int differentName(int x, int y); +} + +interface DiffNames2 { + int differentName(int y, int x); +} + +interface Generics { + List> genericParams(int code, List> names); +} + +interface GenericsModelInf { + GenericsModel genericParamsModel(int code, GenericsModel model); +} + +interface ObjectInf { + GenericsModel obj(GenericsModel obj); +} + +@Component +public class TestWeakPojo implements CategorizedTestCase { + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private DiffNames diffNames; + + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private DiffNames2 diffNames2; + + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private Generics generics; + + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private GenericsModelInf genericsModelInf; + + @RpcReference(microserviceName = "pojo", schemaId = "WeakPojo") + private ObjectInf objectInf; + + @Override + public void testRestTransport() throws Exception { + + } + + @Override + public void testHighwayTransport() throws Exception { + + } + + @Override + public void testAllTransport() throws Exception { + testDiffName(); + + testGenerics(); + + testGenericsModel(); + + testObject(); + } + + private void testObject() throws JsonProcessingException { + GenericsModel model = new GenericsModel(); + model.setName("model"); + List> namesList = new ArrayList<>(); + List names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + model.setNameList(namesList); + List>> objectLists = new ArrayList<>(); + List> objectList = new ArrayList<>(); + List objects = new ArrayList<>(); + objects.add("object"); + objectList.add(objects); + objectLists.add(objectList); + model.setObjectLists(objectLists); + GenericsModel result = objectInf.obj(model); + TestMgr.check(JsonUtils.writeValueAsString(model), JsonUtils.writeValueAsString(result)); + } + + private void testGenericsModel() throws JsonProcessingException { + GenericsModel model = new GenericsModel(); + model.setName("model"); + List> namesList = new ArrayList<>(); + List names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + model.setNameList(namesList); + List>> objectLists = new ArrayList<>(); + List> objectList = new ArrayList<>(); + List objects = new ArrayList<>(); + objects.add("object"); + objectList.add(objects); + objectLists.add(objectList); + model.setObjectLists(objectLists); + GenericsModel result = genericsModelInf.genericParamsModel(100, model); + TestMgr.check(JsonUtils.writeValueAsString(model), JsonUtils.writeValueAsString(result)); + } + + private void testGenerics() { + List> namesList = new ArrayList<>(); + List names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + List> nameListResult = generics.genericParams(100, namesList); + TestMgr.check(1, nameListResult.size()); + TestMgr.check(1, nameListResult.get(0).size()); + TestMgr.check("hello", nameListResult.get(0).get(0)); + } + + private void testDiffName() { + TestMgr.check(7, diffNames.differentName(2, 3)); + TestMgr.check(8, diffNames2.differentName(2, 3)); + Map args = new HashMap<>(); + args.put("x", 2); + args.put("y", 3); + Map swaggerArgs = new HashMap<>(); + swaggerArgs.put("differentNameBody", args); + TestMgr.check(7, InvokerUtils.syncInvoke("pojo", "WeakPojo", + "differentName", swaggerArgs, Integer.class)); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/ClientModel.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/ClientModel.java new file mode 100644 index 00000000000..fd699064d46 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/ClientModel.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client.invoker; + +public class ClientModel { + private String name; + private int code; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/TestInvokerEndpoint.java b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/TestInvokerEndpoint.java new file mode 100644 index 00000000000..025e67a0b49 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/invoker/TestInvokerEndpoint.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.client.invoker; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.stereotype.Component; + +@Component +@SuppressWarnings({"unchecked", "rawtypes"}) +public class TestInvokerEndpoint implements CategorizedTestCase { + @Override + public void testRestTransport() throws Exception { + testInvokerUtilsDiffModelRest(); + } + + @Override + public void testHighwayTransport() throws Exception { + testInvokerUtilsDiffModelHighway(); + } + + @Override + public void testAllTransport() throws Exception { + testInvokerUtilsDiffModel(); + testInvokerUtilsDiffModelMapArgs(); + } + + private void testInvokerUtilsDiffModelHighway() throws Exception { + Map args = new HashMap<>(); + ClientModel model = new ClientModel(); + model.setCode(200); + model.setName("hello"); + args.put("request", model); + + Map result = InvokerUtils.syncInvoke("pojo", "highway", "InvokerEndpoint", + "model", args, Map.class); + TestMgr.check(model.getCode(), result.get("code")); + TestMgr.check(model.getName(), result.get("name")); + + ClientModel modelResult = InvokerUtils + .syncInvoke("pojo", "highway", "InvokerEndpoint", "model", args, ClientModel.class); + TestMgr.check(model.getCode(), modelResult.getCode()); + TestMgr.check(model.getName(), modelResult.getName()); + + CountDownLatch countDownLatch = new CountDownLatch(1); + InvokerUtils + .reactiveInvoke("pojo", "highway", "InvokerEndpoint", "model", args, ClientModel.class, response -> { + ClientModel reactiveResult = response.getResult(); + TestMgr.check(model.getCode(), reactiveResult.getCode()); + TestMgr.check(model.getName(), reactiveResult.getName()); + System.out.println("done"); + countDownLatch.countDown(); + }); + countDownLatch.await(); + } + + private void testInvokerUtilsDiffModelRest() throws Exception { + Map args = new HashMap<>(); + ClientModel model = new ClientModel(); + model.setCode(200); + model.setName("hello"); + args.put("request", model); + + Map result = InvokerUtils.syncInvoke("pojo", "rest", "InvokerEndpoint", + "model", args, Map.class); + TestMgr.check(model.getCode(), result.get("code")); + TestMgr.check(model.getName(), result.get("name")); + + ClientModel modelResult = InvokerUtils + .syncInvoke("pojo", "rest", "InvokerEndpoint", "model", args, ClientModel.class); + TestMgr.check(model.getCode(), modelResult.getCode()); + TestMgr.check(model.getName(), modelResult.getName()); + + CountDownLatch countDownLatch = new CountDownLatch(1); + InvokerUtils.reactiveInvoke("pojo", "rest", "InvokerEndpoint", "model", args, ClientModel.class, response -> { + ClientModel reactiveResult = response.getResult(); + TestMgr.check(model.getCode(), reactiveResult.getCode()); + TestMgr.check(model.getName(), reactiveResult.getName()); + System.out.println("done"); + countDownLatch.countDown(); + }); + countDownLatch.await(); + } + + private void testInvokerUtilsDiffModel() throws Exception { + Map args = new HashMap<>(); + ClientModel model = new ClientModel(); + model.setCode(200); + model.setName("hello"); + args.put("request", model); + + Map result = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", + "model", args, Map.class); + TestMgr.check(model.getCode(), result.get("code")); + TestMgr.check(model.getName(), result.get("name")); + + ClientModel modelResult = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class); + TestMgr.check(model.getCode(), modelResult.getCode()); + TestMgr.check(model.getName(), modelResult.getName()); + + CountDownLatch countDownLatch = new CountDownLatch(1); + InvokerUtils.reactiveInvoke("pojo", "InvokerEndpoint", "model", args, + ClientModel.class, response -> { + ClientModel reactiveResult = response.getResult(); + TestMgr.check(model.getCode(), reactiveResult.getCode()); + TestMgr.check(model.getName(), reactiveResult.getName()); + System.out.println("done"); + countDownLatch.countDown(); + }); + countDownLatch.await(); + } + + private void testInvokerUtilsDiffModelMapArgs() throws Exception { + Map args = new HashMap<>(); + Map model = new HashMap(); + model.put("code", 20); + model.put("name", "hello"); + args.put("request", model); + + Map result = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", "model", args, Map.class); + TestMgr.check(model.get("code"), result.get("code")); + TestMgr.check(model.get("name"), result.get("name")); + + ClientModel modelResult = InvokerUtils.syncInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class); + TestMgr.check(model.get("code"), modelResult.getCode()); + TestMgr.check(model.get("name"), modelResult.getName()); + + CountDownLatch countDownLatch = new CountDownLatch(1); + InvokerUtils.reactiveInvoke("pojo", "InvokerEndpoint", "model", args, ClientModel.class, response -> { + ClientModel reactiveResult = response.getResult(); + TestMgr.check(model.get("code"), reactiveResult.getCode()); + TestMgr.check(model.get("name"), reactiveResult.getName()); + countDownLatch.countDown(); + }); + countDownLatch.await(); + } +} diff --git a/demo/demo-pojo/pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml b/demo/demo-pojo/pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml index b806ebadc9e..bba1822fd9b 100644 --- a/demo/demo-pojo/pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml +++ b/demo/demo-pojo/pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml @@ -35,9 +35,6 @@ - - - diff --git a/demo/demo-pojo/pojo-client/src/main/resources/log4j2.xml b/demo/demo-pojo/pojo-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-pojo/pojo-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml index 47b01f50416..45c62dffcf1 100644 --- a/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml +++ b/demo/demo-pojo/pojo-client/src/main/resources/microservice.yaml @@ -15,27 +15,35 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: pojotest -service_description: - name: pojoClient - version: 0.0.1 servicecomb: service: - registry: + application: pojotest + name: pojoClient + version: 0.0.1 + registry: + sc: address: http://127.0.0.1:30100 - instance: - healthCheck: - interval: 2 - watch: false - empty: - protection: true - handler: - chain: - Consumer: - default: qps-flowcontrol-consumer,bizkeeper-consumer,loadbalance + rest.client.enabled: false # using only http2 + swagger: + disableDataTypeCheck: true + isolation: Consumer: enabled: false loadbalance: strategy: - name: Random \ No newline at end of file + name: Random + metrics: + window_time: 12000 + publisher.defaultLog.enabled: false # when in testing , can turn on + flowcontrol: + enabled: true + Consumer: + qps: + limit: + pojo: + FlowControlClientSchema: + foo: 3 + bar: 3000 + provider: + name: pojo diff --git a/demo/demo-pojo/pojo-client/src/test/java/org/apache/servicecomb/demo/pojo/PojoIT.java b/demo/demo-pojo/pojo-client/src/test/java/org/apache/servicecomb/demo/pojo/PojoIT.java index 8385ca03033..c0c4f7542c3 100644 --- a/demo/demo-pojo/pojo-client/src/test/java/org/apache/servicecomb/demo/pojo/PojoIT.java +++ b/demo/demo-pojo/pojo-client/src/test/java/org/apache/servicecomb/demo/pojo/PojoIT.java @@ -17,25 +17,28 @@ package org.apache.servicecomb.demo.pojo; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.pojo.client.PojoClient; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = PojoClient.class) public class PojoIT { - @Before + @BeforeEach public void setUp() throws Exception { TestMgr.errors().clear(); } @Test public void clientGetsNoError() throws Exception { - PojoClient.main(new String[0]); + PojoClient.run(); - assertThat(TestMgr.errors().isEmpty(), is(true)); + Assertions.assertTrue(TestMgr.errors().isEmpty()); } } diff --git a/demo/demo-pojo/pojo-server/pom.xml b/demo/demo-pojo/pojo-server/pom.xml index 210b7223e79..b0b673ef47e 100644 --- a/demo/demo-pojo/pojo-server/pom.xml +++ b/demo/demo-pojo/pojo-server/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-pojo - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT pojo-server Java Chassis::Demo::POJO::Server @@ -32,33 +32,18 @@ org.apache.servicecomb.demo demo-schema - - org.apache.servicecomb - provider-pojo - org.apache.servicecomb.demo.pojo.server.PojoServer + true + - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - ${project.version} - - - + org.springframework.boot + spring-boot-maven-plugin @@ -66,15 +51,51 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/CodeFirstPojo.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/CodeFirstPojo.java index 3d03071563a..680d7981d05 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/CodeFirstPojo.java +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/CodeFirstPojo.java @@ -18,22 +18,73 @@ package org.apache.servicecomb.demo.pojo.server; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import org.apache.servicecomb.demo.CodeFirstPojoIntf; import org.apache.servicecomb.demo.compute.Person; +import org.apache.servicecomb.demo.mapnull.ParseRequest; +import org.apache.servicecomb.demo.mapnull.ParseResponse; +import org.apache.servicecomb.demo.server.MapModel; import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.provider.pojo.RpcSchema; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.SwaggerDefinition; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.servers.Server; @RpcSchema() -@SwaggerDefinition(basePath = "/pojo/rest") +@OpenAPIDefinition(servers = {@Server(url = "/pojo/rest")}) public class CodeFirstPojo implements CodeFirstPojoIntf { + @Override + public ParseResponse parse(ParseRequest request) { + ParseResponse r = new ParseResponse(); + r.setResultCode("CU1I0000"); + r.setResultInfo("报文处理成功!报文解析成功!"); + r.setMsgType("cncc.111.001.01"); + Map h = new HashMap<>(); + h.put("C11", "20200101"); + h.put("F41", "3"); + h.put("F40", "cncc.111.001.01"); + h.put("E24", "HVPA5C30177808463743"); + h.put("E35", "HVPA5C30177808463743"); + h.put("A29", "{N:, K20=}"); + h.put("F38", "HVPS"); + h.put("K13", "01"); + h.put("F39", "SAPS"); + h.put("K14", "CMT"); + h.put("K16", ""); + h.put("C92", "102633"); + r.setMsgHeader(h); + Map b = new HashMap<>(); + b.put("E50", "hvps.141.001.01"); + b.put("A00", "402451000010"); + b.put("A01", "105100000017"); + b.put("F32", "NORM"); + b.put("E57", "19218385"); + b.put("D14", "200000.00"); + b.put("C14", "20200101"); + b.put("F25", "02711"); + b.put("A70", "908100000002"); + b.put("C92", "20200101"); + b.put("F2H", "G105"); + r.setMsgBody(b); + return r; + } + + @Override + public MapModel testMapModel(MapModel model) { + return model; + } + + @Override + public Map testMap(Map map) { + return map; + } + @Override public Map testUserMap(Map userMap) { return userMap; @@ -67,18 +118,6 @@ public Person sayHello(Person user) { return user; } - // @SuppressWarnings("unchecked") - // public String testRawJsonString(String jsonInput) { - // Map person; - // try { - // person = RestObjectMapper.INSTANCE.readValue(jsonInput.getBytes(), Map.class); - // } catch (Exception e) { - // e.printStackTrace(); - // return null; - // } - // return "hello " + person.get("name"); - // } - public String saySomething(String prefix, Person user) { return prefix + " " + user.getName(); } @@ -90,7 +129,7 @@ public String sayHi(String name) { : ContextUtils.getInvocationContext().getContext("k")); } - @ApiOperation(nickname = "sayHi2", value = "") + @Operation(operationId = "sayHi2", summary = "") public CompletableFuture sayHi2Async(String name) { CompletableFuture future = new CompletableFuture<>(); future.complete(name + " sayhi 2"); @@ -102,10 +141,10 @@ public boolean isTrue() { } public String addString(List s) { - String result = ""; + StringBuilder result = new StringBuilder(); for (String x : s) { - result += x; + result.append(x); } - return result; + return result.toString(); } } diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlClientSchema.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlClientSchema.java new file mode 100644 index 00000000000..d94bcba140b --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlClientSchema.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "FlowControlClientSchema") +public class FlowControlClientSchema { + public int foo(int num) { + return num; + } + + public int bar(int num) { + return num; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlSchema.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlSchema.java new file mode 100644 index 00000000000..ba2c29338c7 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/FlowControlSchema.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "FlowControlSchema") +public class FlowControlSchema { + public int foo(int num) { + return num; + } + + public int bar(int num) { + return num; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java new file mode 100644 index 00000000000..cd2e3deede1 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/NotRecommendedService.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.demo.server.AbstractModel; +import org.apache.servicecomb.demo.server.NotRecommendedServiceInf; +import org.apache.servicecomb.demo.server.WrappedAbstractModel; +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "NotRecommendedService", schemaInterface = NotRecommendedServiceInf.class) +public class NotRecommendedService implements NotRecommendedServiceInf { + + @Override + public Map longMap(Map map) { + return map; + } + + @Override + public List listAbstractModel(List listModel) { + return listModel; + } + + @Override + public AbstractModel abstractModel(AbstractModel model) { + return model; + } + + @Override + public Map mapAbstractModel(Map mapModel) { + return mapModel; + } + + @Override + public WrappedAbstractModel wrappedAbstractModel(WrappedAbstractModel wrappedModel) { + return wrappedModel; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoProducersCustomized.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoProducersCustomized.java new file mode 100644 index 00000000000..2e8b05fb7e9 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoProducersCustomized.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import org.apache.servicecomb.provider.pojo.schema.PojoProducers; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +@Primary +@Component +// This example shows user's how to customize PojoProducers by @Primary annotation +public class PojoProducersCustomized extends PojoProducers { +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoServer.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoServer.java index b13f18f166e..1ae04e578ee 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoServer.java +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/PojoServer.java @@ -17,12 +17,19 @@ package org.apache.servicecomb.demo.pojo.server; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ImportResource; +@SpringBootApplication +@ImportResource(value = "classpath*:META-INF/spring/*.bean.xml") public class PojoServer { public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); + try { + new SpringApplicationBuilder(PojoServer.class).web(WebApplicationType.NONE).run(args); + } catch (Throwable e) { + e.printStackTrace(); + } } } diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterface.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterface.java new file mode 100644 index 00000000000..cee5bd44b66 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterface.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +public interface SchemaInterface { + String echo(String content); +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterfaceImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterfaceImpl.java new file mode 100644 index 00000000000..6e8645d460e --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemaInterfaceImpl.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +public class SchemaInterfaceImpl implements SchemaInterface { + @Override + public String echo(String content) { + return content; + } + + public String echoError(String content) { + return content; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojo.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojo.java new file mode 100644 index 00000000000..7a503944798 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojo.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +public interface SchemeInterfacePojo { + int reduce(int a, int b); +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojoImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojoImpl.java new file mode 100644 index 00000000000..0e544409a5f --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SchemeInterfacePojoImpl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "SchemeInterfacePojoImpl", schemaInterface = SchemeInterfacePojo.class) +public class SchemeInterfacePojoImpl implements SchemeInterfacePojo { + @Override + public int reduce(int a, int b) { + return a - b; + } + + public int add(int a, int b) { + return a + b; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SmartCareImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SmartCareImpl.java index 69a4abdac69..7b34256a923 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SmartCareImpl.java +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/SmartCareImpl.java @@ -28,7 +28,6 @@ public class SmartCareImpl implements SmartCare { @Override public Response addApplication(Application application) { - // TODO: add application LOG.info(application.toString()); Response resp = new Response(); @@ -40,7 +39,6 @@ public Response addApplication(Application application) { @SuppressWarnings("divzero") @Override public Response delApplication(String appName) { - // TODO: delete application LOG.info(appName); try { diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java index 1d201c1d8b0..230dfd804fe 100644 --- a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java @@ -20,7 +20,7 @@ import java.util.Arrays; import java.util.List; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.demo.server.Test; import org.apache.servicecomb.demo.server.TestRequest; import org.apache.servicecomb.demo.server.User; @@ -37,7 +37,7 @@ public String testStringArray(String[] arr) { @Override public String getTestString(String code) { - return String.format("code is '%s'", String.valueOf(code)); + return String.format("code is '%s'", code); } @Override @@ -88,7 +88,7 @@ public User splitParam(int index, User user) { @Override public User wrapParam(TestRequest request) { - if (request == null) { + if (request == null || request.getUser() == null) { return null; } return doTest(request.getIndex(), request.getUser(), request.getUsers(), request.getData()); @@ -103,6 +103,11 @@ public String addString(String[] strArr) { @Override public String testTraceId() { - return ContextUtils.getInvocationContext().getContext(Const.TRACE_ID_NAME); + return ContextUtils.getInvocationContext().getContext(CoreConst.TRACE_ID_NAME); + } + + @Override + public int[] testIntArray(int[] request) { + return request; } } diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java new file mode 100644 index 00000000000..962952531d0 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/WeakPojo.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server; + +import java.util.List; + +import org.apache.servicecomb.demo.server.GenericsModel; +import org.apache.servicecomb.provider.pojo.RpcSchema; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; + +@RpcSchema(schemaId = "WeakPojo") +public class WeakPojo { + @Operation(summary = "differentName", operationId = "differentName") + public int diffNames(@Parameter(name = "x") int a, @Parameter(name = "y") int b) { + return a * 2 + b; + } + + public List> genericParams(int code, List> names) { + return names; + } + + public GenericsModel genericParamsModel(int code, GenericsModel model) { + return model; + } + + public Object obj(Object obj) { + return obj; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/InvokerEndpoint.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/InvokerEndpoint.java new file mode 100644 index 00000000000..4333bf30bcb --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/InvokerEndpoint.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.invoker; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "InvokerEndpoint") +public class InvokerEndpoint { + public ServerModel model(ServerModel request) { + return request; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/ServerModel.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/ServerModel.java new file mode 100644 index 00000000000..3320f273ce0 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/invoker/ServerModel.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.invoker; + +public class ServerModel { + private String name; + private int code; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterface.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterface.java new file mode 100644 index 00000000000..340ddf355eb --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterface.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk1; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; + +@OpenAPIDefinition(servers = {@Server(url = "/SameInterface1")}) +public interface SameInterface { + String sayHello(String name); +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterfaceImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterfaceImpl.java new file mode 100644 index 00000000000..e0f79bb1e0c --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameInterfaceImpl.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk1; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.springframework.stereotype.Component; + +@RpcSchema(schemaId = "SameInterface1", schemaInterface = SameInterface.class) +@Component("SameInterface1") +public class SameInterfaceImpl implements SameInterface { + @Override + public String sayHello(String name) { + return "pk1-inf-" + name; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameService.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameService.java new file mode 100644 index 00000000000..9a59104e99c --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk1/SameService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk1; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.springframework.stereotype.Component; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; + +@RpcSchema(schemaId = "SameService1") +@Component("SameService1") +@OpenAPIDefinition(servers = {@Server(url = "/SameService1")}) +public class SameService { + public String sayHello(String name) { + return "pk1-svc-" + name; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterface.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterface.java new file mode 100644 index 00000000000..7410776ef65 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterface.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk2; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; + +@OpenAPIDefinition(servers = {@Server(url = "/SameInterface2")}) +public interface SameInterface { + String sayHello(String name); +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterfaceImpl.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterfaceImpl.java new file mode 100644 index 00000000000..59080d80169 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameInterfaceImpl.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk2; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.springframework.stereotype.Component; + +@RpcSchema(schemaId = "SameInterface2", schemaInterface = SameInterface.class) +@Component("SameInterface2") +public class SameInterfaceImpl implements SameInterface { + @Override + public String sayHello(String name) { + return "pk2-inf-" + name; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameService.java b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameService.java new file mode 100644 index 00000000000..38fc544681c --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/same/pk2/SameService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.pojo.server.same.pk2; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.springframework.stereotype.Component; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; + +@RpcSchema(schemaId = "SameService2") +@Component("SameService2") +@OpenAPIDefinition(servers = {@Server(url = "/SameService2")}) +public class SameService { + public String sayHello(String name) { + return "pk2-svc-" + name; + } +} diff --git a/demo/demo-pojo/pojo-server/src/main/resources/META-INF/spring/pojo.server.bean.xml b/demo/demo-pojo/pojo-server/src/main/resources/META-INF/spring/pojo.server.bean.xml index 93bd0056ebd..f64fb18a918 100644 --- a/demo/demo-pojo/pojo-server/src/main/resources/META-INF/spring/pojo.server.bean.xml +++ b/demo/demo-pojo/pojo-server/src/main/resources/META-INF/spring/pojo.server.bean.xml @@ -28,4 +28,7 @@ + + diff --git a/demo/demo-pojo/pojo-server/src/main/resources/log4j2.xml b/demo/demo-pojo/pojo-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-pojo/pojo-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml b/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml index e7051832043..0fe723a06ff 100644 --- a/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml +++ b/demo/demo-pojo/pojo-server/src/main/resources/microservice.yaml @@ -15,21 +15,30 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: pojotest -service_description: - name: pojo - version: 0.0.4 servicecomb: service: - registry: + application: pojotest + name: pojo + version: 0.0.4 + registry: + sc: address: http://127.0.0.1:30100 rest: address: 0.0.0.0:8080?protocol=http2 + server: + http2: + useAlpnEnabled: false highway: address: 0.0.0.0:7070 - #executors: - #default: test - #Provider: - #server: test - #server.wrapParam: test + swagger: + disableDataTypeCheck: true + flowcontrol: + enabled: true + Provider: + qps: + limit: + ANY: + FlowControlSchema: + foo: 3 + bar: 3000 diff --git a/demo/demo-pojo/pojo-tests/pom.xml b/demo/demo-pojo/pojo-tests/pom.xml deleted file mode 100644 index 33ef9f50553..00000000000 --- a/demo/demo-pojo/pojo-tests/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - demo-pojo - org.apache.servicecomb.demo - 1.2.0-SNAPSHOT - - 4.0.0 - - pojo-tests - Java Chassis::Demo::POJO::Tests - - - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-pojo - - - junit - junit - - - - diff --git a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/PojoReferenceIntegrationTest.java b/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/PojoReferenceIntegrationTest.java deleted file mode 100644 index 9706e33c0cb..00000000000 --- a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/PojoReferenceIntegrationTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.integration; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.junit.BeforeClass; -import org.junit.Test; - -import com.seanyinx.github.unit.scaffolding.Randomness; - -public class PojoReferenceIntegrationTest { - - private final int expected = Randomness.nextInt(); - - @BeforeClass - public static void setUp() throws Exception { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - SomePojoTestMain.main(new String[0]); - } - - @Test - public void startsUpAsUsualWhenRpcReferenceIsNotReachable() { - assertThat(SomePojoTestMain.pojoService.localIdentity(expected), is(expected)); - } -} diff --git a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoService.java b/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoService.java deleted file mode 100644 index 12b2bd8e290..00000000000 --- a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoService.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.integration; - -import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.springframework.stereotype.Component; - -@Component -class SomePojoService { - @RpcReference(microserviceName = "pojo", schemaId = "org.apache.servicecomb.demo.CodeFirstPojoIntf") - private CodeFirstPojoIntf codeFirstPojo; - - int localIdentity(int expected) { - return expected; - } - - String remoteSayHi(String username) { - return codeFirstPojo.sayHi(username); - } -} diff --git a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoTestMain.java b/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoTestMain.java deleted file mode 100644 index 30c298dd2e7..00000000000 --- a/demo/demo-pojo/pojo-tests/src/test/java/org/apache/servicecomb/demo/integration/SomePojoTestMain.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.integration; - -import javax.inject.Inject; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.springframework.stereotype.Component; - -@Component -class SomePojoTestMain { - - static SomePojoService pojoService; - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } - - @Inject - public void setPojoService(SomePojoService pojoService) { - SomePojoTestMain.pojoService = pojoService; - } -} diff --git a/demo/demo-pojo/pojo-tests/src/test/resources/microservice.yaml b/demo/demo-pojo/pojo-tests/src/test/resources/microservice.yaml deleted file mode 100644 index 12e0ac5bf3d..00000000000 --- a/demo/demo-pojo/pojo-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: pojotest -service_description: - name: pojo-test - version: 0.0.4 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - -servicecomb: - rpcReference: - loadingMode: eager diff --git a/demo/demo-pojo/pom.xml b/demo/demo-pojo/pom.xml index da25c1066e2..96217173a03 100644 --- a/demo/demo-pojo/pom.xml +++ b/demo/demo-pojo/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-pojo Java Chassis::Demo::POJO @@ -30,7 +30,35 @@ pojo-server pojo-client - pojo-tests - + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + handler-publickey-auth + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + diff --git a/demo/demo-register-url-prefix/README.md b/demo/demo-register-url-prefix/README.md new file mode 100644 index 00000000000..e0b2df4db0b --- /dev/null +++ b/demo/demo-register-url-prefix/README.md @@ -0,0 +1,19 @@ +This demo is an integration test for testing + +```yaml +servicecomb: + service: + registry: + registerUrlPrefix: true +``` + +When this configuration is enabled, web context path is added to swagger, and consumer can +invoke with context path + +```yaml +template.getForObject( + "cse://demo-register-url-prefix-server/hellodemo/register/url/prefix/getName?name=2", + String.class) +``` + +This feature is not recommended for use by default, but for some backward capabilities. diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-client/pom.xml b/demo/demo-register-url-prefix/demo-register-url-prefix-client/pom.xml new file mode 100644 index 00000000000..1b7fc782cd1 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-client/pom.xml @@ -0,0 +1,134 @@ + + + + + 4.0.0 + demo-register-url-prefix-client + Java Chassis::Demo::Register URL Prefix client + + org.apache.servicecomb.demo + demo-register-url-prefix + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.prefix.Application + + + + org.apache.servicecomb.demo + demo-schema + + + + + + docker + + demo-register-url-prefix-server + + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/java/org/apache/servicecomb/demo/prefix/Application.java b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/java/org/apache/servicecomb/demo/prefix/Application.java new file mode 100644 index 00000000000..8b53c6c6bd4 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/java/org/apache/servicecomb/demo/prefix/Application.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.prefix; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.web.client.RestOperations; + +@SpringBootApplication +public class Application { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(Application.class).web(WebApplicationType.SERVLET).build().run(args); + + runTest(); + } + + public static void runTest() { + RestOperations template = RestTemplateBuilder.create(); + TestMgr.check("2", template + .getForObject("cse://demo-register-url-prefix-server/hellodemo/register/url/prefix/getName?name=2", + String.class)); + TestMgr.summary(); + } +} diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/application.yml b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/application.yml new file mode 100644 index 00000000000..65b87064740 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/application.yml @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: demo-register-url-prefix + name: demo-register-url-prefix-client + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 + handler: + chain: + Consumer: + default: loadbalance diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/log4j2.xml b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/test/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixIT.java b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/test/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixIT.java new file mode 100644 index 00000000000..e4ae70fad6c --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-client/src/test/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixIT.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.prefix; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringApplication; + +public class RegisterUrlPrefixIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + SpringApplication.run(Application.class); + + Application.runTest(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/pom.xml b/demo/demo-register-url-prefix/demo-register-url-prefix-server/pom.xml new file mode 100644 index 00000000000..2d34ae62051 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/pom.xml @@ -0,0 +1,101 @@ + + + + + 4.0.0 + demo-register-url-prefix-server + Java Chassis::Demo::Register URL Prefix Server + + org.apache.servicecomb.demo + demo-register-url-prefix + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.prefix.PrefixApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/PrefixApplication.java b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/PrefixApplication.java new file mode 100644 index 00000000000..2fc02f7adbd --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/PrefixApplication.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.prefix; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class PrefixApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(PrefixApplication.class).web(WebApplicationType.SERVLET).build().run(args); + } +} diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixEndpoint.java b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixEndpoint.java new file mode 100644 index 00000000000..dae91a50f49 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/java/org/apache/servicecomb/demo/prefix/RegisterUrlPrefixEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.prefix; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "RegisterUrlPrefixEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class RegisterUrlPrefixEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/application.yml b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/application.yml new file mode 100644 index 00000000000..8a4140eeced --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/application.yml @@ -0,0 +1,33 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + servlet: + context-path: /hellodemo + port: 8080 + +servicecomb: + service: + application: demo-register-url-prefix + name: demo-register-url-prefix-server + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 + registerUrlPrefix: true + rest: + address: 0.0.0.0:8080 diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/log4j2.xml b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/logback.xml b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/logback.xml new file mode 100644 index 00000000000..cc214e46e64 --- /dev/null +++ b/demo/demo-register-url-prefix/demo-register-url-prefix-server/src/main/resources/logback.xml @@ -0,0 +1,29 @@ + + + + + + + %d [%level] [%thread] - %msg (%F:%L\)%n + + + + + + + diff --git a/demo/demo-register-url-prefix/pom.xml b/demo/demo-register-url-prefix/pom.xml new file mode 100644 index 00000000000..e51630b5397 --- /dev/null +++ b/demo/demo-register-url-prefix/pom.xml @@ -0,0 +1,66 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-register-url-prefix + Java Chassis::Demo::Register URL Prefix + pom + + demo-register-url-prefix-server + demo-register-url-prefix-client + + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + org.apache.servicecomb + foundation-test-scaffolding + compile + + + diff --git a/demo/demo-schema/pom.xml b/demo/demo-schema/pom.xml index ac2542017f9..b17f345111b 100644 --- a/demo/demo-schema/pom.xml +++ b/demo/demo-schema/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-schema Java Chassis::Demo::Schema @@ -30,37 +30,13 @@ org.apache.servicecomb - handler-bizkeeper + solution-basic org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-rest-servlet - - - javax.servlet - javax.servlet-api + foundation-test-scaffolding compile - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - swagger-generator-springmvc - diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCase.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCase.java new file mode 100644 index 00000000000..c5267878c92 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCase.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo; + +public interface CategorizedTestCase { + /** + * test case which only successful in REST transport + */ + default void testRestTransport() throws Exception { + + } + + /** + * test case which only successful in HIGHWAY transport + */ + default void testHighwayTransport() throws Exception { + + } + + /** + * test case which successful in both REST and HIGHWAY transport + */ + default void testAllTransport() throws Exception { + + } + + default String getMicroserviceName() { + return null; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCaseRunner.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCaseRunner.java new file mode 100644 index 00000000000..acb82190374 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CategorizedTestCaseRunner.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo; + +import java.util.Map; + +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CategorizedTestCaseRunner { + private static final Logger LOGGER = LoggerFactory.getLogger(CategorizedTestCaseRunner.class); + + public static void runCategorizedTestCase(String microserviceName) throws Exception { + Map tests = BeanUtils.getContext().getBeansOfType(CategorizedTestCase.class); + for (String transport : DemoConst.transports) { + for (CategorizedTestCase testCase : tests.values()) { + + try { + if (testCase.getMicroserviceName() != null) { + changeTransport(testCase.getMicroserviceName(), transport); + } else { + changeTransport(microserviceName, transport); + } + + testCase.testAllTransport(); + if ("rest".equals(transport)) { + testCase.testRestTransport(); + } else if ("highway".equals(transport)) { + testCase.testHighwayTransport(); + } + } catch (Exception e) { + LOGGER.error("run categorized test case " + + testCase.getClass().getName() + + " failed.", e); + throw e; + } + } + } + } + + public static void changeTransport(String microserviceName, String transport) { + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); + TestMgr.setMsg(microserviceName, transport); + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstPojoIntf.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstPojoIntf.java index bcf5681ace5..38779b3e141 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstPojoIntf.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstPojoIntf.java @@ -22,9 +22,18 @@ import java.util.Map; import org.apache.servicecomb.demo.compute.Person; +import org.apache.servicecomb.demo.mapnull.ParseRequest; +import org.apache.servicecomb.demo.mapnull.ParseResponse; +import org.apache.servicecomb.demo.server.MapModel; import org.apache.servicecomb.demo.server.User; public interface CodeFirstPojoIntf { + ParseResponse parse(ParseRequest request); + + MapModel testMapModel(MapModel model); + + Map testMap(Map map); + Map testUserMap(Map userMap); List testUserArray(List users); diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java index d5a12be1284..ee2bf395847 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CodeFirstRestTemplate.java @@ -21,41 +21,47 @@ import java.util.HashMap; import java.util.Map; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.demo.ignore.InputModelForTestIgnore; import org.apache.servicecomb.demo.ignore.OutputModelForTestIgnore; -import org.apache.servicecomb.demo.jaxbbean.JAXBJob; -import org.apache.servicecomb.demo.jaxbbean.JAXBPerson; import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.env.Environment; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; import io.vertx.core.json.JsonObject; public class CodeFirstRestTemplate { + protected Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + protected void changeTransport(String microserviceName, String transport) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); TestMgr.setMsg(microserviceName, transport); } - public void testCodeFirst(RestTemplate template, String microserviceName, String basePath) { + public void testCodeFirst(RestOperations template, String microserviceName, String basePath) { String cseUrlPrefix = "cse://" + microserviceName + basePath; changeTransport(microserviceName, "highway"); testOnlyHighway(template, cseUrlPrefix); - changeTransport(microserviceName, Const.RESTFUL); - testOnlyRest(template, cseUrlPrefix); + changeTransport(microserviceName, CoreConst.RESTFUL); + testOnlyRest(microserviceName, template, cseUrlPrefix); for (String transport : DemoConst.transports) { changeTransport(microserviceName, transport); @@ -63,10 +69,9 @@ public void testCodeFirst(RestTemplate template, String microserviceName, String } } - protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) { + protected void testAllTransport(String microserviceName, RestOperations template, String cseUrlPrefix) { testCodeFirstUserMap(template, cseUrlPrefix); testCodeFirstTextPlain(template, cseUrlPrefix); - testCodeFirstAppXml(template, cseUrlPrefix); testCodeFirstBytes(template, cseUrlPrefix); testCseResponse(microserviceName, template, cseUrlPrefix); testCodeFirstAddDate(template, cseUrlPrefix); @@ -77,7 +82,6 @@ protected void testAllTransport(String microserviceName, RestTemplate template, testCodeFirstSayHi2(template, cseUrlPrefix); testCodeFirstSayHi(template, cseUrlPrefix); testCodeFirstSaySomething(template, cseUrlPrefix); - // testCodeFirstRawJsonString(template, cseUrlPrefix); testCodeFirstSayHello(template, cseUrlPrefix); testCodeFirstReduce(template, cseUrlPrefix); @@ -86,19 +90,26 @@ protected void testAllTransport(String microserviceName, RestTemplate template, testRawJson(template, cseUrlPrefix); } - protected void testOnlyHighway(RestTemplate template, String cseUrlPrefix) { + protected void testOnlyHighway(RestOperations template, String cseUrlPrefix) { } - protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) { - // TODO: highway unsupported until JAV-394 completed - testModelFieldIgnore(template, cseUrlPrefix); + protected void testOnlyRest(String microserviceName, RestOperations template, String cseUrlPrefix) { + testCodeFirstUserMap(template, cseUrlPrefix); + testCodeFirstTextPlain(template, cseUrlPrefix); + testCodeFirstBytes(template, cseUrlPrefix); + testCseResponse(microserviceName, template, cseUrlPrefix); + testCodeFirstAddDate(template, cseUrlPrefix); + testCodeFirstAdd(template, cseUrlPrefix); + testCodeFirstAddString(template, cseUrlPrefix); + testModelFieldIgnore(template, cseUrlPrefix); + testCodeFirstReduce(template, cseUrlPrefix); // only rest transport will set trace id testTraceIdOnNotSetBefore(template, cseUrlPrefix); } - private void testCodeFirstUserMap(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstUserMap(RestOperations template, String cseUrlPrefix) { User user1 = new User(); user1.setNames(new String[] {"u1", "u2"}); @@ -109,10 +120,16 @@ private void testCodeFirstUserMap(RestTemplate template, String cseUrlPrefix) { userMap.put("u1", user1); userMap.put("u2", user2); - @SuppressWarnings("unchecked") - Map result = template.postForObject(cseUrlPrefix + "testUserMap", - userMap, - Map.class); + // TODO: shall we support this usage? Seams not valid, cause result should be Map and type not defined. +// @SuppressWarnings("unchecked") +// Map result = template.postForObject(cseUrlPrefix + "testUserMap", +// userMap, +// Map.class); + + Map result = template.exchange(cseUrlPrefix + "testUserMap", HttpMethod.POST, + new HttpEntity<>(userMap), + new ParameterizedTypeReference>() { + }).getBody(); TestMgr.check("u1", result.get("u1").getNames()[0]); TestMgr.check("u2", result.get("u1").getNames()[1]); @@ -120,7 +137,7 @@ private void testCodeFirstUserMap(RestTemplate template, String cseUrlPrefix) { TestMgr.check("u4", result.get("u2").getNames()[1]); } - private void testCodeFirstTextPlain(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstTextPlain(RestOperations template, String cseUrlPrefix) { String body = "a=1"; String result = template.postForObject(cseUrlPrefix + "textPlain", body, @@ -128,22 +145,7 @@ private void testCodeFirstTextPlain(RestTemplate template, String cseUrlPrefix) TestMgr.check(body, result); } - private void testCodeFirstAppXml(RestTemplate template, String cseUrlPrefix) { - JAXBPerson person = new JAXBPerson("jake", 22, "it", "60kg"); - person.setJob(new JAXBJob("developer", "coding")); - HttpHeaders headers = new HttpHeaders(); - headers.add("Accept", MediaType.APPLICATION_XML_VALUE); - headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE); - HttpEntity requestEntity = new HttpEntity<>(person, headers); - ResponseEntity resEntity = template.exchange(cseUrlPrefix + "appXml", - HttpMethod.POST, - requestEntity, - JAXBPerson.class); - TestMgr.check(-1, ProduceProcessorManager.INSTANCE.ensureFindValue(MediaType.APPLICATION_XML_VALUE).getOrder()); - TestMgr.check(person, resEntity.getBody()); - } - - private void testCodeFirstBytes(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstBytes(RestOperations template, String cseUrlPrefix) { byte[] body = new byte[] {0, 1, 2}; byte[] result = template.postForObject(cseUrlPrefix + "bytes", body, @@ -154,13 +156,13 @@ private void testCodeFirstBytes(RestTemplate template, String cseUrlPrefix) { TestMgr.check(2, result[2]); } - protected void checkStatusCode(String microserviceName, int expectStatusCode, HttpStatus httpStatus) { + protected void checkStatusCode(String microserviceName, int expectStatusCode, HttpStatusCode httpStatus) { TestMgr.check(expectStatusCode, httpStatus.value()); } - private void testCseResponse(String targetMicroserviceName, RestTemplate template, + private void testCseResponse(String targetMicroserviceName, RestOperations template, String cseUrlPrefix) { - String srcMicroserviceName = RegistryUtils.getMicroservice().getServiceName(); + String srcMicroserviceName = BootStrapProperties.readServiceName(environment); ResponseEntity responseEntity = template.exchange(cseUrlPrefix + "cseResponse", HttpMethod.GET, null, User.class); @@ -170,7 +172,7 @@ private void testCseResponse(String targetMicroserviceName, RestTemplate templat checkStatusCode(targetMicroserviceName, 202, responseEntity.getStatusCode()); } - private void testCodeFirstAddDate(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstAddDate(RestOperations template, String cseUrlPrefix) { Map body = new HashMap<>(); Date date = new Date(); body.put("date", date); @@ -183,7 +185,7 @@ private void testCodeFirstAddDate(RestTemplate template, String cseUrlPrefix) { TestMgr.check(new Date(date.getTime() + seconds * 1000), result); } - protected void testCodeFirstAddString(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstAddString(RestOperations template, String cseUrlPrefix) { ResponseEntity responseEntity = template.exchange(cseUrlPrefix + "addstring?s=a&s=b", HttpMethod.DELETE, @@ -192,25 +194,25 @@ protected void testCodeFirstAddString(RestTemplate template, String cseUrlPrefix TestMgr.check("ab", responseEntity.getBody()); } - protected void testCodeFirstIsTrue(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstIsTrue(RestOperations template, String cseUrlPrefix) { boolean result = template.getForObject(cseUrlPrefix + "istrue", boolean.class); TestMgr.check(true, result); } - protected void testCodeFirstSayHi2(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstSayHi2(RestOperations template, String cseUrlPrefix) { ResponseEntity responseEntity = template.exchange(cseUrlPrefix + "sayhi/{name}/v2", HttpMethod.PUT, null, String.class, "world"); TestMgr.check("world sayhi 2", responseEntity.getBody()); } - protected void testCodeFirstSayHi(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstSayHi(RestOperations template, String cseUrlPrefix) { ResponseEntity responseEntity = template.exchange(cseUrlPrefix + "sayhi/{name}", HttpMethod.PUT, null, String.class, "world"); - TestMgr.check(202, responseEntity.getStatusCode()); + TestMgr.check(202, responseEntity.getStatusCode().value()); TestMgr.check("world sayhi", responseEntity.getBody()); } - protected void testCodeFirstSaySomething(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstSaySomething(RestOperations template, String cseUrlPrefix) { Person person = new Person(); person.setName("person name"); @@ -223,7 +225,7 @@ protected void testCodeFirstSaySomething(RestTemplate template, String cseUrlPre TestMgr.check("prefix prefix person name", result); } - protected void testCodeFirstSayHello(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstSayHello(RestOperations template, String cseUrlPrefix) { Map persionFieldMap = new HashMap<>(); persionFieldMap.put("name", "person name from map"); Person result = template.postForObject(cseUrlPrefix + "sayhello", persionFieldMap, Person.class); @@ -235,7 +237,7 @@ protected void testCodeFirstSayHello(RestTemplate template, String cseUrlPrefix) TestMgr.check("hello person name from Object", result); } - protected void testCodeFirstAdd(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstAdd(RestOperations template, String cseUrlPrefix) { Map params = new HashMap<>(); params.put("a", "5"); params.put("b", "3"); @@ -244,7 +246,7 @@ protected void testCodeFirstAdd(RestTemplate template, String cseUrlPrefix) { TestMgr.check(8, result); } - protected void testCodeFirstReduce(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstReduce(RestOperations template, String cseUrlPrefix) { Map params = new HashMap<>(); params.put("a", "5"); @@ -257,10 +259,10 @@ protected void testCodeFirstReduce(RestTemplate template, String cseUrlPrefix) { TestMgr.check(2, result.getBody()); } - protected void testModelFieldIgnore(RestTemplate template, String cseUrlPrefix) { + private void testModelFieldIgnore(RestOperations template, String cseUrlPrefix) { InputModelForTestIgnore input = new InputModelForTestIgnore("input_id_rest", "input_id_content", new Person("inputSomeone"), new JsonObject("{\"InputJsonKey\" : \"InputJsonValue\"}"), () -> { - }); + }); OutputModelForTestIgnore output = template .postForObject(cseUrlPrefix + "ignore", input, OutputModelForTestIgnore.class); @@ -277,22 +279,22 @@ protected void testModelFieldIgnore(RestTemplate template, String cseUrlPrefix) TestMgr.check(null, output.getOutputObject()); } - protected void testRawJson(RestTemplate template, String cseUrlPrefix) { + private void testRawJson(RestOperations template, String cseUrlPrefix) { String input = "{\"name\" : \"zyy\"}"; String output = template.postForObject(cseUrlPrefix + "rawJsonAnnotation", input, String.class); TestMgr.check("hello zyy", output); } - protected void testTraceIdOnNotSetBefore(RestTemplate template, String cseUrlPrefix) { + private void testTraceIdOnNotSetBefore(RestOperations template, String cseUrlPrefix) { String traceIdUrl = cseUrlPrefix + "traceId"; String result = template.getForObject(traceIdUrl, String.class); TestMgr.checkNotEmpty(result); } - protected void testTraceIdOnContextContainsTraceId(RestTemplate template, String cseUrlPrefix) { + private void testTraceIdOnContextContainsTraceId(RestOperations template, String cseUrlPrefix) { String traceIdUrl = cseUrlPrefix + "traceId"; InvocationContext invocationContext = new InvocationContext(); - invocationContext.addContext(Const.TRACE_ID_NAME, String.valueOf(Long.MIN_VALUE)); + invocationContext.addContext(CoreConst.TRACE_ID_NAME, String.valueOf(Long.MIN_VALUE)); ContextUtils.setInvocationContext(invocationContext); String result = template.getForObject(traceIdUrl, String.class); TestMgr.check(String.valueOf(Long.MIN_VALUE), result); diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CommonSchemaInterface.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CommonSchemaInterface.java new file mode 100644 index 00000000000..550f9e5adaf --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/CommonSchemaInterface.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo; + +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.Operation; + +@RequestMapping("/CommonSchemaInterface") +public interface CommonSchemaInterface { + @GetMapping(path = "testInvocationTimeout") + String testInvocationTimeout(@RequestParam("timeout") long timeout, @RequestParam("name") String name); + + @GetMapping(path = "testInvocationTimeoutWithInvocation") + @Operation(summary = "testInvocationTimeoutWithInvocation", operationId = "testInvocationTimeoutWithInvocation") + String testInvocationTimeout(InvocationContext context, @RequestParam("timeout") long timeout, + @RequestParam("name") String name); + + @GetMapping(path = "testInvocationTimeoutInClientWait") + String testInvocationTimeoutInClientWait(@RequestParam("timeout") long timeout, @RequestParam("name") String name); +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoConst.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoConst.java index 47286385353..84018a5254b 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoConst.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoConst.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.demo; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; public interface DemoConst { - String[] transports = new String[] {"highway", "rest", Const.ANY_TRANSPORT}; + String[] transports = new String[] {"rest", "highway", CoreConst.ANY_TRANSPORT}; } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoSSLCustom.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoSSLCustom.java index 3ee9978ccf8..ee8e5fd918b 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoSSLCustom.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/DemoSSLCustom.java @@ -17,11 +17,16 @@ package org.apache.servicecomb.demo; -import java.net.URL; +import java.io.File; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DemoSSLCustom extends SSLCustom { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoSSLCustom.class); + @Override public char[] decode(char[] encrypted) { return encrypted; @@ -29,11 +34,40 @@ public char[] decode(char[] encrypted) { @Override public String getFullPath(String filename) { - URL url = Thread.currentThread().getContextClassLoader().getResource("certificates/" + filename); - if (url == null) { - return filename; + LOGGER.info("current working dir :" + System.getProperty("user.dir")); + + if (StringUtils.isEmpty(filename)) { + return null; + } + + // local for different IDEs + File localFile = new File( + System.getProperty("user.dir") + "/demo/demo-springmvc/springmvc-server/src/main/resources/certificates/" + + filename); + if (localFile.isFile()) { + return localFile.getAbsolutePath(); + } + + localFile = new File( + System.getProperty("user.dir") + "/src/main/resources/certificates/" + + filename); + if (localFile.isFile()) { + return localFile.getAbsolutePath(); + } + + localFile = new File(System.getProperty("user.dir") + "/certificates/" + filename); + if (localFile.isFile()) { + return localFile.getAbsolutePath(); + } + + // docker + localFile = new File("/maven/maven/certificates/" + filename); + if (localFile.isFile()) { + return localFile.getAbsolutePath(); } - return url.getPath(); + // in jar, maybe + LOGGER.info("not found file {} in file system, maybe in jar.", filename); + return "certificates/" + filename; } } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapper.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapper.java index d90160c1082..a15d4cb3f52 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapper.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapper.java @@ -19,7 +19,7 @@ import java.io.IOException; -import org.apache.servicecomb.common.rest.codec.RestObjectMapper; +import org.apache.servicecomb.foundation.common.utils.RestObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java index f2218bcdab0..c90fe8bc1a5 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/TestMgr.java @@ -19,10 +19,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; public class TestMgr { private static final Logger LOGGER = LoggerFactory.getLogger(TestMgr.class); @@ -31,6 +32,8 @@ public class TestMgr { private static String msg = ""; + private static final AtomicLong checks = new AtomicLong(0); + public static void setMsg(String msg) { TestMgr.msg = msg; } @@ -44,6 +47,8 @@ public static void check(Object expect, Object real) { } public static void check(Object expect, Object real, Throwable error) { + checks.incrementAndGet(); + if (expect == real) { return; } @@ -61,15 +66,23 @@ public static void check(Object expect, Object real, Throwable error) { } public static void checkNotEmpty(String real) { + checks.incrementAndGet(); + if (StringUtils.isEmpty(real)) { errorList.add(new Error(msg + " | unexpected null result, method is " + getCaller())); } } + public static void fail(String desc) { + failed(desc, new Exception(desc)); + } + public static void failed(String desc, Throwable e) { + checks.incrementAndGet(); + Error error = new Error(msg + " | " + desc + ", method is " + getCaller()); if (e != null) { - error.setStackTrace(error.getStackTrace()); + error.setStackTrace(e.getStackTrace()); } errorList.add(error); } @@ -81,10 +94,14 @@ public static boolean isSuccess() { public static void summary() { if (errorList.isEmpty()) { LOGGER.info("............. test finished ............"); + LOGGER.info("............. total checks : " + checks.get()); return; } LOGGER.info("............. test not finished ............"); + LOGGER.info("............. total checks : " + checks.get()); + LOGGER.info("............. total errors : " + errorList.size()); + LOGGER.info("............. error details: "); for (Throwable e : errorList) { LOGGER.info("", e); } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java new file mode 100644 index 00000000000..8ee60ff27dd --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.api; + +import java.util.List; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.ParameterStyle; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; + +@Path("/headerList") +public interface IHeaderParamWithListSchema { + @Path("headerListDefault") + @GET + String headerListDefault( + @HeaderParam("headerList") List headerList); + + @Path("headerListCSV") + @GET + String headerListCSV( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.FORM, explode = Explode.FALSE) + List headerList); + + @Path("headerListMULTI") + @GET + String headerListMULTI( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.FORM, explode = Explode.TRUE) + List headerList); + + @Path("headerListSSV") + @GET + String headerListSSV( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.SPACEDELIMITED, explode = Explode.FALSE) + List headerList); + + @Path("headerListPIPES") + @GET + String headerListPIPES( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.PIPEDELIMITED, explode = Explode.FALSE) + List headerList); +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchemaSpringMvc.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchemaSpringMvc.java new file mode 100644 index 00000000000..75875f8790c --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchemaSpringMvc.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.api; + + +import java.util.List; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.ParameterStyle; + +@RequestMapping("/headerList") +public interface IHeaderParamWithListSchemaSpringMvc { + @GetMapping("headerListDefault") + String headerListDefault( + @RequestHeader("headerList") List headerList); + + @GetMapping("headerListCSV") + String headerListCSV( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.FORM, explode = Explode.FALSE) + List headerList); + + @GetMapping("headerListMULTI") + String headerListMULTI( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.FORM, explode = Explode.TRUE) + List headerList); + + @GetMapping("headerListSSV") + String headerListSSV( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.SPACEDELIMITED, explode = Explode.FALSE) + List headerList); + + @GetMapping("headerListPIPES") + String headerListPIPES( + @Parameter(name = "headerList", in = ParameterIn.HEADER, style = ParameterStyle.PIPEDELIMITED, explode = Explode.FALSE) + List headerList); +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java index 3ec6f17c5e3..206f652e6cf 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java @@ -28,7 +28,11 @@ public String getStr() { return str; } - public GenericParam setStr(String str) { + public void setStr(String str) { + this.str = str; + } + + public GenericParam str(String str) { this.str = str; return this; } @@ -37,7 +41,11 @@ public long getNum() { return num; } - public GenericParam setNum(long num) { + public void setNum(long num) { + this.num = num; + } + + public GenericParam num(long num) { this.num = num; return this; } @@ -46,14 +54,18 @@ public T getData() { return data; } - public GenericParam setData(T data) { + public void setData(T data) { + this.data = data; + } + + public GenericParam data(T data) { this.data = data; return this; } @Override public String toString() { - final StringBuilder sb = new StringBuilder("GenericParam{"); + StringBuilder sb = new StringBuilder("GenericParam{"); sb.append("str='").append(str).append('\''); sb.append(", num=").append(num); sb.append(", data=").append(data); diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java index 1f97197f424..084a8e95136 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java @@ -26,7 +26,11 @@ public String getStrExtended() { return strExtended; } - public GenericParamExtended setStrExtended(String strExtended) { + public void setStrExtended(String strExtended) { + this.strExtended = strExtended; + } + + public GenericParamExtended strExtended(String strExtended) { this.strExtended = strExtended; return this; } @@ -35,14 +39,18 @@ public int getIntExtended() { return intExtended; } - public GenericParamExtended setIntExtended(int intExtended) { + public void setIntExtended(int intExtended) { + this.intExtended = intExtended; + } + + public GenericParamExtended intExtended(int intExtended) { this.intExtended = intExtended; return this; } @Override public String toString() { - final StringBuilder sb = new StringBuilder("GenericParamExtended{"); + StringBuilder sb = new StringBuilder("GenericParamExtended{"); sb.append("strExtended='").append(strExtended).append('\''); sb.append(", intExtended=").append(intExtended); sb.append(", super=").append(super.toString()); diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java index 0a295a88132..448f64b9f4e 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java @@ -31,7 +31,11 @@ public String getStr() { return str; } - public GenericParamWithJsonIgnore setStr(String str) { + public void setStr(String str) { + this.str = str; + } + + public GenericParamWithJsonIgnore str(String str) { this.str = str; return this; } @@ -40,7 +44,11 @@ public long getNum() { return num; } - public GenericParamWithJsonIgnore setNum(long num) { + public void setNum(long num) { + this.num = num; + } + + public GenericParamWithJsonIgnore num(long num) { this.num = num; return this; } @@ -49,14 +57,18 @@ public T getData() { return data; } - public GenericParamWithJsonIgnore setData(T data) { + public void setData(T data) { + this.data = data; + } + + public GenericParamWithJsonIgnore data(T data) { this.data = data; return this; } @Override public String toString() { - final StringBuilder sb = new StringBuilder("GenericParamWithJsonIgnore{"); + StringBuilder sb = new StringBuilder("GenericParamWithJsonIgnore{"); sb.append("str='").append(str).append('\''); sb.append(", num=").append(num); sb.append(", data=").append(data); diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/Controller.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/Controller.java index f8752fb84dc..b82cd345a52 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/Controller.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/Controller.java @@ -27,4 +27,6 @@ public interface Controller { String sayHi(String name); String sayHei(String name); + + String sayHello1(String name); } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/PersonAlias.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/PersonAlias.java new file mode 100644 index 00000000000..a1766eb29c2 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/controller/PersonAlias.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.controller; + +public class PersonAlias { + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java index a84ac020671..d9b35305ae6 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java @@ -18,7 +18,7 @@ package org.apache.servicecomb.demo.helloworld.greeter; public interface Hello { - public String SayHello(String name); + String SayHello(String name); - public String SayHelloAgain(String name); + String SayHelloAgain(String name); } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBJob.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBJob.java index 620879803ab..797833437a7 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBJob.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBJob.java @@ -16,11 +16,12 @@ */ package org.apache.servicecomb.demo.jaxbbean; -import javax.xml.bind.annotation.XmlAccessOrder; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorOrder; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; + +import jakarta.xml.bind.annotation.XmlAccessOrder; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorOrder; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "job") @XmlAccessorType(XmlAccessType.FIELD) diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBPerson.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBPerson.java index bd66e9dbd9f..450ebacabe8 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBPerson.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxbbean/JAXBPerson.java @@ -18,13 +18,13 @@ import java.io.Serializable; -import javax.xml.bind.annotation.XmlAccessOrder; -import javax.xml.bind.annotation.XmlAccessorOrder; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; -import javax.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.XmlAccessOrder; +import jakarta.xml.bind.annotation.XmlAccessorOrder; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlTransient; +import jakarta.xml.bind.annotation.XmlType; @XmlType(propOrder = {"name", "role", "job"}) @XmlRootElement(name = "person") diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java index 09e26129b7e..7a99260c393 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java @@ -19,7 +19,7 @@ import java.util.List; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; public class ValidationModel { @NotNull diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseRequest.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseRequest.java new file mode 100644 index 00000000000..1544e99b81d --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseRequest.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.mapnull; + +import java.util.HashMap; +import java.util.Map; + +public class ParseRequest { + public String msgType = ""; + + public String strMsg; + + public String strID = ""; + + public Map flags = new HashMap<>(); + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getStrMsg() { + return strMsg; + } + + public void setStrMsg(String strMsg) { + this.strMsg = strMsg; + } + + public String getStrID() { + return strID; + } + + public void setStrID(String strID) { + this.strID = strID; + } + + public Map getFlags() { + return flags; + } + + public void setFlags(Map flags) { + this.flags = flags; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseResponse.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseResponse.java new file mode 100644 index 00000000000..8330fe8c9cc --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/mapnull/ParseResponse.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.mapnull; + +import java.util.Map; + +public class ParseResponse { + public String resultCode = "99999999"; + + public String resultInfo = "unknown result"; + + public String msgType = ""; + + public Map msgHeader; + + public Map msgBody; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public Map getMsgHeader() { + return msgHeader; + } + + public void setMsgHeader(Map msgHeader) { + this.msgHeader = msgHeader; + } + + public Map getMsgBody() { + return msgBody; + } + + public void setMsgBody(Map msgBody) { + this.msgBody = msgBody; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/model/SpecialNameModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/model/SpecialNameModel.java new file mode 100644 index 00000000000..dfacc030852 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/model/SpecialNameModel.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class SpecialNameModel { + // names starts with only one lower case , although getter/setter generated by IDE is correct, + // will cause jackson generate incorrect swagger names. + // @JsonProperty must be used to make json work in a predictable way. + @JsonProperty("aIntName") + private int aIntName; + + public int getaIntName() { + return aIntName; + } + + public void setaIntName(int aIntName) { + this.aIntName = aIntName; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/ProduceAppXmlProcessor.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/ProduceAppXmlProcessor.java index 26ea1951f5d..17659cfed21 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/ProduceAppXmlProcessor.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/ProduceAppXmlProcessor.java @@ -18,8 +18,9 @@ import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; import org.apache.servicecomb.demo.utils.JAXBUtils; @@ -40,7 +41,7 @@ public int getOrder() { @Override public void doEncodeResponse(OutputStream output, Object result) throws Exception { - output.write(JAXBUtils.convertToXml(result).getBytes()); + output.write(JAXBUtils.convertToXml(result).getBytes(StandardCharsets.UTF_8)); } @Override diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/override/ProduceAppXmlProcessor.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/override/ProduceAppXmlProcessor.java index 45acf3af2cc..aebe13eb116 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/override/ProduceAppXmlProcessor.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/produceprocessor/override/ProduceAppXmlProcessor.java @@ -18,8 +18,9 @@ import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; import org.apache.servicecomb.demo.utils.JAXBUtils; @@ -40,7 +41,7 @@ public int getOrder() { @Override public void doEncodeResponse(OutputStream output, Object result) throws Exception { - output.write(JAXBUtils.convertToXml(result).getBytes()); + output.write(JAXBUtils.convertToXml(result).getBytes(StandardCharsets.UTF_8)); } @Override diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java new file mode 100644 index 00000000000..9cf13285e26 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/AbstractModel.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +// 当使用 List 等 Collection 类型的时候, jackson 序列化不会携带类以外的其他属性 +// 即会忽略掉类型信息。 当抽象类型用于 Collection 类型参数的时候,必须使用已有的属性(例子中的 property = "type")来确定类型, +// 并在子类中显示指定属性的值,而不能使用和依赖jackson根据类型信息自己生成的类型。 + +// 还有一种方法,是序列化的时候指定类型, see: https://www.studytrails.com/2016/09/12/java-jackson-serialization-list/ +// 但是多数序列化接口,包括 RestTemplate 等,都无法得知参数的类型。 这种方式难于应用于开发框架实现,因此对于Collection 类型参数场景,使用已有属性 +// 是最简洁的方法。 + +@JsonTypeInfo( + use = Id.NAME, property = "type" +) +@JsonSubTypes({ + @JsonSubTypes.Type(value = DefaultAbstractModel.class, name = "default"), + @JsonSubTypes.Type(value = SecondAbstractModel.class, name = "second"), +}) +public abstract class AbstractModel { + protected String type; + + protected String name; + + public abstract String getType(); + + public abstract String getName(); + + public abstract void setName(String name); +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java new file mode 100644 index 00000000000..c9f06eeacf7 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/DefaultAbstractModel.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +public class DefaultAbstractModel extends AbstractModel { + @Override + public String getType() { + return "default"; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/GenericsModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/GenericsModel.java new file mode 100644 index 00000000000..45853dbb1aa --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/GenericsModel.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +import java.util.List; + +public class GenericsModel { + private String name; + + private List> nameList; + + private List>> objectLists; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List> getNameList() { + return nameList; + } + + public void setNameList(List> nameList) { + this.nameList = nameList; + } + + public List>> getObjectLists() { + return objectLists; + } + + public void setObjectLists(List>> objectLists) { + this.objectLists = objectLists; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/MapModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/MapModel.java new file mode 100644 index 00000000000..695310c1255 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/MapModel.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +import java.util.Map; + +public class MapModel { + private String name; + + private Map names; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getNames() { + return names; + } + + public void setNames(Map names) { + this.names = names; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java new file mode 100644 index 00000000000..f6be5ae58c1 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/NotRecommendedServiceInf.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +import java.util.List; +import java.util.Map; + +public interface NotRecommendedServiceInf { + Map longMap(Map map); + + List listAbstractModel(List listModel); + + AbstractModel abstractModel(AbstractModel model); + + Map mapAbstractModel(Map mapModel); + + WrappedAbstractModel wrappedAbstractModel(WrappedAbstractModel wrappedModel); +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java new file mode 100644 index 00000000000..46a0b857fd4 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/SecondAbstractModel.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +public class SecondAbstractModel extends AbstractModel { + @Override + public String getType() { + return "second"; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public void setName(String name) { + this.name = name; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/Test.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/Test.java index 0afa62a6434..0369d576073 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/Test.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/Test.java @@ -35,4 +35,6 @@ public interface Test { String addString(String[] strArr); String testTraceId(); + + int[] testIntArray(int[] request); } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java new file mode 100644 index 00000000000..8015ccf54f6 --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/server/WrappedAbstractModel.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.server; + +import java.util.List; +import java.util.Map; + +public class WrappedAbstractModel { + private String name; + + private Map mapModel; + + private List listModel; + + private AbstractModel model; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getMapModel() { + return mapModel; + } + + public void setMapModel(Map mapModel) { + this.mapModel = mapModel; + } + + public List getListModel() { + return listModel; + } + + public void setListModel(List listModel) { + this.listModel = listModel; + } + + public AbstractModel getModel() { + return model; + } + + public void setModel(AbstractModel model) { + this.model = model; + } +} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/tccserver/TestTcc.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/tccserver/TestTcc.java deleted file mode 100644 index be5f1dfe769..00000000000 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/tccserver/TestTcc.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.tccserver; - -import org.apache.servicecomb.demo.server.TestRequest; -import org.apache.servicecomb.demo.server.User; - -public interface TestTcc { - User wrapParam(TestRequest request); - - User splitParam(int index, User user); -} diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/utils/JAXBUtils.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/utils/JAXBUtils.java index 72b08b82a39..7ff2518e8a3 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/utils/JAXBUtils.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/utils/JAXBUtils.java @@ -20,9 +20,6 @@ import java.io.StringWriter; import java.nio.charset.StandardCharsets; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; @@ -33,9 +30,16 @@ import com.fasterxml.jackson.databind.JavaType; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.Marshaller; +import jakarta.xml.bind.Unmarshaller; + public class JAXBUtils { private static final Logger LOGGER = LoggerFactory.getLogger(JAXBUtils.class); + private JAXBUtils() { + } + public static String convertToXml(Object obj) { return convertToXml(obj, StandardCharsets.UTF_8.toString()); } @@ -52,7 +56,7 @@ public static String convertToXml(Object obj, String encoding) { marshaller.marshal(obj, writer); result = writer.toString(); } catch (Exception e) { - LOGGER.error("Bean convert to xml failed, error message: {}", e.getMessage()); + LOGGER.error("Bean convert to xml failed, error message: {}", e.getMessage(), e); } return result; } diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Student.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Student.java index 65feea2ec7f..3117c5e1f82 100644 --- a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Student.java +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Student.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.demo.validator; -import javax.validation.constraints.Max; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.NotNull; public class Student { @NotNull diff --git a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Teacher.java b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Teacher.java new file mode 100644 index 00000000000..b7015e2920e --- /dev/null +++ b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/validator/Teacher.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.validator; + +import jakarta.validation.constraints.NotBlank; + +public class Teacher { + + @NotBlank(message = "must not be blank") + private String name; + + private String age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + @Override + public String toString() { + return name + " " + age; + } +} diff --git a/demo/demo-schema/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor b/demo/demo-schema/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor index ff9a6cb9a54..acd03890620 100644 --- a/demo/demo-schema/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor +++ b/demo/demo-schema/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor @@ -16,4 +16,4 @@ # org.apache.servicecomb.demo.produceprocessor.ProduceAppXmlProcessor -org.apache.servicecomb.demo.produceprocessor.override.ProduceAppXmlProcessor \ No newline at end of file +org.apache.servicecomb.demo.produceprocessor.override.ProduceAppXmlProcessor diff --git a/demo/demo-schema/src/main/resources/config/log4j.eclipse.properties b/demo/demo-schema/src/main/resources/config/log4j.eclipse.properties deleted file mode 100644 index 8d7c9ffb587..00000000000 --- a/demo/demo-schema/src/main/resources/config/log4j.eclipse.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=../../../../cse-demo-bin/logs/ -log4j.appender.stdout.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS/zzz}][%t][%p]%m %l%n diff --git a/demo/demo-schema/src/main/resources/config/log4j.properties b/demo/demo-schema/src/main/resources/config/log4j.properties deleted file mode 100644 index 94010942506..00000000000 --- a/demo/demo-schema/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=../target/logs/ -paas.logs.file=cse.log - -log4j.rootLogger=INFO,paas,stdout -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-schema/src/main/resources/microservice.yaml b/demo/demo-schema/src/main/resources/microservice.yaml index d26c026d57a..28df63a4323 100644 --- a/demo/demo-schema/src/main/resources/microservice.yaml +++ b/demo/demo-schema/src/main/resources/microservice.yaml @@ -16,10 +16,14 @@ ## --------------------------------------------------------------------------- servicecomb-config-order: -1 -cse: - test: - duplicate1: older +demo.multi.service.center.serverB: + key1: key1 + key2: key2 + key3: key3 servicecomb: - test: - duplicate2: older \ No newline at end of file + # verbose exceptions information + invocation: + exception: + print-stack-trace: true + print-rate-limit: true diff --git a/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml b/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml deleted file mode 100644 index 66eb476c5ec..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml +++ /dev/null @@ -1,200 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: rest test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.compute.Compute - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /compute -produces: - - application/json - -paths: - /add: - post: - operationId: add - parameters: - - name: a - in: formData - required: true - type: integer - format: int32 - - name: b - in: formData - required: true - type: integer - format: int32 - responses: - 200: - description: add numer - schema: - type: integer - format: int32 - /reduce: - get: - operationId: reduce - parameters: - - name: a - in: query - required: true - type: integer - format: int32 - - name: b - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: reduce - schema: - type: integer - format: int32 - /sayhello: - post: - operationId: sayHello - parameters: - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say hello - schema: - $ref: '#/definitions/Person' - /testrawjson: - post: - operationId: testRawJsonString - parameters: - - name: jsonInput - in: body - required: true - x-raw-json: true - type: string - responses: - 200: - description: test RawJson String - schema: - type: string - /saysomething: - post: - operationId: saySomething - parameters: - - name: prefix - in: header - required: true - type: string - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say something - schema: - type: string - /sayhi/{name}: - put: - operationId: sayHi - parameters: - - name: name - in: path - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - 202: - description: say hi - schema: - type: string - /sayhi/{name}/v2: - put: - operationId: sayHi2 - parameters: - - name: name - in: path - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - /sayhei: - delete: - operationId: sayHei - parameters: - - name: name - in: query - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - /istrue: - get: - operationId: isTrue - responses: - 200: - description: is true - schema: - type: boolean - /addstring: - delete: - operationId: addString - produces: - - text/plain - parameters: - - name: s - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: add string - schema: - type: string - -definitions: - Person: - type: object - properties: - name: - type: string - x-java-class: "org.apache.servicecomb.demo.compute.Person" diff --git a/demo/demo-schema/src/main/resources/microservices/no-use/cse.basic.Basic/main.idl b/demo/demo-schema/src/main/resources/microservices/no-use/cse.basic.Basic/main.idl deleted file mode 100644 index 6b5cd765367..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/no-use/cse.basic.Basic/main.idl +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You under the Apache License, Version 2.0 -// (the "License"); you may not use this file except in compliance with -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -package cse.basic; - -message BasicRequest { - required AllBasicTypes request = 1; -} - -message BasicResponse { - required AllBasicTypes request = 1; -} - -message AllBasicTypes { - required double tdouble = 1; - required float tfloat = 2; - required int32 tint32 = 3; - required int64 tint64 = 4; - required uint32 tuint32 = 5; - required uint64 tuint64 = 6; - required sint32 tsint32 = 7; - required sint64 tsint64 = 8; - required fixed32 tfixed32 = 9; - required fixed64 tfixed64 = 10; - required sfixed32 tsfixed32 = 11; - required sfixed64 tsfixed64 = 12; - required bool tbool = 13; - required string tstring = 14; - required bytes tbytes = 15; - - enum EnumType { - ONE = 0; - TWO = 1; - } - required EnumType enumType = 16; - - // map mapType = 17; - //message MapFieldEntry { - //required string key = 1; - //required string value = 2; - //} - //repeated MapFieldEntry mapType = 17; - - repeated string tstringList = 17; -} - -service Basic { - rpc schalarType(BasicRequest) returns(BasicResponse); -} diff --git a/demo/demo-schema/src/main/resources/microservices/no-use/hello/main.idl b/demo/demo-schema/src/main/resources/microservices/no-use/hello/main.idl deleted file mode 100644 index 6a6fd47fd1a..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/no-use/hello/main.idl +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You under the Apache License, Version 2.0 -// (the "License"); you may not use this file except in compliance with -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -service Greeter { - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -message HelloRequest { - required string name = 1; -} - -message HelloReply { - required string message = 1; -} diff --git a/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Greeter/main.idl b/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Greeter/main.idl deleted file mode 100644 index e415db0350e..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Greeter/main.idl +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You under the Apache License, Version 2.0 -// (the "License"); you may not use this file except in compliance with -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package helloworld; - -service Greeter { - rpc SayHello (HelloRequest) returns (HelloReply); - rpc SayHelloAgain (HelloRequest) returns (HelloReply); -} - -message HelloRequest { - required string name = 1; -} - -message HelloReply { - required string message = 1; -} diff --git a/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Standard/main.idl b/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Standard/main.idl deleted file mode 100644 index 2cf0a7a738a..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/no-use/helloworld.Standard/main.idl +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You under the Apache License, Version 2.0 -// (the "License"); you may not use this file except in compliance with -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package helloworld; - -message StandardRequest { - required ComplexType args0 = 1; -} - -message StandardResponse { - required ComplexType response = 1; -} - -message ComplexType { - repeated int32 intType = 1; - repeated bool boolType = 2; - repeated string stringType = 3; -} - -service Standard { - rpc sayHelloComplex (StandardRequest) returns (StandardResponse); -} diff --git a/demo/demo-schema/src/main/resources/microservices/no-use/server/main.idl b/demo/demo-schema/src/main/resources/microservices/no-use/server/main.idl deleted file mode 100644 index d60a7a86798..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/no-use/server/main.idl +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You under the Apache License, Version 2.0 -// (the "License"); you may not use this file except in compliance with -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -message TestRequest{ - required int32 index = 1; - required User user = 2; - required bytes data = 3; - //repeated MapFieldEntry friends = 4; -} - -message User{ - required string name = 1; - required int32 age = 2; - required int32 index = 3; - //repeated MapFieldEntry friends = 4; -} - -message MapFieldEntry { - required string key = 1; - required int32 value = 2; -} - -message TestResponse{ - required User user = 1; -} - -enum EnumType { - ONE = 0; - TWO = 1; -} - -message EnumMessage{ - required EnumType enumType = 1; -} - -message Empty{ -} - -message MicroService{ - optional string service_id = 1; - required string app_id = 2; - required string name = 3; - required string version = 4; - optional string description = 5; - optional string level = 6 [default = "front"]; - repeated ServiceDefinition definitions = 7; - optional ServiceStatus status = 8 [default = INSERVICE]; -} - -message ServiceDefinition { - required string name = 1; - required string version = 2; - required string transport = 3; - repeated string schema = 4; - //map properties = 5; -} - -enum ServiceStatus { - INSERVICE = 0; - OUTOFSERVICE = 1; -} - -message MicroServiceWrap{ - required MicroService service = 1; -} - -service server { - rpc splitParam(TestRequest) returns(User); - rpc standard(TestRequest) returns(TestResponse); - rpc sayHello (HelloRequest) returns (HelloReply); - rpc standardSayHello (HelloRequest) returns (HelloReply); - rpc testEnum(EnumMessage) returns(EnumMessage); - rpc testStandardEnum(EnumMessage) returns(EnumMessage); - rpc testEmpty(Empty) returns(Empty); - rpc testMicroService(MicroService) returns(MicroService); - rpc testCreateMicroService(MicroServiceWrap) returns(MicroServiceWrap); -} - -message HelloRequest { - required string name = 1; -} - -message HelloReply { - required string message = 1; -} diff --git a/demo/demo-schema/src/main/resources/microservices/pojo/helloworld.Greeter.yaml b/demo/demo-schema/src/main/resources/microservices/pojo/helloworld.Greeter.yaml deleted file mode 100644 index c3272c1c723..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/pojo/helloworld.Greeter.yaml +++ /dev/null @@ -1,74 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: helloworld.Greeter - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.helloworld.greeter.Hello - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/helloworld.Greeter -produces: - - application/json - -paths: - /SayHello: - post: - operationId: SayHello - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: asdf - schema: - type: string - default: - description: asf - schema: - type: string - /SayHelloAgain: - post: - operationId: SayHelloAgain - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: asdf - schema: - type: string - default: - description: asf - schema: - type: string diff --git a/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml b/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml deleted file mode 100644 index 15b1d827063..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml +++ /dev/null @@ -1,218 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: cse test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.server.Test - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest -produces: - - application/json - -paths: - /testStringArray: - get: - operationId: testStringArray - parameters: - - name: arr - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: asdf - schema: - type: string - /testStatic: - get: - operationId: getTestString - parameters: - - name: code - in: query - required: false - type: string - responses: - 200: - description: asdf - schema: - type: string - post: - operationId: postTestStatic - parameters: - - name: code - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: asdf - schema: - type: string - patch: - operationId: patchTestStatic - parameters: - - name: code - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: asdf - schema: - type: string - /testException/{code}: - get: - operationId: testException - parameters: - - name: code - in: path - required: true - type: integer - format: int32 - responses: - 200: - description: asdf - schema: - type: string - 456: - description: asdf - schema: - type: string - 556: - description: asdf - schema: - type: array - items: - type: string - 557: - description: asdf - schema: - type: array - items: - type: array - items: - type: string - /splitParam: - post: - operationId: splitParam - parameters: - - name: index - in: query - required: true - type: integer - format: int32 - - name: user - in: body - schema: - $ref: '#/definitions/User' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /wrapParam: - post: - operationId: wrapParam - parameters: - - name: TestRequest - in: body - required: false - schema: - $ref: '#/definitions/TestRequest' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /addstring: - delete: - operationId: addString - parameters: - - name: strArr - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: add string - schema: - type: string - /testTraceId: - get: - operationId: testTraceId - responses: - 200: - description: get trace id - schema: - type: string -definitions: - Error: - type: object - x-java-class: org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData - properties: - message: - type: string - TestRequest: - type: object - properties: - index: - type: number - user: - $ref: '#/definitions/User' - users: - type: array - items: - $ref: '#/definitions/User' - data: - type: string - format: byte - User: - type: object - properties: - name: - type: string - age: - type: integer - index: - type: number - x-java-class: "org.apache.servicecomb.demo.server.User" diff --git a/demo/demo-schema/src/main/resources/microservices/pojo/smartcare.yaml b/demo/demo-schema/src/main/resources/microservices/pojo/smartcare.yaml deleted file mode 100644 index 0879c3bda2d..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/pojo/smartcare.yaml +++ /dev/null @@ -1,136 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: smartcare test - version: 1.0.0 -# x-java-interface is optional, remove it should works well, but sometimes need to generate more class in memory -# x-java-interface: org.apache.servicecomb.demo.smartcare.SmartCare - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/plat/meta/v1 -produces: - - application/json - -paths: - /applications: - post: - operationId: addApplication - parameters: - - name: application - in: body - required: true - schema: - $ref: '#/definitions/Application' - responses: - 201: - description: success - schema: - $ref: '#/definitions/Response' - 400: - description: error - schema: - $ref: '#/definitions/Response' - 500: - description: error - schema: - $ref: '#/definitions/Response' - - /applications/{appName}: - delete: - operationId: delApplication - parameters: - - name: appName - in: path - required: true - type: string - responses: - 201: - description: success - schema: - $ref: '#/definitions/Response' - 400: - description: error - schema: - $ref: '#/definitions/Response' - 500: - description: error - schema: - $ref: '#/definitions/Response' - - -definitions: - Application: - type: object - properties: - name: - type: string - labelEN: - type: string - labelCH: - type: string - defaultGroup: - type: string - version: - type: string - dynamicFlag: - type: boolean - groups: - type: array - items: - $ref: '#/definitions/Group' - required: - - name - - defaultGroup - - version - - dynamicFlag - - groups - - Group: - type: object - properties: - name: - type: string - labelEN: - type: string - labelCH: - type: string - required: - - name - - Response: - type: object - x-java-class: org.apache.servicecomb.demo.smartcare.Response - properties: - resultCode: - type: integer - format: int32 - resultMessage: - type: string - required: - - resultCode - diff --git a/demo/demo-schema/src/main/resources/microservices/pojo/tcc-server.yaml b/demo/demo-schema/src/main/resources/microservices/pojo/tcc-server.yaml deleted file mode 100644 index 677cce1de39..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/pojo/tcc-server.yaml +++ /dev/null @@ -1,108 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: cse test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.tccserver.TestTcc - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/tcc-server -produces: - - application/json - -paths: - /splitParam: - post: - operationId: splitParam - parameters: - - name: index - in: query - required: true - type: number - - name: user - in: body - schema: - $ref: '#/definitions/User' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /wrapParam: - post: - operationId: wrapParam - parameters: - - name: TestRequest - in: body - required: true - schema: - $ref: '#/definitions/TestRequest' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - -definitions: - Error: - type: object - x-java-class: org.apache.servicecomb.core.exception.CommonExceptionData - properties: - message: - type: string - TestRequest: - type: object - properties: - index: - type: number - user: - $ref: '#/definitions/User' - users: - type: array - items: - $ref: '#/definitions/User' - data: - type: string - format: byte - User: - type: object - properties: - name: - type: string - age: - type: number - index: - type: number diff --git a/demo/demo-schema/src/main/resources/microservices/springmvc/controller.yaml b/demo/demo-schema/src/main/resources/microservices/springmvc/controller.yaml deleted file mode 100644 index bc1841892ee..00000000000 --- a/demo/demo-schema/src/main/resources/microservices/springmvc/controller.yaml +++ /dev/null @@ -1,123 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: rest test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.controller.Controller - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /springmvc/controller -produces: - - application/json - -paths: - /add: - get: - operationId: add - parameters: - - name: a - in: query - required: true - type: integer - format: int32 - - name: b - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: add numer - schema: - type: integer - format: int32 - - /sayhello/{name}: - post: - operationId: sayHello - parameters: - - name: name - in: path - required: true - type: string - responses: - 200: - description: say hello - schema: - type: string - /saysomething: - post: - operationId: saySomething - parameters: - - name: prefix - in: query - required: true - type: string - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say something - schema: - type: string - /sayhi: - get: - operationId: sayHi - parameters: - - name: name - in: query - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - /sayhei: - get: - operationId: sayHei - parameters: - - name: name - in: header - required: true - type: string - responses: - 200: - description: say hei - schema: - type: string - -definitions: - Person: - type: object - properties: - name: - type: string diff --git a/demo/demo-server-servlet/pom.xml b/demo/demo-server-servlet/pom.xml deleted file mode 100644 index 91728781b1d..00000000000 --- a/demo/demo-server-servlet/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - demo-server-servlet - Java Chassis::Demo::Server Servlet - - war - - - - org.apache.servicecomb.demo - springmvc-server - - - - - pojo - - diff --git a/demo/demo-server-servlet/src/main/resources/microservice.yaml b/demo/demo-server-servlet/src/main/resources/microservice.yaml deleted file mode 100644 index cb4ae437d17..00000000000 --- a/demo/demo-server-servlet/src/main/resources/microservice.yaml +++ /dev/null @@ -1,26 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -servicecomb-config-order: 100 - -servicecomb: - rest: - servlet: - urlPattern: /rest/* - address: 0.0.0.0:8080?sslEnabled=false - highway: - address: 0.0.0.0:7070?sslEnabled=false diff --git a/demo/demo-server-servlet/src/main/webapp/WEB-INF/web.xml b/demo/demo-server-servlet/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index cb2b22e5842..00000000000 --- a/demo/demo-server-servlet/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - contextConfigLocation - - classpath*:META-INF/spring/*.bean.xml - - - - - - - - org.apache.servicecomb.transport.rest.servlet.RestServletContextListener - - - - - - - - - - - - - - - - - - diff --git a/demo/demo-signature/pom.xml b/demo/demo-signature/pom.xml deleted file mode 100644 index 51e8f915a4c..00000000000 --- a/demo/demo-signature/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - demo-signature - Java Chassis::Demo::Signature - - - - org.apache.servicecomb - common-rest - - - diff --git a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java deleted file mode 100644 index aa715d2bc07..00000000000 --- a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ClientSignature.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.signature; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ClientSignature implements HttpClientFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(ClientSignature.class); - - @Override - public int getOrder() { - return 0; - } - - @Override - public void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx) { - String signature = SignatureUtils.genSignature(requestEx); - requestEx.setHeader("signature", signature); - } - - @Override - public Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx) { - String signature = SignatureUtils.genSignature(responseEx); - String serverSignature = responseEx.getHeader("signature"); - - if (serverSignature != null) { - LOGGER.debug("check response signature, client: {}, server: {}.", signature, serverSignature); - if (!signature.equals(serverSignature)) { - LOGGER.error("check response signature failed"); - return Response.create(Status.UNAUTHORIZED, "check response signature failed"); - } - } - return null; - } -} diff --git a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java deleted file mode 100644 index 937aa7ff63c..00000000000 --- a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/ServerSignature.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.signature; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ServerSignature implements HttpServerFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(ServerSignature.class); - - public ServerSignature() { - } - - @Override - public int getOrder() { - return 0; - } - - @Override - public boolean needCacheRequest(OperationMeta operationMeta) { - return true; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - String signature = SignatureUtils.genSignature(requestEx); - String clientSignature = requestEx.getHeader("signature"); - LOGGER.debug("check request signature, client: {}, server: {}.", clientSignature, signature); - if (!signature.equals(clientSignature)) { - LOGGER.error("check request signature failed: {}", invocation.getInvocationQualifiedName()); - return Response - .create(Status.UNAUTHORIZED, "check request signature failed: " + invocation.getInvocationQualifiedName()); - } - - return null; - } - - @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - String signature = SignatureUtils.genSignature(responseEx); - responseEx.addHeader("signature", signature); - } -} diff --git a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/SignatureUtils.java b/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/SignatureUtils.java deleted file mode 100644 index 33e485b1f8d..00000000000 --- a/demo/demo-signature/src/main/java/org/apache/servicecomb/demo/signature/SignatureUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.signature; - -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import javax.ws.rs.core.MediaType; - -import org.apache.commons.lang.StringUtils; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; - -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import com.netflix.config.DynamicStringListProperty; - -public class SignatureUtils { - private static final DynamicStringListProperty PARAM_NAMES_PROPERTY = - new DynamicStringListProperty("servicecomb.demo.signature.param-names", Arrays.asList("userId")); - - private static List paramNames = PARAM_NAMES_PROPERTY.get(); - - static { - PARAM_NAMES_PROPERTY.addCallback(() -> { - List tmpNames = PARAM_NAMES_PROPERTY.get(); - tmpNames.sort(Comparator.naturalOrder()); - paramNames = tmpNames; - }); - } - - public static String genSignature(HttpServletRequestEx requestEx) { - Hasher hasher = Hashing.sha256().newHasher(); - hasher.putString(requestEx.getRequestURI(), StandardCharsets.UTF_8); - for (String paramName : paramNames) { - String paramValue = requestEx.getHeader(paramName); - if (paramValue != null) { - hasher.putString(paramName, StandardCharsets.UTF_8); - hasher.putString(paramValue, StandardCharsets.UTF_8); - System.out.printf("%s %s\n", paramName, paramValue); - } - } - - if (!StringUtils.startsWithIgnoreCase(requestEx.getContentType(), MediaType.APPLICATION_FORM_URLENCODED)) { - byte[] bytes = requestEx.getBodyBytes(); - if (bytes != null) { - hasher.putBytes(bytes, 0, requestEx.getBodyBytesLength()); - } - } - - return hasher.hash().toString(); - } - - public static String genSignature(HttpServletResponseEx responseEx) { - Hasher hasher = Hashing.sha256().newHasher(); - byte[] bytes = responseEx.getBodyBytes(); - if (bytes != null) { - hasher.putBytes(bytes, 0, responseEx.getBodyBytesLength()); - } - - return hasher.hash().toString(); - } -} diff --git a/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter b/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter deleted file mode 100644 index 9533c795685..00000000000 --- a/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.demo.signature.ClientSignature diff --git a/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter deleted file mode 100644 index 37d7671228c..00000000000 --- a/demo/demo-signature/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.demo.signature.ServerSignature diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/pom.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/pom.xml deleted file mode 100644 index c53a954dec5..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-spring-boot-discovery - 1.2.0-SNAPSHOT - - demo-spring-boot-discovery-client - Java Chassis::Demo::Spring Boot Discovery::Client - - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - spring-boot-starter-discovery - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - ${project.version} - - - - - - - - - - docker - - demo-spring-boot-discovery-server - -Dcse.rest.address=0.0.0.0:8080 - - - - - io.fabric8 - docker-maven-plugin - - - - - - diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/java/org/apache/servicecomb/demo/discovery/client/DiscoveryClientIT.java b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/java/org/apache/servicecomb/demo/discovery/client/DiscoveryClientIT.java deleted file mode 100644 index 3bd84337142..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/java/org/apache/servicecomb/demo/discovery/client/DiscoveryClientIT.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.discovery.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - -import java.net.URI; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.web.client.RestTemplate; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, classes = DiscoveryClientIT.DiscoveryTestApplication.class) -public class DiscoveryClientIT { - - @Autowired - private DiscoveryClient discoveryClient; - - // @Autowired - // private LoadBalancerClient client; - - private final RestTemplate restTemplate = new RestTemplate(); - - @Test - public void getsRemoteServiceFromDiscoveryClient() throws Exception { - URI remoteUri = discoveryClient.getInstances("discoveryServer").get(0).getUri(); - - assertThat(remoteUri).isNotNull(); - - String response = restTemplate.getForObject( - remoteUri.toString() + "/greeting/sayhello/{name}", - String.class, - "Mike"); - - assertThat(response).isEqualTo("hello Mike"); - } - - @SpringBootApplication - @EnableServiceComb - @EnableDiscoveryClient - static class DiscoveryTestApplication { - - public static void main(String[] args) throws Exception { - SpringApplication.run(DiscoveryTestApplication.class, args); - } - } -} diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/logback-test.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/logback-test.xml deleted file mode 100644 index 52d292541b6..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/logback-test.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/microservice.yaml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/microservice.yaml deleted file mode 100644 index 346bef083f3..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-client/src/test/resources/microservice.yaml +++ /dev/null @@ -1,28 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: discoverytest -service_description: - name: discoveryClient - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - references: - discoveryServer: - version-rule: 0.0.2 diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/pom.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/pom.xml deleted file mode 100644 index 24ec68b98c9..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-spring-boot-discovery - 1.2.0-SNAPSHOT - - demo-spring-boot-discovery-server - Java Chassis::Demo::Spring Boot Discovery::Server - - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-springmvc - - - - - org.apache.servicecomb.demo.discovery.server.DiscoveryServer - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - 1.2.0-SNAPSHOT - - - - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/DiscoveryServer.java b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/DiscoveryServer.java deleted file mode 100644 index 2792e995af2..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/DiscoveryServer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.discovery.server; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class DiscoveryServer { - public static void main(String[] args) throws Exception { - SpringApplication.run(DiscoveryServer.class, args); - } -} diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/GreetingController.java b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/GreetingController.java deleted file mode 100644 index f9f72eae827..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/java/org/apache/servicecomb/demo/discovery/server/GreetingController.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.discovery.server; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; - -@RestSchema(schemaId = "greeting") -@RequestMapping(path = "/greeting", produces = MediaType.TEXT_PLAIN) -public class GreetingController { - - @RequestMapping(path = "/sayhello/{name}", method = RequestMethod.GET) - @ResponseBody - public String sayHello(@PathVariable("name") String name) { - return "hello " + name; - } -} diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.properties b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.properties deleted file mode 100644 index 69bb3b1805e..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# temp file -spring.main.web-environment=true diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.yaml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.yaml deleted file mode 100644 index 9723c7769bf..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/application.yaml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 8080 diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/log4j.properties b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/log4j.properties deleted file mode 100644 index fbbee883b2d..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/log4j.properties +++ /dev/null @@ -1,36 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -##log4j DEBUG < INFO < WARN < ERROR < FATAL -log4j.rootLogger=INFO,paas,stdout -paas.logs.dir=./ -paas.logs.file=cse.log - -#if not set runLogger level ,log4Utils.init will meet a null point error -log4j.logger.runLogger=INFO - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%p] %m %l%n - -log4j.appender.paas=org.apache.servicecomb.foundation.common.utils.RollingFileAppenderExt -log4j.appender.paas.file=${paas.logs.dir}${paas.logs.file} -log4j.appender.paas.MaxFileSize=20MB -log4j.appender.paas.MaxBackupIndex=10 -log4j.appender.paas.layout=org.apache.log4j.PatternLayout -log4j.appender.paas.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS/zzz}][%t][%p]%m %l%n -log4j.appender.paas.logPermission=rw------- diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/logback-test.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/logback-test.xml deleted file mode 100644 index 52d292541b6..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/logback-test.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/microservice.yaml b/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/microservice.yaml deleted file mode 100644 index c4297e4f3dc..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-discovery-server/src/main/resources/microservice.yaml +++ /dev/null @@ -1,35 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: discoverytest -service_description: - name: discoveryServer - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - #add highway for test filter - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider -servicecomb.rest.servlet.urlPattern: /* diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/pom.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/pom.xml deleted file mode 100644 index 23bbb1f360c..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-spring-boot-discovery - 1.2.0-SNAPSHOT - - demo-spring-boot-zuul-proxy - Java Chassis::Demo::Spring Boot Discovery::Zuul Proxy - - org.apache.servicecomb.demo.discovery.zuul.DiscoveryZuulProxyIT.DiscoveryZuulProxy - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.cloud - spring-cloud-starter-zuul - - - org.springframework.cloud - spring-cloud-starter-ribbon - - - org.springframework.cloud - spring-cloud-starter-hystrix - - - org.apache.servicecomb - spring-boot-starter-discovery - - - org.apache.servicecomb.demo - demo-schema - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - 1.2.0-SNAPSHOT - - - - - - - - - - docker - - demo-spring-boot-discovery-server - -Dcse.rest.address=0.0.0.0:8080?sslEnabled=false - - - - - io.fabric8 - docker-maven-plugin - - - - - - diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/java/org/apache/servicecomb/demo/discovery/zuul/DiscoveryZuulProxyIT.java b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/java/org/apache/servicecomb/demo/discovery/zuul/DiscoveryZuulProxyIT.java deleted file mode 100644 index ed3a9631a59..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/java/org/apache/servicecomb/demo/discovery/zuul/DiscoveryZuulProxyIT.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.discovery.zuul; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = DiscoveryZuulProxyIT.DiscoveryZuulProxy.class, webEnvironment = RANDOM_PORT) -public class DiscoveryZuulProxyIT { - - @Autowired - private TestRestTemplate restTemplate; - - @Test - public void getsRemoteServiceThroughGateway() { - //loop three time to insure only rest endpoint get - for (int i = 0; i < 3; i++) { - String response = restTemplate.getForObject( - "/gateway/greeting/sayhello/{name}", - String.class, - "Mike"); - - assertThat(response).isEqualTo("hello Mike"); - } - } - - @SpringBootApplication - @EnableZuulProxy - @EnableDiscoveryClient - @EnableServiceComb - static class DiscoveryZuulProxy { - - public static void main(String[] args) { - SpringApplication.run(DiscoveryZuulProxy.class, args); - } - } -} diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.properties b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.properties deleted file mode 100644 index 4289b8906c3..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -spring.main.web-environment=true diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.yml b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.yml deleted file mode 100644 index ef24bce0c5c..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/application.yml +++ /dev/null @@ -1,35 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 0 - -zuul: - routes: - gateway: - serviceId: discoveryServer -discoveryServer: - ribbon: - eureka: - enabled: false -hystrix: - command: - default: - execution: - isolation: - thread: - timeoutInMilliseconds: 5000 diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/logback-test.xml b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/logback-test.xml deleted file mode 100644 index 52d292541b6..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/logback-test.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/microservice.yaml b/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/microservice.yaml deleted file mode 100644 index 0901fe193b0..00000000000 --- a/demo/demo-spring-boot-discovery/demo-spring-boot-zuul-proxy/src/test/resources/microservice.yaml +++ /dev/null @@ -1,27 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: discoverytest -service_description: - name: discoveryGateway - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8082 diff --git a/demo/demo-spring-boot-discovery/pom.xml b/demo/demo-spring-boot-discovery/pom.xml deleted file mode 100644 index f9deab0ec9c..00000000000 --- a/demo/demo-spring-boot-discovery/pom.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - demo-spring-boot-discovery - Java Chassis::Demo::Spring Boot Discovery - - pom - - demo-spring-boot-discovery-server - demo-spring-boot-discovery-client - demo-spring-boot-zuul-proxy - - - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.apache.servicecomb - spring-boot-starter-transport - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-test - test - - - - - ch.qos.logback - logback-classic - - - org.slf4j - log4j-over-slf4j - - - diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/pom.xml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/pom.xml deleted file mode 100644 index 29e9232b45c..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - demo-spring-boot-jaxrs-client - Java Chassis::Demo::Spring Boot::JAXRS Client - - org.apache.servicecomb.demo - demo-spring-boot - 1.2.0-SNAPSHOT - - - - org.apache.servicecomb.demo - jaxrs-client - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - 1.2.0-SNAPSHOT - - - - - - - - - docker - - demo-spring-boot-jaxrs-server - - -Dservicecomb.highway.address=0.0.0.0:7070 - -Dservicecomb.rest.address=0.0.0.0:8080 - - - - - - io.fabric8 - docker-maven-plugin - - - - - - diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java deleted file mode 100644 index 3e1ea78224b..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.jaxrs.client; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class JaxrsClient { - - public static void main(String[] args) throws Exception { - RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); - RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); - Log4jUtils.init(); - SpringApplication.run(JaxrsClient.class, args); - org.apache.servicecomb.demo.jaxrs.client.JaxrsClient.run(); - TestMgr.summary(); - } -} diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/application.yml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/application.yml deleted file mode 100644 index d13e64cb44b..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/application.yml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 8999 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/microservice.yaml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/microservice.yaml deleted file mode 100644 index 0a7457f94c9..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -servicecomb-config-order: 1 -APPLICATION_ID: spring-boot-jaxrstest -service_description: - name: jaxrsClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/test/java/org/apache/servicecomb/springboot/jaxrs/SpringBootJaxrsIT.java b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/test/java/org/apache/servicecomb/springboot/jaxrs/SpringBootJaxrsIT.java deleted file mode 100644 index 35c1b5df0bc..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/test/java/org/apache/servicecomb/springboot/jaxrs/SpringBootJaxrsIT.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.jaxrs; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.springboot.jaxrs.client.JaxrsClient; -import org.junit.Before; -import org.junit.Test; - -public class SpringBootJaxrsIT { - - @Before - public void setUp() throws Exception { - TestMgr.errors().clear(); - } - - @Test - public void clientGetsNoError() throws Exception { - JaxrsClient.main(new String[0]); - - assertThat(TestMgr.errors().isEmpty(), is(true)); - } -} diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/pom.xml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/pom.xml deleted file mode 100644 index 58da5a8bc5a..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - demo-spring-boot-jaxrs-server - Java Chassis::Demo::Spring Boot::JAXRS Server - - org.apache.servicecomb.demo - demo-spring-boot - 1.2.0-SNAPSHOT - - - org.apache.servicecomb.springboot.jaxrs.server.JaxrsServer - - - - org.apache.servicecomb.demo - jaxrs-server - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - 1.2.0-SNAPSHOT - - - - - - - - - - docker - - - - io.fabric8 - docker-maven-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - - - - - - diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java deleted file mode 100644 index fc133f62ed9..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.jaxrs.server; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper; -import org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class JaxrsServer { - public static void main(final String[] args) throws Exception { - RestObjectMapperFactory.setDefaultRestObjectMapper(new RestObjectMapperWithStringMapper()); - RestObjectMapperFactory.setConsumerWriterMapper(new RestObjectMapperWithStringMapperNotWriteNull()); - Log4jUtils.init(); - SpringApplication.run(JaxrsServer.class, args); - } -} diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/application.yml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/application.yml deleted file mode 100644 index 046fe0b0f45..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/application.yml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 0 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/microservice.yaml b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/microservice.yaml deleted file mode 100644 index 09c50e3fe17..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/resources/microservice.yaml +++ /dev/null @@ -1,34 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -servicecomb-config-order: 1 -APPLICATION_ID: spring-boot-jaxrstest -service_description: - name: jaxrs - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/pom.xml b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/pom.xml deleted file mode 100644 index 42d8b9cf4b0..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 4.0.0 - org.apache.servicecomb.springboot.springmvc.client - demo-spring-boot-springmvc-client - Java Chassis::Demo::Spring Boot::Spring MVC Client - - org.apache.servicecomb.demo - demo-spring-boot - 1.2.0-SNAPSHOT - - - - org.apache.servicecomb.demo - springmvc-client - - - diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringmvcClient.java b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringmvcClient.java deleted file mode 100644 index 4a4e7446cbd..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringmvcClient.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.springmvc.client; - -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * SpringmvcClient - * - * - */ -@SpringBootApplication -@EnableServiceComb -public class SpringmvcClient { - - public static void main(final String[] args) throws Exception { - Log4jUtils.init(); - SpringApplication.run(SpringmvcClient.class, args); - - org.apache.servicecomb.demo.springmvc.client.SpringmvcClient.run(); - - TestMgr.summary(); - } -} diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/application.yml b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/application.yml deleted file mode 100644 index d13e64cb44b..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/application.yml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 8999 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/pom.xml b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/pom.xml deleted file mode 100644 index 2e26431c7d0..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 4.0.0 - org.apache.servicecomb.springboot.springmvc.server - demo-spring-boot-springmvc-server - Java Chassis::Demo::Spring Boot::Spring MVC Client - - org.apache.servicecomb.demo - demo-spring-boot - 1.2.0-SNAPSHOT - - - - org.apache.servicecomb.demo - springmvc-server - - - diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java deleted file mode 100644 index b0eb55b1139..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.springmvc.server; - -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class SpringmvcServer { - - public static void main(final String[] args) throws Exception { - Log4jUtils.init(); - SpringApplication.run(SpringmvcServer.class, args); - } -} diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/application.yml b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/application.yml deleted file mode 100644 index c21992cc27c..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/application.yml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 7999 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-provider/pom.xml b/demo/demo-spring-boot-provider/pom.xml deleted file mode 100644 index 767b18b02d7..00000000000 --- a/demo/demo-spring-boot-provider/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - demo-spring-boot - Java Chassis::Demo::Spring Boot - pom - - demo-spring-boot-jaxrs-server - demo-spring-boot-jaxrs-client - demo-spring-boot-springmvc-server - demo-spring-boot-springmvc-client - - - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/pom.xml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/pom.xml index 31b63d85f30..372d3a8ccc3 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/pom.xml +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/pom.xml @@ -25,60 +25,97 @@ org.apache.servicecomb.demo demo-spring-boot-transport - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT - org.apache.servicecomb.springboot.pojo.client.PojoClient + org.apache.servicecomb.demo.springboot.pojo.client.PojoClient - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - 1.2.0-SNAPSHOT - - - - - - docker demo-spring-boot-pojo-server - -Dcse.rest.address=0.0.0.0:8080 + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + io.fabric8 diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/Test.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/Test.java deleted file mode 100644 index d853caffc13..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/Test.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public interface Test { - String testStringArray(String[] arr); - - String getTestString(String code); - - String postTestStatic(int code); - - String testException(int code); - - User wrapParam(TestRequest request); - - User splitParam(int index, User user); - - String addString(String[] strArr); -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java deleted file mode 100644 index 6f622686271..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -import java.util.ArrayList; -import java.util.List; - -public class TestRequest { - private int index; - - private User user; - - private List users = new ArrayList<>(); - - private byte[] data; - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public List getUsers() { - return users; - } - - public void setUsers(List users) { - this.users = users; - } - - public byte[] getData() { - return data; - } - - public void setData(byte[] data) { - this.data = data; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java deleted file mode 100644 index c6baa8e0078..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public class TestResponse { - private User user; - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - @Override - public String toString() { - return "TestResponse [user=" + user + "]"; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/User.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/User.java deleted file mode 100644 index e7d4e94d40d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/server/User.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public class User { - private String name = "nameA"; - - private int age = 100; - - private int index; - - private String[] names; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String[] getNames() { - return names; - } - - public void setNames(String[] names) { - this.names = names; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @Override - public String toString() { - return "User [name=" + name + ", age=" + age + ", index=" + index + "]"; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/DemoConst.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/DemoConst.java similarity index 82% rename from demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/DemoConst.java rename to demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/DemoConst.java index 3dd5f64cc22..eb60d1e9d83 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/DemoConst.java +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/DemoConst.java @@ -15,10 +15,10 @@ * limitations under the License. */ -package org.apache.servicecomb.demo; +package org.apache.servicecomb.demo.springboot.pojo.client; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; public interface DemoConst { - String[] transports = new String[] {"rest", Const.ANY_TRANSPORT}; + String[] transports = new String[] {"rest", CoreConst.ANY_TRANSPORT}; } diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClient.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClient.java new file mode 100644 index 00000000000..b5a590b65e7 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClient.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.client; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ImportResource; + +/** + * SpringmvcClient + * + * + */ +@SpringBootApplication +@ImportResource(value = "classpath*:META-INF/spring/*.bean.xml") +public class PojoClient { + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(PojoClient.class).web(WebApplicationType.SERVLET).build().run(args); + + PojoClientTest.runTest(); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClientTest.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientTest.java similarity index 75% rename from demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClientTest.java rename to demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientTest.java index fdc7e388063..4e0525a1230 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/pojo/client/PojoClientTest.java +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientTest.java @@ -15,17 +15,17 @@ * limitations under the License. */ -package org.apache.servicecomb.demo.pojo.client; +package org.apache.servicecomb.demo.springboot.pojo.client; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; import org.apache.servicecomb.core.provider.consumer.InvokerUtils; -import org.apache.servicecomb.demo.DemoConst; -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.server.TestRequest; -import org.apache.servicecomb.demo.server.User; +import org.apache.servicecomb.demo.springboot.pojo.server.schema.server.Test; +import org.apache.servicecomb.demo.springboot.pojo.server.schema.server.TestRequest; +import org.apache.servicecomb.demo.springboot.pojo.server.schema.server.User; import org.apache.servicecomb.provider.pojo.RpcReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,12 +35,12 @@ public class PojoClientTest { private static Logger LOGGER = LoggerFactory.getLogger(PojoClientTest.class); - @RpcReference(microserviceName = "pojo") + @RpcReference(microserviceName = "spring-boot-pojo-server", schemaId = "server") public static Test test; - public static Test testFromXml; + private static Test testFromXml; - public static final byte buffer[] = new byte[1024]; + public static final byte[] buffer = new byte[1024]; public static final String SPLITPARAM_RESPONSE_USER_SUFFIX = "(modified by MyHandler)"; @@ -53,10 +53,10 @@ public static void setTestFromXml(Test testFromXml) { } public static void runTest() throws Exception { - String microserviceName = "pojo"; + String microserviceName = "spring-boot-pojo-server"; for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); TestMgr.setMsg(microserviceName, transport); LOGGER.info("test {}, transport {}", microserviceName, transport); @@ -89,18 +89,29 @@ private static void testSplitParam(Test test) { result); } + @SuppressWarnings({"deprecation"}) private static void testCommonInvoke(String transport) { - Object result = InvokerUtils.syncInvoke("pojo", "server", "splitParam", new Object[] {2, new User()}); + Map arguments = new HashMap<>(); + Map wrap = new HashMap<>(); + arguments.put("index", 2); + arguments.put("user", new User()); + wrap.put("splitParamBody", arguments); + + Object result = InvokerUtils.syncInvoke("spring-boot-pojo-server", "server", "splitParam", wrap, User.class); TestMgr.check("User [name=nameA, users count:0" + SPLITPARAM_RESPONSE_USER_SUFFIX + ", age=100, index=2]", result); + arguments = new HashMap<>(); + arguments.put("index", 3); + arguments.put("user", new User()); + wrap = new HashMap<>(); + wrap.put("splitParamBody", arguments); result = - InvokerUtils.syncInvoke("pojo", - "0.0.1", + InvokerUtils.syncInvoke("spring-boot-pojo-server", transport, "server", "splitParam", - new Object[] {3, new User()}); + wrap, User.class); TestMgr.check("User [name=nameA, users count:0" + SPLITPARAM_RESPONSE_USER_SUFFIX + ", age=100, index=3]", result); } diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/TestMgr.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/TestMgr.java similarity index 97% rename from demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/TestMgr.java rename to demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/TestMgr.java index e9444722faf..f0505643417 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/TestMgr.java +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/client/TestMgr.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.demo; +package org.apache.servicecomb.demo.springboot.pojo.client; import java.util.ArrayList; import java.util.List; diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java new file mode 100644 index 00000000000..6542be49ffc --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public interface Test { + String testStringArray(String[] arr); + + String getTestString(String code); + + String postTestStatic(int code); + + String testException(int code); + + User wrapParam(TestRequest request); + + User splitParam(int index, User user); + + String addString(String[] strArr); +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java new file mode 100644 index 00000000000..2b0aeeac41e --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +import java.util.ArrayList; +import java.util.List; + +public class TestRequest { + private int index; + + private User user; + + private List users = new ArrayList<>(); + + private byte[] data; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java new file mode 100644 index 00000000000..290ab4e9d58 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public class TestResponse { + private User user; + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + @Override + public String toString() { + return "TestResponse [user=" + user + "]"; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java new file mode 100644 index 00000000000..a46291ed9ff --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public class User { + private String name = "nameA"; + + private int age = 100; + + private int index; + + private String[] names; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getNames() { + return names; + } + + public void setNames(String[] names) { + this.names = names; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + @Override + public String toString() { + return "User [name=" + name + ", age=" + age + ", index=" + index + "]"; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/springboot/pojo/client/PojoClient.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/springboot/pojo/client/PojoClient.java deleted file mode 100644 index 6b8aee4d6f8..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/java/org/apache/servicecomb/springboot/pojo/client/PojoClient.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.pojo.client; - -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * SpringmvcClient - * - * - */ -@SpringBootApplication -@EnableServiceComb -public class PojoClient { - - public static void main(final String[] args) throws Exception { - Log4jUtils.init(); - SpringApplication.run(PojoClient.class, args); - - org.apache.servicecomb.demo.pojo.client.PojoClientTest.runTest(); - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml index 753ff9a29fe..a2219f31ba4 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/META-INF/spring/pojo.client.bean.xml @@ -22,10 +22,10 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.huawei.com/schema/paas/cse/rpc classpath:META-INF/spring/spring-paas-cse-rpc.xsd"> - + - + diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/application.yml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/application.yml new file mode 100644 index 00000000000..1d901a66c99 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/application.yml @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: spring-boot-pojotest + name: spring-boot-pojo-client + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 + handler: + chain: + Consumer: + default: loadbalance + isolation: + Consumer: + enabled: false + references: + pojo: + version-rule: 0.0.1 diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/microservice.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/microservice.yaml deleted file mode 100644 index 4069ea25ebe..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/main/resources/microservice.yaml +++ /dev/null @@ -1,36 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: spring-boot-pojotest -service_description: - name: pojoClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - #default: loadbalance - default: bizkeeper-consumer,loadbalance - isolation: - Consumer: - enabled: false - references: - pojo: - version-rule: 0.0.1 diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientIT.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientIT.java new file mode 100644 index 00000000000..1312a72739b --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/demo/springboot/pojo/client/PojoClientIT.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.client; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = PojoClient.class) +public class PojoClientIT { + + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + PojoClientTest.runTest(); + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/springboot/pojo/client/PojoClientIT.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/springboot/pojo/client/PojoClientIT.java deleted file mode 100644 index 77725ac6dc8..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-client/src/test/java/org/apache/servicecomb/springboot/pojo/client/PojoClientIT.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.pojo.client; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.apache.servicecomb.demo.TestMgr; -import org.junit.Before; -import org.junit.Test; -import org.springframework.boot.SpringApplication; - -public class PojoClientIT { - - @Before - public void setUp() throws Exception { - TestMgr.errors().clear(); - } - - @Test - public void clientGetsNoError() throws Exception { - SpringApplication.run(PojoClient.class); - - assertThat(TestMgr.errors().isEmpty(), is(true)); - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/pom.xml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/pom.xml index e6d93cb8e90..60761704af9 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/pom.xml +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/pom.xml @@ -25,52 +25,25 @@ org.apache.servicecomb.demo demo-spring-boot-transport - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT - org.apache.servicecomb.springboot.pojo.server.PojoServer + org.apache.servicecomb.demo.springboot.pojo.server.PojoServer + - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - javax.ws.rs - javax.ws.rs-api - - - org.apache.servicecomb - spring-boot-starter-transport + jakarta.ws.rs + jakarta.ws.rs-api + - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - ${project.version} - - - + org.springframework.boot + spring-boot-maven-plugin @@ -79,15 +52,50 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java deleted file mode 100644 index a84ac020671..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/helloworld/greeter/Hello.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.helloworld.greeter; - -public interface Hello { - public String SayHello(String name); - - public String SayHelloAgain(String name); -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/HelloImpl.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/HelloImpl.java deleted file mode 100644 index e2933daf5cf..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/HelloImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.server; - -import org.apache.servicecomb.demo.helloworld.greeter.Hello; -import org.apache.servicecomb.provider.pojo.RpcSchema; - -@RpcSchema(schemaId = "helloworld.Greeter") -public class HelloImpl implements Hello { - - @Override - public String SayHello(String name) { - return "Hello Message fast"; - } - - @Override - public String SayHelloAgain(String name) { - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello Message slow"; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java deleted file mode 100644 index c842f929456..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/pojo/server/TestImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.server; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.server.TestRequest; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -@RpcSchema(schemaId = "server") -public class TestImpl implements Test { - @Override - public String testStringArray(String[] arr) { - return String.format("arr is '%s'", Arrays.toString(arr)); - } - - @Override - public String getTestString(String code) { - return String.format("code is '%s'", String.valueOf(code)); - } - - @Override - public String postTestStatic(int code) { - return null; - } - - private User doTest(int index, User user, List users, byte[] data) { - if (user == null) { - user = new User(); - } - - user.setIndex(index); - - int userCount = (users == null) ? 0 : users.size(); - user.setName(user.getName() + ", users count:" + userCount); - return user; - } - - @Override - public String testException(int code) { - String strCode = String.valueOf(code); - switch (code) { - case 200: - return strCode; - case 456: - throw new InvocationException(code, strCode, strCode + " error"); - case 556: - throw new InvocationException(code, strCode, Arrays.asList(strCode + " error")); - case 557: - throw new InvocationException(code, strCode, Arrays.asList(Arrays.asList(strCode + " error"))); - default: - break; - } - - return "not expected"; - } - - @Override - public User splitParam(int index, User user) { - return doTest(index, user, null, null); - } - - @Override - public User wrapParam(TestRequest request) { - if (request == null) { - return null; - } - return doTest(request.getIndex(), request.getUser(), request.getUsers(), request.getData()); - } - - @Override - public String addString(String[] strArr) { - String result = Arrays.toString(strArr); - System.out.println("addString: " + result); - return result; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/Test.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/Test.java deleted file mode 100644 index d853caffc13..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/Test.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public interface Test { - String testStringArray(String[] arr); - - String getTestString(String code); - - String postTestStatic(int code); - - String testException(int code); - - User wrapParam(TestRequest request); - - User splitParam(int index, User user); - - String addString(String[] strArr); -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java deleted file mode 100644 index 6f622686271..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestRequest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -import java.util.ArrayList; -import java.util.List; - -public class TestRequest { - private int index; - - private User user; - - private List users = new ArrayList<>(); - - private byte[] data; - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public List getUsers() { - return users; - } - - public void setUsers(List users) { - this.users = users; - } - - public byte[] getData() { - return data; - } - - public void setData(byte[] data) { - this.data = data; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java deleted file mode 100644 index c6baa8e0078..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/TestResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public class TestResponse { - private User user; - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - @Override - public String toString() { - return "TestResponse [user=" + user + "]"; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/User.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/User.java deleted file mode 100644 index e7d4e94d40d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/server/User.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.server; - -public class User { - private String name = "nameA"; - - private int age = 100; - - private int index; - - private String[] names; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String[] getNames() { - return names; - } - - public void setNames(String[] names) { - this.names = names; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @Override - public String toString() { - return "User [name=" + name + ", age=" + age + ", index=" + index + "]"; - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/PojoServer.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/PojoServer.java new file mode 100644 index 00000000000..30af50bf5f5 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/PojoServer.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class PojoServer { + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(PojoServer.class).web(WebApplicationType.SERVLET).build().run(args); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/handler/MyHandler.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/handler/MyHandler.java new file mode 100644 index 00000000000..09d2e2eb06d --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/handler/MyHandler.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.handler; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.demo.springboot.pojo.server.schema.server.User; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class MyHandler extends AbstractFilter implements ProviderFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class); + + public static final String SPLITPARAM_RESPONSE_USER_SUFFIX = "(modified by MyHandler)"; + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 100; + } + + @Override + public String getName() { + return "test-my-filter"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + LOGGER.info("If you see this log, that means this demo project has been converted to ServiceComb framework."); + + return nextNode.onFilter(invocation).whenComplete((response, throwable) -> { + if (invocation.getOperationMeta().getSchemaQualifiedName().equals("server.splitParam")) { + User user = response.getResult(); + user.setName(user.getName() + SPLITPARAM_RESPONSE_USER_SUFFIX); + } + }); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/greeter/Hello.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/greeter/Hello.java new file mode 100644 index 00000000000..7279c9fede1 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/greeter/Hello.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.greeter; + +public interface Hello { + String SayHello(String name); + + String SayHelloAgain(String name); +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/HelloImpl.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/HelloImpl.java new file mode 100644 index 00000000000..4bf9381a738 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/HelloImpl.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +import org.apache.servicecomb.demo.springboot.pojo.server.schema.greeter.Hello; +import org.apache.servicecomb.provider.pojo.RpcSchema; + +@RpcSchema(schemaId = "helloworld.Greeter") +public class HelloImpl implements Hello { + + @Override + public String SayHello(String name) { + return "Hello Message fast"; + } + + @Override + public String SayHelloAgain(String name) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hello Message slow"; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java new file mode 100644 index 00000000000..6542be49ffc --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/Test.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public interface Test { + String testStringArray(String[] arr); + + String getTestString(String code); + + String postTestStatic(int code); + + String testException(int code); + + User wrapParam(TestRequest request); + + User splitParam(int index, User user); + + String addString(String[] strArr); +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestImpl.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestImpl.java new file mode 100644 index 00000000000..6b9622a0804 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestImpl.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +@RpcSchema(schemaId = "server") +public class TestImpl implements Test { + @Override + public String testStringArray(String[] arr) { + return String.format("arr is '%s'", Arrays.toString(arr)); + } + + @Override + public String getTestString(String code) { + return String.format("code is '%s'", code); + } + + @Override + public String postTestStatic(int code) { + return null; + } + + private User doTest(int index, User user, List users, byte[] data) { + if (user == null) { + user = new User(); + } + + user.setIndex(index); + + int userCount = (users == null) ? 0 : users.size(); + user.setName(user.getName() + ", users count:" + userCount); + return user; + } + + @Override + public String testException(int code) { + String strCode = String.valueOf(code); + switch (code) { + case 200: + return strCode; + case 456: + throw new InvocationException(code, strCode, strCode + " error"); + case 556: + throw new InvocationException(code, strCode, Arrays.asList(strCode + " error")); + case 557: + throw new InvocationException(code, strCode, Arrays.asList(Arrays.asList(strCode + " error"))); + default: + break; + } + + return "not expected"; + } + + @Override + public User splitParam(int index, User user) { + return doTest(index, user, null, null); + } + + @Override + public User wrapParam(TestRequest request) { + if (request == null) { + return null; + } + return doTest(request.getIndex(), request.getUser(), request.getUsers(), request.getData()); + } + + @Override + public String addString(String[] strArr) { + String result = Arrays.toString(strArr); + System.out.println("addString: " + result); + return result; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java new file mode 100644 index 00000000000..2b0aeeac41e --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestRequest.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +import java.util.ArrayList; +import java.util.List; + +public class TestRequest { + private int index; + + private User user; + + private List users = new ArrayList<>(); + + private byte[] data; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java new file mode 100644 index 00000000000..290ab4e9d58 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/TestResponse.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public class TestResponse { + private User user; + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + @Override + public String toString() { + return "TestResponse [user=" + user + "]"; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java new file mode 100644 index 00000000000..a46291ed9ff --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/demo/springboot/pojo/server/schema/server/User.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springboot.pojo.server.schema.server; + +public class User { + private String name = "nameA"; + + private int age = 100; + + private int index; + + private String[] names; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getNames() { + return names; + } + + public void setNames(String[] names) { + this.names = names; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + @Override + public String toString() { + return "User [name=" + name + ", age=" + age + ", index=" + index + "]"; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/handler/MyHandler.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/handler/MyHandler.java deleted file mode 100644 index 6719d03780d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/handler/MyHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.handler; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MyHandler implements Handler { - - private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class); - - public static final String SPLITPARAM_RESPONSE_USER_SUFFIX = "(modified by MyHandler)"; - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - LOGGER.info("If you see this log, that means this demo project has been converted to ServiceComb framework."); - - invocation.next(response -> { - if (invocation.getOperationMeta().getSchemaQualifiedName().equals("server.splitParam")) { - User user = response.getResult(); - user.setName(user.getName() + SPLITPARAM_RESPONSE_USER_SUFFIX); - asyncResp.handle(response); - } else { - asyncResp.handle(response); - } - }); - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/springboot/pojo/server/PojoServer.java b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/springboot/pojo/server/PojoServer.java deleted file mode 100644 index 2208b6238eb..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/java/org/apache/servicecomb/springboot/pojo/server/PojoServer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.pojo.server; - -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class PojoServer { - - public static void main(final String[] args) throws Exception { - Log4jUtils.init(); - SpringApplication.run(PojoServer.class, args); - } -} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/application.yml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/application.yml index 9723c7769bf..e7c0ccf1da0 100644 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/application.yml +++ b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/application.yml @@ -17,3 +17,14 @@ server: port: 8080 + +servicecomb: + service: + application: spring-boot-pojotest + name: spring-boot-pojo-server + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 + rest: + address: 0.0.0.0:8080 diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/cse.handler.xml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/cse.handler.xml deleted file mode 100644 index e4838960750..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/log4j.properties b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservice.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservice.yaml deleted file mode 100644 index 91fa6c7c21d..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: spring-boot-pojotest -service_description: - name: pojo - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: myhandler diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/helloworld.Greeter.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/helloworld.Greeter.yaml deleted file mode 100644 index c3272c1c723..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/helloworld.Greeter.yaml +++ /dev/null @@ -1,74 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: helloworld.Greeter - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.helloworld.greeter.Hello - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/helloworld.Greeter -produces: - - application/json - -paths: - /SayHello: - post: - operationId: SayHello - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: asdf - schema: - type: string - default: - description: asf - schema: - type: string - /SayHelloAgain: - post: - operationId: SayHelloAgain - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: asdf - schema: - type: string - default: - description: asf - schema: - type: string diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml deleted file mode 100644 index 3fa0fdab021..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml +++ /dev/null @@ -1,197 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: cse test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.server.Test - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest -produces: - - application/json - -paths: - /testStringArray: - get: - operationId: testStringArray - parameters: - - name: arr - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: asdf - schema: - type: string - /testStatic: - get: - operationId: getTestString - parameters: - - name: code - in: query - required: true - type: string - responses: - 200: - description: asdf - schema: - type: string - post: - operationId: postTestStatic - parameters: - - name: code - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: asdf - schema: - type: string - /testException/{code}: - get: - operationId: testException - parameters: - - name: code - in: path - required: true - type: integer - format: int32 - responses: - 200: - description: asdf - schema: - type: string - 456: - description: asdf - schema: - type: string - 556: - description: asdf - schema: - type: array - items: - type: string - 557: - description: asdf - schema: - type: array - items: - type: array - items: - type: string - /splitParam: - post: - operationId: splitParam - parameters: - - name: index - in: query - required: true - type: number - - name: user - in: body - schema: - $ref: '#/definitions/User' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /wrapParam: - post: - operationId: wrapParam - parameters: - - name: TestRequest - in: body - required: true - schema: - $ref: '#/definitions/TestRequest' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /addstring: - delete: - operationId: addString - parameters: - - name: strArr - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: add string - schema: - type: string - -definitions: - Error: - type: object - x-java-class: org.apache.servicecomb.core.exception.CommonExceptionData - properties: - message: - type: string - TestRequest: - type: object - properties: - index: - type: number - user: - $ref: '#/definitions/User' - users: - type: array - items: - $ref: '#/definitions/User' - data: - type: string - format: byte - User: - type: object - properties: - name: - type: string - age: - type: number - index: - type: number - x-java-class: "org.apache.servicecomb.demo.server.User" \ No newline at end of file diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/smartcare.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/smartcare.yaml deleted file mode 100644 index 49a8ac93e72..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/smartcare.yaml +++ /dev/null @@ -1,135 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: smartcare test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.smartcare.SmartCare - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/plat/meta/v1 -produces: - - application/json - -paths: - /applications: - post: - operationId: addApplication - parameters: - - name: application - in: body - required: true - schema: - $ref: '#/definitions/Application' - responses: - 201: - description: success - schema: - $ref: '#/definitions/Response' - 400: - description: error - schema: - $ref: '#/definitions/Response' - 500: - description: error - schema: - $ref: '#/definitions/Response' - - /applications/{appName}: - delete: - operationId: delApplication - parameters: - - name: appName - in: path - required: true - type: string - responses: - 201: - description: success - schema: - $ref: '#/definitions/Response' - 400: - description: error - schema: - $ref: '#/definitions/Response' - 500: - description: error - schema: - $ref: '#/definitions/Response' - - -definitions: - Application: - type: object - properties: - name: - type: string - labelEN: - type: string - labelCH: - type: string - defaultGroup: - type: string - version: - type: string - dynamicFlag: - type: boolean - groups: - type: array - items: - $ref: '#/definitions/Group' - required: - - name - - defaultGroup - - version - - dynamicFlag - - groups - - Group: - type: object - properties: - name: - type: string - labelEN: - type: string - labelCH: - type: string - required: - - name - - Response: - type: object - x-java-class: org.apache.servicecomb.demo.smartcare.Response - properties: - resultCode: - type: integer - format: int32 - resultMessage: - type: string - required: - - resultCode - diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/tcc-server.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/tcc-server.yaml deleted file mode 100644 index 677cce1de39..00000000000 --- a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/tcc-server.yaml +++ /dev/null @@ -1,108 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# this is an example of the Uber API -# as a demonstration of an API spec in YAML -swagger: '2.0' -info: - title: cse test - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.tccserver.TestTcc - -# the domain of the service -#host: api.uber.com - -# array of all schemes that your API supports -#schemes: -# - https - -# will be prefixed to all paths -basePath: /pojo/rest/tcc-server -produces: - - application/json - -paths: - /splitParam: - post: - operationId: splitParam - parameters: - - name: index - in: query - required: true - type: number - - name: user - in: body - schema: - $ref: '#/definitions/User' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - /wrapParam: - post: - operationId: wrapParam - parameters: - - name: TestRequest - in: body - required: true - schema: - $ref: '#/definitions/TestRequest' - responses: - 200: - description: asdf - schema: - $ref: '#/definitions/User' - default: - description: asf - schema: - $ref: '#/definitions/Error' - -definitions: - Error: - type: object - x-java-class: org.apache.servicecomb.core.exception.CommonExceptionData - properties: - message: - type: string - TestRequest: - type: object - properties: - index: - type: number - user: - $ref: '#/definitions/User' - users: - type: array - items: - $ref: '#/definitions/User' - data: - type: string - format: byte - User: - type: object - properties: - name: - type: string - age: - type: number - index: - type: number diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/pom.xml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/pom.xml new file mode 100644 index 00000000000..edd73c1428b --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/pom.xml @@ -0,0 +1,131 @@ + + + + + 4.0.0 + + demo-spring-boot-springmvc-client + Java Chassis::Demo::Spring Boot::Spring MVC Client + + org.apache.servicecomb.demo + demo-spring-boot-transport + 3.4.0-SNAPSHOT + + + + + org.apache.servicecomb.demo + demo-schema + + + + + docker + + demo-spring-boot-springmvc-server + + + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/PlaceHolderSchemaTest.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/PlaceHolderSchemaTest.java new file mode 100644 index 00000000000..f7e066497d1 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/PlaceHolderSchemaTest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class PlaceHolderSchemaTest implements CategorizedTestCase { + @Override + public void testRestTransport() throws Exception { + RestOperations template = RestTemplateBuilder.create(); + String result = template.getForObject("servicecomb://springmvc/placeholder/schema?name=test", String.class); + TestMgr.check("test", result); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ReactiveStreamIT.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ReactiveStreamIT.java new file mode 100644 index 00000000000..c9c1957ddf5 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ReactiveStreamIT.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.client; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.springboot.springmvc.client.ThirdSvcConfiguration.ReactiveStreamClient; +import org.apache.servicecomb.springboot.springmvc.client.ThirdSvcConfiguration.ReactiveStreamClient.Model; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +public class ReactiveStreamIT implements CategorizedTestCase { + @Autowired + @Qualifier("reactiveStreamProvider") + ReactiveStreamClient reactiveStreamProvider; + + @Override + public void testRestTransport() throws Exception { + testSseString(reactiveStreamProvider); + testSseModel(reactiveStreamProvider); + } + + private void testSseModel(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseModel(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(Model s) { + buffer.append(s.getName()).append(s.getAge()); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("jack0jack1jack2jack3jack4", buffer.toString()); + } + + private void testSseString(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseString(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(String s) { + buffer.append(s); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("abc", buffer.toString()); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClient.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClient.java new file mode 100644 index 00000000000..8ce77d9818e --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClient.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +/** + * SpringMvcClient + * + * + */ +@SpringBootApplication +public class SpringMvcClient { + + public static void main(final String[] args) throws Exception { + + new SpringApplicationBuilder().sources(SpringMvcClient.class).web(WebApplicationType.SERVLET).build().run(args); + + runTest(); + } + + public static void runTest() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("springmvc"); + + TestMgr.summary(); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/TestAnnotationsSchema.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/TestAnnotationsSchema.java new file mode 100644 index 00000000000..7d77fa1be35 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/TestAnnotationsSchema.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.springboot.springmvc.client; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; +import org.apache.servicecomb.provider.springmvc.reference.UrlWithServiceNameClientHttpRequestFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class TestAnnotationsSchema implements CategorizedTestCase { + private static final String microserviceName = "springmvc"; + + private static final RestTemplate templateUrlWithServiceName = new CseRestTemplate(); + + @Override + public void testRestTransport() throws Exception { + templateUrlWithServiceName.setRequestFactory(new UrlWithServiceNameClientHttpRequestFactory()); + testRequiredBody(templateUrlWithServiceName, microserviceName); + testRegExpPath(); + } + + private void testRegExpPath() { + String prefix = "cse://" + microserviceName; + String result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a?name={name}", + String.class, "a"); + TestMgr.check("a", result); + result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a/b?name={name}", + String.class, "ab"); + TestMgr.check("ab", result); + result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a/b/c?name={name}", + String.class, "abc"); + TestMgr.check("abc", result); + } + + private static void testRequiredBody(RestTemplate template, String microserviceName) { + String prefix = "cse://" + microserviceName; + Person user = new Person(); + + TestMgr.check("No user data found", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + user, + String.class, + "ha")); + + user.setName("world"); + TestMgr.check("ha world", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + user, + String.class, + "ha")); + + TestMgr.check("No user data found", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + null, + String.class, + "ha")); + + TestMgr.check("No user name found", + template.postForObject(prefix + "/annotations/say", + "", + String.class, + "ha")); + TestMgr.check("test", + template.postForObject(prefix + "/annotations/say", + "test", + String.class, + "ha")); + + try { + template.postForObject(prefix + "/annotations/testRequiredBody", + null, + String.class); + TestMgr.fail("should fail"); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ThirdSvcConfiguration.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ThirdSvcConfiguration.java new file mode 100644 index 00000000000..098a36828ed --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/ThirdSvcConfiguration.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.client; + +import org.apache.servicecomb.provider.pojo.Invoker; +import org.reactivestreams.Publisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Configuration +public class ThirdSvcConfiguration { + @RequestMapping(path = "/") + public interface ReactiveStreamClient { + class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + Publisher sseString(); + + @GetMapping("/sseModel") + Publisher sseModel(); + } + + @Bean("reactiveStreamProvider") + public ReactiveStreamClient reactiveStreamProvider() { + return Invoker.createProxy("springmvc", "ReactiveStreamController", ReactiveStreamClient.class); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java new file mode 100644 index 00000000000..18054cf4f4a --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.springboot.springmvc.client; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class UploadDownloadSchemaTest implements CategorizedTestCase { + RestOperations restOperations = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testEmptyFileUploadWork(); + testNonEmptyFileUploadWork(); + } + + private void testNonEmptyFileUploadWork() throws Exception { + String file2Content = " bonjour"; + File someFile = File.createTempFile("upload2", ".txt"); + FileUtils.writeStringToFile(someFile, file2Content, StandardCharsets.UTF_8, false); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + Map params = new HashMap<>(); + params.put("name", "test"); + params.put("file", someFile); + HttpEntity> entity = new HttpEntity<>(params, headers); + String url = "servicecomb://springmvc/up/down/upload"; + String result = restOperations.postForObject(url, entity, String.class); + TestMgr.check("test; bonjour", result); + } + + private void testEmptyFileUploadWork() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + Map params = new HashMap<>(); + params.put("name", "test"); + HttpEntity> entity = new HttpEntity<>(params, headers); + String url = "servicecomb://springmvc/up/down/upload"; + String result = restOperations.postForObject(url, entity, String.class); + TestMgr.check("test;", result); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/application.yml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/application.yml new file mode 100644 index 00000000000..68ab69a48cb --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/application.yml @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8999 +servicecomb: + service: + application: springmvcboottest + name: springmvcclient + version: 0.0.3 + registry: + sc: + address: http://127.0.0.1:30100 + test: + vert: + transport: false diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/certificates/server.p12 b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/certificates/server.p12 similarity index 100% rename from demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/certificates/server.p12 rename to demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/certificates/server.p12 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/certificates/trust.jks b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/certificates/trust.jks similarity index 100% rename from demo/demo-spring-boot-provider/demo-spring-boot-springmvc-client/src/main/resources/certificates/trust.jks rename to demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/certificates/trust.jks diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/microservice.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..587c6bbf55a --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/resources/microservice.yaml @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb-config-order: 100 + +3rd-svc: + urls: + - rest://localhost:8080?sslEnabled=false diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/test/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClientIT.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/test/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClientIT.java new file mode 100644 index 00000000000..ae3ef5b0044 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/test/java/org/apache/servicecomb/springboot/springmvc/client/SpringMvcClientIT.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.client; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = SpringMvcClient.class) +public class SpringMvcClientIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + try { + SpringMvcClient.runTest(); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } catch (Throwable e) { + e.printStackTrace(); + Assertions.fail("test case failed, message=" + e.getMessage()); + } + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/pom.xml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/pom.xml new file mode 100644 index 00000000000..efa0723b59a --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/pom.xml @@ -0,0 +1,98 @@ + + + + + 4.0.0 + + demo-spring-boot-springmvc-server + Java Chassis::Demo::Spring Boot::Spring MVC Server + + org.apache.servicecomb.demo + demo-spring-boot-transport + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo + demo-schema + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/AnnotationsSchema.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/AnnotationsSchema.java new file mode 100644 index 00000000000..b1bcaba83ed --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/AnnotationsSchema.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.server; + +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "annotations") +@RequestMapping(path = "/springmvc/annotations", produces = MediaType.APPLICATION_JSON) +public class AnnotationsSchema { + @GetMapping(path = "/add") + public int add(@RequestParam(name = "a", defaultValue = "10") int a, + @RequestParam(name = "b", defaultValue = "10") int b) { + return a + b; + } + + @RequestMapping(path = "/sayhei", method = RequestMethod.GET) + public String sayHei(@RequestHeader(name = "name", defaultValue = "test") String name) { + return "hei " + name; + } + + @GetMapping(path = "/sayhi") + @Parameters({ + @Parameter(name = "name", in = ParameterIn.QUERY, schema = @Schema(type = "string", defaultValue = "test")), + @Parameter(name = "age", in = ParameterIn.QUERY, schema = @Schema(type = "integer", defaultValue = "20")) + }) + public String sayHi(String name, int age) { + return "hi " + name + " your age is : " + age; + } + + @RequestMapping(path = "/saysomething", method = RequestMethod.POST) + public String saySomething(String prefix, @RequestBody(required = false) Person user) { + if (user == null || user.getName() == null || user.getName().isEmpty()) { + return "No user data found"; + } + return prefix + " " + user.getName(); + } + + @RequestMapping(path = "/say", method = RequestMethod.POST) + public String say(@RequestBody(required = false) String user) { + if (user == null || user.isEmpty()) { + return "No user name found"; + } + return user; + } + + @RequestMapping(path = "/testRequiredBody", method = RequestMethod.POST) + public String testRequiredBody(@RequestBody(required = true) Person user) { + if (user == null) { + return "Should not happen"; + } + return user.getName(); + } + + @RequestMapping(path = "/testRegExpPath/{path: .+}", method = RequestMethod.GET) + public String testRegExpPath(@RequestParam("name") String name) { + return name; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/PlaceHolderSchema.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/PlaceHolderSchema.java new file mode 100644 index 00000000000..bb75e8e8a9a --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/PlaceHolderSchema.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "PlaceHolderSchema") +@RequestMapping(path = "${test.placeholder.schema}") +public class PlaceHolderSchema { + @GetMapping(path = "/") + public String root(@RequestParam("name") String name) { + return name; + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/ReactiveStreamController.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/ReactiveStreamController.java new file mode 100644 index 00000000000..e82028d1286 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/ReactiveStreamController.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.springboot.springmvc.server; + + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.reactivex.rxjava3.core.Flowable; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +public class ReactiveStreamController { + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + public Publisher sseString() { + return Flowable.fromArray("a", "b", "c"); + } + + @GetMapping("/sseModel") + public Publisher sseModel() { + return Flowable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS) + .map(item -> new Model("jack", item.intValue())); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java new file mode 100644 index 00000000000..acbd39e0cc4 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/SpringmvcServer.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.server; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication(exclude = {WebMvcAutoConfiguration.class}) +public class SpringmvcServer { + private static final Logger LOGGER = LoggerFactory.getLogger(SpringmvcServer.class); + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(SpringmvcServer.class).web(WebApplicationType.SERVLET).build().run(args); + + assertPropertyCorrect(); + } + + private static void assertPropertyCorrect() { + // spring environment will fail for unresolved placeholder property + try { + LegacyPropertyFactory.getStringProperty("test.unresolved.placeholder"); + } catch (IllegalArgumentException e) { + return; + } + LOGGER.error("tests for configuration error, stop"); + SCBEngine.getInstance().destroy(); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java new file mode 100644 index 00000000000..ec80bedbec4 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.springmvc.server; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "UploadDownloadSchema") +@RequestMapping(path = "/up/down") +public class UploadDownloadSchema { + @PostMapping(path = "/upload", consumes = MediaType.MULTIPART_FORM_DATA) + public String fileUpload(@RequestPart MultipartFile file, @RequestPart(value = "name") String name) throws Exception { + StringBuilder result = new StringBuilder(); + result.append(name).append(";"); + if (file == null || file.isEmpty()) { + return result.toString(); + } + try (InputStream is = file.getInputStream()) { + result.append(IOUtils.toString(is, StandardCharsets.UTF_8)); + } + return result.toString(); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/application.yml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/application.yml new file mode 100644 index 00000000000..7cd484f51bb --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/application.yml @@ -0,0 +1,36 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8080 + +test.unresolved.placeholder: jdbc:postgresql://${ip}:${port}/pt +test: + placeholder: + schema: placeholder/schema + +servicecomb: + service: + application: springmvcboottest + name: springmvc + version: 0.0.3 + registry: + sc: + address: http://127.0.0.1:30100 + test: + vert: + transport: false diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/certificates/server.p12 b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/certificates/server.p12 similarity index 100% rename from demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/certificates/server.p12 rename to demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/certificates/server.p12 diff --git a/demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/certificates/trust.jks b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/certificates/trust.jks similarity index 100% rename from demo/demo-spring-boot-provider/demo-spring-boot-springmvc-server/src/main/resources/certificates/trust.jks rename to demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/certificates/trust.jks diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/microservice.yaml b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..c3738a1dd60 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/resources/microservice.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + config: + ignoreResolveFailure: true + + service: + registry: + registerPath: true + address: http://127.0.0.1:9980,http://127.0.0.1:30100 + client: + timeout: + idle: 60 + watch: 60 + instance: + healthCheck: + interval: 3 + pull: + interval: 10 + watch: true + autodiscovery: true + uploads: + directory: target + + rest: + address: 0.0.0.0:8080?sslEnabled=false diff --git a/demo/demo-spring-boot-transport/pom.xml b/demo/demo-spring-boot-transport/pom.xml index d2d6a70a9df..bd7650a3f26 100644 --- a/demo/demo-spring-boot-transport/pom.xml +++ b/demo/demo-spring-boot-transport/pom.xml @@ -22,24 +22,54 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-spring-boot-transport Java Chassis::Demo::Spring Boot::Transport pom + demo-spring-boot-springmvc-server + demo-spring-boot-springmvc-client demo-spring-boot-pojo-server demo-spring-boot-pojo-client - org.springframework.boot - spring-boot-starter-web + org.apache.servicecomb + solution-basic - org.springframework.boot - spring-boot-starter-actuator + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + foundation-test-scaffolding + compile diff --git a/demo/demo-springmvc/pom.xml b/demo/demo-springmvc/pom.xml index 7988c7c8fe5..c307aa7741b 100644 --- a/demo/demo-springmvc/pom.xml +++ b/demo/demo-springmvc/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb.demo demo-parent - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT demo-springmvc Java Chassis::Demo::Spring MVC @@ -31,5 +31,34 @@ springmvc-server springmvc-client - + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + diff --git a/demo/demo-springmvc/springmvc-client/pom.xml b/demo/demo-springmvc/springmvc-client/pom.xml index 56ee49a73a3..17b7bbcd709 100644 --- a/demo/demo-springmvc/springmvc-client/pom.xml +++ b/demo/demo-springmvc/springmvc-client/pom.xml @@ -23,78 +23,102 @@ org.apache.servicecomb.demo demo-springmvc - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT springmvc-client Java Chassis::Demo::Spring MVC::Client - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - config-cc - - - org.apache.servicecomb - handler-fault-injection - - - - org.apache.servicecomb.demo - demo-signature - - - org.apache.servicecomb - foundation-test-scaffolding - - org.apache.servicecomb.demo.springmvc.client.SpringmvcClient + org.apache.servicecomb.demo.springmvc.SpringmvcClient - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-run-config - ${project.version} - - - - - - + docker springmvc-server - - -Dcse.highway.address=0.0.0.0:7070 - -Dcse.rest.address=0.0.0.0:8080?sslEnabled=false - + + + + io.fabric8 + docker-maven-plugin + + + + servicecomb/service-center + service-center + + + server is ready + + + 30100 + + + + + + 30100:30100 + + + + + ${demo.service.name}:${project.version} + ${demo.service.name} + + + + -Dservicecomb.registry.sc.address=http://sc.servicecomb.io:30100 + + /maven/maven/${demo.service.name}-${project.version}.jar + + + service-center:sc.servicecomb.io + + + ServiceComb is ready + + + 8080 + + + + + + 7070:7070 + 8080:8080 + + + service-center + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + io.fabric8 diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcClient.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcClient.java new file mode 100644 index 00000000000..b827884d323 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcClient.java @@ -0,0 +1,519 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.DemoConst; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.demo.springmvc.client.CodeFirstRestTemplateSpringmvc; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.provider.springmvc.reference.UrlWithProviderPrefixClientHttpRequestFactory; +import org.apache.servicecomb.provider.springmvc.reference.UrlWithServiceNameClientHttpRequestFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.annotation.ImportResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + + +@SpringBootApplication +@ImportResource(value = "classpath*:META-INF/spring/*.bean.xml") +public class SpringmvcClient { + private static final Logger LOGGER = LoggerFactory.getLogger(SpringmvcClient.class); + + private static RestTemplate templateUrlWithServiceName = new CseRestTemplate(); + + private static RestTemplate templateUrlWithProviderPrefix = new CseRestTemplate(); + + private static RestOperations restTemplate; + + public static void main(String[] args) { + new SpringApplicationBuilder(SpringmvcClient.class).web(WebApplicationType.NONE).run(args); + + run(); + } + + private static void changeTransport(String microserviceName, String transport) { + InMemoryDynamicPropertiesSource.update("servicecomb.references.transport." + microserviceName, transport); + TestMgr.setMsg(microserviceName, transport); + } + + public static void run() { + try { + runImpl(); + } catch (Throwable e) { + TestMgr.check("success", "failed"); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + LOGGER.info("-------------- last time updated checks(maybe more/less): 1344 -------------"); + } + + private static void runImpl() throws Exception { + testHttpClientsIsOk(); + + templateUrlWithServiceName.setRequestFactory(new UrlWithServiceNameClientHttpRequestFactory()); + restTemplate = RestTemplateBuilder.create(); + templateUrlWithProviderPrefix.setRequestFactory(new UrlWithProviderPrefixClientHttpRequestFactory("/pojo/rest")); + + String prefix = "cse://springmvc"; + String microserviceName = "springmvc"; + + try { + // only works in rest, highway does not have name param, because not defined. + templateUrlWithServiceName.getForObject(prefix + "/controller/sayhi?name=throwexception", String.class); + TestMgr.check("true", "false"); + } catch (Exception e) { + TestMgr.check("true", "true"); + } + try { + // only works in rest, highway does not have name param, because not defined. + templateUrlWithServiceName.getForObject(prefix + "/controller/sayhi?name=throwexception", String.class); + TestMgr.check("true", "false"); + } catch (Exception e) { + TestMgr.check("true", "true"); + } + + testHandler(microserviceName); + CodeFirstRestTemplateSpringmvc codeFirstClient = + BeanUtils.getContext().getBean(CodeFirstRestTemplateSpringmvc.class); + codeFirstClient.testCodeFirst(restTemplate, "springmvc", "/codeFirstSpringmvc/"); + codeFirstClient.testCodeFirst(templateUrlWithProviderPrefix, "springmvc", "/pojo/rest/codeFirstSpringmvc/"); + testAllTransport(microserviceName); + testRestTransport(microserviceName, prefix); + CategorizedTestCaseRunner.runCategorizedTestCase(microserviceName); + } + + private static void testHandler(String microserviceName) { + changeTransport(microserviceName, "rest"); + String prefix = "cse://springmvc"; + String result = templateUrlWithServiceName.getForObject(prefix + "/controller/sayHello1?name=tom", String.class); + TestMgr.check("Hello tom,v", result); + } + + private static void testHttpClientsIsOk() { + TestMgr.check(HttpClients.getClient("http-transport-client") != null, true); + TestMgr.check(HttpClients.getClient("http2-transport-client") != null, true); + + TestMgr.check(HttpClients.getClient("http-transport-client", false) != null, true); + TestMgr.check(HttpClients.getClient("http2-transport-client", false) != null, true); + } + + private static void testRestTransport(String microserviceName, String prefix) { + changeTransport(microserviceName, "rest"); + + testControllerRest(templateUrlWithServiceName, microserviceName); + testSpringMvcDefaultValuesRest(templateUrlWithServiceName, microserviceName); + testSpringMvcDefaultValuesJavaPrimitiveRest(templateUrlWithServiceName, microserviceName); + + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept-Encoding", "gzip"); + HttpEntity entity = new HttpEntity<>(headers); + ResponseEntity entityCompress = + restTemplate.exchange(prefix + + "/codeFirstSpringmvc/sayhi/compressed/{name}/v2", HttpMethod.GET, entity, String.class, "Test"); + TestMgr.check( + "Test sayhi compressed:This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text!", + entityCompress.getBody()); + // if server response is compressed, the content-length header will be removed , so can't check this. + // the transfer-encoding header will be missing when the server is set to not compressed + if (entityCompress.getHeaders().get("transfer-encoding") != null) { + TestMgr.check("chunked", entityCompress.getHeaders().get("transfer-encoding").get(0)); + } + + //0.5.0 later version metrics integration test + @SuppressWarnings("unchecked") + Map metrics = restTemplate.getForObject(prefix + "/scb/metrics", Map.class); + + // TestMgr.check(true, metrics.get("jvm(name=heapUsed,statistic=gauge)") != 0); + TestMgr.check(true, metrics.size() > 0); + + //prometheus integration test + try { + String content = restTemplate + .getForObject("cse://springmvc/codeFirstSpringmvc/prometheusForTest", String.class); + + String application = LegacyPropertyFactory.getStringProperty("servicecomb.service.application", ""); + + TestMgr.check(true, + content.contains( + "servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.addDate")); + TestMgr.check(true, + content.contains( + "servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.sayHello")); + TestMgr.check(true, + content + .contains("servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.isTrue")); + TestMgr.check(true, + content.contains("servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.add")); + TestMgr.check(true, + content + .contains("servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.sayHi2")); + TestMgr.check(true, content + .contains( + "servicecomb_invocation{appId=\"" + application + "\",operation=\"springmvc.codeFirst.saySomething")); + + String[] metricLines = content.split("\n"); + if (metricLines.length > 0) { + for (String metricLine : metricLines) { + if (!metricLine.startsWith("#")) { + String[] metricKeyAndValue = metricLine.split(" "); + if (!metricKeyAndValue[0].startsWith("jvm") && !metricKeyAndValue[0].startsWith("os")) { + if (Double.parseDouble(metricKeyAndValue[1]) < 0) { + TestMgr.check("true", "false"); + break; + } + } + } + } + } else { + TestMgr.check("true", "false"); + } + } catch (Exception e) { + LOGGER.error("", e); + TestMgr.check("true", "false"); + } + } + + private static void testAllTransport(String microserviceName) { + for (String transport : DemoConst.transports) { + changeTransport(microserviceName, transport); + + TestMgr.setMsg(microserviceName, transport); + + testControllerAllTransport(templateUrlWithServiceName, microserviceName); + + testSpringMvcDefaultValuesAllTransport(templateUrlWithServiceName, microserviceName); + testSpringMvcDefaultValuesJavaPrimitiveAllTransport(templateUrlWithServiceName, microserviceName); + } + } + + private static void testControllerRest(RestTemplate template, String microserviceName) { + String prefix = "cse://" + microserviceName; + + TestMgr.check("hi world [world]", + template.getForObject(prefix + "/controller/sayhi?name=world", + String.class)); + + TestMgr.check("hi world boot [world boot]", + template.getForObject(prefix + "/controller/sayhi?name=world boot", + String.class)); + + TestMgr.check("hi world boot [world boot]", + template.getForObject(prefix + "/controller/sayhi?name=world+boot", + String.class)); + + TestMgr.check("hi world1 [world1]", + template.getForObject(prefix + "/controller/sayhi?name={name}", + String.class, + "world1")); + + TestMgr.check("hi world1+world2 [world1+world2]", + template.getForObject(prefix + "/controller/sayhi?name={name}", + String.class, + "world1+world2")); + + TestMgr.check("hi hi 中国 [hi 中国]", + template.getForObject(prefix + "/controller/sayhi?name={name}", + String.class, + "hi 中国")); + + Map params = new HashMap<>(); + params.put("name", "world2"); + TestMgr.check("hi world2 [world2]", + template.getForObject(prefix + "/controller/sayhi?name={name}", + String.class, + params)); + + try { + template.postForObject(prefix + "/controller/sayhello/{name}", + null, + String.class, + "exception"); + TestMgr.check(true, false); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 503); + } + } + + private static void testControllerAllTransport(RestTemplate template, String microserviceName) { + String prefix = "cse://" + microserviceName; + + TestMgr.check(7, + template.getForObject(prefix + "/controller/add?a=3&b=4", + Integer.class)); + + try { + template.getForObject(prefix + "/controller/add", + Integer.class); + TestMgr.check("failed", "success"); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 400); + } + + TestMgr.check("hello world", + template.postForObject(prefix + "/controller/sayhello/{name}", + null, + String.class, + "world")); + TestMgr.check("hello hello 中国", + template.postForObject(prefix + "/controller/sayhello/{name}", + null, + String.class, + "hello 中国")); + + try { + template.postForObject(prefix + "/controller/sayhello/{name}", + null, + String.class, + "exception"); + TestMgr.check(true, false); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), 503); + } + + HttpHeaders headers = new HttpHeaders(); + headers.add("name", "world"); + @SuppressWarnings("rawtypes") + HttpEntity entity = new HttpEntity<>(null, headers); + ResponseEntity response = template.exchange(prefix + "/controller/sayhei", + HttpMethod.GET, + entity, + String.class); + TestMgr.check("hei world", response.getBody()); + + Person user = new Person(); + user.setName("world"); + TestMgr.check("ha world", + template.postForObject(prefix + "/controller/saysomething?prefix={prefix}", + user, + String.class, + "ha")); + } + + private static void testSpringMvcDefaultValuesRest(RestTemplate template, String microserviceName) { + String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; + String result = template.getForObject(cseUrlPrefix + "/query?d=10", String.class); + TestMgr.check("Hello 20bobo4010", result); + boolean failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); + TestMgr.check("Hello 20bobo40302", result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + } + + private static void testSpringMvcDefaultValuesAllTransport(RestTemplate template, String microserviceName) { + String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; + //default values + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap map = new LinkedMultiValueMap<>(); + HttpEntity> request = new HttpEntity<>(map, headers); + String result = template.postForObject(cseUrlPrefix + "/form", request, String.class); + TestMgr.check("Hello 20bobo", result); + + headers = new HttpHeaders(); + HttpEntity entity = new HttpEntity<>(null, headers); + result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); + TestMgr.check("Hello 20bobo30", result); + + result = template.getForObject(cseUrlPrefix + "/query?d=10", String.class); + TestMgr.check("Hello 20bobo4010", result); + boolean failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); + TestMgr.check("Hello 20bobo40302", result); + + failed = false; + result = null; + try { + result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); + } catch (InvocationException e) { + failed = true; + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + TestMgr.check(true, failed); + TestMgr.check(null, result); + + result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", String.class); + TestMgr.check("Hello 302", result); + + result = template.getForObject(cseUrlPrefix + "/query3?a=30", String.class); + TestMgr.check("Hello 30null", result); + + //input values + headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + HttpEntity> requestPara = new HttpEntity<>(null, headers); + result = template.postForObject(cseUrlPrefix + "/form?a=30&b=sam", requestPara, String.class); + TestMgr.check("Hello 30sam", result); + + headers = new HttpHeaders(); + headers.add("a", "30"); + headers.add("b", "sam"); + headers.add("c", "40"); + entity = new HttpEntity<>(null, headers); + result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); + TestMgr.check("Hello 30sam40", result); + + result = template.getForObject(cseUrlPrefix + "/query?a=3&b=sam&c=5&d=30", String.class); + TestMgr.check("Hello 3sam530", result); + + result = template.getForObject(cseUrlPrefix + "/query2?a=3&b=4&c=5&d=30&e=2", String.class); + TestMgr.check("Hello 345302", result); + } + + private static void testSpringMvcDefaultValuesJavaPrimitiveAllTransport(RestTemplate template, + String microserviceName) { + String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; + //default values with primitive + String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", null, String.class); + TestMgr.check("Hello 0bobo", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", null, String.class); + TestMgr.check("Hello 0.0false", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", null, String.class); + TestMgr.check("Hello", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", null, String.class); + TestMgr.check("Hello nullnull", result); + + result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); + TestMgr.check("Hello false,\0,0,0,0,0,0.0,0.0,null", result); + + result = template.postForObject(cseUrlPrefix + + "/allprimitivetypes?pBoolean=true&pChar=c&pByte=20&pShort=30&pInt=40&pLong=50&pFloat=60&pDouble=70&pDoubleWrap=80", + null, String.class); + TestMgr.check("Hello true,c,20,30,40,50,60.0,70.0,80.0", result); + } + + private static void testSpringMvcDefaultValuesJavaPrimitiveRest(RestTemplate template, String microserviceName) { + String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; + //default values with primitive + String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", null, String.class); + TestMgr.check("Hello 0bobo", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", null, String.class); + TestMgr.check("Hello 0.0false", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", null, String.class); + TestMgr.check("Hello", result); + + result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", null, String.class); + TestMgr.check("Hello nullnull", result); + + result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); + TestMgr.check("Hello false,\0,0,0,0,0,0.0,0.0,null", result); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java index 1c92669e7f2..d30edc6b495 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java @@ -26,18 +26,16 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.Part; - import org.apache.commons.io.FileUtils; -import org.apache.servicecomb.bizkeeper.BizkeeperExceptionUtils; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.demo.CodeFirstRestTemplate; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.foundation.common.part.FilePart; import org.apache.servicecomb.provider.pojo.Invoker; import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; -import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.PathResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -47,16 +45,18 @@ import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; + +import jakarta.servlet.http.Part; @Component public class CodeFirstRestTemplateSpringmvc extends CodeFirstRestTemplate { interface UploadPartAndFile { - String fileUpload(Part file1, File file2); + String fileUpload(Part file1, File someFile); } interface UploadStreamAndResource { - String fileUpload(InputStream file1, Resource file2); + String fileUpload(InputStream file1, Resource someFile); } private UploadPartAndFile uploadPartAndFile = Invoker.createProxy("springmvc", "codeFirst", UploadPartAndFile.class); @@ -74,15 +74,21 @@ interface UploadStreamAndResource { private TestContentType testContentType = new TestContentType(); - private TestBizkeeper testBizkeeper = new TestBizkeeper(); + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + testResponse.setEnvironment(environment); + } @Override - protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) { + protected void testOnlyRest(String microservcieName, RestOperations template, String cseUrlPrefix) { try { testUpload(template, cseUrlPrefix); } catch (IOException e) { throw new IllegalStateException(e); } + testResponseEntity("springmvc", template, cseUrlPrefix); + testCodeFirstTestFormRest(template, cseUrlPrefix); testResponse.runRest(); testObject.runRest(); @@ -90,41 +96,38 @@ protected void testOnlyRest(RestTemplate template, String cseUrlPrefix) { testRestTemplate.runRest(); testContentType.runAllTest(); - super.testOnlyRest(template, cseUrlPrefix); + super.testOnlyRest(microservcieName, template, cseUrlPrefix); } @Override - protected void testOnlyHighway(RestTemplate template, String cseUrlPrefix) { + protected void testOnlyHighway(RestOperations template, String cseUrlPrefix) { testResponse.runHighway(); testObject.runHighway(); testGeneric.runHighway(); - + testCodeFirstTestFormHighway(template, cseUrlPrefix); super.testOnlyHighway(template, cseUrlPrefix); } @Override - protected void testAllTransport(String microserviceName, RestTemplate template, String cseUrlPrefix) { + protected void testAllTransport(String microserviceName, RestOperations template, String cseUrlPrefix) { testResponse.runAllTransport(); testObject.runAllTransport(); testGeneric.runAllTransport(); testRestTemplate.runAllTest(); - testBizkeeper.runAllTest(); - testResponseEntity("springmvc", template, cseUrlPrefix); testCodeFirstTestForm(template, cseUrlPrefix); - testFallback(template, cseUrlPrefix); super.testAllTransport(microserviceName, template, cseUrlPrefix); } - private void testUpload(RestTemplate template, String cseUrlPrefix) throws IOException { + private void testUpload(RestOperations template, String cseUrlPrefix) throws IOException { String file1Content = "hello world"; File file1 = File.createTempFile("测 试", ".txt"); - FileUtils.writeStringToFile(file1, file1Content); + FileUtils.writeStringToFile(file1, file1Content, StandardCharsets.UTF_8, false); String file2Content = " bonjour"; File someFile = File.createTempFile("upload2", ".txt"); - FileUtils.writeStringToFile(someFile, file2Content); + FileUtils.writeStringToFile(someFile, file2Content, StandardCharsets.UTF_8, false); String expect = String.format("%s:%s:%s\n" + "%s:%s:%s", @@ -138,15 +141,16 @@ private void testUpload(RestTemplate template, String cseUrlPrefix) throws IOExc String result = testRestTemplateUpload(template, cseUrlPrefix, file1, someFile); TestMgr.check(expect, result); + result = uploadPartAndFile.fileUpload(new FilePart(null, file1), someFile); + TestMgr.check(expect, result); + + expect = "hello world"; MultiValueMap map = new LinkedMultiValueMap<>(); map.add("file1", new FileSystemResource(file1)); - result = template.postForObject( cseUrlPrefix + "/upload1", new HttpEntity<>(map), String.class); - - result = uploadPartAndFile.fileUpload(new FilePart(null, file1), someFile); TestMgr.check(expect, result); expect = String.format("null:%s:%s\n" @@ -158,11 +162,11 @@ private void testUpload(RestTemplate template, String cseUrlPrefix) throws IOExc file2Content); result = uploadStreamAndResource .fileUpload(new ByteArrayInputStream(file1Content.getBytes(StandardCharsets.UTF_8)), - new PathResource(someFile.getAbsolutePath())); + new org.springframework.core.io.PathResource(someFile.getAbsolutePath())); TestMgr.check(expect, result); } - private String testRestTemplateUpload(RestTemplate template, String cseUrlPrefix, File file1, File someFile) { + private String testRestTemplateUpload(RestOperations template, String cseUrlPrefix, File file1, File someFile) { MultiValueMap map = new LinkedMultiValueMap<>(); map.add("file1", new FileSystemResource(file1)); map.add("someFile", new FileSystemResource(someFile)); @@ -173,41 +177,7 @@ private String testRestTemplateUpload(RestTemplate template, String cseUrlPrefix String.class); } - private void testFallback(RestTemplate template, String cseUrlPrefix) { - long start = System.currentTimeMillis(); - String result = template.getForObject(cseUrlPrefix + "/fallback/returnnull/hello", String.class); - TestMgr.check(result, "hello"); - result = template.getForObject(cseUrlPrefix + "/fallback/returnnull/throwexception", String.class); - TestMgr.check(result, null); - - result = template.getForObject(cseUrlPrefix + "/fallback/throwexception/hello", String.class); - TestMgr.check(result, "hello"); - try { - result = template.getForObject(cseUrlPrefix + "/fallback/throwexception/throwexception", String.class); - TestMgr.check(false, true); - } catch (Exception e) { - TestMgr.check(e.getCause().getMessage(), - BizkeeperExceptionUtils.createBizkeeperException(BizkeeperExceptionUtils.SERVICECOMB_BIZKEEPER_FALLBACK, - null, - "springmvc.codeFirst.fallbackThrowException").getMessage()); - } - - result = template.getForObject(cseUrlPrefix + "/fallback/fromcache/hello", String.class); - TestMgr.check(result, "hello"); - result = template.getForObject(cseUrlPrefix + "/fallback/fromcache/hello", String.class); - TestMgr.check(result, "hello"); - result = template.getForObject(cseUrlPrefix + "/fallback/fromcache/throwexception", String.class); - TestMgr.check(result, "hello"); - - result = template.getForObject(cseUrlPrefix + "/fallback/force/hello", String.class); - TestMgr.check(result, "mockedreslut"); - - // This test case is fallback testing and will return null if failed. - // In order to check if failed due to some unexpected timeout exception, check the time. - TestMgr.check(System.currentTimeMillis() - start < 10000, true); - } - - private void testResponseEntity(String microserviceName, RestTemplate template, String cseUrlPrefix) { + private void testResponseEntity(String microserviceName, RestOperations template, String cseUrlPrefix) { Map body = new HashMap<>(); Date date = new Date(); body.put("date", date); @@ -215,7 +185,7 @@ private void testResponseEntity(String microserviceName, RestTemplate template, CseHttpEntity> httpEntity = new CseHttpEntity<>(body); httpEntity.addContext("contextKey", "contextValue"); - String srcName = RegistryUtils.getMicroservice().getServiceName(); + String srcName = BootStrapProperties.readServiceName(environment); ResponseEntity responseEntity = template.exchange(cseUrlPrefix + "responseEntity", HttpMethod.POST, httpEntity, Date.class); @@ -233,18 +203,52 @@ private void testResponseEntity(String microserviceName, RestTemplate template, int retryResult = template.getForObject(cseUrlPrefix + "retrySuccess?a=2&b=3", Integer.class); TestMgr.check(retryResult, 5); + retryResult = template.getForObject(cseUrlPrefix + "retrySuccess?a=2&b=3", Integer.class); + TestMgr.check(retryResult, 5); } - protected void testCodeFirstTestForm(RestTemplate template, String cseUrlPrefix) { + private void testCodeFirstTestForm(RestOperations template, String cseUrlPrefix) { HttpHeaders formHeaders = new HttpHeaders(); formHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); Map map = new HashMap<>(); String code = "servicecomb%2bwelcome%40%23%24%25%5e%26*()%3d%3d"; map.put("form1", code); - HttpEntity> formEntiry = new HttpEntity<>(map, formHeaders); + HttpEntity> formEntry = new HttpEntity<>(map, formHeaders); TestMgr.check(code + "null", - template.postForEntity(cseUrlPrefix + "/testform", formEntiry, String.class).getBody()); + template.postForEntity(cseUrlPrefix + "/testform", formEntry, String.class).getBody()); + map.put("form2", "hello"); + TestMgr + .check(code + "hello", template.postForEntity(cseUrlPrefix + "/testform", formEntry, String.class).getBody()); + } + + private void testCodeFirstTestFormHighway(RestOperations template, String cseUrlPrefix) { + HttpHeaders formHeaders = new HttpHeaders(); + formHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + Map map = new HashMap<>(); + String code = "servicecomb%2bwelcome%40%23%24%25%5e%26*()%3d%3d"; + map.put("form1", code); + map.put("form2", ""); + HttpEntity> formEntry = new HttpEntity<>(map, formHeaders); + TestMgr.check(code + "", template.postForEntity(cseUrlPrefix + "/testform", formEntry, String.class).getBody()); + + map = new HashMap<>(); + code = "servicecomb%2bwelcome%40%23%24%25%5e%26*()%3d%3d"; + map.put("form1", code); + map.put("form2", null); + formEntry = new HttpEntity<>(map, formHeaders); + TestMgr.check(code + "null", + template.postForEntity(cseUrlPrefix + "/testform", formEntry, String.class).getBody()); + } + + private void testCodeFirstTestFormRest(RestOperations template, String cseUrlPrefix) { + HttpHeaders formHeaders = new HttpHeaders(); + formHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + Map map = new HashMap<>(); + String code = "servicecomb%2bwelcome%40%23%24%25%5e%26*()%3d%3d"; + map.put("form1", code); map.put("form2", ""); - TestMgr.check(code + "", template.postForEntity(cseUrlPrefix + "/testform", formEntiry, String.class).getBody()); + HttpEntity> formEntry = new HttpEntity<>(map, formHeaders); + // Rest will have empty string, but users will try to avoid depend on this, This is different from highway + TestMgr.check(code + "", template.postForEntity(cseUrlPrefix + "/testform", formEntry, String.class).getBody()); } } diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java index 509e15c7ae5..f7401c30017 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java @@ -20,14 +20,13 @@ import java.util.List; import java.util.Map; -import javax.xml.ws.Holder; - import org.apache.servicecomb.demo.EmptyObject; import org.apache.servicecomb.demo.Generic; import org.apache.servicecomb.demo.compute.GenericParam; import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.demo.springmvc.decoderesponse.DecodeTestResponse; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.swagger.invocation.Response; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -37,6 +36,8 @@ public interface CodeFirstSpringmvcIntf { Response cseResponse(); + Response cseResponseCorrect(); + Object testObject(Object input); EmptyObject testEmpty(EmptyObject input); diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ConsumerTestsAfterBootup.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ConsumerTestsAfterBootup.java deleted file mode 100644 index d89f20da1c9..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ConsumerTestsAfterBootup.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.apache.servicecomb.demo.springmvc.client; -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.springframework.stereotype.Component; - -/** - * Testing after bootup. - */ -@Component -public class ConsumerTestsAfterBootup implements BootListener { - public void testRegisterPath() { - TestMgr.check(RegistryUtils.getMicroservice().getPaths().size(), 0); - } - - @Override - public void onBootEvent(BootEvent event) { - if (event.getEventType() == BootListener.EventType.AFTER_REGISTRY) { - testRegisterPath(); - if (!TestMgr.isSuccess()) { - TestMgr.summary(); - throw new IllegalStateException("some tests are failed. "); - } - } - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CustomEndpointDiscoveryFilter.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CustomEndpointDiscoveryFilter.java new file mode 100644 index 00000000000..6bf78279d42 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CustomEndpointDiscoveryFilter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.registry.discovery.AbstractEndpointDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; + +public class CustomEndpointDiscoveryFilter extends AbstractEndpointDiscoveryFilter { + @Override + protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { + //only need rest endpoints + return "rest"; + } + + @Override + protected Object createEndpoint(DiscoveryContext context, String transportName, String endpoint, + StatefulDiscoveryInstance instance) { + return endpoint; + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ICompatible1xTestSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ICompatible1xTestSchema.java new file mode 100644 index 00000000000..ac8c10ecbda --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ICompatible1xTestSchema.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; + +import io.swagger.v3.oas.annotations.Operation; + +public interface ICompatible1xTestSchema { + String parameterName(int c, int d); + + @Operation(operationId = "parameterName", summary = "parameterName") + String parameterNamePartMatchLeft(int a, int d); + + @Operation(operationId = "parameterName", summary = "parameterName") + String parameterNamePartMatchRight(int c, int b); + + String parameterName(InvocationContext context, int c, int d); + + String parameterNameServerContext(int c, int d); + + String beanParameter(String notName, int notAge); +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MicroserviceArray.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MicroserviceArray.java deleted file mode 100644 index 15842e4f4e9..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MicroserviceArray.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.springmvc.client; - -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -public class MicroserviceArray { - - private List services; - - public List getServices() { - return services; - } - - public void setServices(List services) { - this.services = services; - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MockedFallbackExample.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MockedFallbackExample.java deleted file mode 100644 index 019f4023e4d..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/MockedFallbackExample.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.springmvc.client; - -import org.apache.servicecomb.bizkeeper.FallbackPolicy; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.stereotype.Component; - -@Component -public class MockedFallbackExample implements FallbackPolicy { - - @Override - public String name() { - return "mycustom"; - } - - @Override - public Response getFallbackResponse(Invocation invocation) { - return Response.succResp("mockedreslut"); - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ResponseOKData.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ResponseOKData.java new file mode 100644 index 00000000000..df2bf9c5f42 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ResponseOKData.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +public class ResponseOKData { + private String errorCode; + + private String errorMessage; + + public ResponseOKData() { + + } + + public ResponseOKData(String errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SchemeInterfaceSpringmvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SchemeInterfaceSpringmvc.java new file mode 100644 index 00000000000..9bce39f0af7 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SchemeInterfaceSpringmvc.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +public interface SchemeInterfaceSpringmvc { + int add(int a, int b); + + int reduce(int a, int b); + + String tailingSlash(int a, int b); + + String nonTailingSlash(int a, int b); +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ServiceCenterExample.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ServiceCenterExample.java deleted file mode 100644 index 84d39473a36..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ServiceCenterExample.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.client; - -import java.net.URI; - -import org.springframework.http.HttpMethod; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -public class ServiceCenterExample { - - public static void main(String[] args) throws Exception { - RestTemplate template = new RestTemplate(); - template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); - MultiValueMap headers = new LinkedMultiValueMap<>(); - headers.add("X-Tenant-Name", "default"); - - RequestEntity requestEntity = new RequestEntity(headers, HttpMethod.GET, - new URI("http://127.0.0.1:9980/registry/v3/microservices")); - ResponseEntity stringResponseEntity = template.exchange(requestEntity, String.class); - System.out.println(stringResponseEntity.getBody()); - ResponseEntity microseriveResponseEntity = template - .exchange(requestEntity, MicroserviceArray.class); - MicroserviceArray microserives = microseriveResponseEntity.getBody(); - System.out.println(microserives.getServices().get(1).getServiceId()); - - // instance - headers.add("X-ConsumerId", microserives.getServices().get(1).getServiceId()); - requestEntity = new RequestEntity(headers, HttpMethod.GET, - new URI("http://127.0.0.1:9980/registry/v3/microservices/" + microserives.getServices().get(1).getServiceId() - + "/instances")); - ResponseEntity microserviceInstanceResponseEntity = template.exchange(requestEntity, String.class); - System.out.println(microserviceInstanceResponseEntity.getBody()); - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringMVCSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringMVCSchema.java new file mode 100644 index 00000000000..42c912188af --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringMVCSchema.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.servlet.http.HttpServletRequest; + +@RestSchema(schemaId = "SpringMVCSchema") +@RequestMapping("/springMvcSchema") +public class SpringMVCSchema { + // TODO: examples not serialized by yaml parser + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content( + schema = @Schema(implementation = String.class, example = "wget http://localhost/springMvcSchema/testApiExample"), + examples = {@ExampleObject(value = "wget http://localhost/springMvcSchema/testApiExample", name = "text"), + @ExampleObject(value = "{name:hello}", name = "application/json"), + @ExampleObject(value = "{name:hello}", name = "json")}) + , description = "success" + )}) + @RequestMapping(path = "/testApiExample", method = RequestMethod.POST) + public String testApiExample(@RequestBody String name, HttpServletRequest request) { + return null; + } + + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class), + examples = {@ExampleObject(value = "wget http://localhost/springMvcSchema/testApiExample", name = "text"), + @ExampleObject(value = "{name:hello}", name = "application/json"), + @ExampleObject(value = "{name:hello}", name = "json")}) + , description = "success" + )}) + @RequestMapping(path = "/testDefaultGetApiExample") + public String testDefaultGetApiExample(@RequestParam String name, HttpServletRequest request) { + return null; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java deleted file mode 100644 index 411aa11b824..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.client; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.http.HttpStatus; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.demo.DemoConst; -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.demo.controller.Controller; -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.provider.springmvc.reference.UrlWithProviderPrefixClientHttpRequestFactory; -import org.apache.servicecomb.provider.springmvc.reference.UrlWithServiceNameClientHttpRequestFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -import com.netflix.config.DynamicPropertyFactory; - -public class SpringmvcClient { - private static RestTemplate templateUrlWithServiceName = new CseRestTemplate(); - - private static RestTemplate templateUrlWithProviderPrefix = new CseRestTemplate(); - - private static RestTemplate restTemplate; - - private static Controller controller; - - public static void main(String[] args) throws Exception { - try { - Log4jUtils.init(); - BeanUtils.init(); - - run(); - - TestMgr.summary(); - } catch (Throwable e) { - TestMgr.check("success", "failed"); - System.err.println("-------------- test failed -------------"); - e.printStackTrace(); - System.err.println("-------------- test failed -------------"); - } - } - - public static void run() { - testConfigurationDuplicate(); - - templateUrlWithServiceName.setRequestFactory(new UrlWithServiceNameClientHttpRequestFactory()); - restTemplate = RestTemplateBuilder.create(); - templateUrlWithProviderPrefix.setRequestFactory(new UrlWithProviderPrefixClientHttpRequestFactory("/pojo/rest")); - controller = BeanUtils.getBean("controller"); - - String prefix = "cse://springmvc"; - - try { - // this test class is intended for retry hanging issue JAV-127 - templateUrlWithServiceName.getForObject(prefix + "/controller/sayhi?name=throwexception", String.class); - TestMgr.check("true", "false"); - } catch (Exception e) { - TestMgr.check("true", "true"); - } - - CodeFirstRestTemplateSpringmvc codeFirstClient = - BeanUtils.getContext().getBean(CodeFirstRestTemplateSpringmvc.class); - codeFirstClient.testCodeFirst(restTemplate, "springmvc", "/codeFirstSpringmvc/"); - codeFirstClient.testCodeFirst(templateUrlWithProviderPrefix, "springmvc", "/pojo/rest/codeFirstSpringmvc/"); - - String microserviceName = "springmvc"; - for (String transport : DemoConst.transports) { - CseContext.getInstance().getConsumerProviderManager().setTransport(microserviceName, transport); - TestMgr.setMsg(microserviceName, transport); - - testController(templateUrlWithServiceName, microserviceName); - - testController(); - testRequiredBody(templateUrlWithServiceName, microserviceName); - testSpringMvcDefaultValues(templateUrlWithServiceName, microserviceName); - testSpringMvcDefaultValuesJavaPrimitive(templateUrlWithServiceName, microserviceName); - } - HttpHeaders headers = new HttpHeaders(); - headers.set("Accept-Encoding", "gzip"); - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity entityCompress = - restTemplate.exchange(prefix - + "/codeFirstSpringmvc/sayhi/compressed/{name}/v2", HttpMethod.GET, entity, String.class, "Test"); - TestMgr.check( - "Test sayhi compressed:This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text,This is a big text!", - entityCompress.getBody()); - // if server response is compressed, the content-length header will be removed , so can't check this. - // the transfer-encoding header will be missing when the server is set to not compressed - if (entityCompress.getHeaders().get("transfer-encoding") != null) { - TestMgr.check("chunked", entityCompress.getHeaders().get("transfer-encoding").get(0)); - } - - //0.5.0 later version metrics integration test - @SuppressWarnings("unchecked") - Map metrics = restTemplate.getForObject(prefix + "/metrics", Map.class); - - // TestMgr.check(true, metrics.get("jvm(name=heapUsed,statistic=gauge)") != 0); - TestMgr.check(true, metrics.size() > 0); - - //prometheus integration test - try { - String content = restTemplate - .getForObject("cse://springmvc/codeFirstSpringmvc/prometheusForTest", String.class); - - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.addDate")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.sayHello")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.fallbackFromCache")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.isTrue")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.add")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.sayHi2")); - TestMgr.check(true, content.contains("servicecomb_invocation{operation=\"springmvc.codeFirst.saySomething")); - - String[] metricLines = content.split("\n"); - if (metricLines.length > 0) { - for (String metricLine : metricLines) { - if (!metricLine.startsWith("#")) { - String[] metricKeyAndValue = metricLine.split(" "); - if (!metricKeyAndValue[0].startsWith("jvm") && !metricKeyAndValue[0].startsWith("os")) { - if (Double.parseDouble(metricKeyAndValue[1]) < 0) { - TestMgr.check("true", "false"); - break; - } - } - } - } - } else { - TestMgr.check("true", "false"); - } - } catch (Exception e) { - TestMgr.check("true", "false"); - } - } - - private static void testController(RestTemplate template, String microserviceName) { - String prefix = "cse://" + microserviceName; - - TestMgr.check(7, - template.getForObject(prefix + "/controller/add?a=3&b=4", - Integer.class)); - - try { - template.getForObject(prefix + "/controller/add", - Integer.class); - TestMgr.check("failed", "success"); - } catch (InvocationException e) { - TestMgr.check(e.getStatusCode(), 400); - } - - TestMgr.check("hi world [world]", - template.getForObject(prefix + "/controller/sayhi?name=world", - String.class)); - - TestMgr.check("hi world1 [world1]", - template.getForObject(prefix + "/controller/sayhi?name={name}", - String.class, - "world1")); - TestMgr.check("hi hi 中国 [hi 中国]", - template.getForObject(prefix + "/controller/sayhi?name={name}", - String.class, - "hi 中国")); - - Map params = new HashMap<>(); - params.put("name", "world2"); - TestMgr.check("hi world2 [world2]", - template.getForObject(prefix + "/controller/sayhi?name={name}", - String.class, - params)); - - TestMgr.check("hello world", - template.postForObject(prefix + "/controller/sayhello/{name}", - null, - String.class, - "world")); - TestMgr.check("hello hello 中国", - template.postForObject(prefix + "/controller/sayhello/{name}", - null, - String.class, - "hello 中国")); - - try { - template.postForObject(prefix + "/controller/sayhello/{name}", - null, - String.class, - "exception"); - TestMgr.check(true, false); - } catch (InvocationException e) { - TestMgr.check(e.getStatusCode(), 503); - } - - HttpHeaders headers = new HttpHeaders(); - headers.add("name", "world"); - @SuppressWarnings("rawtypes") - HttpEntity entity = new HttpEntity<>(null, headers); - ResponseEntity response = template.exchange(prefix + "/controller/sayhei", - HttpMethod.GET, - entity, - String.class); - TestMgr.check("hei world", response.getBody()); - - Person user = new Person(); - user.setName("world"); - TestMgr.check("ha world", - template.postForObject(prefix + "/controller/saysomething?prefix={prefix}", - user, - String.class, - "ha")); - } - - private static void testController() { - TestMgr.check("hi world [world]", controller.sayHi("world")); - Person user = new Person(); - user.setName("world"); - TestMgr.check("ha world", controller.saySomething("ha", user)); - } - - private static void testConfigurationDuplicate() { - // this configuration will give warning messages: - // Key servicecomb.test.duplicate2 with an ambiguous item cse.test.duplicate2 exists, please use the same prefix or will get unexpected merged value. - // Key servicecomb.test.duplicate1 with an ambiguous item cse.test.duplicate1 exists, please use the same prefix or will get unexpected merged value. - // and the expected value is not quite determined. But will not get wrong value like 'older,newer' or 'newer,older' - TestMgr.check(DynamicPropertyFactory.getInstance().getStringProperty("cse.test.duplicate2", "wrong").get(), - "newer"); - TestMgr.check(DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.test.duplicate2", "wrong").get(), - "newer"); - TestMgr.check(DynamicPropertyFactory.getInstance().getStringProperty("cse.test.duplicate1", "wrong").get(), - "older"); - TestMgr.check(DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.test.duplicate1", "wrong").get(), - "newer"); - } - - private static void testRequiredBody(RestTemplate template, String microserviceName) { - String prefix = "cse://" + microserviceName; - Person user = new Person(); - - TestMgr.check("No user data found", - template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", - user, - String.class, - "ha")); - - user.setName("world"); - TestMgr.check("ha world", - template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", - user, - String.class, - "ha")); - - TestMgr.check("No user data found", - template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", - null, - String.class, - "ha")); - - TestMgr.check("No user name found", - template.postForObject(prefix + "/annotations/say", - "", - String.class, - "ha")); - TestMgr.check("test", - template.postForObject(prefix + "/annotations/say", - "test", - String.class, - "ha")); - } - - private static void testSpringMvcDefaultValues(RestTemplate template, String microserviceName) { - String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; - //default values - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - MultiValueMap map = new LinkedMultiValueMap<>(); - HttpEntity> request = new HttpEntity<>(map, headers); - String result = template.postForObject(cseUrlPrefix + "/form", request, String.class); - TestMgr.check("Hello 20bobo", result); - - headers = new HttpHeaders(); - HttpEntity entity = new HttpEntity<>(null, headers); - result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); - TestMgr.check("Hello 20bobo30", result); - - result = template.getForObject(cseUrlPrefix + "/query?d=10", String.class); - TestMgr.check("Hello 20bobo4010", result); - boolean failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2?d=2&e=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query2?a=&d=2&e=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - result = template.getForObject(cseUrlPrefix + "/query2?d=30&e=2", String.class); - TestMgr.check("Hello 20bobo40302", result); - - failed = false; - try { - result = template.getForObject(cseUrlPrefix + "/query3?a=2&b=2", String.class); - } catch (InvocationException e) { - failed = true; - TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); - } - TestMgr.check(failed, true); - - result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", String.class); - TestMgr.check("Hello 302", result); - - result = template.getForObject(cseUrlPrefix + "/query3?a=30", String.class); - TestMgr.check("Hello 30null", result); - - //input values - headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - HttpEntity> requestPara = new HttpEntity<>(null, headers); - result = template.postForObject(cseUrlPrefix + "/form?a=30&b=sam", requestPara, String.class); - TestMgr.check("Hello 30sam", result); - - headers = new HttpHeaders(); - headers.add("a", "30"); - headers.add("b", "sam"); - headers.add("c", "40"); - entity = new HttpEntity<>(null, headers); - result = template.postForObject(cseUrlPrefix + "/header", entity, String.class); - TestMgr.check("Hello 30sam40", result); - - result = template.getForObject(cseUrlPrefix + "/query?a=3&b=sam&c=5&d=30", String.class); - TestMgr.check("Hello 3sam530", result); - - result = template.getForObject(cseUrlPrefix + "/query2?a=3&b=4&c=5&d=30&e=2", String.class); - TestMgr.check("Hello 345302", result); - } - - private static void testSpringMvcDefaultValuesJavaPrimitive(RestTemplate template, String microserviceName) { - String cseUrlPrefix = "cse://" + microserviceName + "/SpringMvcDefaultValues/"; - //default values with primitive - String result = template.postForObject(cseUrlPrefix + "/javaprimitiveint", null, String.class); - TestMgr.check("Hello 0bobo", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivenumber", null, String.class); - TestMgr.check("Hello 0.0false", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivestr", null, String.class); - TestMgr.check("Hello", result); - - result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", null, String.class); - TestMgr.check("Hello nullnull", result); - - result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, String.class); - TestMgr.check("Hello false,0,0,0,0,0,0.0,0.0,null", result); - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestAnnotationsSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestAnnotationsSchema.java new file mode 100644 index 00000000000..89f7862384b --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestAnnotationsSchema.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.http.HttpStatus; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; +import org.apache.servicecomb.provider.springmvc.reference.UrlWithServiceNameClientHttpRequestFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class TestAnnotationsSchema implements CategorizedTestCase { + private static final String microserviceName = "springmvc"; + + private static final RestTemplate templateUrlWithServiceName = new CseRestTemplate(); + + @Override + public void testAllTransport() throws Exception { + templateUrlWithServiceName.setRequestFactory(new UrlWithServiceNameClientHttpRequestFactory()); + testRequiredBody(templateUrlWithServiceName, microserviceName); + testRegExpPath(); + } + + private void testRegExpPath() { + String prefix = "cse://" + microserviceName; + String result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a?name={name}", + String.class, "a"); + TestMgr.check("a", result); + result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a/b?name={name}", + String.class, "ab"); + TestMgr.check("ab", result); + result = templateUrlWithServiceName.getForObject(prefix + "/annotations/testRegExpPath/a/b/c?name={name}", + String.class, "abc"); + TestMgr.check("abc", result); + } + + private static void testRequiredBody(RestTemplate template, String microserviceName) { + String prefix = "cse://" + microserviceName; + Person user = new Person(); + + TestMgr.check("No user data found", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + user, + String.class, + "ha")); + + user.setName("world"); + TestMgr.check("ha world", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + user, + String.class, + "ha")); + + TestMgr.check("No user data found", + template.postForObject(prefix + "/annotations/saysomething?prefix={prefix}", + null, + String.class, + "ha")); + + TestMgr.check("No user name found", + template.postForObject(prefix + "/annotations/say", + "", + String.class, + "ha")); + TestMgr.check("test", + template.postForObject(prefix + "/annotations/say", + "test", + String.class, + "ha")); + + try { + template.postForObject(prefix + "/annotations/testRequiredBody", + null, + String.class); + TestMgr.fail("should fail"); + } catch (InvocationException e) { + TestMgr.check(e.getStatusCode(), HttpStatus.SC_BAD_REQUEST); + } + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBigNumberSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBigNumberSchema.java new file mode 100644 index 00000000000..3b70709e6d2 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBigNumberSchema.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestBigNumberSchema implements CategorizedTestCase { + interface IBigNumberSchema { + BigInteger bigInteger(BigInteger intHeader, BigInteger intQuery, BigInteger intForm); + + BigDecimal bigDecimal(BigDecimal decimalHeader, BigDecimal decimalQuery, BigDecimal decimalForm); + } + + @RpcReference(microserviceName = "springmvc", schemaId = "BigNumberSchema") + private IBigNumberSchema schema; + + @Override + public void testAllTransport() throws Exception { + testBigInteger(); + testBigDecimal(); + } + + public void testBigInteger() { + BigInteger result = schema.bigInteger(BigInteger.valueOf(100L), BigInteger.valueOf(3000000000000000000L), + BigInteger.valueOf(200L)); + TestMgr.check("3000000000000000300", result.toString()); + } + + public void testBigDecimal() { + BigDecimal a = BigDecimal.valueOf(100.1D); + BigDecimal b = BigDecimal.valueOf(300000000000000000.1D); + BigDecimal c = BigDecimal.valueOf(200.1D); + BigDecimal expected = a.add(b).add(c); + BigDecimal result = schema.bigDecimal(a, b, c); + TestMgr.check(expected, result); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBizkeeper.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBizkeeper.java deleted file mode 100644 index 325f59f2498..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestBizkeeper.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.client; - -import java.util.concurrent.TimeoutException; - -import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.web.client.RestTemplate; - -public class TestBizkeeper { - private RestTemplate restTemplate = RestTemplateBuilder.create(); - - private String prefix = "cse://springmvc/codeFirstBizkeeperTest"; - - public void runAllTest() { - testTimeout(); - } - - private void testTimeout() { - //config timeout starts with cse.xxx, from yaml - try { - restTemplate.getForObject(prefix + "/testTimeout?name={1}&delaytime={2}", String.class, "joker", 1000); - TestMgr.check("expect: throw timeout exception", "real: not throw timeout exception"); - } catch (Exception e) { - TestMgr.check(TimeoutException.class, e.getCause().getCause().getClass()); - } - //modify config timeout starts with servicecomb.xxx, can change the timeout effect - ArchaiusUtils.setProperty( - "servicecomb.isolation.Consumer.springmvc.codeFirstBizkeeperTest.testTimeout.timeout.enabled", "false"); - try { - String result = - restTemplate.getForObject(prefix + "/testTimeout?name={1}&delaytime={2}", String.class, "joker", 1000); - TestMgr.check("joker", result); - } catch (Exception e) { - TestMgr.check("expect: not throw timeout exception", "real: throw timeout exception"); - } - - try { - ArchaiusUtils.setProperty( - "servicecomb.fallback.Consumer.springmvc.codeFirstBizkeeperTest.testTimeout.enabled", "false"); - ArchaiusUtils.setProperty( - "servicecomb.isolation.Consumer.springmvc.codeFirstBizkeeperTest.testTimeout.timeout.enabled", "true"); - ArchaiusUtils.setProperty( - "servicecomb.isolation.Consumer.springmvc.codeFirstBizkeeperTest.testTimeout.timeoutInMilliseconds", 500); - restTemplate.getForObject(prefix + "/testTimeout?name={1}&delaytime={2}", String.class, "joker", 500); - TestMgr.check("expect: throw timeout exception", "real: not throw timeout exception"); - } catch (InvocationException e) { - TestMgr.check(TimeoutException.class, e.getCause().getCause().getClass()); - } - } -} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java index 65fc1461dd7..aa0d9d0f63d 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java @@ -17,24 +17,27 @@ package org.apache.servicecomb.demo.springmvc.client; -import javax.ws.rs.core.MediaType; - import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.MediaType; public class TestContentType { - private RestTemplate restTemplate = RestTemplateBuilder.create(); + private RestOperations restTemplate = RestTemplateBuilder.create(); public void runAllTest() { testGlobalSetting(); testApiOperation(); testRequestMapping(); + testProtoBuffer(); testResponseTypeOverwrite(); } @@ -53,15 +56,15 @@ private void testGlobalSetting() { private void testApiOperation() { HttpHeaders requestHeaders = new HttpHeaders(); - requestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + requestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN); CseHttpEntity requestEntity = new CseHttpEntity<>("from testApiOperation", requestHeaders); ResponseEntity responseEntity = restTemplate .exchange("cse://springmvc/contentTypeSpringmvc/testApiOperation", HttpMethod.POST, requestEntity, String.class); TestMgr.check( - "testApiOperation: name=[from testApiOperation], request content-type=[" + MediaType.APPLICATION_JSON + "]", + "testApiOperation: name=[from testApiOperation], request content-type=[" + MediaType.TEXT_PLAIN + "]", responseEntity.getBody()); - TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType())); + TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType())); } private void testRequestMapping() { @@ -77,6 +80,24 @@ private void testRequestMapping() { TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType())); } + + private void testProtoBuffer() { + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.add(HttpHeaders.CONTENT_TYPE, SwaggerConst.PROTOBUF_TYPE); + User user = new User(); + user.setIndex(100); + user.setName("hello"); + user.setNames(new String[] {"a1", "a2"}); + CseHttpEntity requestEntity = new CseHttpEntity<>(user, requestHeaders); + ResponseEntity responseEntity = restTemplate + .exchange("cse://springmvc/contentTypeSpringmvc/testProtoBuffer", HttpMethod.POST, + requestEntity, String.class); + TestMgr.check( + "testRequestMapping: name=[hello:100:[a1, a2]], request content-type=[application/protobuf]", + responseEntity.getBody()); + TestMgr.check(SwaggerConst.PROTOBUF_TYPE, extractContentType(responseEntity.getHeaders().getContentType())); + } + private void testResponseTypeOverwrite() { ResponseEntity responseEntity = restTemplate .getForEntity("cse://springmvc/contentTypeSpringmvcOverwrite/testResponseTypeOverwrite", String.class); diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestControllerImpl.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestControllerImpl.java new file mode 100644 index 00000000000..3264caa9fa9 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestControllerImpl.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.controller.Controller; +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.demo.controller.PersonAlias; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.http.client.common.HttpUtils; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestControllerImpl implements CategorizedTestCase { + private static final String SERVER = "servicecomb://springmvc"; + + @Autowired + Controller controller; + + RestOperations restTemplate = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testQueryParamSpecial(); + testResponseModel(); + } + + @Override + public void testAllTransport() throws Exception { + testControllerBodyModel(); + testControllerHeaderModel(); + } + + private void testControllerHeaderModel() throws Exception { + // HTTP header只允许 ASCII 字符。 + // 在Header参数中使用特殊字符,需要在发送请求前进行编码,在收到响应后进行解码,具体编码方式可以业务自行选择。 + // 如果不进行编码,则可能会出现乱码(HTTP协议历史上只标准化了ASCII字符,其他字符集可能工作,可能不工作)。 + String encodedResult = controller.sayHei(HttpUtils.encodeURLParam("中文HTTP Header")); + TestMgr.check("hei 中文HTTP Header", HttpUtils.decodeURLParam(encodedResult)); + + // 普通ASCII字符不需要编码 + TestMgr.check("hei ~!@#$%^&*()_+-={}[]|\\:\";''<>?,./AL340", + controller.sayHei("~!@#$%^&*()_+-={}[]|\\:\";''<>?,./AL340")); + } + + private void testControllerBodyModel() { + Person user = new Person(); + user.setName("world"); + TestMgr.check("ha world", controller.saySomething("ha", user)); + } + + private void testResponseModel() { + Person person = restTemplate.getForObject(SERVER + "/springmvc/controller/testResponseModel", Person.class); + TestMgr.check("jack", person.getName()); + + PersonAlias personAlias = restTemplate.getForObject(SERVER + "/springmvc/controller/testResponseModel", + PersonAlias.class); + TestMgr.check("jack", personAlias.getName()); + } + + private void testQueryParamSpecial() { + // vert.x and servlet container have different query parameter implementations + if (LegacyPropertyFactory.getBooleanProperty("servicecomb.test.vert.transport", true)) { + + TestMgr.check(restTemplate.getForObject( + SERVER + "/springmvc/controller/sayHello1?name=you;me", String.class), "Hello you,v"); + } else { + TestMgr.check(restTemplate.getForObject( + SERVER + "/springmvc/controller/sayHello1?name=you;me", String.class), "Hello you;me,v"); + } + TestMgr.check(restTemplate.getForObject( + SERVER + "/springmvc/controller/sayHello1?name={1}", + String.class, "you;me"), "Hello you;me,v"); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDataTypesAnnotationsSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDataTypesAnnotationsSchema.java new file mode 100644 index 00000000000..6234b0a99f6 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDataTypesAnnotationsSchema.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestDataTypesAnnotationsSchema implements CategorizedTestCase { + public interface DataTypesAnnotationsItf { + int[] testIntArrayQuery(int[] param); + + Integer[] testIntegerArrayQuery(Integer[] param); + } + + @RpcReference(schemaId = "DataTypesAnnotationsSchema", microserviceName = "springmvc") + private DataTypesAnnotationsItf client; + + @Override + public void testAllTransport() throws Exception { + testIntArrayQuery(); + testIntegerArrayQuery(); + } + + private void testIntArrayQuery() { + int[] request = new int[] {5, 11, 4}; + int[] result = client.testIntArrayQuery(request); + TestMgr.check(request.length, result.length); + TestMgr.check(request[1], result[1]); + } + + private void testIntegerArrayQuery() { + Integer[] request = new Integer[] {5, 11, 4}; + Integer[] result = client.testIntegerArrayQuery(request); + TestMgr.check(request.length, result.length); + TestMgr.check(request[1], result[1]); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDateTimeSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDateTimeSchema.java new file mode 100644 index 00000000000..580192c71a1 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDateTimeSchema.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.net.URI; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; + +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.loadbalance.LoadBalanceFilter; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +interface DateTimeSchemaInf { + Date getDate(Date date); + + Date getDatePath(Date date); + + Date postDate(Date date); + + LocalDate getLocalDate(LocalDate date); + + LocalDate getLocalDatePath(LocalDate date); + + LocalDate postLocalDate(LocalDate date); + + LocalDateTime getLocalDateTime(LocalDateTime date); + + LocalDateTime getLocalDateTimePath(LocalDateTime date); + + LocalDateTime postLocalDateTime(LocalDateTime date); +} + +interface DateTimeSchemaWithContextInf { + Date getDate(InvocationContext context, Date date); +} + +@Component +public class TestDateTimeSchema implements CategorizedTestCase { + @RpcReference(microserviceName = "springmvc", schemaId = "DateTimeSchema") + private DateTimeSchemaInf dateTimeSchemaInf; + + @RpcReference(microserviceName = "springmvc", schemaId = "DateTimeSchema") + private DateTimeSchemaWithContextInf dateTimeSchemaWithContextInf; + + private DiscoveryTree discoveryTree; + + private SCBEngine scbEngine; + + @Autowired + public void setScbEngine(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryTree = new DiscoveryTree(discoveryManager); + discoveryTree.setDiscoveryFilters(List.of(new CustomEndpointDiscoveryFilter())); + } + + public TestDateTimeSchema() { + + } + + @Override + public void testAllTransport() throws Exception { + testDateTimeSchema(); + testDateTimeSchemaMulticast(); + testDateTimeSchemaMulticastRestTemplate(); + } + + private void testDateTimeSchema() { + Date date = new Date(); + TestMgr.check(date.getTime(), dateTimeSchemaInf.getDate(date).getTime()); + TestMgr.check(date.getTime(), dateTimeSchemaInf.getDatePath(date).getTime()); + TestMgr.check(date.getTime(), dateTimeSchemaInf.postDate(date).getTime()); + + LocalDate localDate = LocalDate.of(2020, 2, 1); + TestMgr.check(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), + dateTimeSchemaInf.getLocalDate(localDate).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + TestMgr.check(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), + dateTimeSchemaInf.getLocalDatePath(localDate).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + TestMgr.check(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), + dateTimeSchemaInf.postLocalDate(localDate).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + + LocalDateTime localDateTime = LocalDateTime.of(2020, 2, 1, 23, 23, 30, 333); + TestMgr.check(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")), + dateTimeSchemaInf.getLocalDateTime(localDateTime) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))); + TestMgr.check(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")), + dateTimeSchemaInf.getLocalDateTimePath(localDateTime) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))); + TestMgr.check(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")), + dateTimeSchemaInf.postLocalDateTime(localDateTime) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))); + } + + private void testDateTimeSchemaMulticast() throws Exception { + DiscoveryContext context = new DiscoveryContext(); + VersionedCache serversVersionedCache = discoveryTree.discovery(context, "springmvctest", "springmvc"); + List endpoints = serversVersionedCache.data(); + + for (String endpoint : endpoints) { + InvocationContext invocationContext = new InvocationContext(); + invocationContext.addLocalContext(LoadBalanceFilter.SERVICECOMB_SERVER_ENDPOINT, endpoint); + Date date = new Date(); + TestMgr.check(date.getTime(), dateTimeSchemaWithContextInf.getDate(invocationContext, date).getTime()); + + invocationContext = new InvocationContext(); + invocationContext.addLocalContext(LoadBalanceFilter.SERVICECOMB_SERVER_ENDPOINT, parseEndpoint(endpoint)); + date = new Date(); + TestMgr.check(date.getTime(), dateTimeSchemaWithContextInf.getDate(invocationContext, date).getTime()); + } + } + + private Endpoint parseEndpoint(String endpointUri) throws Exception { + URI formatUri = new URI(endpointUri); + Transport transport = scbEngine.getTransportManager().findTransport(formatUri.getScheme()); + return new Endpoint(transport, endpointUri); + } + + private void testDateTimeSchemaMulticastRestTemplate() throws Exception { + DiscoveryContext context = new DiscoveryContext(); + VersionedCache serversVersionedCache = discoveryTree.discovery(context, "springmvctest", "springmvc"); + List endpoints = serversVersionedCache.data(); + + RestOperations restTemplate = RestTemplateBuilder.create(); + + for (String endpoint : endpoints) { + CseHttpEntity entity = new CseHttpEntity<>(null); + InvocationContext invocationContext = new InvocationContext(); + invocationContext.addLocalContext(LoadBalanceFilter.SERVICECOMB_SERVER_ENDPOINT, endpoint); + entity.setContext(invocationContext); + + Date date = new Date(); + String dateValue = RestObjectMapperFactory.getRestObjectMapper().convertToString(date); + TestMgr.check(date.getTime(), + restTemplate + .exchange("cse://springmvc/dateTime/getDate?date={1}", HttpMethod.GET, + entity, Date.class, dateValue).getBody().getTime()); + + entity = new CseHttpEntity<>(null); + invocationContext = new InvocationContext(); + invocationContext.addLocalContext(LoadBalanceFilter.SERVICECOMB_SERVER_ENDPOINT, parseEndpoint(endpoint)); + entity.setContext(invocationContext); + + date = new Date(); + dateValue = RestObjectMapperFactory.getRestObjectMapper().convertToString(date); + TestMgr.check(date.getTime(), + restTemplate + .exchange("cse://springmvc/dateTime/getDate?date={1}", HttpMethod.GET, + entity, Date.class, dateValue).getBody().getTime()); + } + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDownloadSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDownloadSchema.java new file mode 100644 index 00000000000..f1ba4b87095 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestDownloadSchema.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class TestDownloadSchema implements CategorizedTestCase { + @Autowired + DiscoveryManager discoveryManager; + + @Override + public void testRestTransport() throws Exception { + testDownloadFileAndDeleted(); + testDownloadFileAndDeletedCN(); + testDownloadFileNotDeleted(); + testDownloadFileWithNull(); + testSetContentTypeByResponseEntity(); + testResponseOKException(); + } + + private void testResponseOKException() { + List instances = + discoveryManager.findServiceInstances("springmvctest", "springmvc"); + String endpoint = instances.get(0).getEndpoints().stream() + .filter(item -> item.startsWith("rest")).findFirst().get(); + URI endpointItem = URI.create(endpoint); + RestTemplate template = new RestTemplate(); + + // This is for compatible usage. For best practise, any status code + // should have only one type of response. + ResponseEntity resultFail = template.getForEntity( + "http://" + endpointItem.getHost() + ":" + endpointItem.getPort() + + "/api/download/testResponseOKExceptionBean?exception=true", ResponseOKData.class); + TestMgr.check(200, resultFail.getStatusCode().value()); + TestMgr.check("code-005", resultFail.getBody().getErrorCode()); + TestMgr.check("error-005", resultFail.getBody().getErrorMessage()); + ResponseEntity resultOK = template.getForEntity( + "http://" + endpointItem.getHost() + ":" + endpointItem.getPort() + + "/api/download/testResponseOKExceptionBean?exception=false", boolean.class); + TestMgr.check(true, resultOK.getBody()); + + resultFail = template.getForEntity( + "http://" + endpointItem.getHost() + ":" + endpointItem.getPort() + + "/api/download/testResponseOKExceptionDownload?exception=true&content=ddd&contentType=plain/text", + ResponseOKData.class); + TestMgr.check(200, resultFail.getStatusCode().value()); + TestMgr.check("code-005", resultFail.getBody().getErrorCode()); + TestMgr.check("error-005", resultFail.getBody().getErrorMessage()); + + ResponseEntity resultPartOK = template.getForEntity( + "http://" + endpointItem.getHost() + ":" + endpointItem.getPort() + + "/api/download/testResponseOKExceptionDownload?exception=false&content=ddd&contentType=plain/text", + String.class); + TestMgr.check(200, resultPartOK.getStatusCode().value()); + TestMgr.check("ddd", resultPartOK.getBody()); + } + + private void testDownloadFileAndDeleted() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + ReadStreamPart readStreamPart = restTemplate + .getForObject("servicecomb://springmvc/download/deleteAfterFinished?content=hello", ReadStreamPart.class); + String hello = readStreamPart.saveAsString().get(); + TestMgr.check(hello, "hello"); + + boolean exists = restTemplate + .getForObject("servicecomb://springmvc/download/assertLastFileDeleted", boolean.class); + TestMgr.check(exists, false); + } + + private void testDownloadFileAndDeletedCN() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + ReadStreamPart readStreamPart = restTemplate + .getForObject("servicecomb://springmvc/download/deleteAfterFinished?content={1}&fileName={2}", + ReadStreamPart.class, "hello", "中文"); + String hello = readStreamPart.saveAsString().get(); + TestMgr.check(hello, "hello"); + + boolean exists = restTemplate + .getForObject("servicecomb://springmvc/download/assertLastFileDeleted", boolean.class); + TestMgr.check(exists, false); + } + + private void testDownloadFileWithNull() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + ReadStreamPart readStreamPart = restTemplate + .getForObject("servicecomb://springmvc/download/partIsNull?content=test", ReadStreamPart.class); + String result = readStreamPart.saveAsString().get(); + TestMgr.check(result, "test"); + + readStreamPart = restTemplate + .getForObject("servicecomb://springmvc/download/partIsNull?content=", ReadStreamPart.class); + result = readStreamPart.saveAsString().get(); + TestMgr.check(result, ""); + } + + private void testDownloadFileNotDeleted() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + ReadStreamPart readStreamPart = restTemplate + .getForObject("servicecomb://springmvc/download/notDeleteAfterFinished?content=hello", ReadStreamPart.class); + String hello = readStreamPart.saveAsString().get(); + TestMgr.check(hello, "hello"); + + boolean exists = restTemplate + .getForObject("servicecomb://springmvc/download/assertLastFileDeleted", boolean.class); + TestMgr.check(exists, true); + } + + private void testSetContentTypeByResponseEntity() throws Exception { + RestOperations restTemplate = RestTemplateBuilder.create(); + ResponseEntity responseEntity = restTemplate + .getForEntity( + "servicecomb://springmvc/download/setContentTypeByResponseEntity?content=hello&contentType=customType", + ReadStreamPart.class); + String hello = responseEntity.getBody().saveAsString().get(); + TestMgr.check(responseEntity.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections.singletonList("customType")); + TestMgr.check(hello, "hello"); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java new file mode 100644 index 00000000000..78295f47a8a --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestFactoryBean.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.springmvc.client.factory.ServiceBean; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class TestFactoryBean implements CategorizedTestCase, ApplicationContextAware { + ApplicationContext applicationContext; + + @Override + public void testRestTransport() throws Exception { + ServiceBean serviceBean = (ServiceBean) this.applicationContext.getBean("ServiceFactoryBean"); + TestMgr.check("a-3", serviceBean.getName()); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestGeneric.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestGeneric.java index 82103e8d917..ce976f10d5b 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestGeneric.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestGeneric.java @@ -18,20 +18,19 @@ import java.util.Date; -import javax.xml.ws.Holder; - import org.apache.servicecomb.demo.Generic; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.server.User; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; import org.springframework.http.HttpStatus; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; public class TestGeneric { private CodeFirstSpringmvcIntf intf; - private RestTemplate restTemplate = new CseRestTemplate(); + private RestOperations restTemplate = RestTemplateBuilder.create(); private String prefix = "cse://springmvc/codeFirstSpringmvc"; diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestInvokeWhenServerNotReady.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestInvokeWhenServerNotReady.java new file mode 100644 index 00000000000..899de3dcdca --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestInvokeWhenServerNotReady.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CommonSchemaInterface; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestInvokeWhenServerNotReady { + @RpcReference(schemaId = "SpringMVCCommonSchemaInterface", microserviceName = "springmvc") + private CommonSchemaInterface client; + + // only invoke RPC before system is up, these setup is for testing calls before system ready + public TestInvokeWhenServerNotReady() { + startRestTemplateCall(); + startRpcCall(); + startInvokerUtilsCall(); + } + + private void startRestTemplateCall() { + new Thread(() -> { + for (int i = 0; i < 100; i++) { + try { + RestOperations template = RestTemplateBuilder.create(); + template.getForObject("servicecomb://springmvc/upload/isServerStartUpSuccess", Boolean.class); + } catch (Throwable e) { + // ignore + } + } + }).start(); + } + + private void startRpcCall() { + new Thread(() -> { + for (int i = 0; i < 100; i++) { + try { + InvocationContext context = new InvocationContext(); + client.testInvocationTimeout(context, 1001, "customized"); + } catch (Throwable e) { + // ignore + } + } + }).start(); + } + + private void startInvokerUtilsCall() { + new Thread(() -> { + for (int i = 0; i < 100; i++) { + try { + Map args = new HashMap<>(); + args.put("timeout", 1); + args.put("name", "customized"); + InvokerUtils + .syncInvoke("springmvc", "SpringMVCCommonSchemaInterface", "testInvocationTimeout", args, String.class); + } catch (Throwable e) { + // ignore + } + } + }).start(); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestManagementEndpoint.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestManagementEndpoint.java new file mode 100644 index 00000000000..edac80715a8 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestManagementEndpoint.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.Map; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.solution.basic.integration.ManagementEndpoint; +import org.springframework.stereotype.Component; + +@Component +public class TestManagementEndpoint implements CategorizedTestCase { + private static final String CONTENT_SCHEMA = """ + openapi: 3.0.1 + info: + title: swagger definition for org.apache.servicecomb.demo.springmvc.server.SchemeInterfaceSpringmvc + version: 1.0.0 + servers: + - url: /springmvc/schemaInterface + paths: + /add: + get: + operationId: add + parameters: + - name: a + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + - name: b + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + /nonTailingSlash: + get: + operationId: nonTailingSlash + parameters: + - name: a + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + - name: b + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /tailingSlash/: + get: + operationId: tailingSlash + parameters: + - name: a + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + - name: b + in: query + required: true + schema: + minimum: 1 + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + components: {} + """; + + @RpcReference(microserviceName = "springmvc", schemaId = "SchemeInterfaceSpringmvc") + private SchemeInterfaceSpringmvc schemeInterfaceSpringmvc; + + @RpcReference(microserviceName = "springmvc", schemaId = ManagementEndpoint.NAME) + private ManagementEndpoint managementEndpoint; + + @Override + public void testAllTransport() throws Exception { + testSchemeInterfaceSpringmvcContentCorrect(); + } + + @Override + public void testRestTransport() throws Exception { + testSchemeInterfaceSpringmvcPathSlashCorrect(); + testSchemeInterfaceSpringmvcPathNonSlashCorrect(); + } + + private void testSchemeInterfaceSpringmvcPathSlashCorrect() { + String result = schemeInterfaceSpringmvc.tailingSlash(3, 5); + TestMgr.check("/api/springmvc/schemaInterface/tailingSlash/;" + + "/api/springmvc/schemaInterface/tailingSlash/;" + + "/api/springmvc/schemaInterface/tailingSlash/;" + + "-2", result); + } + + private void testSchemeInterfaceSpringmvcPathNonSlashCorrect() { + String result = schemeInterfaceSpringmvc.nonTailingSlash(3, 5); + TestMgr.check("/api/springmvc/schemaInterface/nonTailingSlash;" + + "/api/springmvc/schemaInterface/nonTailingSlash;" + + "/api/springmvc/schemaInterface/nonTailingSlash;" + + "-2", result); + } + + private void testSchemeInterfaceSpringmvcContentCorrect() { + Map contents = managementEndpoint.schemaContents(); + TestMgr.check(CONTENT_SCHEMA, contents.get("SchemeInterfaceSpringmvc")); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestMaxHttpUrlLength.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestMaxHttpUrlLength.java new file mode 100644 index 00000000000..08f9cdda1ee --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestMaxHttpUrlLength.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import static jakarta.ws.rs.core.Response.Status.REQUEST_URI_TOO_LONG; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +import com.google.common.base.Strings; + +@Component +public class TestMaxHttpUrlLength implements CategorizedTestCase { + @Override + public void testRestTransport() throws Exception { + if (LegacyPropertyFactory.getBooleanProperty("servicecomb.test.vert.transport", true)) { + testUrlNotLongerThan4096(); + } + } + + private void testUrlNotLongerThan4096() { + RestOperations restTemplate = RestTemplateBuilder.create(); + // \r doesn't count for url length Since netty 4.1.88.Final See https://github.com/netty/netty/pull/12321 + String q = Strings.repeat("q", + 4096 + 1 - "GET /api/springmvc/controller/sayhi?name=".length() - " HTTP/1.1\r".length()); + TestMgr.check("hi " + q + " [" + q + "]", + restTemplate.getForObject("cse://springmvc/springmvc/controller/sayhi?name=" + q, + String.class)); + + q = Strings.repeat("q", 4096 + 2 - "GET /api/springmvc/controller/sayhi?name=".length() - " HTTP/1.1\r".length()); + try { + restTemplate.getForObject("cse://springmvc/springmvc/controller/sayhi?name=" + q, + String.class); + TestMgr.check(true, false); + } catch (InvocationException e) { + TestMgr.check(REQUEST_URI_TOO_LONG.getStatusCode(), e.getStatusCode()); + } + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java index a482587163a..498a7d0c832 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestObject.java @@ -18,23 +18,21 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import javax.xml.ws.Holder; - import org.apache.servicecomb.demo.EmptyObject; import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; -import org.springframework.web.client.RestTemplate; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.web.client.RestOperations; public class TestObject { private CodeFirstSpringmvcIntf intf; - private RestTemplate restTemplate = new CseRestTemplate(); + private RestOperations restTemplate = RestTemplateBuilder.create(); private String prefix = "cse://springmvc/codeFirstSpringmvc"; @@ -43,17 +41,17 @@ public TestObject() { } public void runRest() { - testEmptyObject_rest(); - testMapObject_rest(); + } public void runHighway() { - testEmptyObject_highway(); - testMapObject_highway(); + } public void runAllTransport() { testObject(); + testMapObject(); + testEmptyObject(); testListObject(); testHolderObject(); } @@ -81,10 +79,11 @@ private void testListObject() { } @SuppressWarnings("unchecked") - private void testMapObject_rest() { + private void testMapObject() { Map map = Collections.singletonMap("k", "v"); Map result = intf.testMapObject(map); TestMgr.check("{k=v}", result); + // This is a behavior change in 2.0.0, before 2.0.0 runtime type of RAW is HashMap TestMgr.check(LinkedHashMap.class, result.getClass()); result = restTemplate.postForObject(prefix + "/mapObject", map, Map.class); @@ -92,29 +91,7 @@ private void testMapObject_rest() { TestMgr.check(LinkedHashMap.class, result.getClass()); } - @SuppressWarnings("unchecked") - private void testMapObject_highway() { - Map map = Collections.singletonMap("k", "v"); - Map result = intf.testMapObject(map); - TestMgr.check("{k=v}", result); - TestMgr.check(HashMap.class, result.getClass()); - - result = restTemplate.postForObject(prefix + "/mapObject", map, Map.class); - TestMgr.check("{k=v}", result); - TestMgr.check(HashMap.class, result.getClass()); - } - - private void testEmptyObject_highway() { - // protobuf can not express empty/null - // everything empty will be null - EmptyObject result = intf.testEmpty(new EmptyObject()); - TestMgr.check(null, result); - - result = restTemplate.postForObject(prefix + "/emptyObject", new EmptyObject(), EmptyObject.class); - TestMgr.check(null, result); - } - - private void testEmptyObject_rest() { + private void testEmptyObject() { EmptyObject result = intf.testEmpty(new EmptyObject()); TestMgr.check(EmptyObject.class, result.getClass()); @@ -144,34 +121,38 @@ private void testObject() { // emptyObject result = intf.testObject(new EmptyObject()); - TestMgr.check("{}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + // result may not be an empty map in highway + // TestMgr.check("{}", result); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", new EmptyObject(), EmptyObject.class); - TestMgr.check("{}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + TestMgr.check(EmptyObject.class, result.getClass()); + result = restTemplate.postForObject(prefix + "/object", new EmptyObject(), EmptyObject.class); + TestMgr.check(EmptyObject.class, result.getClass()); // map Map map = Collections.singletonMap("k", "v"); result = intf.testObject(map); TestMgr.check("{k=v}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", map, Map.class); TestMgr.check("{k=v}", result); - TestMgr.check(LinkedHashMap.class, result.getClass()); + TestMgr.check(true, Map.class.isAssignableFrom(result.getClass())); // list List list = Collections.singletonList("v"); result = intf.testObject(list); TestMgr.check("[v]", result); - TestMgr.check(ArrayList.class, result.getClass()); + TestMgr.check(true, List.class.isAssignableFrom(result.getClass())); result = restTemplate.postForObject(prefix + "/object", list, List.class); TestMgr.check("[v]", result); - TestMgr.check(ArrayList.class, result.getClass()); + TestMgr.check(true, List.class.isAssignableFrom(result.getClass())); // generic + // This test case for HIGHWAY is not stable. + // When proto schema contains Holder message, the result type is Map. Or the result is Holder(using json). Holder holder = new Holder<>("v"); result = intf.testObject(holder); TestMgr.check("v", ((Map) result).get("value")); diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java index 9bbc4fcc1f7..bede84dadaf 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java @@ -18,14 +18,17 @@ import java.util.Date; import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.demo.compute.GenericParam; import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.core.env.Environment; import org.springframework.http.ResponseEntity; import com.fasterxml.jackson.databind.exc.InvalidFormatException; @@ -33,6 +36,12 @@ public class TestResponse { private CodeFirstSpringmvcIntf intf; + private Environment environment; + + public void setEnvironment(Environment environment) { + this.environment = environment; + } + public TestResponse() { intf = Invoker.createProxy("springmvc", "codeFirst", CodeFirstSpringmvcIntf.class); } @@ -43,38 +52,52 @@ public void runRest() { testDelay(); testAbort(); testDecodeResponseError(); + checkQueryObject(); + testCseResponse(); + testResponseEntity(); + testCseResponseCorrect(); } public void runHighway() { } public void runAllTransport() { - testResponseEntity(); - testCseResponse(); testvoidResponse(); testVoidResponse(); checkQueryObject(); + testCseResponse(); + testResponseEntity(); } private void testCseResponse() { - String srcName = RegistryUtils.getMicroservice().getServiceName(); + String srcName = BootStrapProperties.readServiceName(environment); Response cseResponse = intf.cseResponse(); TestMgr.check("User [name=nameA, age=100, index=0]", cseResponse.getResult()); - TestMgr.check("h1v " + srcName, cseResponse.getHeaders().getFirst("h1")); - TestMgr.check("h2v " + srcName, cseResponse.getHeaders().getFirst("h2")); + TestMgr.check("h1v " + srcName, cseResponse.getHeader("h1")); + TestMgr.check("h2v " + srcName, cseResponse.getHeader("h2")); + TestMgr.check(cseResponse.getStatusCode(), 202); + } + + private void testCseResponseCorrect() { + String srcName = BootStrapProperties.readServiceName(environment); + Response cseResponse = intf.cseResponseCorrect(); + TestMgr.check("User [name=nameA, age=100, index=0]", cseResponse.getResult()); + TestMgr.check("h1v " + srcName, cseResponse.getHeader("h1")); + TestMgr.check("h2v " + srcName, cseResponse.getHeader("h2")); + TestMgr.check(cseResponse.getStatusCode(), 202); } private void testResponseEntity() { Date date = new Date(); - String srcName = RegistryUtils.getMicroservice().getServiceName(); + String srcName = BootStrapProperties.readServiceName(environment); ResponseEntity responseEntity = intf.responseEntity(date); TestMgr.check(date, responseEntity.getBody()); TestMgr.check("h1v " + srcName, responseEntity.getHeaders().getFirst("h1")); TestMgr.check("h2v " + srcName, responseEntity.getHeaders().getFirst("h2")); - TestMgr.check(202, responseEntity.getStatusCode()); + TestMgr.check(202, responseEntity.getStatusCode().value()); } private void testvoidResponse() { @@ -92,8 +115,8 @@ private void checkQueryObject() { } private void checkQueryGenericObject() { - final GenericParam requestBody = new GenericParam<>(); - requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson")); + GenericParam requestBody = new GenericParam<>(); + requestBody.num(1).str("str1").setData(new Person("bodyPerson")); String result = intf.checkQueryGenericObject(requestBody, "str2", 2); TestMgr.check( "str=str2,generic=GenericParamWithJsonIgnore{str='str2', num=2, data=null},requestBody=GenericParam{str='str1', num=1, data=bodyPerson}", @@ -101,8 +124,8 @@ private void checkQueryGenericObject() { } private void checkQueryGenericString() { - final GenericParam requestBody = new GenericParam<>(); - requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson")); + GenericParam requestBody = new GenericParam<>(); + requestBody.num(1).str("str1").setData(new Person("bodyPerson")); String result = intf.checkQueryGenericString("str2", requestBody, 2, "dataTest", "strInSubclass", 33); TestMgr.check( "str=str2,generic=GenericParamExtended{strExtended='strInSubclass', intExtended=33, super=" @@ -119,20 +142,19 @@ private void testDelay() { } private void testAbort() { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < 4; ++i) { - String response; + AtomicInteger count = new AtomicInteger(0); + for (int i = 0; i < 100; ++i) { try { - response = intf.testAbort(); + String response = intf.testAbort(); + count.incrementAndGet(); + TestMgr.check("OK", response); } catch (InvocationException e) { - response = e.getMessage(); + TestMgr.check(421, e.getStatusCode()); + TestMgr.check("aborted by fault inject", ((CommonExceptionData) e.getErrorData()).getMessage()); } - result.append(response).append("|"); } - TestMgr.check( - "OK|InvocationException: code=421;msg=CommonExceptionData [message=aborted by fault inject]|" - + "OK|InvocationException: code=421;msg=CommonExceptionData [message=aborted by fault inject]|", - result.toString()); + // 50% percent fail + TestMgr.check(true, count.get() >= 30 && count.get() <= 70); } private void testDecodeResponseError() { @@ -148,10 +170,7 @@ private void testDecodeResponseError() { Throwable cause = exception.getCause(); TestMgr.check(InvalidFormatException.class, cause.getClass()); TestMgr.check( - "Cannot deserialize value of type `java.util.Date` from String \"returnOK\": not a valid representation " - + "(error: Failed to parse Date value 'returnOK': Failed to parse date \"returnOK\": Invalid number: retu)\n" - + " at [Source: (org.apache.servicecomb.foundation.vertx.stream.BufferInputStream); line: 1, column: 12] " - + "(through reference chain: org.apache.servicecomb.demo.springmvc.decoderesponse.DecodeTestResponse[\"content\"])", - ((InvalidFormatException) cause).getMessage()); + ((InvalidFormatException) cause).getMessage().contains("Cannot deserialize value of type `java.util.Date`"), + true); } } diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java index 06c302a562f..a9d02553bf7 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java @@ -25,10 +25,10 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; public class TestRestTemplate { - private RestTemplate restTemplate = RestTemplateBuilder.create(); + private RestOperations restTemplate = RestTemplateBuilder.create(); public void runAllTest() { testvoidResponse(); @@ -40,28 +40,38 @@ public void runAllTest() { public void runRest() { checkQueryGenericObject(); checkQueryGenericString(); + checkQueryObject(); } private void testvoidResponse() { - final ResponseEntity resultEntity = restTemplate + ResponseEntity resultEntity = restTemplate .getForEntity("cse://springmvc/codeFirstSpringmvc/testvoidInRestTemplate", void.class); - Assert.isTrue(200 == resultEntity.getStatusCodeValue(), "void return type invocation failed"); + Assert.isTrue(200 == resultEntity.getStatusCode().value(), "void return type invocation failed"); } private void testVoidResponse() { - final ResponseEntity resultEntity = restTemplate + ResponseEntity resultEntity = restTemplate .getForEntity("cse://springmvc/codeFirstSpringmvc/testVoidInRestTemplate", Void.class); - Assert.isTrue(200 == resultEntity.getStatusCodeValue(), "Void return type invocation failed"); + Assert.isTrue(200 == resultEntity.getStatusCode().value(), "Void return type invocation failed"); + resultEntity = restTemplate + .getForEntity("servicecomb://springmvc/codeFirstSpringmvc/testVoidInRestTemplate", Void.class); + Assert.isTrue(200 == resultEntity.getStatusCode().value(), "Void return type invocation failed"); + resultEntity = restTemplate + .getForEntity("servicecomb://springmvc/codeFirstSpringmvc/testDefaultGetApiExample", Void.class); + Assert.isTrue(200 == resultEntity.getStatusCode().value(), "Void return type invocation failed"); } private void checkAllVoidTestResult() { - final ResponseEntity resultEntity = restTemplate + ResponseEntity resultEntity = restTemplate .getForEntity("cse://springmvc/codeFirstSpringmvc/checkVoidResult", boolean.class); Assert.isTrue(resultEntity.getBody(), "not all void test is passed"); + restTemplate + .getForEntity("servicecomb://springmvc/codeFirstSpringmvc/checkVoidResult", boolean.class); + Assert.isTrue(resultEntity.getBody(), "not all void test is passed"); } private void checkQueryObject() { - final ResponseEntity responseEntity = restTemplate + ResponseEntity responseEntity = restTemplate .postForEntity("cse://springmvc/codeFirstSpringmvc/checkQueryObject?name={1}&otherName={2}", new Person("bodyName"), String.class, "name1", "otherName2"); TestMgr.check("invocationContext_is_null=false,person=name1,otherName=otherName2,name=name1,requestBody=bodyName", @@ -69,10 +79,10 @@ private void checkQueryObject() { } private void checkQueryGenericObject() { - final GenericParam requestBody = new GenericParam<>(); - requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson")); - final HttpEntity> requestEntity = new HttpEntity<>(requestBody); - final ResponseEntity responseEntity = restTemplate + GenericParam requestBody = new GenericParam<>(); + requestBody.num(1).str("str1").setData(new Person("bodyPerson")); + HttpEntity> requestEntity = new HttpEntity<>(requestBody); + ResponseEntity responseEntity = restTemplate .exchange("cse://springmvc/codeFirstSpringmvc/checkQueryGenericObject?str={1}&num={2}", HttpMethod.PUT, requestEntity, String.class, "str2", 2); TestMgr.check( @@ -81,9 +91,9 @@ private void checkQueryGenericObject() { } private void checkQueryGenericString() { - final GenericParam requestBody = new GenericParam<>(); - requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson")); - final ResponseEntity responseEntity = restTemplate.exchange( + GenericParam requestBody = new GenericParam<>(); + requestBody.num(1).str("str1").setData(new Person("bodyPerson")); + ResponseEntity responseEntity = restTemplate.exchange( "cse://springmvc/codeFirstSpringmvc/checkQueryGenericString?str={1}&num={2}&data={3}&strExtended={4}&intExtended={5}", HttpMethod.PUT, new HttpEntity<>(requestBody), String.class, "str2", 2, "dataTest", "strInSubclass", 33); diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRetrySchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRetrySchema.java new file mode 100644 index 00000000000..501ff30f1fc --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRetrySchema.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class TestRetrySchema implements CategorizedTestCase { + interface RetrySchemaInf { + boolean successWhenRetry(); + + CompletableFuture successWhenRetryAsync(); + } + + @RpcReference(microserviceName = "springmvc", schemaId = "RetrySchema") + private RetrySchemaInf retrySchemaInf; + + RestOperations restTemplate = RestTemplateBuilder.create(); + + private static final String SERVER = "servicecomb://springmvc"; + + @Override + public void testAllTransport() throws Exception { + testRetryGovernanceRestTemplate(); + testRetryGovernanceRpc(); + } + + private void testRetryGovernanceRpc() throws Exception { + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + TestMgr.check(retrySchemaInf.successWhenRetry(), true); + + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + TestMgr.check(retrySchemaInf.successWhenRetryAsync().get(), true); + } + + private void testRetryGovernanceRestTemplate() { + TestMgr.check(restTemplate.getForObject(SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + TestMgr.check(restTemplate.getForObject(SERVER + "/retry/governance/successWhenRetry", boolean.class), true); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSchemeInterfaceSpringmvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSchemeInterfaceSpringmvc.java new file mode 100644 index 00000000000..03dd6c019a4 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSchemeInterfaceSpringmvc.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +@Component +public class TestSchemeInterfaceSpringmvc implements CategorizedTestCase { + @RpcReference(schemaId = "SchemeInterfaceSpringmvc", microserviceName = "springmvc") + private SchemeInterfaceSpringmvc springmvc; + + public void testAllTransport() throws Exception { + TestMgr.check(3, springmvc.add(1, 2)); + + try { + springmvc.reduce(1, 3); + TestMgr.failed("should throw exception", new Exception()); + } catch (InvocationException e) { + TestMgr.check( + "Consumer method org.apache.servicecomb.demo.springmvc.client.SchemeInterfaceSpringmvc:reduce not " + + "exist in contract, microserviceName=springmvc, " + + "schemaId=SchemeInterfaceSpringmvc.", + ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java new file mode 100644 index 00000000000..e832cbbf5b1 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestSpringMVCCommonSchemaInterface.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.invocation.timeout.ProcessingTimeStrategy; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.CommonSchemaInterface; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.stereotype.Component; + +@Component +public class TestSpringMVCCommonSchemaInterface implements CategorizedTestCase { + @RpcReference(schemaId = "SpringMVCCommonSchemaInterface", microserviceName = "springmvc") + private CommonSchemaInterface client; + + @Override + public void testAllTransport() throws Exception { + testInvocationTimeoutInServer(); + testInvocationTimeoutInServerUserCheck(); + testInvocationAlreadyTimeoutInClient(); + testInvocationTimeoutInClientWait(); + } + + private void testInvocationTimeoutInClientWait() { + try { + long begin = System.currentTimeMillis(); + String result = client.testInvocationTimeoutInClientWait(1000, "hello"); + System.out.println("test code from testInvocationTimeoutInClientWait: " + + (System.currentTimeMillis() - begin) + ":" + result); + TestMgr.fail("should timeout"); + } catch (InvocationException e) { + TestMgr.check(408, e.getStatusCode()); + TestMgr.check("Invocation Timeout.", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testInvocationTimeoutInServerUserCheck() { + try { + InvocationContext context = new InvocationContext(); + client.testInvocationTimeout(context, 1001, "customized"); + TestMgr.fail("should timeout"); + } catch (InvocationException e) { + TestMgr.check(408, e.getStatusCode()); + TestMgr.check("Invocation Timeout.", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testInvocationAlreadyTimeoutInClient() { + try { + InvocationContext context = new InvocationContext(); + context.addLocalContext(ProcessingTimeStrategy.CHAIN_START_TIME, System.nanoTime()); + context.addLocalContext(ProcessingTimeStrategy.CHAIN_PROCESSING, TimeUnit.SECONDS.toNanos(2)); + + long begin = System.currentTimeMillis(); + String result = client.testInvocationTimeout(context, 10, "hello"); + System.out.println("testInvocationAlreadyTimeoutInClient from invocation timeout: " + + (System.currentTimeMillis() - begin) + ":" + result); + TestMgr.fail("should timeout"); + } catch (InvocationException e) { + TestMgr.check(408, e.getStatusCode()); + TestMgr.check("Invocation Timeout.", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } + + private void testInvocationTimeoutInServer() { + try { + client.testInvocationTimeout(1001, "hello"); + TestMgr.fail("should timeout"); + } catch (InvocationException e) { + TestMgr.check(408, e.getStatusCode()); + TestMgr.check("Invocation Timeout.", ((CommonExceptionData) e.getErrorData()).getMessage()); + } + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdPartyRegistration.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdPartyRegistration.java new file mode 100644 index 00000000000..8dc088010fb --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdPartyRegistration.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.Date; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +@Component +public class TestThirdPartyRegistration implements BootListener, CategorizedTestCase { + @Autowired + private ThirdPartyService thirdPartyService; + + @Override + public void onAfterRegistry(BootEvent event) { + } + + @Override + public void testRestTransport() throws Exception { + Date date = new Date(); + ResponseEntity responseEntity = thirdPartyService.responseEntity(date); + TestMgr.check(date, responseEntity.getBody()); + // Third party invocation will pass cse-context to the target too + TestMgr.check("h1v null", responseEntity.getHeaders().getFirst("h1")); + TestMgr.check("h2v null", responseEntity.getHeaders().getFirst("h2")); + + TestMgr.check(202, responseEntity.getStatusCode().value()); + } + + @Override + public String getMicroserviceName() { + return "testServiceName"; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdSvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdSvc.java new file mode 100644 index 00000000000..98592c9bce2 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestThirdSvc.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.Date; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.springmvc.client.ThirdSvc.ThirdSvcClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +@Component +public class TestThirdSvc implements CategorizedTestCase { + private ThirdSvcClient client; + + @Autowired + public void setThirdSvcClient(ThirdSvcClient client) { + this.client = client; + } + + @Override + public void testAllTransport() throws Exception { + testResponseEntity(); + + testDifferentParameterName(); + } + + private void testDifferentParameterName() { + String result = client.getAuthorization("test", "param", "auth"); + TestMgr.check("testparamauth", result); + } + + private void testResponseEntity() { + Date date = new Date(); + ResponseEntity responseEntity = client.responseEntity(date); + TestMgr.check(date, responseEntity.getBody()); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestTransportSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestTransportSchema.java new file mode 100644 index 00000000000..d818ed439d4 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestTransportSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class TestTransportSchema implements CategorizedTestCase { + interface TransportClient { + boolean restTransport(); + + boolean highwayTransport(); + } + + @RpcReference(microserviceName = "springmvc", schemaId = "TransportSchema") + private TransportClient transportClient; + + @Override + public void testRestTransport() throws Exception { + testTransportSchema(); + } + + @Override + public void testHighwayTransport() throws Exception { + testTransportSchema(); + } + + @Override + public void testAllTransport() throws Exception { + testTransportSchema(); + } + + private void testTransportSchema() { + TestMgr.check(true, transportClient.highwayTransport()); + TestMgr.check(true, transportClient.restTransport()); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java new file mode 100644 index 00000000000..0e6d810d4a5 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestUploadSchema.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; + +@Component +public class TestUploadSchema implements CategorizedTestCase { + + interface FileUploadMultiInf { + String fileUploadMultiRpc(List files); + } + + @RpcReference(microserviceName = "springmvc", schemaId = "UploadSchema") + private FileUploadMultiInf fileUploadMultiInf; + + @Override + public void testRestTransport() throws Exception { + testServerStartupSuccess(); + testUploadMultiBigFiles(); + testFileUploadMultiRpc(); + testUploadFileAndAttribute(); + testUploadFileAndAttributeCN(); + testUploadFileRequestPartAttribute(); + testUploadFileRequestPartAttributeList(); + } + + private void testServerStartupSuccess() { + RestOperations template = RestTemplateBuilder.create(); + boolean result = template.getForObject("servicecomb://springmvc/upload/isServerStartUpSuccess", Boolean.class); + TestMgr.check(result, true); + } + + private void testUploadMultiBigFiles() throws Exception { + final int fileNum = 5; + List files = new ArrayList<>(fileNum); + + String fileName = UUID.randomUUID().toString(); + for (int i = 0; i < fileNum; i++) { + File tempFile = new File("random-client-" + fileName + i); + files.add(tempFile); + FileOutputStream fo = new FileOutputStream(tempFile); + byte[] data = new byte[1024 * 1024 * 10]; + Arrays.fill(data, (byte) 33); + IOUtils.write(data, fo); + fo.close(); + } + + RestOperations template = RestTemplateBuilder.create(); + + MultiValueMap map = new LinkedMultiValueMap<>(); + for (int i = 0; i < fileNum; i++) { + map.add("files", new FileSystemResource(files.get(i))); + } + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + HttpEntity> entity = new HttpEntity<>(map, headers); + + String result = template.postForObject("servicecomb://springmvc/upload/fileUpload", entity, String.class); + TestMgr.check(result, "success"); + + files.forEach(File::delete); + } + + private void testFileUploadMultiRpc() throws IOException { + File file1 = File.createTempFile("file1", ".txt"); + File file2 = File.createTempFile("file2", ".txt"); + List files = new ArrayList<>(); + files.add(new FileSystemResource(file1)); + files.add(new FileSystemResource(file2)); + String result = fileUploadMultiInf.fileUploadMultiRpc(files); + TestMgr.check(result, "fileUploadMulti success, and fileNum is 2"); + } + + private void testUploadFileAndAttribute() throws Exception { + RestOperations template = RestTemplateBuilder.create(); + Map map = new HashMap<>(); + String message = "hi"; + File file = File.createTempFile("file", ".txt"); + FileUtils.writeStringToFile(file, "test", StandardCharsets.UTF_8, false); + + map.put("file", new FileSystemResource(file)); + map.put("attribute", message); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + String result = template.postForObject("servicecomb://springmvc/upload/uploadFileAndAttribute", + new HttpEntity<>(map, headers), String.class); + TestMgr.check("hi test", result); + } + + private void testUploadFileAndAttributeCN() throws Exception { + RestOperations template = RestTemplateBuilder.create(); + Map map = new HashMap<>(); + String message = "hi"; + File file = File.createTempFile("中文名称", ".txt"); + FileUtils.writeStringToFile(file, "test", StandardCharsets.UTF_8, false); + + map.put("file", new FileSystemResource(file)); + map.put("attribute", message); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + String result = template.postForObject("servicecomb://springmvc/upload/uploadFileAndAttribute", + new HttpEntity<>(map, headers), String.class); + TestMgr.check("hi test", result); + } + + + private void testUploadFileRequestPartAttribute() throws Exception { + RestOperations template = RestTemplateBuilder.create(); + Map map = new HashMap<>(); + String message = "hi"; + File file = File.createTempFile("file", ".txt"); + FileUtils.writeStringToFile(file, "test", StandardCharsets.UTF_8, false); + + map.put("file", new FileSystemResource(file)); + map.put("attribute", message); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + String result = template.postForObject("servicecomb://springmvc/upload/uploadFileRequestPartAttribute", + new HttpEntity<>(map, headers), String.class); + TestMgr.check("hi test", result); + } + + private void testUploadFileRequestPartAttributeList() throws Exception { + RestOperations template = RestTemplateBuilder.create(); + MultiValueMap map = new LinkedMultiValueMap<>(); + String message1 = "msg1"; + String message2 = "msg2"; + File file1 = File.createTempFile("file1", ".txt"); + FileUtils.writeStringToFile(file1, "test1", StandardCharsets.UTF_8, false); + File file2 = File.createTempFile("file2", ".txt"); + FileUtils.writeStringToFile(file2, "test2", StandardCharsets.UTF_8, false); + + map.add("files", new FileSystemResource(file1)); + map.add("files", new FileSystemResource(file2)); + map.add("attributes", message1); + map.add("attributes", message2); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + String result = template.postForObject("servicecomb://springmvc/upload/uploadFileRequestPartAttributeList", + new HttpEntity<>(map, headers), String.class); + TestMgr.check("test1test2msg1msg2", result); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestWeakSpringmvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestWeakSpringmvc.java new file mode 100644 index 00000000000..df9f8236215 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestWeakSpringmvc.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.demo.model.SpecialNameModel; +import org.apache.servicecomb.demo.server.GenericsModel; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +import com.fasterxml.jackson.core.JsonProcessingException; + +/* +This is the provider definition: + + + @GetMapping(path = "/diffNames") + @ApiOperation(value = "differentName", nickname = "differentName") + public int diffNames(@RequestParam("x") int a, @RequestParam("y") int b) + + +and the swagger is: + + + paths: + /diffNames: + get: + summary: "differentName" + operationId: "differentName" + parameters: + - name: "x" + in: "query" + required: true + type: "integer" + format: "int32" + - name: "y" + in: "query" + required: true + type: "integer" + format: "int32" + responses: + "200": + description: "response of 200" + schema: + type: "integer" + format: "int32" + + +In consumer, you can define any prototype that matches generated swagger of provider. + */ + +interface DiffNames { + int differentName(int x, int y); +} + +interface DiffNames2 { + int differentName(int y, int x); +} + +interface Generics { + List> genericParams(int code, List> names); +} + +interface GenericsModelInf { + GenericsModel genericParamsModel(int code, GenericsModel model); +} + +interface SpecialNameModelInf { + SpecialNameModel specialNameModel(int code, SpecialNameModel model); +} + +@Component +public class TestWeakSpringmvc implements CategorizedTestCase { + @Value("${servicecomb.service.application}") + private String applicationName; + + @RpcReference(microserviceName = "springmvc", schemaId = "weakSpringmvc") + private DiffNames diffNames; + + @RpcReference(microserviceName = "springmvc", schemaId = "weakSpringmvc") + private DiffNames2 diffNames2; + + @RpcReference(microserviceName = "springmvc", schemaId = "weakSpringmvc") + private Generics generics; + + @RpcReference(microserviceName = "springmvc", schemaId = "weakSpringmvc") + private GenericsModelInf genericsModelInf; + + @RpcReference(microserviceName = "springmvc", schemaId = "weakSpringmvc") + private SpecialNameModelInf specialNameModelInf; + + @RpcReference(microserviceName = "${servicecomb.service.application}:springmvc", schemaId = "weakSpringmvc") + private SpecialNameModelInf specialNameModelInfWithAppId; + + private RestOperations restTemplate = RestTemplateBuilder.create(); + + @Override + public void testAllTransport() throws Exception { + testDiffName(); + + testGenerics(); + + testGenericsModel(); + + testSpecialNameModel(); + } + + private void testSpecialNameModel() { + SpecialNameModel model = new SpecialNameModel(); + model.setaIntName(30); + SpecialNameModel result = specialNameModelInf.specialNameModel(0, model); + TestMgr.check(30, result.getaIntName()); + result = specialNameModelInfWithAppId.specialNameModel(0, model); + TestMgr.check(30, result.getaIntName()); + } + + private void testGenericsModel() throws JsonProcessingException { + GenericsModel model = new GenericsModel(); + model.setName("model"); + List> namesList = new ArrayList<>(); + List names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + model.setNameList(namesList); + List>> objectLists = new ArrayList<>(); + List> objectList = new ArrayList<>(); + List objects = new ArrayList<>(); + objects.add("object"); + objectList.add(objects); + objectLists.add(objectList); + model.setObjectLists(objectLists); + GenericsModel result = genericsModelInf.genericParamsModel(100, model); + TestMgr.check(JsonUtils.writeValueAsString(model), JsonUtils.writeValueAsString(result)); + } + + private void testGenerics() { + List> namesList = new ArrayList<>(); + List names = new ArrayList<>(); + names.add("hello"); + namesList.add(names); + List> nameListResult = generics.genericParams(100, namesList); + TestMgr.check(1, nameListResult.size()); + TestMgr.check(1, nameListResult.get(0).size()); + TestMgr.check("hello", nameListResult.get(0).get(0)); + } + + private void testDiffName() { + TestMgr.check(7, diffNames.differentName(2, 3)); + TestMgr.check(8, diffNames2.differentName(2, 3)); + TestMgr.check(7, restTemplate.getForObject("cse://springmvc/weakSpringmvc/diffNames?x=2&y=3", Integer.class)); + TestMgr.check(7, restTemplate + .getForObject("cse://" + applicationName + ":springmvc/weakSpringmvc/diffNames?x=2&y=3", + Integer.class)); + Map args = new HashMap<>(); + args.put("x", 2); + args.put("y", 3); + TestMgr.check(7, InvokerUtils.syncInvoke("springmvc", + "weakSpringmvc", "differentName", args, Integer.class)); + TestMgr.check(7, InvokerUtils.syncInvoke(applicationName + ":springmvc", + "weakSpringmvc", "differentName", args, Integer.class)); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdPartyService.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdPartyService.java new file mode 100644 index 00000000000..e31e1183333 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdPartyService.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.Date; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +@RequestMapping(path = "/codeFirstSpringmvc", produces = MediaType.APPLICATION_JSON_VALUE) +public interface ThirdPartyService { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Date.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) + @RequestMapping(path = "/responseEntity", method = RequestMethod.POST) + ResponseEntity responseEntity(@RequestAttribute("date") Date date); +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java new file mode 100644 index 00000000000..3cbd8dd97dd --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/ThirdSvc.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.client; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.apache.servicecomb.provider.pojo.Invoker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +@Configuration +public class ThirdSvc { + @Autowired + Environment environment; + + @RequestMapping(path = "/codeFirstSpringmvc") + public interface ThirdSvcClient { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Date.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) + @RequestMapping(path = "/responseEntity", method = RequestMethod.POST) + ResponseEntity responseEntity(@RequestAttribute("date") Date date); + + @GetMapping(value = "/getAuthorization", produces = {"application/json"}) + String getAuthorization( + @RequestHeader(value = "test") String test, + @RequestParam(value = "param") String param, + @RequestHeader("Authorization") String authorization); + } + + @Bean + public RegistryBean thirdRegistryBean() { + String endpoint; + if (environment.getProperty("servicecomb.test.vert.transport", boolean.class, true)) { + endpoint = "rest://localhost:8080?sslEnabled=false&urlPrefix=%2Fapi"; + } else { + endpoint = "rest://localhost:8080?sslEnabled=false"; + } + + return new RegistryBean().addSchemaInterface("schema-1", ThirdSvcClient.class) + .setAppId("springmvctest") + .setServiceName("3rd-svc") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of(new Instance().setEndpoints(List.of(endpoint))))); + } + + @Bean + public ThirdSvcClient thirdSvcClient() { + return Invoker.createProxy("3rd-svc", "schema-1", ThirdSvcClient.class); + } + + @Bean + public RegistryBean thirdPartyServiceRegistryBean() { + List endpoints = new ArrayList<>(); + if (environment.getProperty("servicecomb.test.vert.transport", boolean.class, true)) { + endpoints.add("rest://localhost:8080?sslEnabled=false&urlPrefix=%2Fapi"); + } else { + endpoints.add("rest://localhost:8080?sslEnabled=false"); + } + + return new RegistryBean().addSchemaInterface("testServiceName", ThirdPartyService.class) + .setAppId("springmvctest") + .setServiceName("testServiceName") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of(new Instance().setEndpoints(endpoints)))); + } + + @Bean + public ThirdPartyService thirdPartyService() { + return Invoker.createProxy("testServiceName", "testServiceName", ThirdPartyService.class); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java new file mode 100644 index 00000000000..1a25838d083 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +public class ServiceBean { + private final String name; + + public ServiceBean(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java new file mode 100644 index 00000000000..9bee6805c48 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceFactoryBean.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("ServiceFactoryBean") +public class ServiceFactoryBean implements FactoryBean { + + ServiceWithReference serviceWithReference; + + @Autowired + public ServiceFactoryBean(ServiceWithReference serviceWithReference) { + this.serviceWithReference = serviceWithReference; + } + + @Override + public ServiceBean getObject() throws Exception { + return new ServiceBean(serviceWithReference.test("a")); + } + + @Override + public Class getObjectType() { + return ServiceBean.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java new file mode 100644 index 00000000000..f371bf35148 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReference.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +public interface ServiceWithReference { + String test(String name); +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java new file mode 100644 index 00000000000..a5f8d7c6bb1 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/factory/ServiceWithReferenceImpl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.client.factory; + +import org.apache.servicecomb.demo.springmvc.client.SchemeInterfaceSpringmvc; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component +public class ServiceWithReferenceImpl implements ServiceWithReference { + @RpcReference(schemaId = "SchemeInterfaceSpringmvc", microserviceName = "springmvc") + private SchemeInterfaceSpringmvc springmvc; + + @Override + public String test(String name) { + return name + "-" + springmvc.add(1, 2); + } +} diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/SpringMVCSchema.yaml b/demo/demo-springmvc/springmvc-client/src/main/resources/SpringMVCSchema.yaml new file mode 100644 index 00000000000..db67a5779a9 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/resources/SpringMVCSchema.yaml @@ -0,0 +1,71 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +################################################################################ +################################################################################ +################################################################################ +################################################################################ +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.springmvc.client.SpringMVCSchema + version: 1.0.0 +servers: +- url: /springMvcSchema +paths: + /testApiExample: + post: + operationId: testApiExample + requestBody: + content: + application/json: + schema: + type: string + required: true + x-name: name + responses: + "200": + description: success + headers: {} + content: + application/json: + schema: + type: string + description: "" + nullable: false + example: wget http://localhost/springMvcSchema/testApiExample + /testDefaultGetApiExample: + get: + operationId: testDefaultGetApiExample + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: success + headers: {} + content: + application/json: + schema: + type: string + description: "" + nullable: false + example: "" +components: + schemas: {} diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/config/log4j.properties b/demo/demo-springmvc/springmvc-client/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-springmvc/springmvc-client/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/log4j2.xml b/demo/demo-springmvc/springmvc-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-springmvc/springmvc-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml index 9a4b2203217..2fe0f881f55 100644 --- a/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml +++ b/demo/demo-springmvc/springmvc-client/src/main/resources/microservice.yaml @@ -15,52 +15,46 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: springmvctest -service_description: - name: springmvcClient - version: 0.0.1 servicecomb: service: - registry: - address: http://127.0.0.1:9980,http://127.0.0.1:30100 + application: springmvctest + name: springmvcClient + version: 0.0.1 + registry: + sc: + address: http://127.0.0.1:30100 autodiscovery: true - client: - timeout: - idle: 60 - watch: 60 - instance: - healthCheck: - interval: 3 - pull: - interval: 90 - watch: false - autodiscovery: true -# can download config center from https://cse-bucket.obs.myhwclouds.com/LocalCSE/Local-CSE-1.0.0.zip to test dynamic config - config: - client: - serverUri: http://127.0.0.1:30113 - refreshMode: 1 - refresh_interval: 5000 - refreshPort: 30114 + healthCheckIntervalInSeconds: 3 + pollIntervalInMillis: 90000 + watch: true + rest: client: connection: compression: true references: version-rule: 0+ - handler: - chain: - Consumer: - default: loadbalance,fault-injection-consumer,bizkeeper-consumer + request: + clientRequestHeaderFilterEnabled: + # Do not copy cse-context to target for microservice(testServiceName) + testServiceName: true + invocation: + timeout: + check: + enabled: true + strategy: processing-time + springmvc: + SpringMVCCommonSchemaInterface: + testInvocationTimeoutInClientWait: + timeout: 300 tracing: enabled: true samplingRate: 0.5 loadbalance: + userDefinedEndpoint.enabled: true strategy: name: WeightedResponse - retryEnabled: true - retryOnSame: 1 - retryOnNext: 1 + filter.status.enabled: false fallbackpolicy: Consumer: springmvc: @@ -83,6 +77,10 @@ servicecomb: name: myDC region: my-Region availableZone: my-Zone + + faultInjection: + enabled: true + governance: Consumer: springmvc: @@ -105,27 +103,29 @@ servicecomb: abort: httpStatus: 421 percent: 50 - test: - duplicate1: newer -cse: - fallback: - Consumer: - springmvc: - codeFirstBizkeeperTest: - testTimeout: - enabled: false - isolation: - Consumer: - springmvc: - codeFirstBizkeeperTest: - testTimeout: - timeout: - enabled: true - timeoutInMilliseconds: 1000 - test: - duplicate2: newer + # test governance retry + matchGroup: + retry-governance: | + matches: + - apiPath: + prefix: "/retry/governance/" + retry-success: | + matches: + - apiPath: + prefix: "/codeFirstSpringmvc/retrySuccess" + retry: + retry-governance: | + maxAttempts: 2 + retryOnResponseStatus: [500] + retry-success: | + maxAttempts: 2 + retryOnResponseStatus: [503] + #########SSL options +# open jdk 8 now TLSv1.3 not available +# ssl.protocols: TLSv1.3 +# ssl.ciphers: TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 ssl.protocols: TLSv1.2 ssl.authPeer: true ssl.checkCN.host: false diff --git a/demo/demo-springmvc/springmvc-client/src/test/java/org/apache/servicecomb/demo/springmvc/SpringMvcIT.java b/demo/demo-springmvc/springmvc-client/src/test/java/org/apache/servicecomb/demo/springmvc/SpringMvcIT.java index 5d610dee91f..c445ce1a647 100644 --- a/demo/demo-springmvc/springmvc-client/src/test/java/org/apache/servicecomb/demo/springmvc/SpringMvcIT.java +++ b/demo/demo-springmvc/springmvc-client/src/test/java/org/apache/servicecomb/demo/springmvc/SpringMvcIT.java @@ -17,25 +17,25 @@ package org.apache.servicecomb.demo.springmvc; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.demo.springmvc.client.SpringmvcClient; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = SpringmvcClient.class) public class SpringMvcIT { - - @Before + @BeforeEach public void setUp() { TestMgr.errors().clear(); } @Test - public void clientGetsNoError() throws Exception { - SpringmvcClient.main(new String[0]); - - assertThat(TestMgr.errors().isEmpty(), is(true)); + public void clientGetsNoError() { + SpringmvcClient.run(); + Assertions.assertTrue(TestMgr.isSuccess()); } } diff --git a/demo/demo-springmvc/springmvc-server/pom.xml b/demo/demo-springmvc/springmvc-server/pom.xml index 5bfe4bbfecf..f88876261d6 100644 --- a/demo/demo-springmvc/springmvc-server/pom.xml +++ b/demo/demo-springmvc/springmvc-server/pom.xml @@ -23,61 +23,26 @@ org.apache.servicecomb.demo demo-springmvc - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT springmvc-server Java Chassis::Demo::Spring MVC::Server - - org.apache.servicecomb.demo - demo-schema - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - swagger-invocation-validator - org.apache.servicecomb metrics-prometheus - - - org.apache.servicecomb - config-cc - - - - org.apache.servicecomb.demo - demo-signature - - org.apache.servicecomb.demo.springmvc.server.SpringmvcServer + org.apache.servicecomb.demo.springmvc.SpringmvcServer - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - 1.2.0-SNAPSHOT - - - + org.springframework.boot + spring-boot-maven-plugin @@ -86,15 +51,50 @@ docker + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + io.fabric8 docker-maven-plugin - - org.commonjava.maven.plugins - directory-maven-plugin - diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcServer.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcServer.java new file mode 100644 index 00000000000..52ede2792d8 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/SpringmvcServer.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class SpringmvcServer { + public static void main(String[] args) throws Exception { + new SpringApplicationBuilder(SpringmvcServer.class).web(WebApplicationType.NONE).run(args); + + runTests(); + + TestMgr.summary(); + if (!TestMgr.isSuccess()) { + System.exit(1); + } + } + + private static void runTests() { + try { + CategorizedTestCaseRunner.runCategorizedTestCase("springmvc"); + } catch (Exception e) { + TestMgr.failed("runCategorizedTestCase failed", e); + } + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/filter/ProviderTestFilter.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/filter/ProviderTestFilter.java new file mode 100644 index 00000000000..310f68e0ca0 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/filter/ProviderTestFilter.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.filter; + + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.stereotype.Component; + +@Component +public class ProviderTestFilter extends AbstractFilter implements ProviderFilter { + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 1800; + } + + @Override + public String getName() { + return "test-provider"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + invocation.addContext("k", "v"); + return nextNode.onFilter(invocation); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsSchema.java new file mode 100644 index 00000000000..45f2c01e4b3 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsSchema.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.demo.controller.Person; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "annotations") +@RequestMapping(path = "/springmvc/annotations", produces = MediaType.APPLICATION_JSON) +public class AnnotationsSchema { + @GetMapping(path = "/add") + public int add(@RequestParam(name = "a", defaultValue = "10") int a, + @RequestParam(name = "b", defaultValue = "10") int b) { + return a + b; + } + + @RequestMapping(path = "/sayhei", method = RequestMethod.GET) + public String sayHei(@RequestHeader(name = "name", defaultValue = "test") String name) { + return "hei " + name; + } + + @GetMapping(path = "/sayhi") + @Parameters({ + @Parameter(name = "name", in = ParameterIn.QUERY, schema = @Schema(type = "string", defaultValue = "test")), + @Parameter(name = "age", in = ParameterIn.QUERY, schema = @Schema(type = "integer", defaultValue = "20")) + }) + public String sayHi(String name, int age) { + return "hi " + name + " your age is : " + age; + } + + @RequestMapping(path = "/saysomething", method = RequestMethod.POST) + public String saySomething(String prefix, @RequestBody(required = false) Person user) { + if (user == null || user.getName() == null || user.getName().isEmpty()) { + return "No user data found"; + } + return prefix + " " + user.getName(); + } + + @RequestMapping(path = "/say", method = RequestMethod.POST) + public String say(@RequestBody(required = false) String user) { + if (user == null || user.isEmpty()) { + return "No user name found"; + } + return user; + } + + @RequestMapping(path = "/testRequiredBody", method = RequestMethod.POST) + public String testRequiredBody(@RequestBody(required = true) Person user) { + if (user == null) { + return "Should not happen"; + } + return user.getName(); + } + + @RequestMapping(path = "/testRegExpPath/{path: .+}", method = RequestMethod.GET) + public String testRegExpPath(@RequestParam("name") String name) { + return name; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsTest.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsTest.java deleted file mode 100644 index 3af7e0ed3ab..00000000000 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/AnnotationsTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.server; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiParam; - -@RestSchema(schemaId = "annotations") -@RequestMapping(path = "/springmvc/annotations", produces = MediaType.APPLICATION_JSON) -public class AnnotationsTest { - @GetMapping(path = "/add") - public int add(@RequestParam(name = "a", defaultValue = "10") int a, - @RequestParam(name = "b", defaultValue = "10") int b) { - return a + b; - } - - @RequestMapping(path = "/sayhei", method = RequestMethod.GET) - public String sayHei(@RequestHeader(name = "name", defaultValue = "test") String name) { - return "hei " + name; - } - - @GetMapping(path = "/sayhi") - @ApiImplicitParams({ - @ApiImplicitParam(name = "name", paramType = "query", dataType = "string", defaultValue = "test"), - @ApiImplicitParam(name = "age", paramType = "query", dataType = "integer", defaultValue = "20") - }) - public String sayHi(String name, int age) { - return "hi " + name + " your age is : " + age; - } - - @RequestMapping(path = "/saysomething", method = RequestMethod.POST) - public String saySomething(String prefix, @RequestBody(required = false) @ApiParam(required = false) Person user) { - if (user == null || user.getName() == null || user.getName().isEmpty()) { - return "No user data found"; - } - return prefix + " " + user.getName(); - } - - @RequestMapping(path = "/say", method = RequestMethod.POST) - public String say(@RequestBody(required = false) String user) { - if (user == null || user.isEmpty()) { - return "No user name found"; - } - return user; - } -} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/BigNumberSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/BigNumberSchema.java new file mode 100644 index 00000000000..1190fde43f8 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/BigNumberSchema.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "BigNumberSchema") +@RequestMapping("/bigNumber") +public class BigNumberSchema { + @PostMapping(path = "/integer", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public BigInteger bigInteger(@RequestHeader("intHeader") BigInteger intHeader, + @RequestParam("intQuery") BigInteger intQuery, @RequestAttribute("intForm") BigInteger intForm) { + return intHeader.add(intQuery).add(intForm); + } + + @PostMapping(path = "/decimal", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public BigDecimal bigDecimal(@RequestHeader("decimalHeader") BigDecimal decimalHeader, + @RequestParam("decimalQuery") BigDecimal decimalQuery, @RequestAttribute("decimalForm") BigDecimal decimalForm) { + return decimalHeader.add(decimalQuery).add(decimalForm); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java index 36adfcbe16e..36f8518afe4 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java @@ -19,21 +19,15 @@ import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import javax.inject.Inject; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - import org.apache.commons.io.IOUtils; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.demo.EmptyObject; import org.apache.servicecomb.demo.Generic; import org.apache.servicecomb.demo.compute.GenericParam; @@ -42,21 +36,21 @@ import org.apache.servicecomb.demo.compute.Person; import org.apache.servicecomb.demo.ignore.InputModelForTestIgnore; import org.apache.servicecomb.demo.ignore.OutputModelForTestIgnore; -import org.apache.servicecomb.demo.jaxbbean.JAXBPerson; import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.demo.springmvc.decoderesponse.DecodeTestResponse; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.metrics.core.MetricsBootListener; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.Headers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -79,25 +73,32 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.vertx.core.json.JsonObject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response.Status; @RestSchema(schemaId = "codeFirst") @RequestMapping(path = "/codeFirstSpringmvc", produces = MediaType.APPLICATION_JSON_VALUE) public class CodeFirstSpringmvc { private static final Logger LOGGER = LoggerFactory.getLogger(CodeFirstSpringmvc.class); - private AtomicInteger firstInovcation = new AtomicInteger(2); + private AtomicInteger invocationCounter = new AtomicInteger(0); private String _fileUpload(MultipartFile file1, Part file2) { try (InputStream is1 = file1.getInputStream(); InputStream is2 = file2.getInputStream()) { - String content1 = IOUtils.toString(is1); - String content2 = IOUtils.toString(is2); + String content1 = IOUtils.toString(is1, StandardCharsets.UTF_8); + String content2 = IOUtils.toString(is2, StandardCharsets.UTF_8); return String.format("%s:%s:%s\n" + "%s:%s:%s", file1.getOriginalFilename(), @@ -113,7 +114,7 @@ private String _fileUpload(MultipartFile file1, Part file2) { @GetMapping(path = "/retrySuccess") public int retrySuccess(@RequestParam("a") int a, @RequestParam("b") int b) { - if (firstInovcation.getAndDecrement() > 0) { + if (invocationCounter.getAndIncrement() % 3 != 0) { throw new InvocationException(Status.SERVICE_UNAVAILABLE, "try again later."); } return a + b; @@ -122,7 +123,7 @@ public int retrySuccess(@RequestParam("a") int a, @RequestParam("b") int b) { @PostMapping(path = "/upload1", produces = MediaType.TEXT_PLAIN_VALUE) public String fileUpload1(@RequestPart(name = "file1") MultipartFile file1) throws IOException { try (InputStream is = file1.getInputStream()) { - return IOUtils.toString(is); + return IOUtils.toString(is, StandardCharsets.UTF_8); } } @@ -132,37 +133,69 @@ public String fileUpload(@RequestPart(name = "file1") MultipartFile file1, return _fileUpload(file1, file2); } - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Date.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) @RequestMapping(path = "/responseEntity", method = RequestMethod.POST) public ResponseEntity responseEntity(InvocationContext c1, @RequestAttribute("date") Date date) { HttpHeaders headers = new HttpHeaders(); - headers.add("h1", "h1v " + c1.getContext().get(Const.SRC_MICROSERVICE)); + headers.add("h1", "h1v " + c1.getContext().get(CoreConst.SRC_MICROSERVICE)); InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.add("h2", "h2v " + c2.getContext().get(Const.SRC_MICROSERVICE)); + headers.add("h2", "h2v " + c2.getContext().get(CoreConst.SRC_MICROSERVICE)); return new ResponseEntity<>(date, headers, HttpStatus.ACCEPTED); } - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) + @GetMapping(value = "/getAuthorization", produces = {"application/json"}) + public String getAuthorization( + @RequestHeader(value = "test") String test, + @RequestParam(value = "param") String param, + @Parameter(description = "Authorization header", required = true, in = ParameterIn.HEADER, + name = "Authorization") @RequestHeader("Authorization") String authorization) { + return test + param + authorization; + } + + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Date.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) @RequestMapping(path = "/responseEntity", method = RequestMethod.PATCH) public ResponseEntity responseEntityPATCH(InvocationContext c1, @RequestAttribute("date") Date date) { return responseEntity(c1, date); } - @ApiResponse(code = 200, response = User.class, message = "") - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) + // This definition is not correct, response type is not + // same as the actual one. May be not support in future. + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = User.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) @RequestMapping(path = "/cseResponse", method = RequestMethod.GET) public Response cseResponse(InvocationContext c1) { Response response = Response.createSuccess(Status.ACCEPTED, new User()); - Headers headers = response.getHeaders(); - headers.addHeader("h1", "h1v " + c1.getContext().get(Const.SRC_MICROSERVICE)); + response.addHeader("h1", "h1v " + c1.getContext().get(CoreConst.SRC_MICROSERVICE)); + + InvocationContext c2 = ContextUtils.getInvocationContext(); + response.addHeader("h2", "h2v " + c2.getContext().get(CoreConst.SRC_MICROSERVICE)); + + return response; + } + + // This definition is correct, but not supported by highway. + // highway do not support define code other than 200 + @ApiResponse(responseCode = "202", content = @Content(schema = @Schema(implementation = User.class)) + , description = "", + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class)), + @Header(name = "h2", schema = @Schema(implementation = String.class))}) + @RequestMapping(path = "/cseResponseCorrect", method = RequestMethod.GET) + public Response cseResponseCorrect(InvocationContext c1) { + Response response = Response.createSuccess(Status.ACCEPTED, new User()); + response.addHeader("h1", "h1v " + c1.getContext().get(CoreConst.SRC_MICROSERVICE)); InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.addHeader("h2", "h2v " + c2.getContext().get(Const.SRC_MICROSERVICE)); + response.addHeader("h2", "h2v " + c2.getContext().get(CoreConst.SRC_MICROSERVICE)); return response; } @@ -177,11 +210,6 @@ public String textPlain(@RequestBody String body) { return body; } - @RequestMapping(path = "/appXml", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_XML_VALUE) - public JAXBPerson appXml(@RequestBody JAXBPerson person) { - return person; - } - @RequestMapping(path = "/bytes", method = RequestMethod.POST) public byte[] bytes(@RequestBody byte[] input) { input[0] = (byte) (input[0] + 1); @@ -194,7 +222,7 @@ public Date addDate(@RequestAttribute("date") Date date, @QueryParam("seconds") } // this should be ignored as it's hidden - @ApiOperation(value = "", hidden = true, httpMethod = "POST") + @Operation(summary = "", hidden = true, method = "POST") public int add(@RequestParam("a") int a) { return a; } @@ -205,7 +233,7 @@ public int add(@RequestAttribute("a") int a, @RequestAttribute("b") int b) { } @GetMapping(path = "/reduce") - @ApiImplicitParams({@ApiImplicitParam(name = "a", dataType = "integer", format = "int32", paramType = "query")}) + @Parameters({@Parameter(name = "a", schema = @Schema(implementation = int.class), in = ParameterIn.QUERY)}) public int reduce(HttpServletRequest request, @CookieValue(name = "b") int b) { int a = Integer.parseInt(request.getParameter("a")); return a - b; @@ -222,7 +250,8 @@ public Person sayHello(@RequestBody Person user) { public String testRawJsonString(String jsonInput) { Map person; try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); + person = RestObjectMapperFactory.getRestObjectMapper() + .readValue(jsonInput.getBytes(StandardCharsets.UTF_8), Map.class); } catch (Exception e) { e.printStackTrace(); return null; @@ -265,18 +294,19 @@ public boolean isTrue() { @DeleteMapping(path = "/addstring", produces = MediaType.TEXT_PLAIN_VALUE) public String addString(@RequestParam(name = "s") List s) { - String result = ""; + StringBuilder result = new StringBuilder(); for (String x : s) { - result += x; + result.append(x); } - return result; + return result.toString(); } // Using 490, 590 error code, the response type should be CommonExceptionData. Or we need - // complex ExceptionConverters to deal with exceptions thrown by Hanlders, etc. + // complex ExceptionConverters to deal with exceptions thrown by Handlers, etc. @RequestMapping(path = "/fallback/returnnull/{name}", method = RequestMethod.GET) - @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, message = "xxx"), - @ApiResponse(code = 490, response = CommonExceptionData.class, message = "xxx")}) + @ApiResponses(value = {@ApiResponse(responseCode = "200", + content = @Content(schema = @Schema(implementation = String.class)), description = "xxx"), + @ApiResponse(responseCode = "490", content = @Content(schema = @Schema(implementation = CommonExceptionData.class)), description = "xxx")}) public String fallbackReturnNull(@PathVariable(name = "name") String name) { if ("throwexception".equals(name)) { throw new InvocationException(490, "490", new CommonExceptionData("xxx")); @@ -285,8 +315,11 @@ public String fallbackReturnNull(@PathVariable(name = "name") String name) { } @RequestMapping(path = "/fallback/throwexception/{name}", method = RequestMethod.GET) - @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, message = "xxx"), - @ApiResponse(code = 490, response = CommonExceptionData.class, message = "xxx")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)) + , description = "xxx"), + @ApiResponse(responseCode = "490", content = @Content(schema = @Schema(implementation = CommonExceptionData.class)) + , description = "xxx")}) public String fallbackThrowException(@PathVariable(name = "name") String name) { if ("throwexception".equals(name)) { throw new InvocationException(490, "490", new CommonExceptionData("xxx")); @@ -295,8 +328,11 @@ public String fallbackThrowException(@PathVariable(name = "name") String name) { } @RequestMapping(path = "/fallback/fromcache/{name}", method = RequestMethod.GET) - @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, message = "xxx"), - @ApiResponse(code = 490, response = CommonExceptionData.class, message = "xxx")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)) + , description = "xxx"), + @ApiResponse(responseCode = "490", content = @Content(schema = @Schema(implementation = CommonExceptionData.class)) + , description = "xxx")}) public String fallbackFromCache(@PathVariable(name = "name") String name) { if ("throwexception".equals(name)) { throw new InvocationException(490, "490", new CommonExceptionData("xxx")); @@ -305,8 +341,11 @@ public String fallbackFromCache(@PathVariable(name = "name") String name) { } @RequestMapping(path = "/fallback/force/{name}", method = RequestMethod.GET) - @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, message = "xxx"), - @ApiResponse(code = 490, response = CommonExceptionData.class, message = "xxx")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)) + , description = "xxx"), + @ApiResponse(responseCode = "490", content = @Content(schema = @Schema(implementation = CommonExceptionData.class)) + , description = "xxx")}) public String fallbackForce(@PathVariable(name = "name") String name) { if ("throwexception".equals(name)) { throw new InvocationException(490, "490", new CommonExceptionData("xxx")); @@ -314,14 +353,17 @@ public String fallbackForce(@PathVariable(name = "name") String name) { return name; } - enum NameType { + public enum NameType { abc, def } @RequestMapping(path = "/testenum/{name}", method = RequestMethod.GET) - @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, message = "200 normal"), - @ApiResponse(code = 490, response = CommonExceptionData.class, message = "490 exception")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)) + , description = "xxx"), + @ApiResponse(responseCode = "490", content = @Content(schema = @Schema(implementation = CommonExceptionData.class)) + , description = "xxx")}) public String testEnum(@RequestParam(name = "username") String username, @PathVariable(value = "name") NameType nameType) { return nameType.toString(); @@ -342,7 +384,8 @@ public OutputModelForTestIgnore testModelWithIgnoreField(@RequestBody InputModel public String testRawJsonAnnotation(@RawJsonRequestBody String jsonInput) { Map person; try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); + person = RestObjectMapperFactory.getRestObjectMapper() + .readValue(jsonInput.getBytes(StandardCharsets.UTF_8), Map.class); } catch (Exception e) { e.printStackTrace(); return null; @@ -351,11 +394,13 @@ public String testRawJsonAnnotation(@RawJsonRequestBody String jsonInput) { } @PostMapping(path = "/testform") - @ApiImplicitParams({ - @ApiImplicitParam(name = "form1", dataType = "string", paramType = "form", value = "a required form param", - required = true), - @ApiImplicitParam(name = "form2", dataType = "string", paramType = "form", value = "an optional form param", - required = false)}) + @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = {@Content(mediaType = SwaggerConst.FORM_MEDIA_TYPE, + schema = @Schema(name = "form1", implementation = String.class, + nullable = false, description = "a required form param")), + @Content(mediaType = SwaggerConst.FORM_MEDIA_TYPE, + schema = @Schema(name = "form2", implementation = String.class, + nullable = true, description = "an optional form param"))}) public String testform(HttpServletRequest request) { String form1 = request.getParameter("form1"); String form2 = request.getParameter("form2"); @@ -363,7 +408,7 @@ public String testform(HttpServletRequest request) { return form1 + form2; } - @Inject + @Autowired MetricsBootListener metricsBootListener; //Only for Prometheus integration test @@ -378,7 +423,7 @@ public String prometheusForTest() { @GetMapping(path = "/traceId") public String getTraceId() { - return ContextUtils.getInvocationContext().getContext(Const.TRACE_ID_NAME); + return ContextUtils.getInvocationContext().getContext(CoreConst.TRACE_ID_NAME); } @PostMapping(path = "/emptyObject") @@ -450,7 +495,7 @@ public Generic> testGenericGenericUser(@RequestBody Generic requestBody, - GenericParamWithJsonIgnore generic, String str) { + GenericParamWithJsonIgnore generic) { LOGGER.info("checkQueryGenericObject() is called!"); - return "str=" + str + ",generic=" + generic + ",requestBody=" + requestBody; + return "str=" + generic.getStr() + ",generic=" + generic + ",requestBody=" + requestBody; } /** @@ -518,10 +563,10 @@ public String checkQueryGenericObject(@RequestBody GenericParam requestB * The same for those simple type field inherited from the parent class. */ @PutMapping(path = "/checkQueryGenericString") - public String checkQueryGenericString(String str, @RequestBody GenericParam requestBody, + public String checkQueryGenericString(@RequestBody GenericParam requestBody, GenericParamExtended generic) { LOGGER.info("checkQueryGenericObject() is called!"); - return "str=" + str + ",generic=" + generic + ",requestBody=" + requestBody; + return "str=" + generic.getStr() + ",generic=" + generic + ",requestBody=" + requestBody; } @GetMapping(path = "/testDelay") @@ -542,4 +587,14 @@ public DecodeTestResponse testDecodeResponseError() { response.setContent("returnOK"); return response; } + + @RequestMapping(path = "/testDefaultGetApiExample") + public void testDefaultGetApiExample() { + LOGGER.info("testDefaultGetApiExample() is called!"); + } + + @RequestMapping(path = "/testHolder") + public void testHolder(@RequestBody Holder name) { + LOGGER.info("testDefaultGetApiExample() is called!"); + } } diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvcForSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvcForSchema.java index fd5ddcecf28..7b5c7e4f30b 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvcForSchema.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvcForSchema.java @@ -32,7 +32,7 @@ * only checksum is validated to make sure schema is not changed. */ @RestSchema(schemaId = "CodeFirstSpringmvcForSchema") -@RequestMapping(path = "/forScheam") +@RequestMapping(path = "/forSchema") public class CodeFirstSpringmvcForSchema { /* * Using http://editor.swagger.io/ . Listing errors not handled: diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/Compatible1xTestSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/Compatible1xTestSchema.java new file mode 100644 index 00000000000..41f034dfcab --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/Compatible1xTestSchema.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +import jakarta.ws.rs.core.MediaType; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "Compatible1xTestSchema") +@RequestMapping(path = "/compatible", produces = MediaType.APPLICATION_JSON) +public class Compatible1xTestSchema { + @GetMapping(path = "/parameterName") + public String parameterName(@RequestParam(name = "a", defaultValue = "10") int a, + @RequestParam(name = "b", defaultValue = "10") int b) { + return ContextUtils.getInvocationContext().getContext(CoreConst.SRC_MICROSERVICE) + a + b * 2; + } + + @GetMapping(path = "/parameterNameServerContext") + public String parameterNameServerContext(InvocationContext context, + @RequestParam(name = "a", defaultValue = "10") int a, + @RequestParam(name = "b", defaultValue = "10") int b) { + return context.getContext(CoreConst.SRC_MICROSERVICE) + a + b * 2; + } + + @GetMapping(path = "/beanParameter") + public String beanParameter(CompatibleQueryBean bean) { + return bean.getName() + bean.getAge(); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CompatibleQueryBean.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CompatibleQueryBean.java new file mode 100644 index 00000000000..65135037278 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CompatibleQueryBean.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +public class CompatibleQueryBean { + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ConfigurationProblemsCollectorTest.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ConfigurationProblemsCollectorTest.java new file mode 100644 index 00000000000..7f020450d4e --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ConfigurationProblemsCollectorTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.core.bootup.ConfigurationProblemsAlarmEvent; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.springframework.stereotype.Component; + +import com.google.common.eventbus.Subscribe; + +@Component +public class ConfigurationProblemsCollectorTest implements CategorizedTestCase { + private ConfigurationProblemsAlarmEvent event; + + public ConfigurationProblemsCollectorTest() { + EventManager.register(this); + } + + @Subscribe + public void onConfigurationProblemsAlarmEvent(ConfigurationProblemsAlarmEvent event) { + this.event = event; + } + + @Override + public void testRestTransport() throws Exception { + TestMgr.check(event != null, true); + TestMgr.check(event.getProblems(), "[WARN]Configurations warnings:\n" + + "Configurations with prefix `service_description` is deprecated, " + + "use `servicecomb.service` instead. Find keys [service_description.initialStatus]\n" + + "Configuration `servicecomb.loadbalance.isolation.*` is removed, use governance instead. " + + "See https://servicecomb.apache.org/references/java-chassis/zh_CN/references-handlers/governance-best-practise.html"); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java index 94281caeae0..14bc6e78f73 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java @@ -17,20 +17,20 @@ package org.apache.servicecomb.demo.springmvc.server; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.MediaType; +import java.util.Arrays; +import org.apache.servicecomb.demo.server.User; import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.core.MediaType; @RestSchema(schemaId = "contentTypeSpringmvc") -@RequestMapping("/contentTypeSpringmvc") -@Api(consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_PLAIN) +@RequestMapping(value = "/contentTypeSpringmvc", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_PLAIN) public class ContentTypeSpringmvc { @RequestMapping(path = "/testGlobalSetting", method = RequestMethod.POST) public String testGlobalSetting(@RequestBody String name, HttpServletRequest request) { @@ -38,7 +38,6 @@ public String testGlobalSetting(@RequestBody String name, HttpServletRequest req } @RequestMapping(path = "/testApiOperation", method = RequestMethod.POST) - @ApiOperation(value = "testApiOperation desc", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) public String testApiOperation(@RequestBody String name, HttpServletRequest request) { return String.format("testApiOperation: name=[%s], request content-type=[%s]", name, request.getContentType()); } @@ -48,4 +47,12 @@ public String testApiOperation(@RequestBody String name, HttpServletRequest requ public String testRequestMapping(@RequestBody String name, HttpServletRequest request) { return String.format("testRequestMapping: name=[%s], request content-type=[%s]", name, request.getContentType()); } + + @RequestMapping(path = "/testProtoBuffer", method = RequestMethod.POST, + consumes = SwaggerConst.PROTOBUF_TYPE, produces = SwaggerConst.PROTOBUF_TYPE) + public String testProtoBuffer(@RequestBody User user, HttpServletRequest request) { + return String.format("testRequestMapping: name=[%s], request content-type=[%s]", + user.getName() + ":" + user.getIndex() + ":" + + Arrays.toString(user.getNames()), request.getContentType()); + } } diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvcOverwrite.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvcOverwrite.java index 74b2d132737..e690512bd2a 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvcOverwrite.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvcOverwrite.java @@ -17,17 +17,14 @@ package org.apache.servicecomb.demo.springmvc.server; -import javax.ws.rs.core.MediaType; - import org.apache.servicecomb.provider.rest.common.RestSchema; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.annotations.Api; +import jakarta.ws.rs.core.MediaType; @RestSchema(schemaId = "contentTypeSpringmvcOverwrite") @RequestMapping(value = "/contentTypeSpringmvcOverwrite", produces = MediaType.TEXT_PLAIN) -@Api(produces = MediaType.APPLICATION_JSON) public class ContentTypeSpringmvcOverwrite { @RequestMapping(value = "/testResponseTypeOverwrite", method = RequestMethod.GET) public String testResponseTypeOverwrite() { diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ControllerImpl.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ControllerImpl.java index 46adbe68f10..3d49ba734fc 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ControllerImpl.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ControllerImpl.java @@ -19,13 +19,11 @@ import java.util.Arrays; -import javax.servlet.http.HttpServletRequest; -import javax.validation.constraints.Min; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; - +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; import org.apache.servicecomb.demo.controller.Person; import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -36,6 +34,13 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; + +// This class tests "contract first", the controller.yaml will override annotations defined in class. + @RestSchema(schemaId = "controller") @RequestMapping(path = "/springmvc/controller", produces = MediaType.APPLICATION_JSON) public class ControllerImpl { @@ -57,6 +62,7 @@ public String saySomething(String prefix, @RequestBody Person user) { return prefix + " " + user.getName(); } + @Transport(name = CoreConst.RESTFUL) @RequestMapping(path = "/sayhi", method = RequestMethod.GET) public String sayHi(HttpServletRequest request) throws Exception { String addr = request.getRemoteAddr(); @@ -74,4 +80,16 @@ public String sayHi(HttpServletRequest request) throws Exception { public String sayHei(@RequestHeader("name") String name) { return "hei " + name; } + + @RequestMapping(path = "/sayHello1", method = RequestMethod.GET) + public String sayHello1(@RequestParam("name") String name) { + return "Hello " + name + "," + ContextUtils.getInvocationContext().getContext("k"); + } + + @RequestMapping(path = "/testResponseModel", method = RequestMethod.GET) + public Person testResponseModel() { + Person person = new Person(); + person.setName("jack"); + return person; + } } diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DataTypesAnnotationsSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DataTypesAnnotationsSchema.java new file mode 100644 index 00000000000..21077009ccf --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DataTypesAnnotationsSchema.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "DataTypesAnnotationsSchema") +@RequestMapping(path = "/dataTypes") +public class DataTypesAnnotationsSchema { + @GetMapping(path = "/testIntArrayQuery") + public int[] testIntArrayQuery(@RequestParam("param") int[] param) { + return param; + } + + @GetMapping(path = "/testIntegerArrayQuery") + public Integer[] testIntegerArrayQuery(@RequestParam("param") Integer[] param) { + return param; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DateTimeSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DateTimeSchema.java new file mode 100644 index 00000000000..4dfdba44ba0 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DateTimeSchema.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Date; + +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.MediaType; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "DateTimeSchema") +@RequestMapping(path = "/dateTime", produces = MediaType.APPLICATION_JSON) +public class DateTimeSchema { + @GetMapping(path = "/getDate") + public Date getDate(@RequestParam("date") Date date) { + return date; + } + + @GetMapping(path = "/getDatePath/{date}") + public Date getDatePath(@PathParam("date") Date date) { + return date; + } + + @PostMapping(path = "/postDate") + public Date postDate(@RequestBody Date date) { + return date; + } + + @GetMapping(path = "/getLocalDate") + public LocalDate getLocalDate(@RequestParam("date") LocalDate date) { + return date; + } + + @GetMapping(path = "/getLocalDate/{date}") + public LocalDate getLocalDatePath(@PathParam("date") LocalDate date) { + return date; + } + + @PostMapping(path = "/postLocalDate") + public LocalDate postLocalDate(@RequestBody LocalDate date) { + return date; + } + + @GetMapping(path = "/getLocalDateTime") + public LocalDateTime getLocalDateTime(@RequestParam("date") LocalDateTime date) { + return date; + } + + @GetMapping(path = "/getLocalDateTime/{date}") + public LocalDateTime getLocalDateTimePath(@PathParam("date") LocalDateTime date) { + return date; + } + + @PostMapping(path = "/postLocalDateTime") + public LocalDateTime postLocalDateTime(@RequestBody LocalDateTime date) { + return date; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DownloadSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DownloadSchema.java new file mode 100644 index 00000000000..d73824f1ffc --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/DownloadSchema.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.part.FilePart; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.servlet.http.Part; + +@RestSchema(schemaId = "DownloadSchema") +@RequestMapping(path = "/download", produces = MediaType.APPLICATION_JSON_VALUE) +public class DownloadSchema { + private File tempDir = new File("target/downloadTemp"); + + private File lastFile; + + private File createTempFile(String content) throws IOException { + return createTempFile(null, content); + } + + private File createTempFile(String name, String content) throws IOException { + if (name == null) { + name = "download-" + UUID.randomUUID() + ".txt"; + } + File file = new File(tempDir, name); + FileUtils.write(file, content, StandardCharsets.UTF_8, false); + lastFile = file; + return file; + } + + @GetMapping(path = "/deleteAfterFinished") + public ResponseEntity deleteAfterFinished(@RequestParam("content") String content, + @RequestParam(value = "fileName", required = false) String fileName) throws IOException { + File file; + + if (StringUtils.isNotEmpty(fileName)) { + file = createTempFile(fileName, content); + } else { + file = createTempFile(content); + } + + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(new FilePart(null, file) + .setDeleteAfterFinished(true)); + } + + @GetMapping(path = "/partIsNull") + public ResponseEntity partIsNull(@RequestParam("content") String content) throws IOException { + if (StringUtils.isEmpty(content)) { + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(null); + } + File file = createTempFile(content); + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(new FilePart(null, file)); + } + + @GetMapping(path = "/notDeleteAfterFinished") + public ResponseEntity notDeleteAfterFinished(@RequestParam("content") String content) throws IOException { + File file = createTempFile(content); + + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(new FilePart(null, file)); + } + + @GetMapping(path = "/setContentTypeByResponseEntity") + public ResponseEntity setContentTypeByResponseEntity(@RequestParam("content") String content, + @RequestParam("contentType") String contentType) throws IOException { + File file = createTempFile(content); + + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_TYPE, contentType) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(new FilePart(null, file)); + } + + @GetMapping(path = "/assertLastFileDeleted") + public boolean assertLastFileDeleted() { + return lastFile.exists(); + } + + @GetMapping(path = "/testResponseOKExceptionDownload") + public ResponseEntity testResponseOKExceptionDownload( + @RequestParam("exception") boolean exception, + @RequestParam("content") String content, + @RequestParam("contentType") String contentType) throws IOException { + if (exception) { + throw new ResponseOKException(); + } + + File file = createTempFile(content); + + return ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_TYPE, contentType) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") + .body(new FilePart(null, file)); + } + + @GetMapping(path = "/testResponseOKExceptionBean") + public boolean testResponseOKExceptionBean(@RequestParam("exception") boolean exception) { + if (exception) { + throw new ResponseOKException(); + } + return true; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategy.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategy.java new file mode 100644 index 00000000000..1f6544863fb --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategy.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.qps.strategy.AbstractQpsStrategy; + +public class MyStrategy extends AbstractQpsStrategy { + + @Override + public boolean isLimitNewRequest() { + return false; + } + + @Override + public String name() { + return "MyStrategy"; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategyFactory.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategyFactory.java new file mode 100644 index 00000000000..002aa95a6d8 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/MyStrategyFactory.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.qps.strategy.AbstractQpsStrategy; +import org.apache.servicecomb.qps.strategy.IStrategyFactory; + +public class MyStrategyFactory implements IStrategyFactory { + + @Override + public AbstractQpsStrategy createStrategy(String strategyName) { + if (strategyName.equals("MyStrategy")) { + return new MyStrategy(); + } + return null; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java index 6023d1dd94f..ddf56fb5a3f 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java @@ -18,20 +18,19 @@ package org.apache.servicecomb.demo.springmvc.server; import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; import org.apache.servicecomb.demo.TestMgr; -import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectWriter; -import io.swagger.models.Swagger; -import io.swagger.util.Yaml; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; /** * Testing after bootup. @@ -42,27 +41,22 @@ public class ProducerTestsAfterBootup implements BootListener { private ObjectWriter writer = Yaml.pretty(); - @Autowired - private ProducerSchemaFactory factory; - - public void testSchemaNotChange() { + public void testSchemaNotChange(SCBEngine scbEngine) { LOGGER.info("ProducerTestsAfterBootup testing start"); - //we can not set microserviceName any more - SchemaMeta meta = - factory.getOrCreateProducerSchema("test1", - CodeFirstSpringmvcForSchema.class, - new CodeFirstSpringmvcForSchema()); + SchemaMeta meta = scbEngine.getProducerMicroserviceMeta().findSchemaMeta("CodeFirstSpringmvcForSchema"); String codeFirst = getSwaggerContent(meta.getSwagger()); - TestMgr.check("2986daa46b229ec125443122dd7b51ee9a64879f1750d0996f948ce0718685c7", - RegistryUtils.calcSchemaSummary(codeFirst)); - TestMgr.check(codeFirst.length(), 889); - } - public void testRegisteredBasePath() { - TestMgr.check(12, RegistryUtils.getMicroservice().getPaths().size()); + String expectSchema = UnitTestSwaggerUtils.loadExpect("schemas/CodeFirstSpringmvcForSchema.yaml") + .replace("\r\n", "\n").trim(); + int offset = expectSchema.indexOf("---\nopenapi: 3.0.1"); + if (offset > 0) { + expectSchema = expectSchema.substring(offset + 4); + } + + TestMgr.check(expectSchema.trim(), codeFirst.trim()); } - private String getSwaggerContent(Swagger swagger) { + private String getSwaggerContent(OpenAPI swagger) { try { return writer.writeValueAsString(swagger); } catch (JsonProcessingException e) { @@ -73,8 +67,7 @@ private String getSwaggerContent(Swagger swagger) { @Override public void onBootEvent(BootEvent event) { if (event.getEventType() == BootListener.EventType.AFTER_REGISTRY) { - testSchemaNotChange(); - testRegisteredBasePath(); + testSchemaNotChange(event.getScbEngine()); if (!TestMgr.isSuccess()) { TestMgr.summary(); throw new IllegalStateException("some tests are failed. "); @@ -82,4 +75,3 @@ public void onBootEvent(BootEvent event) { } } } - diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ReadFileSource.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ReadFileSource.java new file mode 100644 index 00000000000..77d78324666 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ReadFileSource.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "testFileSource") +@RequestMapping(path = "/springmvc/fileSource") +public class ReadFileSource { + @Value("${int:-1}") + public int testInt; + + @GetMapping(path = "/int") + public int getTestInt() { + return testInt; + } + + @Value("${String:error}") + public String testString; + + @GetMapping(path = "/String") + public String getTestString() { + return testString; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKData.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKData.java new file mode 100644 index 00000000000..aeadbbeda90 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKData.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +public class ResponseOKData { + private String errorCode; + + private String errorMessage; + + public ResponseOKData(String errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKException.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKException.java new file mode 100644 index 00000000000..6dcafb2db99 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKException.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +public class ResponseOKException extends RuntimeException { +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKExceptionConverter.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKExceptionConverter.java new file mode 100644 index 00000000000..7358b72171c --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ResponseOKExceptionConverter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.ExceptionConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; + +public class ResponseOKExceptionConverter implements + ExceptionConverter { + + @Override + public boolean canConvert(Throwable throwable) { + return throwable instanceof ResponseOKException; + } + + @Override + public InvocationException convert(Invocation invocation, ResponseOKException throwable, StatusType genericStatus) { + // This is for compatible usage. For best practise, any status code + // should have only one type of response. + return new InvocationException(Status.OK, new ResponseOKData("code-005", "error-005")); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RestProducersCustomized.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RestProducersCustomized.java new file mode 100644 index 00000000000..a3858541825 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RestProducersCustomized.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.provider.rest.common.RestProducers; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +@Component +@Primary +// This example shows user's how to customize RestProducers by @Primary annotation +public class RestProducersCustomized extends RestProducers { +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RetrySchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RetrySchema.java new file mode 100644 index 00000000000..b3a32b34020 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/RetrySchema.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.springmvc.server; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +// test cases for retry +@RestSchema(schemaId = "RetrySchema") +@RequestMapping(path = "/retry", produces = MediaType.APPLICATION_JSON_VALUE) +public class RetrySchema { + private AtomicLong counter = new AtomicLong(0); + + @GetMapping(path = "/governance/successWhenRetry") + public boolean successWhenRetry() { + if (counter.getAndIncrement() % 3 != 0) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later."); + } + return true; + } + + @GetMapping(path = "/governance/successWhenRetryAsync") + public CompletableFuture successWhenRetryAsync() { + CompletableFuture result = new CompletableFuture<>(); + if (counter.getAndIncrement() % 2 == 0) { + result.completeExceptionally(new InvocationException(Status.INTERNAL_SERVER_ERROR, "try again later.")); + } else { + result.complete(true); + } + return result; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvc.java new file mode 100644 index 00000000000..8d4b02e85b5 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvc.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.core.MediaType; + +@RequestMapping(path = "/springmvc/schemaInterface", produces = MediaType.APPLICATION_JSON) +public interface SchemeInterfaceSpringmvc { + @GetMapping(path = "/add") + int add(@Min(1) @RequestParam("a") int a, @Min(1) @RequestParam("b") int b); + + @GetMapping(path = "/tailingSlash/") + String tailingSlash(HttpServletRequest request, @Min(1) @RequestParam("a") int a, @Min(1) @RequestParam("b") int b); + + @GetMapping(path = "/nonTailingSlash") + String nonTailingSlash(HttpServletRequest request, @Min(1) @RequestParam("a") int a, @Min(1) @RequestParam("b") int b); +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvcImpl.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvcImpl.java new file mode 100644 index 00000000000..828a9fc160d --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SchemeInterfaceSpringmvcImpl.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.Min; + +@RestSchema(schemaId = "SchemeInterfaceSpringmvc", schemaInterface = SchemeInterfaceSpringmvc.class) +public class SchemeInterfaceSpringmvcImpl implements SchemeInterfaceSpringmvc { + @Override + public int add(@Min(1) int a, @Min(1) int b) { + return a + b; + } + + @Override + public String tailingSlash(HttpServletRequest request, int a, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(request.getRequestURI()).append(";") + .append(request.getRequestURL()).append(";") + .append(request.getPathInfo()).append(";") + .append(a - b); + return sb.toString(); + } + + @Override + public String nonTailingSlash(HttpServletRequest request, int a, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(request.getRequestURI()).append(";") + .append(request.getRequestURL()).append(";") + .append(request.getPathInfo()).append(";") + .append(a - b); + return sb.toString(); + } + + public int reduce(int a, int b) { + return a - b; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMVCCommonSchemaInterface.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMVCCommonSchemaInterface.java new file mode 100644 index 00000000000..1bd1abba2e3 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMVCCommonSchemaInterface.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.demo.CommonSchemaInterface; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +@RestSchema(schemaId = "SpringMVCCommonSchemaInterface", schemaInterface = CommonSchemaInterface.class) +public class SpringMVCCommonSchemaInterface implements CommonSchemaInterface { + @Override + public String testInvocationTimeout(long timeout, String name) { + try { + Thread.sleep(timeout); + } catch (InterruptedException e) { + + } + + return name; + } + + @Override + public String testInvocationTimeout(InvocationContext context, long timeout, + String name) { + + if ("customized".equals(name)) { + try { + Thread.sleep(timeout); + } catch (InterruptedException e) { + + } + + Invocation invocation = (Invocation) context; + invocation.ensureInvocationNotTimeout(); + + throw new InvocationException(Status.BAD_REQUEST, "not expected result"); + } + + return testInvocationTimeout(timeout, name); + } + + @Override + public String testInvocationTimeoutInClientWait(long timeout, String name) { + return testInvocationTimeout(timeout, name); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java index 3e915096205..a30b9ad84d3 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java @@ -16,9 +16,9 @@ */ package org.apache.servicecomb.demo.springmvc.server; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.ws.rs.core.MediaType; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.springframework.web.bind.annotation.GetMapping; diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringmvcServer.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringmvcServer.java deleted file mode 100644 index 12af40c09c0..00000000000 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringmvcServer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.server; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class SpringmvcServer { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TransportSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TransportSchema.java new file mode 100644 index 00000000000..158cd806188 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/TransportSchema.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "TransportSchema") +@RequestMapping(path = "/transport") +public class TransportSchema { + @GetMapping(path = "/restTransport") + @Transport(name = CoreConst.RESTFUL) + public boolean restTransport(InvocationContext invocation) { + return CoreConst.RESTFUL.equals(((Invocation) invocation).getTransportName()); + } + + @GetMapping(path = "/highwayTransport") + @Transport(name = CoreConst.HIGHWAY) + public boolean highwayTransport(InvocationContext invocation) { + return CoreConst.HIGHWAY.equals(((Invocation) invocation).getTransportName()); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java new file mode 100644 index 00000000000..1a3a737d592 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/UploadSchema.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +@RestSchema(schemaId = "UploadSchema") +@RequestMapping(path = "/upload", produces = MediaType.APPLICATION_JSON_VALUE) +public class UploadSchema { + @PostMapping(path = "/fileUpload", produces = MediaType.TEXT_PLAIN_VALUE, + consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public String fileUpload(@RequestPart(name = "files") List files) { + try { + String fileName = UUID.randomUUID().toString(); + List savedFiles = new ArrayList<>(); + int index = 0; + for (MultipartFile file : files) { + File tempFile = new File("random-server-" + fileName + index); + savedFiles.add(tempFile); + file.transferTo(tempFile); + index++; + } + savedFiles.forEach(File::delete); + return "success"; + } catch (IOException e) { + return "failed"; + } + } + + @GetMapping(path = "/isServerStartUpSuccess") + public boolean isServerStartUpSuccess() { + return TestMgr.isSuccess(); + } + + @PostMapping(path = "/fileUploadMultiRpc", produces = MediaType.TEXT_PLAIN_VALUE, + consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public String fileUploadMultiRpc(@RequestPart(name = "files") MultipartFile[] files) { + return "fileUploadMulti success, and fileNum is " + files.length; + } + + @PostMapping(path = "/uploadFileRequestPartAttribute", produces = MediaType.TEXT_PLAIN_VALUE) + public String uploadFileRequestPartAttribute(@RequestPart(name = "file") MultipartFile file, + @RequestPart(name = "attribute") String attribute) throws IOException { + try (InputStream is = file.getInputStream()) { + return attribute + " " + IOUtils.toString(is, StandardCharsets.UTF_8); + } + } + + @PostMapping(path = "/uploadFileRequestPartAttributeList", produces = MediaType.TEXT_PLAIN_VALUE) + public String uploadFileRequestPartAttributeList(@RequestPart(name = "files") List files, + @RequestPart(name = "attributes") List attributes) throws IOException { + StringBuilder result = new StringBuilder(); + for (MultipartFile file : files) { + try (InputStream is = file.getInputStream()) { + result.append(IOUtils.toString(is, StandardCharsets.UTF_8)); + } + } + for (String attribute : attributes) { + result.append(attribute); + } + return result.toString(); + } + + @PostMapping(path = "/uploadFileAndAttribute", produces = MediaType.TEXT_PLAIN_VALUE) + public String uploadFileAndAttribute(@RequestPart(name = "file") MultipartFile file, + @RequestAttribute(name = "attribute") String attribute) throws IOException { + try (InputStream is = file.getInputStream()) { + return attribute + " " + IOUtils.toString(is, StandardCharsets.UTF_8); + } + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/WeakSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/WeakSpringmvc.java new file mode 100644 index 00000000000..b9d6a119817 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/WeakSpringmvc.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.server; + +import java.util.List; + +import org.apache.servicecomb.demo.model.SpecialNameModel; +import org.apache.servicecomb.demo.server.GenericsModel; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.Operation; + +@RestSchema(schemaId = "weakSpringmvc") +@RequestMapping(path = "/weakSpringmvc", produces = MediaType.APPLICATION_JSON_VALUE) +public class WeakSpringmvc { + @GetMapping(path = "/diffNames") + @Operation(summary = "differentName", operationId = "differentName") + public int diffNames(@RequestParam("x") int a, @RequestParam("y") int b) { + return a * 2 + b; + } + + @GetMapping(path = "/genericParams") + @Operation(summary = "genericParams", operationId = "genericParams") + public List> genericParams(@RequestParam("code") int code, @RequestBody List> names) { + return names; + } + + @GetMapping(path = "/genericParamsModel") + @Operation(summary = "genericParamsModel", operationId = "genericParamsModel") + public GenericsModel genericParamsModel(@RequestParam("code") int code, @RequestBody GenericsModel model) { + return model; + } + + @GetMapping(path = "/specialNameModel") + @Operation(summary = "specialNameModel", operationId = "specialNameModel") + public SpecialNameModel specialNameModel(@RequestParam("code") int code, @RequestBody SpecialNameModel model) { + return model; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/EarlyConsumer.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/EarlyConsumer.java new file mode 100644 index 00000000000..79b89668560 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/EarlyConsumer.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.third; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * see: https://github.com/apache/servicecomb-java-chassis/issues/2534 + */ +@Component +public class EarlyConsumer implements BootListener { + private static final Logger LOGGER = LoggerFactory.getLogger(EarlyConsumer.class); + + @RpcReference(microserviceName = "third", schemaId = "heartbeat") + private HealthSchema healthSchema; + + private volatile boolean stopped = false; + + public EarlyConsumer() { + new Thread(() -> { + while (!stopped) { + LOGGER.info("calling service"); + try { + healthSchema.heartbeat(); + } catch (Throwable e) { + // ignore error + } + try { + Thread.sleep(500); + } catch (Throwable e) { + // ignore error + } + } + }).start(); + } + + @Override + public void onAfterRegistry(BootEvent event) { + stopped = true; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HealthSchema.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HealthSchema.java new file mode 100644 index 00000000000..eab4a09e89b --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HealthSchema.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.third; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping("/v1") +public interface HealthSchema { + @GetMapping(value = "/heartbeat") + void heartbeat(); +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HeartBeatService.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HeartBeatService.java new file mode 100644 index 00000000000..d01b2103343 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/HeartBeatService.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.third; + +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "health", schemaInterface = HealthSchema.class) +public class HeartBeatService implements HealthSchema { + @Override + public void heartbeat() { + + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/NormalConsumer.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/NormalConsumer.java new file mode 100644 index 00000000000..b9bd2daa7c6 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/NormalConsumer.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.third; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * see: https://github.com/apache/servicecomb-java-chassis/issues/2534 + */ +@Component +public class NormalConsumer implements BootListener { + private static final Logger LOGGER = LoggerFactory.getLogger(NormalConsumer.class); + + @RpcReference(microserviceName = "third", schemaId = "heartbeat") + private HealthSchema healthSchema; + + @Override + public void onAfterRegistry(BootListener.BootEvent event) { + try { + LOGGER.info("calling service after register"); + + healthSchema.heartbeat(); + LOGGER.info("heartbeat succ"); + } catch (Throwable e) { + TestMgr.failed("3rd invoke failed", e); + throw e; + } + } + + + @Override + public int getOrder() { + // 比ThirdServiceRegister晚 + return 0; + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/Register.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/Register.java new file mode 100644 index 00000000000..cc9144fe617 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/third/Register.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.springmvc.third; + +import java.util.List; + +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +/** + * see: https://github.com/apache/servicecomb-java-chassis/issues/2534 + */ +@Configuration +public class Register { + @Autowired + Environment environment; + + @Bean + public RegistryBean thirdRegistryBean() { + String endpoint; + if (environment.getProperty("servicecomb.test.vert.transport", boolean.class, true)) { + endpoint = "rest://localhost:8080?sslEnabled=false&urlPrefix=%2Fapi"; + } else { + endpoint = "rest://localhost:8080?sslEnabled=false"; + } + + return new RegistryBean().addSchemaInterface("heartbeat", HealthSchema.class) + .setAppId("springmvctest") + .setServiceName("third") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of(new Instance().setEndpoints(List.of(endpoint))))); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter b/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter new file mode 100644 index 00000000000..f25ea28e1c1 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.core.exception.ExceptionConverter @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.demo.springmvc.server.ResponseOKExceptionConverter diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory b/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory new file mode 100644 index 00000000000..f1941bac9de --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.demo.springmvc.server.MyStrategyFactory diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/config/log4j.properties b/demo/demo-springmvc/springmvc-server/src/main/resources/config/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/demo/demo-springmvc/springmvc-server/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/log4j2.xml b/demo/demo-springmvc/springmvc-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml index 393dc525755..c5c10c5b41b 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml +++ b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml @@ -15,53 +15,56 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -APPLICATION_ID: springmvctest +# test not supported configuration +# service_description.initialStatus service_description: - name: springmvc - version: 0.0.3 - paths: - - path: /test1/testpath - property: - checksession: false - - path: /test2/testpath - property: - checksession: true + initialStatus: TESTING + servicecomb: - microserviceVersionFactory: org.apache.servicecomb.core.definition.PrivateMicroserviceVersionMetaFactory service: - registry: - registerPath: true - address: http://127.0.0.1:30100 - client: - timeout: - idle: 60 - watch: 60 - instance: - healthCheck: - interval: 3 - pull: - interval: 10 - watch: false + application: springmvctest + name: springmvc + version: 0.0.3 + + registry: + sc: + address: http://127.0.0.1:9980,http://127.0.0.1:30100 autodiscovery: true - # can download config center from https://cse-bucket.obs.myhwclouds.com/LocalCSE/Local-CSE-1.0.0.zip to test dynamic config - config: - client: - serverUri: http://127.0.0.1:30113 - refreshMode: 0 - refresh_interval: 5000 - refreshPort: 30114 + healthCheckIntervalInSeconds: 3 + pollIntervalInMillis: 10000 + watch: true + uploads: directory: target + http: + dispatcher: + rest: + pattern: "/api/(.*)" rest: - address: 0.0.0.0:8082?sslEnabled=true + address: 0.0.0.0:8080?sslEnabled=false server: compression: true highway: - address: 0.0.0.0:7072?sslEnabled=true - handler: - chain: - Provider: - default: bizkeeper-provider + address: 0.0.0.0:7070?sslEnabled=true + invocation: + timeout: + check: + enabled: true + strategy: processing-time + SpringMVCCommonSchemaInterface: + testInvocationTimeout: + timeout: 1000 + testInvocationTimeoutWithInvocation: + timeout: 1000 + + flowcontrol: + strategy: MyStrategy + Provider: + qps: + enabled: true + global: + limit: 10 + bucket: 30 tracing: enabled: true samplingRate: 0.5 @@ -69,7 +72,16 @@ servicecomb: name: myDC region: my-Region availableZone: my-Zone + codec.printErrorMessage: true + + # For old testing + loadbalance: + isolation: + errorThresholdPercentage: 20 #########SSL options +# open jdk 8 now TLSv1.3 not available +# ssl.protocols: TLSv1.3 +# ssl.ciphers: TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 ssl.protocols: TLSv1.2 ssl.authPeer: true ssl.checkCN.host: true @@ -84,3 +96,4 @@ ssl.keyStoreValue: Changeme_123 ssl.crl: revoke.crl ssl.sslCustomClass: org.apache.servicecomb.demo.DemoSSLCustom +vertx.disableFileCPResolving: false # false: create the .vertx directory, true: do not create diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml b/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml new file mode 100644 index 00000000000..2263730b56a --- /dev/null +++ b/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml @@ -0,0 +1,56 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.springmvc.server.CodeFirstSpringmvcForSchema + version: 1.0.0 +servers: +- url: /forSchema +paths: + /uploadFile: + post: + operationId: uploadAwardFile + parameters: + - name: fileType + in: query + required: true + schema: + type: string + - name: zoneId + in: query + required: true + schema: + type: string + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: boolean +components: {} diff --git a/demo/demo-zeroconfig-registry/README.md b/demo/demo-zeroconfig-registry/README.md new file mode 100644 index 00000000000..c2b53cf780c --- /dev/null +++ b/demo/demo-zeroconfig-registry/README.md @@ -0,0 +1,21 @@ +# Introduction + +This demo tests zeroconfig. + +* server + + run in docker + +* client + + run in docker, and find server instances through zeroconfig, find schemas through + schema discovery + +* edge + run in docker, and find server instances through zeroconfig, find schemas through + schema discovery + +* tests + + integration tests run in host machine, find client/edge instances through local, + and schemas from schema discovery. diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/pom.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/pom.xml new file mode 100644 index 00000000000..385bb4950a5 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/pom.xml @@ -0,0 +1,113 @@ + + + + + 4.0.0 + demo-zeroconfig-registry-client + Java Chassis::Demo::ZeroConfig Registry Client + + org.apache.servicecomb.demo + demo-zeroconfig-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.zeroconfig.client.ClientApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-zero-config + + + org.apache.servicecomb.demo + demo-schema + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientApplication.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientApplication.java new file mode 100644 index 00000000000..eaea52f6aa8 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientApplication.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.client; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ClientApplication { + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(ClientApplication.class).web(WebApplicationType.SERVLET) + .build().run(args); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientModel.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientModel.java new file mode 100644 index 00000000000..ed8458a575c --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientModel.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.zeroconfig.client; + +import java.util.Date; + +public class ClientModel { + private Date updateDate; + + public Date getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientServerEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientServerEndpoint.java new file mode 100644 index 00000000000..a2eb8f0ecb7 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ClientServerEndpoint.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.client; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.vertx.core.json.JsonObject; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ClientServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ClientServerEndpoint { + @RpcReference(microserviceName = "demo-zeroconfig-registry-server", schemaId = "ServerEndpoint") + private IServerEndpoint serverEndpoint; + + @RpcReference(microserviceName = "demo-zeroconfig-registry-server", schemaId = "RpcEndpoint") + private IRpcEndpoint rpcEndpoint; + + private DiscoveryManager discoveryManager; + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + return serverEndpoint.getName(name); + } + + @GetMapping(path = "/getRegisteredMicroservice") + public Set getRegisteredMicroservice() { + boolean result = true; + List microserviceList = discoveryManager + .findServiceInstances("demo-zeroconfig-registry", + "demo-zeroconfig-registry-client"); + if (microserviceList.size() != 2) { // local and zero config both have one instance + result = false; + } + microserviceList = discoveryManager + .findServiceInstances("demo-zeroconfig-registry", + "demo-zeroconfig-registry-server"); + if (microserviceList.size() != 1) { + result = false; + } + + if (result) { + Set names = new HashSet<>(); + names.add("demo-zeroconfig-registry-client"); + names.add("demo-zeroconfig-registry-server"); + return names; + } + + return Collections.emptySet(); + } + + @PostMapping(path = "/jsonObject") + public JsonObject jsonObject(@RequestBody JsonObject jsonObject) { + JsonObject param = new JsonObject(); + param.put("map", jsonObject); + JsonObject message = rpcEndpoint.getJsonObject(param); + JsonObject inner = new JsonObject(); + inner.put("map", message); + return inner; + } + + @PostMapping(path = "/getString") + public String getString(@RawJsonRequestBody String jsonString) { + return jsonString; + } + + @PostMapping(path = "/postModel") + public ClientModel postModel(@RequestBody ClientModel clientModel) { + return clientModel; + } + + @GetMapping(path = "/contextMapper") + public String contextMapper(@RequestHeader("gatewayHeader") String gatewayHeader, + @RequestHeader("clientHeader") String clientHeader, + @RequestParam("gatewayQuery") String gatewayQuery, + @RequestParam("clientQuery") String clientQuery) { + InvocationContext context = ContextUtils.getInvocationContext(); + if (gatewayHeader.equals(context.getContext("context-gateway-header")) && + clientHeader.equals(context.getContext("context-client-header")) && + gatewayQuery.equals(context.getContext("context-gateway-query")) && + clientQuery.equals(context.getContext("context-client-query"))) { + return "success"; + } + return "fail"; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/GovernanceEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/GovernanceEndpoint.java new file mode 100644 index 00000000000..574e0a4f605 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/GovernanceEndpoint.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.client; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.RestOperations; + +import jakarta.ws.rs.core.Response.Status; + +@RestSchema(schemaId = "GovernanceEndpoint") +@RequestMapping("/governance") +public class GovernanceEndpoint { + private static final String SERVER = "servicecomb://demo-zeroconfig-registry-server"; + + private RestOperations restTemplate = RestTemplateBuilder.create(); + + private int count = 0; + + @GetMapping("/hello") + public String hello() { + return restTemplate.getForObject(SERVER + "/governance/hello", String.class); + } + + @GetMapping("/helloRpc") + public String helloRpc() { + return restTemplate.getForObject(SERVER + "/governance/hello", String.class); + } + + @GetMapping("/noPrefixRetry") + public String noPrefixRetry(@RequestParam(name = "invocationID") String invocationID) { + return restTemplate + .getForObject(SERVER + "/noPrefixRetry?invocationID={1}", String.class, + invocationID); + } + + @GetMapping("/retry") + public String retry(@RequestParam(name = "invocationID") String invocationID) { + return restTemplate + .getForObject(SERVER + "/governance/retry?invocationID={1}", String.class, + invocationID); + } + + @GetMapping("/retryRpc") + public String retryRpc(@RequestParam(name = "invocationID") String invocationID) { + return restTemplate + .getForObject(SERVER + "/governance/retryRpc?invocationID={1}", String.class, + invocationID); + } + + @GetMapping("/circuitBreaker") + public String circuitBreaker() throws Exception { + count++; + if (count % 3 == 0) { + return "ok"; + } + throw new InvocationException(Status.SERVICE_UNAVAILABLE, "test error"); + } + + @GetMapping("/bulkhead") + public String bulkhead() { + return restTemplate.getForObject(SERVER + "/governance/hello", String.class); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IRpcEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IRpcEndpoint.java new file mode 100644 index 00000000000..edbfc7f28b6 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IRpcEndpoint.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.client; + +import io.vertx.core.json.JsonObject; + +public interface IRpcEndpoint { + JsonObject getJsonObject(JsonObject message); + + String getString(String message); +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IServerEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IServerEndpoint.java new file mode 100644 index 00000000000..4687b6936d1 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/IServerEndpoint.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.client; + +public interface IServerEndpoint { + String getName(String name); +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/application.yml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/application.yml new file mode 100644 index 00000000000..af6c2946515 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/application.yml @@ -0,0 +1,109 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8082 + +servicecomb: + service: + application: demo-zeroconfig-registry + name: demo-zeroconfig-registry-client + version: 0.0.2 + rest: + address: 0.0.0.0:8082 + highway: + address: 0.0.0.0:8084 + config: + client: + # for testing dynamic configuration + # serverUri: http://127.0.0.1:30113 + refreshMode: 0 + # refresh_interval: 5000 + # refreshPort: 30114 + governance: + GovernanceEndpoint.helloRpc: + matchType: rpc + demo-zeroconfig-registry-server.GovernanceEndpoint.retryRpc: + matchType: rpc + matchGroup: + demo-rateLimiting: | + matches: + - apiPath: + exact: "/governance/hello" + demo-rateLimiting-rpc: | + matches: + - apiPath: + exact: "GovernanceEndpoint.helloRpc" + demo-retry: | + matches: + - apiPath: + exact: "/governance/retry" + demo-retry-no-prefix: | + matches: + - apiPath: + exact: "/noPrefixRetry" + demo-retry-rpc: | + matches: + - apiPath: + exact: "demo-zeroconfig-registry-server.GovernanceEndpoint.retryRpc" + demo-circuitBreaker: | + matches: + - apiPath: + exact: "/governance/circuitBreaker" + demo-bulkhead: | + matches: + - apiPath: + exact: "/governance/bulkhead" + rateLimiting: + demo-rateLimiting: | + rate: 10 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + demo-rateLimiting-rpc: | + rate: 10 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + retry: + demo-retry: | + maxAttempts: 3 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + demo-retry-no-prefix: | + maxAttempts: 3 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + demo-retry-rpc: | + maxAttempts: 3 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + circuitBreaker: + demo-circuitBreaker: | + minimumNumberOfCalls: 10 + slidingWindowSize: 10 + failureRateThreshold: 20 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + bulkhead: + demo-bulkhead: | + maxConcurrentCalls: 5 + ## services is optional in configuration file + services: demo-zeroconfig-registry-client + context: + headerContextMapper: | + clientHeader: context-client-header + queryContextMapper: | + clientQuery: context-client-query diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/log4j2.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-client/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/pom.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/pom.xml new file mode 100644 index 00000000000..c8dcb06893a --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/pom.xml @@ -0,0 +1,118 @@ + + + + + 4.0.0 + demo-zeroconfig-registry-edge + Java Chassis::Demo::ZeroConfig Registry Edge + + org.apache.servicecomb.demo + demo-zeroconfig-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.zeroconfig.edge.EdgeApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-zero-config + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/EdgeApplication.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/EdgeApplication.java new file mode 100644 index 00000000000..6ba5795c2a8 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/EdgeApplication.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.edge; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class EdgeApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(EdgeApplication.class).web(WebApplicationType.NONE).build().run(args); + + SelfServiceInvoker invoker = BeanUtils.getBean("SelfServiceInvoker"); + invoker.latch.await(10, TimeUnit.SECONDS); + TestMgr.check(invoker.result, "hello"); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + System.exit(1); + } + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/SelfServiceInvoker.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/SelfServiceInvoker.java new file mode 100644 index 00000000000..e04576d2965 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/SelfServiceInvoker.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.edge; + +import java.util.concurrent.CountDownLatch; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component("SelfServiceInvoker") +public class SelfServiceInvoker implements BootListener { + interface IServerEndpoint { + String getName(String name); + } + + @RpcReference(microserviceName = "demo-zeroconfig-registry-edge", schemaId = "ServerEndpoint") + IServerEndpoint endpoint; + + public CountDownLatch latch = new CountDownLatch(1); + + public String result = ""; + + public void onAfterRegistry(BootEvent event) { + result = endpoint.getName("hello"); + latch.countDown(); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/ServerEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/ServerEndpoint.java new file mode 100644 index 00000000000..71f259366ae --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/java/org/apache/servicecomb/demo/zeroconfig/edge/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.edge; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/edge/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/application.yml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/application.yml new file mode 100644 index 00000000000..14cda29c28d --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/application.yml @@ -0,0 +1,53 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8888 + +servicecomb: + service: + application: demo-zeroconfig-registry + name: demo-zeroconfig-registry-edge + version: 0.0.2 + rest: + address: 0.0.0.0:8888 + filter-chains: + enabled: true + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + client: + prefixSegmentCount: 0 + path: "/register/url/prefix/.*" + microserviceName: demo-zeroconfig-registry-client + versionRule: 0+ + references: + transport: + demo-zeroconfig-registry-client.ClientServerEndpoint.contextMapper: rest + + context: + headerContextMapper: | + gatewayHeader: context-gateway-header + queryContextMapper: | + gatewayQuery: context-gateway-query diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/log4j2.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-edge/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/pom.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/pom.xml new file mode 100644 index 00000000000..f69f1118a0a --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/pom.xml @@ -0,0 +1,118 @@ + + + + + 4.0.0 + demo-zeroconfig-registry-server + Java Chassis::Demo::ZeroConfig Registry Server + + org.apache.servicecomb.demo + demo-zeroconfig-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.zeroconfig.server.ServerApplication + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-zero-config + + + org.apache.servicecomb.demo + demo-schema + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + org.commonjava.maven.plugins + directory-maven-plugin + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceEndpoint.java new file mode 100644 index 00000000000..454e3cbba36 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceEndpoint.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.ws.rs.core.Response.Status; + +@RestSchema(schemaId = "GovernanceEndpoint") +@RequestMapping("/governance") +public class GovernanceEndpoint { + private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceEndpoint.class); + + private Map retryTimes = new HashMap<>(); + + @GetMapping("/hello") + public String sayHello() { + return "Hello world!"; + } + + @GetMapping("/retry") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)), description = ""), + @ApiResponse(responseCode = "502", content = @Content(schema = @Schema(implementation = String.class)), description = "")}) + public String retry(@RequestParam(name = "invocationID") String invocationID) { + LOGGER.info("invoke service: {}", invocationID); + retryTimes.putIfAbsent(invocationID, 0); + retryTimes.put(invocationID, retryTimes.get(invocationID) + 1); + + int retry = retryTimes.get(invocationID); + + if (retry == 3) { + return "try times: " + retry; + } + throw new InvocationException(502, "retry", "retry"); + } + + @GetMapping("/retryRpc") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)), description = ""), + @ApiResponse(responseCode = "502", content = @Content(schema = @Schema(implementation = String.class)), description = "")}) + public String retryRpc(@RequestParam(name = "invocationID") String invocationID) { + return retry(invocationID); + } + + @GetMapping("/circuitBreaker") + public String circuitBreaker() { + throw new InvocationException(Status.SERVICE_UNAVAILABLE, ""); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceNoPrefixEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceNoPrefixEndpoint.java new file mode 100644 index 00000000000..0c5121cac33 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/GovernanceNoPrefixEndpoint.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +@RestSchema(schemaId = "GovernanceNoPrefixEndpoint") +@RequestMapping("/") +public class GovernanceNoPrefixEndpoint { + private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceNoPrefixEndpoint.class); + + private Map retryTimes = new HashMap<>(); + + @GetMapping("/noPrefixRetry") + @ApiResponses({ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = String.class)), description = ""), + @ApiResponse(responseCode = "502", content = @Content(schema = @Schema(implementation = String.class)), description = "")}) + public String noPrefixRetry(@RequestParam(name = "invocationID") String invocationID) { + LOGGER.info("invoke service: {}", invocationID); + retryTimes.putIfAbsent(invocationID, 0); + retryTimes.put(invocationID, retryTimes.get(invocationID) + 1); + + int retry = retryTimes.get(invocationID); + + if (retry == 3) { + return "try times: " + retry; + } + throw new InvocationException(502, "retry", "retry"); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/RpcEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/RpcEndpoint.java new file mode 100644 index 00000000000..37dba6191ab --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/RpcEndpoint.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import org.apache.servicecomb.provider.pojo.RpcSchema; + +import io.vertx.core.json.JsonObject; + +@RpcSchema(schemaId = "RpcEndpoint") +public class RpcEndpoint { + public JsonObject getJsonObject(JsonObject message) { + JsonObject inner = new JsonObject(); + inner.put("map", message); + return inner; + } + + public String getString(String message) { + return message; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/SelfServiceInvoker.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/SelfServiceInvoker.java new file mode 100644 index 00000000000..1f8c6c800c8 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/SelfServiceInvoker.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import java.util.concurrent.CountDownLatch; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.springframework.stereotype.Component; + +@Component("SelfServiceInvoker") +public class SelfServiceInvoker implements BootListener { + interface IServerEndpoint { + String getName(String name); + } + + @RpcReference(microserviceName = "demo-zeroconfig-registry-server", schemaId = "ServerEndpoint") + IServerEndpoint endpoint; + + public CountDownLatch latch = new CountDownLatch(1); + + public String result = ""; + + public void onAfterRegistry(BootEvent event) { + result = endpoint.getName("hello"); + latch.countDown(); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerApplication.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerApplication.java new file mode 100644 index 00000000000..a04249fd63a --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerApplication.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ServerApplication { + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(ServerApplication.class).web(WebApplicationType.SERVLET).build().run(args); + + SelfServiceInvoker invoker = BeanUtils.getBean("SelfServiceInvoker"); + invoker.latch.await(10, TimeUnit.SECONDS); + TestMgr.check(invoker.result, "hello"); + + TestMgr.summary(); + if (!TestMgr.errors().isEmpty()) { + System.exit(1); + } + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerEndpoint.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerEndpoint.java new file mode 100644 index 00000000000..b0dd4ef5d97 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/ServerEndpoint.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.server; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = "ServerEndpoint") +@RequestMapping(path = "/register/url/prefix", produces = MediaType.APPLICATION_JSON) +public class ServerEndpoint { + @GetMapping(path = "/getName") + public String getName(@RequestParam(name = "name") String name) { + ((Invocation) ContextUtils.getInvocationContext()).getTraceIdLogger().info("get name invoked."); + return name; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/application.yml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/application.yml new file mode 100644 index 00000000000..52863ee0bd7 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/application.yml @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +server: + port: 8080 + +servicecomb: + service: + application: demo-zeroconfig-registry + name: demo-zeroconfig-registry-server + version: 0.0.2 + + rest: + address: 0.0.0.0:8080 + filter-chains: + enabled: true diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/log4j2.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ea906df4019 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-server/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/pom.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/pom.xml new file mode 100644 index 00000000000..8c57041ea1d --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/pom.xml @@ -0,0 +1,158 @@ + + + + + 4.0.0 + demo-zeroconfig-registry-tests + Java Chassis::Demo::ZeroConfig Registry Tests + + org.apache.servicecomb.demo + demo-zeroconfig-registry + 3.4.0-SNAPSHOT + + + + org.apache.servicecomb.demo.zeroconfig.tests.Application + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb.demo + demo-schema + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + demo-zeroconfig-registry-server:${project.version} + demo-zeroconfig-registry-server + + + /maven/maven/demo-zeroconfig-registry-server-${project.version}.jar + + + + Service information is shown below + + + 8080 + + + + + + 8080:8080 + + + + + + demo-zeroconfig-registry-client:${project.version} + demo-zeroconfig-registry-client + + + /maven/maven/demo-zeroconfig-registry-client-${project.version}.jar + + + + Service information is shown below + + + 8082 + + + + + + 8082:8082 + + + + + + demo-zeroconfig-registry-edge:${project.version} + demo-zeroconfig-registry-edge + + + /maven/maven/demo-zeroconfig-registry-edge-${project.version}.jar + + + + Service information is shown below + + + 8888 + + + + + + 8888:8888 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/Application.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/Application.java new file mode 100644 index 00000000000..3b98119d918 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/Application.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.tests; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class Application { + private static final Logger LOGGER = LoggerFactory.getLogger(Application.class); + + public static void main(final String[] args) throws Exception { + new SpringApplicationBuilder().sources(Application.class).web(WebApplicationType.NONE) + .build().run(args); + + runTest(); + + TestMgr.summary(); + + LOGGER.info("-------------- last time updated checks(maybe more/less): 662 -------------"); + + if (!TestMgr.errors().isEmpty()) { + throw new IllegalStateException("tests failed"); + } + } + + private static void runTest() throws Exception { + CategorizedTestCaseRunner + .runCategorizedTestCase("demo-zeroconfig-registry-server"); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ClientModel.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ClientModel.java new file mode 100644 index 00000000000..b664eef319d --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ClientModel.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.demo.zeroconfig.tests; + +import java.util.Date; + +public class ClientModel { + private Date updateDate; + + public Date getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/GovernanceTest.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/GovernanceTest.java new file mode 100644 index 00000000000..24899c822c6 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/GovernanceTest.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.tests; + +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class GovernanceTest implements CategorizedTestCase { + String url = "servicecomb://demo-zeroconfig-registry-client/governance"; + + RestOperations template = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testCircuitBreaker(); + testBulkhead(); + testRateLimitingRest(); + testRateLimitingRpc(); + testRetryRest(); + testRetryRestNoPrefix(); + testRetryRpc(); + } + + private void testRetryRestNoPrefix() { + testRetry("/noPrefixRetry"); + } + + private void testRetryRest() { + testRetry("/retry"); + } + + private void testRetryRpc() { + testRetry("/retryRpc"); + } + + private void testRetry(String operation) { + String invocationID = UUID.randomUUID().toString(); + String result = template.getForObject(url + operation + "?invocationID={1}", String.class, invocationID); + TestMgr.check(result, "try times: 3"); + } + + private void testCircuitBreaker() throws Exception { + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + String result = template.getForObject(url + "/circuitBreaker", String.class); + if (!"ok".equals(result)) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if ("InvocationException: code=429;msg=CommonExceptionData [message=circuitBreaker is open.]" + .equals(e.getMessage())) { + expectedFailed.set(true); + } else if ("InvocationException: code=503;msg=CommonExceptionData [message=test error]" + .equals(e.getMessage())) { + // by pass + } else { + notExpectedFailed.set(true); + } + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(true, expectedFailed.get()); + TestMgr.check(false, notExpectedFailed.get()); + } + + private void testBulkhead() throws Exception { + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + String result = template.getForObject(url + "/bulkhead", String.class); + if (!"Hello world!".equals(result)) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (!"InvocationException: code=429;msg=CommonExceptionData [message=bulkhead is full and does not permit further calls.]" + .equals(e.getMessage())) { + notExpectedFailed.set(true); + } + expectedFailed.set(true); + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(true, expectedFailed.get()); + TestMgr.check(false, notExpectedFailed.get()); + } + + private void testRateLimitingRest() throws Exception { + testRateLimiting("/hello"); + } + + private void testRateLimitingRpc() throws Exception { + testRateLimiting("/helloRpc"); + } + + private void testRateLimiting(String operation) throws Exception { + CountDownLatch latch = new CountDownLatch(100); + AtomicBoolean expectedFailed = new AtomicBoolean(false); + AtomicBoolean notExpectedFailed = new AtomicBoolean(false); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + String name = "t-" + i + "-" + j; + new Thread(name) { + public void run() { + try { + String result = template.getForObject(url + operation, String.class); + if (!"Hello world!".equals(result)) { + notExpectedFailed.set(true); + } + } catch (Exception e) { + if (!"InvocationException: code=429;msg=CommonExceptionData [message=rate limited.]" + .equals(e.getMessage())) { + notExpectedFailed.set(true); + } + expectedFailed.set(true); + } + latch.countDown(); + } + }.start(); + } + Thread.sleep(100); + } + + latch.await(20, TimeUnit.SECONDS); + TestMgr.check(true, expectedFailed.get()); + TestMgr.check(false, notExpectedFailed.get()); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java new file mode 100644 index 00000000000..767f43ff74b --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.tests; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; + +import io.vertx.core.json.JsonObject; + +@Component +public class ServerTest implements CategorizedTestCase { + + RestOperations template = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testServerGetName(); + testGetAllMicroservice(); + testJsonObject(); + testString(); + testDateForEdge(); + testContextMapper(); + } + + private void testContextMapper() throws URISyntaxException { + MultiValueMap headers = new HttpHeaders(); + headers.add("clientHeader", "v1"); + headers.add("gatewayHeader", "v2"); + RequestEntity requestEntity = new RequestEntity<>(headers, HttpMethod.GET, + new URI("cse://demo-zeroconfig-registry-edge/register/url/prefix/contextMapper?clientQuery=v3&" + + "gatewayQuery=v4")); + // test two times to check different transport(only use rest) + ResponseEntity response = template.exchange(requestEntity, String.class); + TestMgr.check(response.getBody(), "success"); + response = template.exchange(requestEntity, String.class); + TestMgr.check(response.getBody(), "success"); + } + + @SuppressWarnings("unchecked") + private void testDateForEdge() { + for (int i = 0; i < 3; i++) { + ClientModel clientModelReq = new ClientModel(); + Date date = new Date(1663590135202L); + clientModelReq.setUpdateDate(date); + Map response = template + .postForObject( + "cse://demo-zeroconfig-registry-edge" + + "/register/url/prefix/postModel", clientModelReq, + Map.class); + Object result = response.get("updateDate"); + // TODO: highway and rest Date field will give different result + // we can not change this now, because it is incompatible + if (result instanceof Long) { + TestMgr.check(response.get("updateDate"), 1663590135202L); + } else { + TestMgr.check(response.get("updateDate"), "2022-09-19T12:22:15.202+00:00"); + } + } + } + + private void testServerGetName() throws Exception { + // invoke demo-zeroconfig-registry-client + TestMgr.check("world", template + .getForObject( + "cse://demo-zeroconfig-registry-client/register/url/prefix/getName?name=world", + String.class)); + // invoke demo-zeroconfig-registry-edge + // create many threads to test event-loop not blocking + int thread = 32; + CountDownLatch latch = new CountDownLatch(thread); + for (int i = 0; i < thread; i++) { + new Thread(() -> { + for (int j = 0; j < 20; j++) { + try { + TestMgr.check("world", template + .getForObject( + "cse://demo-zeroconfig-registry-edge/register/url/prefix/getName?name=world", + String.class)); + } catch (Exception e) { + TestMgr.failed("test failed", e); + } + } + latch.countDown(); + }).start(); + } + + latch.await(); + } + + @SuppressWarnings("rawTypes") + private void testGetAllMicroservice() { + // invoke demo-zeroconfig-registry-client + TestMgr.check("2", template + .exchange( + "cse://demo-zeroconfig-registry-client" + + "/register/url/prefix/getRegisteredMicroservice", HttpMethod.GET, null, + new ParameterizedTypeReference>() { + + }).getBody().size()); + // invoke demo-zeroconfig-registry-edge + TestMgr.check("2", template + .exchange( + "cse://demo-zeroconfig-registry-edge" + + "/register/url/prefix/getRegisteredMicroservice", HttpMethod.GET, null, + new ParameterizedTypeReference>() { + + }).getBody().size()); + } + + private void testJsonObject() { + JsonObject in = new JsonObject(); + JsonObject inner = new JsonObject(); + //调用者需要按照swagger传参 + inner.put("hello", "world"); + in.put("map", inner); + + JsonObject result = template + .postForObject( + "cse://demo-zeroconfig-registry-client" + + "/register/url/prefix/jsonObject", in, JsonObject.class); + TestMgr.check(inner.toString(), result.toString()); + TestMgr.check(result.getString("hello"), "world"); + } + + private void testString() { + String in = "{\"hello\":\"world\"}"; + String result = template + .postForObject( + "cse://demo-zeroconfig-registry-client" + + "/register/url/prefix/getString", in, String.class); + TestMgr.check(in, result); + } +} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/application.yml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/application.yml new file mode 100644 index 00000000000..f9f987e88ef --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/application.yml @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + service: + application: demo-zeroconfig-registry + name: demo-zeroconfig-registry-tests + version: 0.0.2 + handler: + chain: + Consumer: + default: loadbalance + loadbalance: + filter: + isolation: + enabled: false diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/logback.xml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/logback.xml new file mode 100644 index 00000000000..cc214e46e64 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/logback.xml @@ -0,0 +1,29 @@ + + + + + + + %d [%level] [%thread] - %msg (%F:%L\)%n + + + + + + + diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/ClientServerEndpoint.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/ClientServerEndpoint.yaml new file mode 100644 index 00000000000..d8e19afb43c --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/ClientServerEndpoint.yaml @@ -0,0 +1,155 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.zeroconfig.client.ClientServerEndpoint + version: 1.0.0 +servers: +- url: /register/url/prefix +paths: + /contextMapper: + get: + operationId: contextMapper + parameters: + - name: gatewayHeader + in: header + required: true + schema: + type: string + - name: clientHeader + in: header + required: true + schema: + type: string + - name: gatewayQuery + in: query + required: true + schema: + type: string + - name: clientQuery + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /getName: + get: + operationId: getName + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /getRegisteredMicroservice: + get: + operationId: getRegisteredMicroservice + responses: + "200": + description: response of 200 + content: + application/json: + schema: + uniqueItems: true + type: array + items: + type: string + /getString: + post: + operationId: getString + requestBody: + content: + application/json: + schema: + type: string + required: true + x-raw-json: true + x-name: jsonString + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /jsonObject: + post: + operationId: jsonObject + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + required: true + x-name: jsonObject + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + /postModel: + post: + operationId: postModel + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ClientModel' + required: true + x-name: clientModel + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: '#/components/schemas/ClientModel' +components: + schemas: + JsonObject: + type: object + properties: + map: + type: object + additionalProperties: + type: object + empty: + type: boolean + x-java-class: io.vertx.core.json.JsonObject + ClientModel: + type: object + properties: + updateDate: + type: string + format: date-time + x-java-class: org.apache.servicecomb.demo.zeroconfig.client.ClientModel diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/GovernanceEndpoint.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/GovernanceEndpoint.yaml new file mode 100644 index 00000000000..6dfbd0d36c8 --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/GovernanceEndpoint.yaml @@ -0,0 +1,114 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.zeroconfig.client.GovernanceEndpoint + version: 1.0.0 +servers: +- url: /governance +paths: + /bulkhead: + get: + operationId: bulkhead + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /circuitBreaker: + get: + operationId: circuitBreaker + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /hello: + get: + operationId: hello + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /helloRpc: + get: + operationId: helloRpc + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /noPrefixRetry: + get: + operationId: noPrefixRetry + parameters: + - name: invocationID + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /retry: + get: + operationId: retry + parameters: + - name: invocationID + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /retryRpc: + get: + operationId: retryRpc + parameters: + - name: invocationID + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/SchemaDiscoveryEndpoint.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/SchemaDiscoveryEndpoint.yaml new file mode 100644 index 00000000000..8a34262bfbe --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-client/SchemaDiscoveryEndpoint.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.schemadiscovery.SchemaDiscoveryEndpoint + version: 1.0.0 +servers: +- url: /v1/schema/discovery +paths: + /getSchema: + get: + operationId: getSchema + parameters: + - name: schemaId + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/ClientServerEndpoint.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/ClientServerEndpoint.yaml new file mode 100644 index 00000000000..d8e19afb43c --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/ClientServerEndpoint.yaml @@ -0,0 +1,155 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.demo.zeroconfig.client.ClientServerEndpoint + version: 1.0.0 +servers: +- url: /register/url/prefix +paths: + /contextMapper: + get: + operationId: contextMapper + parameters: + - name: gatewayHeader + in: header + required: true + schema: + type: string + - name: clientHeader + in: header + required: true + schema: + type: string + - name: gatewayQuery + in: query + required: true + schema: + type: string + - name: clientQuery + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /getName: + get: + operationId: getName + parameters: + - name: name + in: query + required: true + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /getRegisteredMicroservice: + get: + operationId: getRegisteredMicroservice + responses: + "200": + description: response of 200 + content: + application/json: + schema: + uniqueItems: true + type: array + items: + type: string + /getString: + post: + operationId: getString + requestBody: + content: + application/json: + schema: + type: string + required: true + x-raw-json: true + x-name: jsonString + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /jsonObject: + post: + operationId: jsonObject + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + required: true + x-name: jsonObject + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: '#/components/schemas/JsonObject' + /postModel: + post: + operationId: postModel + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ClientModel' + required: true + x-name: clientModel + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: '#/components/schemas/ClientModel' +components: + schemas: + JsonObject: + type: object + properties: + map: + type: object + additionalProperties: + type: object + empty: + type: boolean + x-java-class: io.vertx.core.json.JsonObject + ClientModel: + type: object + properties: + updateDate: + type: string + format: date-time + x-java-class: org.apache.servicecomb.demo.zeroconfig.client.ClientModel diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/SchemaDiscoveryEndpoint.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/SchemaDiscoveryEndpoint.yaml new file mode 100644 index 00000000000..8a34262bfbe --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/microservices/demo-zeroconfig-registry-edge/SchemaDiscoveryEndpoint.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.schemadiscovery.SchemaDiscoveryEndpoint + version: 1.0.0 +servers: +- url: /v1/schema/discovery +paths: + /getSchema: + get: + operationId: getSchema + parameters: + - name: schemaId + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/registry.yaml b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/registry.yaml new file mode 100644 index 00000000000..07360eabfde --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/main/resources/registry.yaml @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +demo-zeroconfig-registry-client: + - id: "001" + version: "0.0.2" + appid: demo-zeroconfig-registry + schemaIds: + - ClientServerEndpoint + - SchemaDiscoveryEndpoint + - GovernanceEndpoint + instances: + - endpoints: + - rest://localhost:8082 +demo-zeroconfig-registry-edge: + - id: "002" + version: "0.0.2" + appid: demo-zeroconfig-registry + schemaIds: + - ClientServerEndpoint + - SchemaDiscoveryEndpoint + instances: + - endpoints: + - rest://localhost:8888 diff --git a/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/test/java/org/apache/servicecomb/demo/zeroconfig/tests/ZeroConfigRegistryIT.java b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/test/java/org/apache/servicecomb/demo/zeroconfig/tests/ZeroConfigRegistryIT.java new file mode 100644 index 00000000000..cd531243e6e --- /dev/null +++ b/demo/demo-zeroconfig-registry/demo-zeroconfig-registry-tests/src/test/java/org/apache/servicecomb/demo/zeroconfig/tests/ZeroConfigRegistryIT.java @@ -0,0 +1,38 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.demo.zeroconfig.tests; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ZeroConfigRegistryIT { + @BeforeEach + public void setUp() throws Exception { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + Application.main(new String[0]); + + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/demo-zeroconfig-registry/pom.xml b/demo/demo-zeroconfig-registry/pom.xml new file mode 100644 index 00000000000..bc02525e483 --- /dev/null +++ b/demo/demo-zeroconfig-registry/pom.xml @@ -0,0 +1,60 @@ + + + + + 4.0.0 + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-zeroconfig-registry + Java Chassis::Demo::ZeroConfig Registry + pom + + demo-zeroconfig-registry-server + demo-zeroconfig-registry-edge + demo-zeroconfig-registry-client + demo-zeroconfig-registry-tests + + + + + org.apache.servicecomb + solution-basic + + + org.apache.servicecomb + foundation-test-scaffolding + compile + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + diff --git a/demo/demo-zookeeper/README.md b/demo/demo-zookeeper/README.md new file mode 100644 index 00000000000..48a74913f83 --- /dev/null +++ b/demo/demo-zookeeper/README.md @@ -0,0 +1,5 @@ +# Notice + +This integration tests is designed for Zookeeper registry and configuration. And extra test cases include: + +* Test cases related to SpringMVC annotations that demo-springmvc can not cover. diff --git a/demo/demo-zookeeper/consumer/pom.xml b/demo/demo-zookeeper/consumer/pom.xml new file mode 100644 index 00000000000..73fb82a25a3 --- /dev/null +++ b/demo/demo-zookeeper/consumer/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-zookeeper + 3.4.0-SNAPSHOT + + + zookeeper-consumer + Java Chassis::Demo::Zookeeper::CONSUMER + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-zookeeper + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java new file mode 100644 index 00000000000..76fb2fb17db --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ClientWebsocketController.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; +import io.vertx.core.http.WebSocket; + +@RestSchema(schemaId = "ClientWebsocketController") +@RequestMapping(path = "/ws") +public class ClientWebsocketController { + interface ProviderService { + WebSocket websocket(); + } + + @RpcReference(schemaId = "WebsocketController", microserviceName = "provider") + private ProviderService providerService; + + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + WebSocket providerWebSocket = providerService.websocket(); + providerWebSocket.closeHandler(v -> serverWebsocket.close()); + providerWebSocket.textMessageHandler(m -> { + System.out.println("send message " + m); + serverWebsocket.writeTextMessage(m); + }); + serverWebsocket.textMessageHandler(m -> { + System.out.println("receive message " + m); + providerWebSocket.writeTextMessage(m); + }); + } +} diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java new file mode 100644 index 00000000000..3e7a2a0e285 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ConsumerApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ConsumerApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java new file mode 100644 index 00000000000..e5dd86d9d64 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ConsumerController") +@RequestMapping(path = "/") +public class ConsumerController { + @RpcReference(schemaId = "ProviderController", microserviceName = "provider") + private ProviderService providerService; + + // consumer service which delegate the implementation to provider service. + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return providerService.sayHello(name); + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return providerService.getConfig(key); + } +} diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java new file mode 100644 index 00000000000..f0e894d6745 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerHeaderParamWithListSchema.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "ConsumerHeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class ConsumerHeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @RpcReference(microserviceName = "provider", schemaId = "HeaderParamWithListSchema") + private IHeaderParamWithListSchemaSpringMvc provider; + + @Override + public String headerListDefault(List headerList) { + return provider.headerListDefault(headerList); + } + + @Override + public String headerListCSV(List headerList) { + return provider.headerListCSV(headerList); + } + + @Override + public String headerListMULTI(List headerList) { + return provider.headerListMULTI(headerList); + } + + @Override + public String headerListSSV(List headerList) { + return provider.headerListSSV(headerList); + } + + @Override + public String headerListPIPES(List headerList) { + return provider.headerListPIPES(headerList); + } +} diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java new file mode 100644 index 00000000000..aa169801cf7 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerReactiveStreamController.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.pojo.RpcReference; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +public class ConsumerReactiveStreamController { + interface ProviderReactiveStreamController { + Publisher sseString(); + + Publisher sseModel(); + } + + @RpcReference(microserviceName = "provider", schemaId = "ReactiveStreamController") + ProviderReactiveStreamController controller; + + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseString() { + return controller.sseString(); + } + + @GetMapping("/sseModel") + @Transport(name = CoreConst.RESTFUL) + public Publisher sseModel() { + return controller.sseModel(); + } +} diff --git a/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java new file mode 100644 index 00000000000..fe71314c9f4 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface ProviderService { + String sayHello(String name); + + String getConfig(String key); +} diff --git a/demo/demo-zookeeper/consumer/src/main/resources/application.yml b/demo/demo-zookeeper/consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..100797f83b4 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/resources/application.yml @@ -0,0 +1,36 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-zookeeper + version: 0.0.1 + name: consumer + properties: + group: red + registry: + zk: + enabled: true + connectString: 127.0.0.1:2181 + + rest: + address: 0.0.0.0:9092?websocketEnabled=true + server: + websocket-prefix: /ws + + highway: + address: 0.0.0.0:7092 diff --git a/demo/demo-zookeeper/consumer/src/main/resources/log4j2.xml b/demo/demo-zookeeper/consumer/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-zookeeper/consumer/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-zookeeper/gateway/pom.xml b/demo/demo-zookeeper/gateway/pom.xml new file mode 100644 index 00000000000..f2676b1ed6d --- /dev/null +++ b/demo/demo-zookeeper/gateway/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-zookeeper + 3.4.0-SNAPSHOT + + + zookeeper-gateway + Java Chassis::Demo::Zookeeper::GATEWAY + jar + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + edge-core + + + org.apache.servicecomb + registry-zookeeper + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zookeeper/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java b/demo/demo-zookeeper/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java new file mode 100644 index 00000000000..7d58caafd9d --- /dev/null +++ b/demo/demo-zookeeper/gateway/src/main/java/org/apache/servicecomb/samples/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-zookeeper/gateway/src/main/resources/application.yml b/demo/demo-zookeeper/gateway/src/main/resources/application.yml new file mode 100644 index 00000000000..ea13ef73d91 --- /dev/null +++ b/demo/demo-zookeeper/gateway/src/main/resources/application.yml @@ -0,0 +1,53 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-zookeeper + version: 0.0.1 + name: gateway + registry: + zk: + enabled: true + connectString: 127.0.0.1:2181 + + rest: + address: 0.0.0.0:9090?websocketEnabled=true + server: + websocket-prefix: /ws + + http: + dispatcher: + edge: + default: + enabled: false + url: + enabled: true + pattern: /(.*) + mappings: + consumer: + prefixSegmentCount: 0 + path: "/.*" + microserviceName: consumer + versionRule: 0.0.0+ + websocket: + mappings: + consumer: + prefixSegmentCount: 0 + path: "/ws/.*" + microserviceName: consumer + versionRule: 0.0.0+ diff --git a/demo/demo-zookeeper/gateway/src/main/resources/log4j2.xml b/demo/demo-zookeeper/gateway/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-zookeeper/gateway/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-zookeeper/pom.xml b/demo/demo-zookeeper/pom.xml new file mode 100644 index 00000000000..aa1030de1ec --- /dev/null +++ b/demo/demo-zookeeper/pom.xml @@ -0,0 +1,61 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-parent + 3.4.0-SNAPSHOT + + demo-zookeeper + Java Chassis::Demo::Zookeeper + pom + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + solution-basic + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + + + provider + consumer + gateway + test-client + + + diff --git a/demo/demo-zookeeper/provider/pom.xml b/demo/demo-zookeeper/provider/pom.xml new file mode 100644 index 00000000000..3b008bfb000 --- /dev/null +++ b/demo/demo-zookeeper/provider/pom.xml @@ -0,0 +1,116 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-zookeeper + 3.4.0-SNAPSHOT + + + zookeeper-provider + Java Chassis::Demo::Zookeeper::PROVIDER + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb + registry-zookeeper + + + org.apache.servicecomb + config-zookeeper + + + io.reactivex.rxjava3 + rxjava + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + ${project.artifactId}:${project.version} + ${project.artifactId} + + eclipse-temurin:17-jre-jammy + + 7070 + 8080 + + + tar + ${root.basedir}/assembly/assembly.xml + + + java -Xmx128m $JAVA_OPTS -jar $JAR_PATH + + + + + + + + build + package + + build + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java new file mode 100644 index 00000000000..8a773f91c72 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchema.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.demo.api.IHeaderParamWithListSchemaSpringMvc; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = "HeaderParamWithListSchema", schemaInterface = IHeaderParamWithListSchemaSpringMvc.class) +public class HeaderParamWithListSchema implements IHeaderParamWithListSchemaSpringMvc { + @Override + public String headerListDefault(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListCSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListMULTI(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListSSV(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } + + @Override + public String headerListPIPES(List headerList) { + return headerList == null ? "null" : headerList.size() + ":" + headerList; + } +} diff --git a/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java new file mode 100644 index 00000000000..fde6f36b2e3 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderApplication.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class ProviderApplication { + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(ProviderApplication.class).run(args); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java new file mode 100644 index 00000000000..a238d77be24 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.zookeeper.ZookeeperClient; +import org.apache.servicecomb.config.zookeeper.ZookeeperConfig; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@RestSchema(schemaId = "ProviderController") +@RequestMapping(path = "/") +public class ProviderController implements InitializingBean { + private Environment environment; + + private ZookeeperConfig zookeeperConfig; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + this.zookeeperConfig = new ZookeeperConfig(environment); + } + + // a very simple service to echo the request parameter + @GetMapping("/sayHello") + public String sayHello(@RequestParam("name") String name) { + return "Hello " + name; + } + + @GetMapping("/getConfig") + public String getConfig(@RequestParam("key") String key) { + return environment.getProperty(key); + } + + @Override + public void afterPropertiesSet() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConfig.getConnectString(), + zookeeperConfig.getSessionTimeoutMillis(), zookeeperConfig.getConnectionTimeoutMillis(), + new ExponentialBackoffRetry(1000, 3)); + client.start(); + client.blockUntilConnected(10, TimeUnit.SECONDS); + + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ZookeeperConfig.ZOOKEEPER_DEFAULT_ENVIRONMENT; + } + + String path = String.format(ZookeeperClient.PATH_ENVIRONMENT, env); + if (client.checkExists().forPath(path + "/config.properties") != null) { + client.delete().forPath(path + "/config.properties"); + } + client.create().creatingParentsIfNeeded(). + forPath(path + "/config.properties", "key1=1\nkey2=2".getBytes(StandardCharsets.UTF_8)); + + path = String.format(ZookeeperClient.PATH_VERSION, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment)); + if (client.checkExists().forPath(path + "/config.properties") != null) { + client.delete().forPath(path + "/config.properties"); + } + client.create().creatingParentsIfNeeded(). + forPath(path + "/config.properties", "key2=3\nkey3=4".getBytes(StandardCharsets.UTF_8)); + + path = String.format(ZookeeperClient.PATH_TAG, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment), + zookeeperConfig.getInstanceTag()); + if (client.checkExists().forPath(path + "/config.properties") != null) { + client.delete().forPath(path + "/config.properties"); + } + client.create().creatingParentsIfNeeded(). + forPath(path + "/config.properties", "key2=3\nkey3=5".getBytes(StandardCharsets.UTF_8)); + + client.close(); + } +} diff --git a/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java new file mode 100644 index 00000000000..8108d15fd46 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/ReactiveStreamController.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.samples; + + +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.reactivestreams.Publisher; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.reactivex.rxjava3.core.Flowable; + +@RestSchema(schemaId = "ReactiveStreamController") +@RequestMapping(path = "/") +@Transport(name = CoreConst.RESTFUL) +public class ReactiveStreamController { + public static class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + public Publisher sseString() { + return Flowable.fromArray("a", "b", "c"); + } + + @GetMapping("/sseModel") + public Publisher sseModel() { + return Flowable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS) + .map(item -> new Model("jack", item.intValue())); + } +} diff --git a/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java new file mode 100644 index 00000000000..6381ef1d54c --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/java/org/apache/servicecomb/samples/WebsocketController.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.ServerWebSocket; + +@RestSchema(schemaId = "WebsocketController") +@RequestMapping(path = "/ws") +public class WebsocketController { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + AtomicInteger receiveCount = new AtomicInteger(0); + CountDownLatch startSend = new CountDownLatch(1); + serverWebsocket.textMessageHandler(s -> { + if ("start".equals(s)) { + startSend.countDown(); + serverWebsocket.writeTextMessage("started"); + return; + } + receiveCount.getAndIncrement(); + }); + serverWebsocket.closeHandler((v) -> System.out.println("closed")); + + new Thread(() -> { + try { + startSend.await(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + serverWebsocket.writeTextMessage("hello"); + + for (int i = 0; i < 5; i++) { + serverWebsocket.writeTextMessage("hello " + i); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + serverWebsocket.writeTextMessage("total " + receiveCount.get()); + serverWebsocket.close(); + }).start(); + } +} diff --git a/demo/demo-zookeeper/provider/src/main/resources/application.yml b/demo/demo-zookeeper/provider/src/main/resources/application.yml new file mode 100644 index 00000000000..dd777236bd8 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/resources/application.yml @@ -0,0 +1,47 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +servicecomb: + service: + application: demo-zookeeper + version: 0.0.1 + name: provider + properties: + group: green + registry: + zk: + connectString: 127.0.0.1:2181 + config: + zk: + connectString: 127.0.0.1:2181 + instance-tag: config-demo + + rest: + address: 0.0.0.0:9094?websocketEnabled=true + server: + websocket-prefix: /ws + + highway: + address: 0.0.0.0:7094 + + cors: + enabled: true + origin: "*" + allowCredentials: false + allowedMethod: "*" + maxAge: 3600 diff --git a/demo/demo-zookeeper/provider/src/main/resources/log4j2.xml b/demo/demo-zookeeper/provider/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-zookeeper/provider/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-zookeeper/test-client/pom.xml b/demo/demo-zookeeper/test-client/pom.xml new file mode 100644 index 00000000000..e527b630005 --- /dev/null +++ b/demo/demo-zookeeper/test-client/pom.xml @@ -0,0 +1,196 @@ + + + + + 4.0.0 + + + org.apache.servicecomb.demo + demo-zookeeper + 3.4.0-SNAPSHOT + + + zookeeper-test-client + Java Chassis::Demo::Zookeeper::TEST-CLIENT + jar + + + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + org.apache.servicecomb.demo + demo-schema + + + org.apache.servicecomb + registry-local + + + + + + docker + + + + + io.fabric8 + docker-maven-plugin + + + + zookeeper:3.8.3 + zookeeper + + alias + + binding to port + + + 2181 + + + + + + zookeeper.port:2181 + + + + + zookeeper-provider:${project.version} + zookeeper-provider + + alias + + + -Dservicecomb.registry.zk.connectString=zookeeper:2181 -Dservicecomb.config.zk.connectString=zookeeper:2181 + + /maven/maven/zookeeper-provider-${project.version}.jar + + + zookeeper:zookeeper + + + ServiceComb is ready + + + 9094 + + + + + + 9094:9094 + + + + + zookeeper-consumer:${project.version} + zookeeper-consumer + + alias + + + -Dservicecomb.registry.zk.connectString=zookeeper:2181 + + /maven/maven/zookeeper-consumer-${project.version}.jar + + + zookeeper:zookeeper + + + ServiceComb is ready + + + 9092 + + + + + + 9092:9092 + + + + + zookeeper-gateway:${project.version} + zookeeper-gateway + + alias + + + -Dservicecomb.registry.zk.connectString=zookeeper:2181 + + /maven/maven/zookeeper-gateway-${project.version}.jar + + + zookeeper:zookeeper + + + ServiceComb is ready + + + 9090 + + + + + + 9090:9090 + + + + + + + + start + pre-integration-test + + start + + + + stop + post-integration-test + + stop + + + + + + + + + + io.fabric8 + docker-maven-plugin + + + + + + diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/Config.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/Config.java new file mode 100644 index 00000000000..2e9105cdd4a --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/Config.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +public interface Config { + String GATEWAY_URL = "http://localhost:9090"; +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java new file mode 100644 index 00000000000..1b129acc2c6 --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HeaderParamWithListSchemaIT.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HeaderParamWithListSchemaIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHeaderListDefault(); + testHeaderListMulti(); + testHeaderListCSV(); + testHeaderListSSV(); + testHeaderListPipes(); + } + + // default to multi + private void testHeaderListDefault() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListDefault", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListPipes() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a|b|c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListPIPES", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListSSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a b c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListSSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListCSV() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a,b,c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + + headers.add("headerList", "a, b, c"); + entity = new HttpEntity<>(headers); + result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } + + private void testHeaderListMulti() { + MultiValueMap headers = new HttpHeaders(); + headers.add("headerList", "a"); + headers.add("headerList", "b"); + headers.add("headerList", "c"); + HttpEntity entity = new HttpEntity<>(headers); + String result = template + .exchange(Config.GATEWAY_URL + "/headerList/headerListMULTI", HttpMethod.GET, entity, String.class).getBody(); + TestMgr.check("3:[a, b, c]", result); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java new file mode 100644 index 00000000000..97e883fb45f --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +@Component +public class HelloWorldIT implements CategorizedTestCase { + RestOperations template = new RestTemplate(); + + @Override + public void testRestTransport() throws Exception { + testHelloWorld(); + testGetConfig(); + } + + private void testGetConfig() { + String result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key1", String.class); + TestMgr.check("1", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key2", String.class); + TestMgr.check("3", result); + result = template + .getForObject(Config.GATEWAY_URL + "/getConfig?key=key3", String.class); + TestMgr.check("5", result); + } + + private void testHelloWorld() { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + TestMgr.check("Hello World", result); + + // test trace id added + MultiValueMap headers = new HttpHeaders(); + headers.add("X-B3-TraceId", "81de2eb7691c2bbb"); + HttpEntity entity = new HttpEntity(headers); + ResponseEntity response = + template.exchange(Config.GATEWAY_URL + "/sayHello?name=World", HttpMethod.GET, entity, String.class); + TestMgr.check(1, response.getHeaders().get("X-B3-TraceId").size()); + TestMgr.check("81de2eb7691c2bbb", response.getHeaders().getFirst("X-B3-TraceId")); + TestMgr.check("Hello World", response.getBody()); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java new file mode 100644 index 00000000000..488a6cf712a --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ReactiveStreamIT.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.ReactiveStreamClient.Model; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +public class ReactiveStreamIT implements CategorizedTestCase { + @Autowired + @Qualifier("reactiveStreamProvider") + ReactiveStreamClient reactiveStreamProvider; + + @Autowired + @Qualifier("reactiveStreamGateway") + ReactiveStreamClient reactiveStreamGateway; + + @Override + public void testRestTransport() throws Exception { + testSseString(reactiveStreamProvider); + testSseModel(reactiveStreamProvider); + testSseString(reactiveStreamGateway); + testSseModel(reactiveStreamGateway); + } + + private void testSseModel(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseModel(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(Model s) { + buffer.append(s.getName()).append(s.getAge()); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("jack0jack1jack2jack3jack4", buffer.toString()); + } + + private void testSseString(ReactiveStreamClient client) throws Exception { + Publisher result = client.sseString(); + StringBuilder buffer = new StringBuilder(); + CountDownLatch countDownLatch = new CountDownLatch(1); + result.subscribe(new Subscriber<>() { + Subscription subscription; + + @Override + public void onSubscribe(Subscription s) { + subscription = s; + subscription.request(1); + } + + @Override + public void onNext(String s) { + buffer.append(s); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + subscription.cancel(); + countDownLatch.countDown(); + } + + @Override + public void onComplete() { + countDownLatch.countDown(); + } + }); + countDownLatch.await(10, TimeUnit.SECONDS); + TestMgr.check("abc", buffer.toString()); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java new file mode 100644 index 00000000000..26a2a491bbe --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/TestClientApplication.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.CategorizedTestCaseRunner; +import org.apache.servicecomb.demo.TestMgr; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; + +@SpringBootApplication +public class TestClientApplication { + private static final Logger LOGGER = LoggerFactory.getLogger(TestClientApplication.class); + + public static void main(String[] args) throws Exception { + try { + new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(TestClientApplication.class).run(args); + + run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + } + + public static void run() throws Exception { + CategorizedTestCaseRunner.runCategorizedTestCase("consumer"); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java new file mode 100644 index 00000000000..5f23c66cdac --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/ThirdSvcConfiguration.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.List; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.annotation.Transport; +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.apache.servicecomb.provider.pojo.Invoker; +import org.reactivestreams.Publisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.vertx.core.http.WebSocket; + +@Configuration +public class ThirdSvcConfiguration { + @RequestMapping(path = "/ws") + public interface WebsocketClient { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + WebSocket websocket(); + } + + @RequestMapping(path = "/") + public interface ReactiveStreamClient { + class Model { + private String name; + + private int age; + + public Model() { + + } + + public Model(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public Model setAge(int age) { + this.age = age; + return this; + } + + public String getName() { + return name; + } + + public Model setName(String name) { + this.name = name; + return this; + } + } + + @GetMapping("/sseString") + Publisher sseString(); + + @GetMapping("/sseModel") + Publisher sseModel(); + } + + @Bean + public RegistryBean providerServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .setAppId("demo-zookeeper") + .setServiceName("provider") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9094"))))); + } + + @Bean + public RegistryBean gatewayServiceBean() { + return new RegistryBean() + .addSchemaInterface("ReactiveStreamController", ReactiveStreamClient.class) + .addSchemaInterface("WebsocketController", WebsocketClient.class) + .setAppId("demo-zookeeper") + .setServiceName("gateway") + .setVersion("0.0.1") + .setInstances(new Instances().setInstances(List.of( + new Instance().setEndpoints(List.of("rest://localhost:9090?websocketEnabled=true"))))); + } + + @Bean("reactiveStreamProvider") + public ReactiveStreamClient reactiveStreamProvider() { + return Invoker.createProxy("provider", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean("reactiveStreamGateway") + public ReactiveStreamClient reactiveStreamGateway() { + return Invoker.createProxy("gateway", "ReactiveStreamController", ReactiveStreamClient.class); + } + + @Bean + public WebsocketClient gatewayWebsocketClient() { + return Invoker.createProxy("gateway", "WebsocketController", WebsocketClient.class); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java new file mode 100644 index 00000000000..c36f2d16d28 --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/java/org/apache/servicecomb/samples/WebsocketIT.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.samples.ThirdSvcConfiguration.WebsocketClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import io.vertx.core.http.WebSocket; + +@Component +public class WebsocketIT implements CategorizedTestCase { + @Autowired + private WebsocketClient websocketClient; + + @Override + public void testRestTransport() throws Exception { + StringBuffer sb = new StringBuffer(); + AtomicBoolean closed = new AtomicBoolean(false); + CountDownLatch latchStarted = new CountDownLatch(1); + CountDownLatch latch = new CountDownLatch(1); + + WebSocket webSocket = websocketClient.websocket(); + webSocket.textMessageHandler(s -> { + if ("started".equals(s)) { + latchStarted.countDown(); + return; + } + sb.append(s); + sb.append(" "); + webSocket.writeTextMessage(s); + }); + webSocket.closeHandler(v -> { + closed.set(true); + latch.countDown(); + }); + + webSocket.writeTextMessage("start"); + int i = 0; + for (; i < 10; i++) { + if (!latchStarted.await(3, TimeUnit.SECONDS)) { + webSocket.writeTextMessage("start"); + continue; + } + break; + } + TestMgr.check(i < 10, true); + latch.await(30, TimeUnit.SECONDS); + TestMgr.check(sb.toString(), "hello hello 0 hello 1 hello 2 hello 3 hello 4 total 6 "); + TestMgr.check(closed.get(), true); + } +} diff --git a/demo/demo-zookeeper/test-client/src/main/resources/application.yml b/demo/demo-zookeeper/test-client/src/main/resources/application.yml new file mode 100644 index 00000000000..6f8a74f5c9d --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/resources/application.yml @@ -0,0 +1,25 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +servicecomb: + service: + application: demo-zookeeper + name: test-client + version: 0.0.1 + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container diff --git a/demo/demo-zookeeper/test-client/src/main/resources/log4j2.xml b/demo/demo-zookeeper/test-client/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c51f7ad5036 --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/main/resources/log4j2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/demo/demo-zookeeper/test-client/src/test/java/org/apache/servicecomb/samples/ZookeeperIT.java b/demo/demo-zookeeper/test-client/src/test/java/org/apache/servicecomb/samples/ZookeeperIT.java new file mode 100644 index 00000000000..549cfe2a300 --- /dev/null +++ b/demo/demo-zookeeper/test-client/src/test/java/org/apache/servicecomb/samples/ZookeeperIT.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.samples; + +import org.apache.servicecomb.demo.TestMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = TestClientApplication.class) +public class ZookeeperIT { + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperIT.class); + + @BeforeEach + public void setUp() { + TestMgr.errors().clear(); + } + + @Test + public void clientGetsNoError() throws Exception { + try { + TestClientApplication.run(); + } catch (Exception e) { + TestMgr.failed("test case run failed", e); + LOGGER.error("-------------- test failed -------------"); + LOGGER.error("", e); + LOGGER.error("-------------- test failed -------------"); + } + TestMgr.summary(); + Assertions.assertTrue(TestMgr.errors().isEmpty()); + } +} diff --git a/demo/docker-build-config/pom.xml b/demo/docker-build-config/pom.xml deleted file mode 100644 index cae4ad22fcc..00000000000 --- a/demo/docker-build-config/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - demo-parent - org.apache.servicecomb.demo - 1.2.0-SNAPSHOT - - 4.0.0 - - docker-build-config - Java Chassis::Demo::Docker Build Config - pom - - - - - - io.fabric8 - docker-maven-plugin - - - - ${project.artifactId}:${project.version} - ${project.artifactId} - - openjdk:8-jre-alpine - - 7070 - 8080 - - - tar - ${root.basedir}/demo/assembly/assembly.xml - - - java $JAVA_OPTS -jar $JAR_PATH - - - - - - - - build - package - - build - - - - - - org.commonjava.maven.plugins - directory-maven-plugin - - - directories - - highest-basedir - - initialize - - root.basedir - - - - - - - - diff --git a/demo/docker-run-config/pom.xml b/demo/docker-run-config/pom.xml deleted file mode 100644 index ac082b99a43..00000000000 --- a/demo/docker-run-config/pom.xml +++ /dev/null @@ -1,195 +0,0 @@ - - - - - demo-parent - org.apache.servicecomb.demo - 1.2.0-SNAPSHOT - - 4.0.0 - - docker-run-config - Java Chassis::Demo::Docker Run Config - - pom - - - - - - io.fabric8 - docker-maven-plugin - - - - servicecomb/service-center - service-center - - - server is ready - - - 30100 - - - - - - service.center.port:30100 - - - - - ${demo.service.name}:${project.version} - ${demo.service.name} - - - - ${demo.vm.options} -Dservicecomb.service.registry.address=http://sc.servicecomb.io:30100 -Dservicecomb.service.publishAddress=${docker.hostname} - - /maven/${demo.service.name}-${project.version}.jar - - - service-center:sc.servicecomb.io - - - Register microservice instance success - - - - - 8080 - - - - - - 7070:7070 - 8080:8080 - - - service-center - - - - - - - - start - pre-integration-test - - start - - - - stop - post-integration-test - - stop - - - - - - - - - - - docker - - - - org.codehaus.gmaven - gmaven-plugin - - - add-default-properties - initialize - - execute - - - - project.properties.setProperty('docker.hostname', 'localhost') - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.19.1 - - - http://${docker.hostname}:${service.center.port} - - ${jacoco.failsafe.argLine} - - - - - integration-test - verify - - - - - - - - - docker-machine - - - - org.codehaus.gmaven - gmaven-plugin - - - add-dynamic-properties - prepare-package - - execute - - - - def process = "docker-machine ip default".execute() - process.waitFor() - project.properties.setProperty('docker.hostname', process.in.text.trim()) - - log.info("Docker hostname is " + project.properties['docker.hostname']) - - - - - - - - - - diff --git a/demo/perf/pom.xml b/demo/perf/pom.xml deleted file mode 100644 index e1e1e79f786..00000000000 --- a/demo/perf/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.demo - demo-parent - 1.2.0-SNAPSHOT - - perf - - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - - ch.qos.logback - logback-classic - - - - io.vertx - vertx-redis-client - ${vertx.version} - - - org.apache.servicecomb - metrics-core - - - - - org.apache.servicecomb.demo.perf.PerfMain - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - \ No newline at end of file diff --git a/demo/perf/readme.MD b/demo/perf/readme.MD deleted file mode 100644 index 00062abf5b9..00000000000 --- a/demo/perf/readme.MD +++ /dev/null @@ -1,45 +0,0 @@ -suppose jar named perf.jar -1.copy perf.jar to different directory - -2.create microservice.yaml in each directory -# change microserviceName to be perf1/perf2/perf3, and so on -service_description: - name: perf1 -cse: - references: - # use which transport to invoke - transport: rest - -# sync mode consumer count -sync-count: 10 -# async mode consumer count -async-count: 20 -# use sync mode or not -# sync: /v1/syncQuery/{id}?step={step}&all={all}&fromDB={fromDB} -# async:/v1/asyncQuery/{id}?step={step}&all={all}&fromDB={fromDB} -sync: false -# producer microserviceName -producer: perf1 -id: 1 -# every producer determine: -# 1)if step equals all, then this is final step, direct return or query from db -# 2)otherwise inc step and invoke next microservice -# 3)if self name if perf1, then next microservice is perf2 -step: 1 -all: 1 -fromDB: false -response-size: 1 - -# redis parameter -redis: - client: - count: 8 - host: - port: - password: - -3.start producers -java -jar perf.jar - -4.start consumer -java -jar perf.jar -c \ No newline at end of file diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Impl.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Impl.java deleted file mode 100644 index e2505ed0bc6..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Impl.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.perf; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@RestSchema(schemaId = "impl") -@RequestMapping(path = "/v1") -public class Impl { - private Intf intf; - - @Value(value = "${service_description.name}") - public void setSelfMicroserviceName(String selfMicroserviceName) { - // self: perf-1/perf-a - // next: perf-2/perf-b - char last = selfMicroserviceName.charAt(selfMicroserviceName.length() - 1); - String nextMicroserviceName = - selfMicroserviceName.substring(0, selfMicroserviceName.length() - 1) + (char) (last + 1); - intf = Invoker.createProxy(nextMicroserviceName, - "impl", - Intf.class); - } - - @GetMapping(path = "/syncQuery/{id}") - public String syncQuery(@PathVariable(name = "id") String id, - @RequestParam(name = "step") int step, @RequestParam(name = "all") int all, - @RequestParam(name = "fromDB") boolean fromDB) { - if (step == all) { - if (fromDB) { - return RedisClientUtils.syncQuery(id); - } - - return buildFromMemoryResponse(id); - } - - return intf.syncQuery(id, step + 1, all, fromDB); - } - - public String buildFromMemoryResponse(String id) { - return PerfConfiguration.buildResponse("memory", id); - } - - @GetMapping(path = "/asyncQuery/{id}") - public CompletableFuture asyncQuery(@PathVariable(name = "id") String id, - @RequestParam(name = "step") int step, @RequestParam(name = "all") int all, - @RequestParam(name = "fromDB") boolean fromDB) { - if (step == all) { - if (fromDB) { - return RedisClientUtils.asyncQuery(id); - } - - CompletableFuture future = new CompletableFuture<>(); - future.complete(buildFromMemoryResponse(id)); - return future; - } - - return intf.asyncQuery(id, step + 1, all, fromDB); - } -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Intf.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Intf.java deleted file mode 100644 index c671fda2ee0..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/Intf.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.perf; - -import java.util.concurrent.CompletableFuture; - -public interface Intf { - String syncQuery(String id, int step, int all, boolean fromDB); - - CompletableFuture asyncQuery(String id, int step, int all, boolean fromDB); -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConfiguration.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConfiguration.java deleted file mode 100644 index 8d750b04167..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConfiguration.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.perf; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import com.google.common.base.Strings; - -@Component -public class PerfConfiguration { - public static int syncCount; - - public static int asyncCount; - - public static boolean sync; - - public static String producer; - - public static String id; - - public static int step; - - public static int all; - - public static boolean fromDB; - - public static int responseSize; - - public static String responseData; - - public static int redisClientCount; - - public static String redisHost; - - public static int redisPort; - - public static String redisPassword; - - public static String buildResponse(String from, String id) { - return new StringBuilder(64 + PerfConfiguration.responseData.length()) - .append(id) - .append(" from ") - .append(from) - .append(": ") - .append(PerfConfiguration.responseData) - .toString(); - } - - @Value(value = "${response-size}") - public void setResponseSize(int responseSize) { - PerfConfiguration.responseSize = responseSize; - PerfConfiguration.responseData = Strings.repeat("a", responseSize); - } - - @Value(value = "${sync-count}") - public void setSyncCount(int syncCount) { - PerfConfiguration.syncCount = syncCount; - } - - @Value(value = "${async-count}") - public void setAsyncCount(int asyncCount) { - PerfConfiguration.asyncCount = asyncCount; - } - - @Value(value = "${sync}") - public void setSync(boolean sync) { - PerfConfiguration.sync = sync; - } - - @Value(value = "${producer}") - public void setProducer(String producer) { - PerfConfiguration.producer = producer; - } - - @Value(value = "${id}") - public void setId(String id) { - PerfConfiguration.id = id; - } - - @Value(value = "${step}") - public void setStep(int step) { - PerfConfiguration.step = step; - } - - @Value(value = "${all}") - public void setAll(int all) { - PerfConfiguration.all = all; - } - - @Value(value = "${fromDB}") - public void setFromDB(boolean fromDB) { - PerfConfiguration.fromDB = fromDB; - } - - @Value(value = "${redis.client.count}") - public void setRedisClientCount(int redisClientCount) { - PerfConfiguration.redisClientCount = redisClientCount; - } - - @Value(value = "${redis.host}") - public void setRedisHost(String redisHost) { - PerfConfiguration.redisHost = redisHost; - } - - @Value(value = "${redis.port}") - public void setRedisPort(int redisPort) { - PerfConfiguration.redisPort = redisPort; - } - - @Value(value = "${redis.password:}") - public void setRedisPassword(String redisPassword) { - if (StringUtils.isEmpty(redisPassword)) { - return; - } - PerfConfiguration.redisPassword = redisPassword; - } -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConsumer.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConsumer.java deleted file mode 100644 index a73b7681dcd..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfConsumer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.perf; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import org.apache.servicecomb.provider.pojo.Invoker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -@Component -public class PerfConsumer { - private static final Logger LOGGER = LoggerFactory.getLogger(PerfConsumer.class); - - private Intf intf; - - public void runConsumer() throws InterruptedException, ExecutionException { - intf = Invoker.createProxy( - PerfConfiguration.producer, - "impl", - Intf.class); - - if (PerfConfiguration.sync) { - runSyncConsumers(); - return; - } - - runAsyncConsumers(); - } - - private void runAsyncConsumers() throws InterruptedException, ExecutionException { - CompletableFuture future = intf.asyncQuery(PerfConfiguration.id, - PerfConfiguration.step, - PerfConfiguration.all, - PerfConfiguration.fromDB); - LOGGER.info("runAsyncConsumer: {}", future.get()); - - for (int idx = 0; idx < PerfConfiguration.asyncCount; idx++) { - runAsyncConsumer(); - } - } - - private void runAsyncConsumer() { - CompletableFuture future = intf.asyncQuery(PerfConfiguration.id, - PerfConfiguration.step, - PerfConfiguration.all, - PerfConfiguration.fromDB); - future.whenComplete((r, e) -> { - if (e == null) { - runAsyncConsumer(); - return; - } - - throw new IllegalStateException("invoke failed.", e); - }); - } - - private void runSyncConsumers() { - LOGGER.info("runSyncConsumer: {}", - intf.syncQuery(PerfConfiguration.id, - PerfConfiguration.step, - PerfConfiguration.all, - PerfConfiguration.fromDB)); - - Executor executor = Executors.newFixedThreadPool(PerfConfiguration.syncCount); - for (int idx = 0; idx < PerfConfiguration.syncCount; idx++) { - executor.execute(this::runSyncConsumer); - } - } - - private void runSyncConsumer() { - try { - for (; ; ) { - intf.syncQuery(PerfConfiguration.id, - PerfConfiguration.step, - PerfConfiguration.all, - PerfConfiguration.fromDB); - } - } catch (Throwable e) { - throw new IllegalStateException("invoke failed.", e); - } - } -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfMain.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfMain.java deleted file mode 100644 index 871ccb430f7..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/PerfMain.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.perf; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; - -public class PerfMain { - - public static void main(String[] args) throws Exception { - BeanUtils.init(); - - // redis - RedisClientUtils.init(VertxUtils.getOrCreateVertxByName("transport", null)); - - List argList = Arrays.asList(args); - if (argList.contains("-c")) { - PerfConsumer consumer = BeanUtils.getContext().getBean(PerfConsumer.class); - consumer.runConsumer(); - } - } -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisClientUtils.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisClientUtils.java deleted file mode 100644 index 0ce693a8aad..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisClientUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.demo.perf; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolFactory; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.redis.RedisClient; -import io.vertx.redis.RedisOptions; - -public class RedisClientUtils { - private static ClientPoolManager clientMgr; - - public static void init(Vertx vertx) throws InterruptedException { - RedisOptions redisOptions = new RedisOptions() - .setHost(PerfConfiguration.redisHost) - .setPort(PerfConfiguration.redisPort) - .setAuth(PerfConfiguration.redisPassword); - ClientPoolFactory factory = (ctx) -> { - return RedisClient.create(vertx, redisOptions); - }; - clientMgr = new ClientPoolManager<>(vertx, factory); - - DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(clientMgr, - PerfConfiguration.redisClientCount); - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); - } - - public static String syncQuery(String id) { - CompletableFuture future = doQuery(id, true); - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - throw new InvocationException(Status.INTERNAL_SERVER_ERROR.getStatusCode(), - Status.INTERNAL_SERVER_ERROR.getReasonPhrase(), (Object) "Failed to query from redis.", e); - } - } - - public static CompletableFuture asyncQuery(String id) { - return doQuery(id, false); - } - - private static CompletableFuture doQuery(String id, boolean sync) { - CompletableFuture future = new CompletableFuture<>(); - RedisClient redisClient = clientMgr.findClientPool(sync); - RedisSession session = new RedisSession(redisClient, id, future); - session.query(); - return future; - } -} diff --git a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisSession.java b/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisSession.java deleted file mode 100644 index f9d657f689c..00000000000 --- a/demo/perf/src/main/java/org/apache/servicecomb/demo/perf/RedisSession.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.perf; - -import java.util.concurrent.CompletableFuture; - -import io.vertx.core.AsyncResult; -import io.vertx.redis.RedisClient; - -public class RedisSession { - RedisClient redis; - - String id; - - CompletableFuture future; - - String createResult; - - public RedisSession(RedisClient redis, String id, CompletableFuture future) { - this.redis = redis; - this.id = id; - this.future = future; - } - - public void query() { - redis.get(id, this::onGetResponse); - } - - private void onGetResponse(AsyncResult ar) { - if (ar.succeeded()) { - if (ar.result() == null) { - createCache(); - return; - } - - future.complete(ar.result()); - return; - } - - future.completeExceptionally(ar.cause()); - } - - private void createCache() { - createResult = PerfConfiguration.buildResponse("redis", id); - redis.set(id, createResult, this::onCreateCacheResponse); - } - - private void onCreateCacheResponse(AsyncResult ar) { - if (ar.succeeded()) { - future.complete(createResult); - return; - } - - future.completeExceptionally(ar.cause()); - } -} diff --git a/demo/perf/src/main/resources/logback.xml b/demo/perf/src/main/resources/logback.xml deleted file mode 100644 index d753514a002..00000000000 --- a/demo/perf/src/main/resources/logback.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - %d [%level] [%thread] - %msg (%F:%L\)%n - - - - - - \ No newline at end of file diff --git a/demo/perf/src/main/resources/microservice.yaml b/demo/perf/src/main/resources/microservice.yaml deleted file mode 100644 index d460f196660..00000000000 --- a/demo/perf/src/main/resources/microservice.yaml +++ /dev/null @@ -1,63 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: perfTest -service_description: - name: perf1 - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080?sslEnabled=false - server: - thread-count: 8 - client: - thread-count: 8 - connection: - maxPoolSize: 30 - highway: - address: 0.0.0.0:7070?sslEnabled=false - server: - thread-count: 8 - client: - thread-count: 8 - references: - transport: highway - metrics: - window_time: 1000 - publisher.defaultLog: - enabled: true - endpoints.client.detail.enabled: true - -sync-count: 10 -async-count: 20 -sync: false -producer: perf1 -id: 1 -step: 1 -all: 1 -fromDB: false -response-size: 1 - -redis: - client: - count: 8 - host: localhost - port: 6379 -# password: diff --git a/demo/pom.xml b/demo/pom.xml index 9aac6bcdd96..d0376883c6b 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -22,41 +22,44 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default org.apache.servicecomb.demo demo-parent Java Chassis::Demo + + + + pom - docker-build-config - docker-run-config - demo-local - demo-server-servlet + demo-schema demo-pojo + demo-filter demo-jaxrs - demo-springmvc - demo-schema demo-crossapp - demo-spring-boot-provider + demo-register-url-prefix + demo-local-registry + demo-multi-registries + demo-zeroconfig-registry demo-spring-boot-transport - demo-spring-boot-discovery - demo-multiple - demo-signature demo-edge - perf + demo-multiple + demo-multi-service-center + demo-cse-v1 + demo-cse-v2 + demo-nacos + + + demo-zookeeper + demo-consul - - org.apache.servicecomb.demo - demo-signature - ${project.version} - org.apache.servicecomb.demo demo-schema @@ -127,35 +130,28 @@ - org.slf4j - slf4j-log4j12 + org.junit.jupiter + junit-jupiter + compile - - com.github.odavid.maven.plugins - mixin-maven-plugin - 0.1-alpha-39 - true - org.commonjava.maven.plugins directory-maven-plugin - 0.1 + 1.0 maven-deploy-plugin - 2.8.2 true maven-install-plugin - 2.5.2 false @@ -163,7 +159,6 @@ org.apache.maven.plugins maven-jar-plugin - 2.6 assembly @@ -180,77 +175,59 @@ + + org.commonjava.maven.plugins + directory-maven-plugin + + + directories + + directory-of + + initialize + + root.basedir + + org.apache.servicecomb.demo + demo-parent + + + + + + + + org.commonjava.maven.plugins + directory-maven-plugin + + - demo-run-release + docker - org.commonjava.maven.plugins - directory-maven-plugin + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + ${jacoco.failsafe.argLine} + - directoryies - directory-of + integration-test + verify - initialize - - root.dir - - org.apache.servicecomb - java-chassis - - - - - - org.apache.maven.plugins - maven-jar-plugin - - ${demo.run.dir}/${project.artifactId} - - - true - ../lib/ - ${demo.main} - - - . .. - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - package - - copy-dependencies - - - ${demo.run.dir}/lib - - - - - - - - ${root.dir}/demo/target - diff --git a/dependencies/bom/pom.xml b/dependencies/bom/pom.xml new file mode 100644 index 00000000000..ed5e1bc91a2 --- /dev/null +++ b/dependencies/bom/pom.xml @@ -0,0 +1,414 @@ + + + + + 4.0.0 + + org.apache.servicecomb + java-chassis-dependencies-parent + 3.4.0-SNAPSHOT + + + java-chassis-bom + Java Chassis::Bom + pom + + + + + + + + org.apache.servicecomb + config-center-client + ${project.version} + + + org.apache.servicecomb + config-clients-common + ${project.version} + + + org.apache.servicecomb + config-kie-client + ${project.version} + + + org.apache.servicecomb + dashboard-client + ${project.version} + + + org.apache.servicecomb + http-client-common + ${project.version} + + + org.apache.servicecomb + service-center-client + ${project.version} + + + + + org.apache.servicecomb + common-access-log + ${project.version} + + + org.apache.servicecomb + common-protobuf + ${project.version} + + + org.apache.servicecomb + common-rest + ${project.version} + + + + + org.apache.servicecomb + java-chassis-core + ${project.version} + + + + + org.apache.servicecomb + config-apollo + ${project.version} + + + org.apache.servicecomb + config-cc + ${project.version} + + + org.apache.servicecomb + config-kie + ${project.version} + + + org.apache.servicecomb + config-nacos + ${project.version} + + + org.apache.servicecomb + config-zookeeper + ${project.version} + + + org.apache.servicecomb + config-consul + ${project.version} + + + + + org.apache.servicecomb + edge-core + ${project.version} + + + + org.apache.servicecomb + foundation-common + ${project.version} + + + org.apache.servicecomb + foundation-config + ${project.version} + + + org.apache.servicecomb + foundation-metrics + ${project.version} + + + org.apache.servicecomb + foundation-protobuf + ${project.version} + + + org.apache.servicecomb + foundation-registry + ${project.version} + + + org.apache.servicecomb + foundation-spi + ${project.version} + + + org.apache.servicecomb + foundation-ssl + ${project.version} + + + org.apache.servicecomb + foundation-test-scaffolding + ${project.version} + test + + + org.apache.servicecomb + foundation-vertx + ${project.version} + + + + + org.apache.servicecomb + servicecomb-governance + ${project.version} + + + + + org.apache.servicecomb + handler-fault-injection + ${project.version} + + + org.apache.servicecomb + handler-flowcontrol-qps + ${project.version} + + + org.apache.servicecomb + handler-governance + ${project.version} + + + org.apache.servicecomb + handler-loadbalance + ${project.version} + + + org.apache.servicecomb + handler-publickey-auth + ${project.version} + + + org.apache.servicecomb + handler-router + ${project.version} + + + org.apache.servicecomb + handler-tracing-zipkin + ${project.version} + + + + + org.apache.servicecomb + metrics-core + ${project.version} + + + org.apache.servicecomb + metrics-prometheus + ${project.version} + + + + org.apache.servicecomb + provider-jaxrs + ${project.version} + + + org.apache.servicecomb + provider-pojo + ${project.version} + + + org.apache.servicecomb + provider-rest-common + ${project.version} + + + org.apache.servicecomb + provider-springmvc + ${project.version} + + + + org.apache.servicecomb + registry-lightweight + ${project.version} + + + org.apache.servicecomb + registry-local + ${project.version} + + + org.apache.servicecomb + registry-service-center + ${project.version} + + + org.apache.servicecomb + registry-zero-config + ${project.version} + + + org.apache.servicecomb + registry-nacos + ${project.version} + + + org.apache.servicecomb + registry-zookeeper + ${project.version} + + + org.apache.servicecomb + registry-etcd + ${project.version} + + + org.apache.servicecomb + config-etcd + ${project.version} + + + org.apache.servicecomb + registry-consul + ${project.version} + + + + org.apache.servicecomb + solution-basic + ${project.version} + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + ${project.version} + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + ${project.version} + + + + org.apache.servicecomb + servicestage + ${project.version} + + + org.apache.servicecomb + dashboard + ${project.version} + + + org.apache.servicecomb + darklaunch + ${project.version} + + + + org.apache.servicecomb + swagger-generator-core + ${project.version} + + + org.apache.servicecomb + swagger-generator-jaxrs + ${project.version} + + + org.apache.servicecomb + swagger-generator-spring-data + ${project.version} + + + org.apache.servicecomb + swagger-generator-springmvc + ${project.version} + + + org.apache.servicecomb + swagger-invocation-core + ${project.version} + + + org.apache.servicecomb + swagger-invocation-jaxrs + ${project.version} + + + org.apache.servicecomb + swagger-invocation-springmvc + ${project.version} + + + org.apache.servicecomb + swagger-invocation-validator + ${project.version} + + + + org.apache.servicecomb + tracing-common + ${project.version} + + + org.apache.servicecomb + tracing-zipkin + ${project.version} + + + + org.apache.servicecomb + transport-common + ${project.version} + + + org.apache.servicecomb + transport-highway + ${project.version} + + + org.apache.servicecomb + transport-rest-client + ${project.version} + + + org.apache.servicecomb + transport-rest-servlet + ${project.version} + + + org.apache.servicecomb + transport-rest-vertx + ${project.version} + + + + diff --git a/dependencies/default/pom.xml b/dependencies/default/pom.xml new file mode 100644 index 00000000000..22f2190ddd1 --- /dev/null +++ b/dependencies/default/pom.xml @@ -0,0 +1,510 @@ + + + + + 4.0.0 + + org.apache.servicecomb + java-chassis-dependencies-parent + 3.4.0-SNAPSHOT + + + java-chassis-dependencies + Java Chassis::Dependencies::Default + pom + + + + 1.2.2 + 3.27.7 + 4.3.0 + 6.3.0 + 1.11.0 + 2.21.0 + 2.6 + 3.20.0 + 1.3.5 + 1.15.0 + 5.9.0 + 1.0.3 + 3.0.2 + 1.17.12 + 1.17.13 + 33.5.0-jre + 5.1.0 + 1.3 + 2.2.2 + 9.1.0.Final + 4.5.14 + 1.5.18 + 2.20.1 + 1.6.0 + 1.3.2 + 1 + 1.5 + 4.0.2 + 1.34 + 4.13.2 + 5.13.4 + 1.2.17 + 2.25.3 + 3.9.12 + 1.16.4 + 5.21.0 + 5.2.0 + 5.15.0 + 3.1.1 + 0.3.0 + 0.16.0 + 3.23.4 + 1.8.0 + 2.2.27 + 1.0.4 + 1.7.0 + 2.7.18 + 3.1.12 + 1.0.0 + 0.13.2 + 6.0.0 + 1.7.36 + 2.5 + 2.2.41 + 5.0.8 + 3.5.1 + 3.4.0 + 0.8.6 + 1.8.0 + + ${basedir}/../.. + + + + + + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + import + pom + + + + org.mockito + mockito-bom + ${mockito.version} + import + pom + + + org.mockito + mockito-inline + ${mockito-inline.version} + test + + + + com.github.seanyinx + unit-scaffolding + ${seanyinx.version} + test + + + + org.apache.curator + curator-x-discovery + ${curator.version} + + + org.apache.curator + curator-framework + ${curator.version} + + + org.apache.curator + curator-recipes + ${curator.version} + + + + com.google.code.findbugs + jsr305 + ${findbugs-jsr305.version} + provided + + + + com.google.guava + guava + ${guava.version} + + + * + * + + + + + com.google.guava + failureaccess + ${failureaccess.version} + + + + com.google.inject + guice + ${guice.version} + + + aopalliance + aopalliance + + + + + com.google.inject.extensions + guice-assistedinject + ${guice.version} + + + + + com.google.protobuf + protobuf-java + ${protobuf.version} + test + + + + commons-beanutils + commons-beanutils + ${commons-beanutils.version} + + + + commons-io + commons-io + ${commons-io.version} + + + + commons-lang + commons-lang + ${commons-lang.version} + + + + commons-logging + commons-logging + ${commons-logging.version} + + + + org.apache.maven + maven-model + ${maven-model.version} + + + + io.micrometer + micrometer-bom + ${micrometer.version} + pom + import + + + io.prometheus + simpleclient_bom + ${prometheus.version} + pom + import + + + + io.protostuff + protostuff-core + ${protostuff.version} + + + io.protostuff + protostuff-parser + ${protostuff-parser.version} + + + org.abego.treelayout + org.abego.treelayout.core + + + com.google.inject.extensions + guice-multibindings + + + + + io.protostuff + protostuff-runtime + ${protostuff.version} + + + + io.swagger.core.v3 + swagger-core-jakarta + ${swagger.version} + + + + io.reactivex.rxjava3 + rxjava + ${rxjava.version} + + + org.reactivestreams + reactive-streams + ${reactive-streams.version} + + + + io.zipkin.brave + brave-bom + ${brave.version} + pom + import + + + + io.zipkin.reporter2 + zipkin-reporter-bom + ${zipkin-reporter.version} + + + + io.zipkin.zipkin2 + zipkin + ${zipkin.version} + + + + jakarta.servlet + jakarta.servlet-api + ${servlet-api.version} + + + com.sun.activation + jakarta.activation + ${activation.version} + + + javax.annotation + javax.annotation-api + ${javax-annotation.version} + + + + javax.inject + javax.inject + ${javax-inject.version} + + + + javax.resource + connector-api + ${javax-resource.version} + + + + junit + junit + ${junit.version} + test + + + org.junit + junit-bom + ${junit5.version} + pom + import + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.apache.commons + commons-text + ${commons-text.version} + + + + org.apache.httpcomponents + httpclient + ${httpcomponents.version} + + + + org.apache.logging.log4j + log4j-api + ${log4j2.version} + + + org.apache.logging.log4j + log4j-core + ${log4j2.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j2.version} + + + + org.awaitility + awaitility + ${awaitility.version} + test + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + org.glassfish.jersey.core + jersey-common + ${jersey.version} + + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + + + org.hamcrest + hamcrest-core + ${hamcrest.version} + test + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + org.hibernate.validator + hibernate-validator-annotation-processor + ${hibernate-validator.version} + + + + org.hdrhistogram + HdrHistogram + ${hdr-histogram.version} + + + + org.jmockit + jmockit + ${jmockit.version} + test + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + io.vertx + vertx-dependencies + ${vertx.version} + pom + import + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.alibaba.nacos + nacos-client + ${nacos-client.version} + + + + io.github.resilience4j + resilience4j-bom + ${resilience4j.versioin} + pom + import + + + + org.java-websocket + Java-WebSocket + ${java-websocket.version} + + + + org.apache.servicecomb + java-chassis-bom + ${project.version} + pom + import + + + + io.etcd + jetcd-core + ${jetcd-core.version} + + + + org.kiwiproject + consul-client + ${consul-client.version} + + + + diff --git a/dependencies/pom.xml b/dependencies/pom.xml new file mode 100644 index 00000000000..4ee9c9ea071 --- /dev/null +++ b/dependencies/pom.xml @@ -0,0 +1,38 @@ + + + + + 4.0.0 + + + org.apache.servicecomb + java-chassis + 3.4.0-SNAPSHOT + + + java-chassis-dependencies-parent + Java Chassis::Dependencies + pom + + + bom + default + + + diff --git a/deployment/README.md b/deployment/README.md deleted file mode 100644 index b2764cc0a49..00000000000 --- a/deployment/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# About Deployment Module - -Deployment is a mechanism to manage how microservics interact with external services. When running a microservice in a Cloud Native environment, it will interact with many external services, like service center, config center, an APM service to report tracing data, a dashboard service to report health data, etc. Deployment Service manages the meta data of these services. Deployment queries the addresses , the parameters, the authentication information of these services and so on. - -Deployment Service is some kind of service like service center, they are differ from two aspects: -1. All microservics will report their information to service center. But Deployment Service acts as a management system and knows the meta information in deploy time. -2. Service center provide some other functions like instance management and heartbeat, while Deployment Service only provides metadata query services and it is simple. - -This module does not provide a Deployment Service, it provides the interface to interacts with Deployment Service. Service providers can implement the interface. - -They are some design constraints need to be considered when implement Deployment interface: -1. Deployment can only read configurations of environment, microservics.yaml. It can not read dynamic configurations. -2. Deployment is initialized before bean initialization. diff --git a/deployment/pom.xml b/deployment/pom.xml deleted file mode 100644 index 8e055b3d012..00000000000 --- a/deployment/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - org.apache.servicecomb - java-chassis-parent - 1.2.0-SNAPSHOT - ../parent - - 4.0.0 - - deployment - Java Chassis::Deployment - - - - org.apache.servicecomb - foundation-config - - - org.apache.servicecomb - foundation-vertx - - - org.apache.servicecomb - foundation-common - - - - io.vertx - vertx-codegen - provided - - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - org.apache.servicecomb - foundation-test-scaffolding - - - org.apache.commons - commons-lang3 - - - diff --git a/deployment/src/main/java/org/apache/servicecomb/deployment/DefaultDeploymentProvider.java b/deployment/src/main/java/org/apache/servicecomb/deployment/DefaultDeploymentProvider.java deleted file mode 100644 index 9099735b047..00000000000 --- a/deployment/src/main/java/org/apache/servicecomb/deployment/DefaultDeploymentProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -import java.util.Arrays; - -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.servicecomb.config.ConfigUtil; - -import com.google.common.annotations.VisibleForTesting; - -public class DefaultDeploymentProvider implements DeploymentProvider { - private static AbstractConfiguration configuration = ConfigUtil.createLocalConfig(); - - @Override - public SystemBootstrapInfo getSystemBootStrapInfo(String systemKey) { - switch (systemKey) { - case SYSTEM_KEY_SERVICE_CENTER: - SystemBootstrapInfo sc = new SystemBootstrapInfo(); - String[] urls = configuration.getStringArray("servicecomb.service.registry.address"); - if (urls == null || urls.length == 0) { - urls = new String[] {"https://127.0.0.1:30100"}; - } - sc.setAccessURL(Arrays.asList(urls)); - return sc; - case SYSTEM_KEY_CONFIG_CENTER: - String[] ccAddresses = configuration.getStringArray("servicecomb.config.client.serverUri"); - if (ccAddresses == null || ccAddresses.length == 0) { - return null; - } - SystemBootstrapInfo cc = new SystemBootstrapInfo(); - cc.setAccessURL(Arrays.asList(ccAddresses)); - return cc; - default: - return null; - } - } - - @VisibleForTesting - public static void setConfiguration(AbstractConfiguration configuration) { - DefaultDeploymentProvider.configuration = configuration; - } -} diff --git a/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java b/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java deleted file mode 100644 index f26980e54de..00000000000 --- a/deployment/src/main/java/org/apache/servicecomb/deployment/Deployment.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; - -public class Deployment { - private static List providerList = SPIServiceUtils.getSortedService(DeploymentProvider.class); - - public static SystemBootstrapInfo getSystemBootStrapInfo(String systemKey) { - for (DeploymentProvider provider : providerList) { - if (provider.getSystemBootStrapInfo(systemKey) != null) { - return provider.getSystemBootStrapInfo(systemKey); - } - } - return null; - } -} diff --git a/deployment/src/main/java/org/apache/servicecomb/deployment/DeploymentProvider.java b/deployment/src/main/java/org/apache/servicecomb/deployment/DeploymentProvider.java deleted file mode 100644 index 703af6ddb49..00000000000 --- a/deployment/src/main/java/org/apache/servicecomb/deployment/DeploymentProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -public interface DeploymentProvider { - String SYSTEM_KEY_SERVICE_CENTER = "ServiceCenter"; - String SYSTEM_KEY_CONFIG_CENTER = "ConfigCenter"; - - default int getOrder() { - return 100; - } - - SystemBootstrapInfo getSystemBootStrapInfo(String systemKey); -} diff --git a/deployment/src/main/java/org/apache/servicecomb/deployment/SystemBootstrapInfo.java b/deployment/src/main/java/org/apache/servicecomb/deployment/SystemBootstrapInfo.java deleted file mode 100644 index c98f93e6a64..00000000000 --- a/deployment/src/main/java/org/apache/servicecomb/deployment/SystemBootstrapInfo.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -import java.util.List; -import java.util.Map; - -public class SystemBootstrapInfo { - private List accessURL; - - private Map properties; - - public List getAccessURL() { - return accessURL; - } - - public void setAccessURL(List accessURL) { - this.accessURL = accessURL; - } - - public Map getProperties() { - return properties; - } - - public void setProperties(Map properties) { - this.properties = properties; - } - - public Object getProperty(String key) { - return properties.get(key); - } -} diff --git a/deployment/src/main/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider b/deployment/src/main/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider deleted file mode 100644 index 49e32f16adf..00000000000 --- a/deployment/src/main/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.deployment.DefaultDeploymentProvider diff --git a/deployment/src/test/java/org/apache/servicecomb/deployment/CustomDeploymentProvider.java b/deployment/src/test/java/org/apache/servicecomb/deployment/CustomDeploymentProvider.java deleted file mode 100644 index df7e226b0f9..00000000000 --- a/deployment/src/test/java/org/apache/servicecomb/deployment/CustomDeploymentProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -import java.util.Arrays; - -public class CustomDeploymentProvider implements DeploymentProvider { - @Override - public int getOrder() { - return 0; - } - - @Override - public SystemBootstrapInfo getSystemBootStrapInfo(String systemKey) { - switch (systemKey) { - case DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER: - SystemBootstrapInfo cc = new SystemBootstrapInfo(); - cc.setAccessURL(Arrays.asList("http://lcalhost/custom")); - return cc; - default: - return null; - } - } -} diff --git a/deployment/src/test/java/org/apache/servicecomb/deployment/TestDeployment.java b/deployment/src/test/java/org/apache/servicecomb/deployment/TestDeployment.java deleted file mode 100644 index 497c50eba9f..00000000000 --- a/deployment/src/test/java/org/apache/servicecomb/deployment/TestDeployment.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.deployment; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -public class TestDeployment { - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testConfiguration() { - DefaultDeploymentProvider.setConfiguration(ConfigUtil.createLocalConfig()); - SystemBootstrapInfo info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER); - Assert.assertEquals(info.getAccessURL().get(0), "https://127.0.0.1:30100"); - info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER); - Assert.assertEquals(info.getAccessURL().get(0), "http://lcalhost/custom"); - - Assert.assertNull(Deployment.getSystemBootStrapInfo("wrong")); - } - - @Test - public void testConfigurationEnv() { - System.setProperty("servicecomb.service.registry.address", "https://localhost:9999"); - System.setProperty("servicecomb.config.client.serverUri", "https://localhost:9988"); - DefaultDeploymentProvider.setConfiguration(ConfigUtil.createLocalConfig()); - - SystemBootstrapInfo info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER); - Assert.assertEquals(info.getAccessURL().get(0), "https://localhost:9999"); - info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER); - Assert.assertEquals(info.getAccessURL().get(0), "http://lcalhost/custom"); - - System.getProperties().remove("servicecomb.service.registry.address"); - System.getProperties().remove("servicecomb.config.client.serverUri"); - } - - @Test - public void testConfigurationEnvTwo() { - System.setProperty("servicecomb.service.registry.address", "https://localhost:9999,https://localhost:9998"); - System.setProperty("servicecomb.config.client.serverUri", "https://localhost:9988,https://localhost:9987"); - DefaultDeploymentProvider.setConfiguration(ConfigUtil.createLocalConfig()); - - SystemBootstrapInfo info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER); - Assert.assertEquals(info.getAccessURL().size(), 2); - Assert.assertEquals(info.getAccessURL().get(0), "https://localhost:9999"); - Assert.assertEquals(info.getAccessURL().get(1), "https://localhost:9998"); - info = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER); - Assert.assertEquals(info.getAccessURL().get(0), "http://lcalhost/custom"); - Assert.assertEquals(info.getAccessURL().size(), 1); - - System.getProperties().remove("servicecomb.service.registry.address"); - System.getProperties().remove("servicecomb.config.client.serverUri"); - } -} diff --git a/deployment/src/test/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider b/deployment/src/test/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider deleted file mode 100644 index d07cc1e76c4..00000000000 --- a/deployment/src/test/resources/META-INF/services/org.apache.servicecomb.deployment.DeploymentProvider +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.deployment.CustomDeploymentProvider diff --git a/distribution/pom.xml b/distribution/pom.xml new file mode 100644 index 00000000000..ddd1e3de25d --- /dev/null +++ b/distribution/pom.xml @@ -0,0 +1,361 @@ + + + + 4.0.0 + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + apache-servicecomb-java-chassis-distribution + Java Chassis::Distribution + pom + + + + + org.apache.servicecomb + config-center-client + + + org.apache.servicecomb + config-clients-common + + + org.apache.servicecomb + config-kie-client + + + org.apache.servicecomb + dashboard-client + + + org.apache.servicecomb + http-client-common + + + org.apache.servicecomb + service-center-client + + + org.apache.servicecomb + registry-nacos + + + + + org.apache.servicecomb + common-access-log + + + org.apache.servicecomb + common-protobuf + + + org.apache.servicecomb + common-rest + + + + + org.apache.servicecomb + java-chassis-core + + + + + org.apache.servicecomb + config-apollo + + + org.apache.servicecomb + config-cc + + + org.apache.servicecomb + config-kie + + + org.apache.servicecomb + config-nacos + + + + + org.apache.servicecomb + edge-core + + + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-metrics + + + org.apache.servicecomb + foundation-protobuf + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + foundation-spi + + + org.apache.servicecomb + foundation-ssl + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.apache.servicecomb + foundation-vertx + + + + + org.apache.servicecomb + servicecomb-governance + + + + + org.apache.servicecomb + handler-fault-injection + + + org.apache.servicecomb + handler-flowcontrol-qps + + + org.apache.servicecomb + handler-governance + + + org.apache.servicecomb + handler-loadbalance + + + org.apache.servicecomb + handler-publickey-auth + + + org.apache.servicecomb + handler-router + + + org.apache.servicecomb + handler-tracing-zipkin + + + + + org.apache.servicecomb + metrics-core + + + org.apache.servicecomb + metrics-prometheus + + + + + org.apache.servicecomb + provider-jaxrs + + + org.apache.servicecomb + provider-pojo + + + org.apache.servicecomb + provider-rest-common + + + org.apache.servicecomb + provider-springmvc + + + + + org.apache.servicecomb + registry-lightweight + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + registry-zero-config + + + + + org.apache.servicecomb + solution-basic + + + + + org.apache.servicecomb + java-chassis-spring-boot-starter-servlet + + + org.apache.servicecomb + java-chassis-spring-boot-starter-standalone + + + + + org.apache.servicecomb + servicestage + + + org.apache.servicecomb + dashboard + + + org.apache.servicecomb + darklaunch + + + + org.apache.servicecomb + swagger-generator-core + + + org.apache.servicecomb + swagger-generator-jaxrs + + + org.apache.servicecomb + swagger-generator-spring-data + + + org.apache.servicecomb + swagger-generator-springmvc + + + + org.apache.servicecomb + swagger-invocation-core + + + org.apache.servicecomb + swagger-invocation-jaxrs + + + org.apache.servicecomb + swagger-invocation-springmvc + + + org.apache.servicecomb + swagger-invocation-validator + + + + + org.apache.servicecomb + tracing-common + + + org.apache.servicecomb + tracing-zipkin + + + + + org.apache.servicecomb + transport-common + + + org.apache.servicecomb + transport-highway + + + org.apache.servicecomb + transport-rest-client + + + org.apache.servicecomb + transport-rest-servlet + + + org.apache.servicecomb + transport-rest-vertx + + + + + + release + + + + maven-assembly-plugin + + + bin + package + + single + + + + src/assembly/bin.xml + + + + + src + package + + single + + + + src/assembly/src.xml + + + + + + + + + + diff --git a/distribution/src/assembly/bin.xml b/distribution/src/assembly/bin.xml new file mode 100644 index 00000000000..214ed04a649 --- /dev/null +++ b/distribution/src/assembly/bin.xml @@ -0,0 +1,58 @@ + + + + true + ${project.build.finalName}-bin + bin + + zip + + + + ../ + ./ + + README_ZH.md + README.md + + + + src/release + ./ + + NOTICE + LICENSE + licenses/** + + + + + + true + false + ./libs + runtime + + org.apache.servicecomb:* + org.apache.servicecomb.archetypes:* + + + + diff --git a/java-chassis-distribution/src/assembly/src.xml b/distribution/src/assembly/src.xml similarity index 100% rename from java-chassis-distribution/src/assembly/src.xml rename to distribution/src/assembly/src.xml diff --git a/distribution/src/release/LICENSE b/distribution/src/release/LICENSE new file mode 100644 index 00000000000..b75be79468a --- /dev/null +++ b/distribution/src/release/LICENSE @@ -0,0 +1,240 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= +Apache ServiceComb Java Chassis Subcomponents: + +The Apache ServiceComb Java Chassis project contains subcomponents with +separate copyright notices and license terms. Your use of these +subcomponents is subject to the terms and conditions of the +following licenses. + +================================================================ +For foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java + transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java +================================================================ +This product bundles files from vertx which is licensed under the Apache License v2. +For details, see https://github.com/vert-x3/vertx-web + +================================================================ +For swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java +================================================================ +This product bundles files from swagger which is licensed under the Apache License v2. +For details, see https://github.com/swagger-api/swagger-core + +================================================================ +For foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldSchema.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldTypeUtils.java + foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/HashFieldMapEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/ByteArrayInputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/InputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/OutputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/package-info.java + foundations/foundation-protobuf/src/main/java/io/protostuff/ProtobufOutputEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaEx.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaReader.java + foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java +================================================================ +This product bundles files from protostuff which is licensed under the Apache License v2. +For details, see https://github.com/protostuff/protostuff diff --git a/distribution/src/release/NOTICE b/distribution/src/release/NOTICE new file mode 100644 index 00000000000..5ed927047d5 --- /dev/null +++ b/distribution/src/release/NOTICE @@ -0,0 +1,5 @@ +Apache ServiceComb Java Chassis +Copyright 2017-2024 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-abego b/distribution/src/release/licenses/LICENSE-abego similarity index 89% rename from java-chassis-distribution/src/release/licenses/LICENSE-abego rename to distribution/src/release/licenses/LICENSE-abego index a4fe241d454..1620af43b30 100644 --- a/java-chassis-distribution/src/release/licenses/LICENSE-abego +++ b/distribution/src/release/licenses/LICENSE-abego @@ -2,26 +2,26 @@ Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org) All rights reserved. -Redistribution and use in source and binary forms, with or without +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. Neither the name of the abego Software GmbH nor the names of its - contributors may be used to endorse or promote products derived from this +3. Neither the name of the abego Software GmbH nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/distribution/src/release/licenses/LICENSE-animalsniffer b/distribution/src/release/licenses/LICENSE-animalsniffer new file mode 100644 index 00000000000..4e28c7bc322 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-animalsniffer @@ -0,0 +1,21 @@ + The MIT License + + Copyright (c) 2009 codehaus.org. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-antlr b/distribution/src/release/licenses/LICENSE-antlr similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-antlr rename to distribution/src/release/licenses/LICENSE-antlr diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-asm b/distribution/src/release/licenses/LICENSE-asm similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-asm rename to distribution/src/release/licenses/LICENSE-asm diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-bouncycastle b/distribution/src/release/licenses/LICENSE-bouncycastle similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-bouncycastle rename to distribution/src/release/licenses/LICENSE-bouncycastle diff --git a/distribution/src/release/licenses/LICENSE-cc0 b/distribution/src/release/licenses/LICENSE-cc0 new file mode 100644 index 00000000000..4417dbeef04 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-cc0 @@ -0,0 +1,26 @@ +Statement of Purpose +The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: + +the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; +moral rights retained by the original author(s) and/or performer(s); +publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; +rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; +rights protecting the extraction, dissemination, use and reuse of data in a Work; +database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and +other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. +2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + +No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. +Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. +Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. +Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-javax-el b/distribution/src/release/licenses/LICENSE-cddl similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-javax-el rename to distribution/src/release/licenses/LICENSE-cddl diff --git a/distribution/src/release/licenses/LICENSE-checkerqual b/distribution/src/release/licenses/LICENSE-checkerqual new file mode 100644 index 00000000000..7f197e96dec --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-checkerqual @@ -0,0 +1,19 @@ +MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/distribution/src/release/licenses/LICENSE-edl-v10 b/distribution/src/release/licenses/LICENSE-edl-v10 new file mode 100644 index 00000000000..90202907fd2 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-edl-v10 @@ -0,0 +1,12 @@ +Eclipse Distribution License - v 1.0 + +Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-epl-v10 b/distribution/src/release/licenses/LICENSE-epl-v10 similarity index 99% rename from java-chassis-distribution/src/release/licenses/LICENSE-epl-v10 rename to distribution/src/release/licenses/LICENSE-epl-v10 index 3fa00836fa4..b0476ee93e8 100644 --- a/java-chassis-distribution/src/release/licenses/LICENSE-epl-v10 +++ b/distribution/src/release/licenses/LICENSE-epl-v10 @@ -83,4 +83,4 @@ All Recipient's rights under this Agreement shall terminate if it fails to compl Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. -This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. \ No newline at end of file +This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. diff --git a/distribution/src/release/licenses/LICENSE-epl-v20 b/distribution/src/release/licenses/LICENSE-epl-v20 new file mode 100644 index 00000000000..cc0fb9400de --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-epl-v20 @@ -0,0 +1,81 @@ +Eclipse Public License - v 2.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS +“Contribution” means: + +a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. +“Contributor” means any person or entity that Distributes the Program. + +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +“Program” means the Contributions Distributed in accordance with this Agreement. + +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. + +2. GRANT OF RIGHTS +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). +3. REQUIREMENTS +3.1 If a Contributor Distributes the Program in any form, then: + +a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and +b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: +i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and +iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. +3.2 When the Program is Distributed as Source Code: + +a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and +b) a copy of this Agreement must be included with each copy of the Program. +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + +Exhibit A – Form of Secondary Licenses Notice +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” + +Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. diff --git a/distribution/src/release/licenses/LICENSE-hamcrest b/distribution/src/release/licenses/LICENSE-hamcrest new file mode 100644 index 00000000000..4933bda5bac --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-hamcrest @@ -0,0 +1,27 @@ +BSD License + +Copyright (c) 2000-2015 www.hamcrest.org +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the distribution. + +Neither the name of Hamcrest nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-hdrhistogram b/distribution/src/release/licenses/LICENSE-hdrhistogram similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-hdrhistogram rename to distribution/src/release/licenses/LICENSE-hdrhistogram diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-icu4j b/distribution/src/release/licenses/LICENSE-icu4j similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-icu4j rename to distribution/src/release/licenses/LICENSE-icu4j diff --git a/distribution/src/release/licenses/LICENSE-jcodings b/distribution/src/release/licenses/LICENSE-jcodings new file mode 100644 index 00000000000..f85e365de02 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-jcodings @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/distribution/src/release/licenses/LICENSE-joni b/distribution/src/release/licenses/LICENSE-joni new file mode 100644 index 00000000000..9341f05eee9 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-joni @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 JRuby Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/distribution/src/release/licenses/LICENSE-jopt b/distribution/src/release/licenses/LICENSE-jopt new file mode 100644 index 00000000000..6b6553bc94e --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-jopt @@ -0,0 +1,22 @@ +The MIT License + + Copyright (c) 2004-2016 Paul R. Holser, Jr. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-jsonp b/distribution/src/release/licenses/LICENSE-jsonp similarity index 99% rename from java-chassis-distribution/src/release/licenses/LICENSE-jsonp rename to distribution/src/release/licenses/LICENSE-jsonp index 07368a285ae..75372e3d2c9 100644 --- a/java-chassis-distribution/src/release/licenses/LICENSE-jsonp +++ b/distribution/src/release/licenses/LICENSE-jsonp @@ -1,5 +1,5 @@ 1. Definitions. - + 1.1. "Contributor" means each individual or entity that creates or contributes to the creation of Modifications. diff --git a/distribution/src/release/licenses/LICENSE-jsoup b/distribution/src/release/licenses/LICENSE-jsoup new file mode 100644 index 00000000000..6ae61c02ba6 --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-jsoup @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2009-2018 Jonathan Hedley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-jsr311-api b/distribution/src/release/licenses/LICENSE-jsr311-api similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-jsr311-api rename to distribution/src/release/licenses/LICENSE-jsr311-api diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-logback b/distribution/src/release/licenses/LICENSE-logback similarity index 90% rename from java-chassis-distribution/src/release/licenses/LICENSE-logback rename to distribution/src/release/licenses/LICENSE-logback index 8953762a3cd..1f99506bfa4 100644 --- a/java-chassis-distribution/src/release/licenses/LICENSE-logback +++ b/distribution/src/release/licenses/LICENSE-logback @@ -11,4 +11,4 @@ the Eclipse Foundation or (per the licensee's choosing) under the terms of the GNU Lesser General Public License version 2.1 -as published by the Free Software Foundation. \ No newline at end of file +as published by the Free Software Foundation. diff --git a/distribution/src/release/licenses/LICENSE-mozilla-v20 b/distribution/src/release/licenses/LICENSE-mozilla-v20 new file mode 100644 index 00000000000..b3b8d93f36c --- /dev/null +++ b/distribution/src/release/licenses/LICENSE-mozilla-v20 @@ -0,0 +1,151 @@ +Mozilla Public License +Version 2.0 +1. Definitions +1.1. “Contributor” +means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. + +1.2. “Contributor Version” +means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” +means Covered Software of a particular Contributor. + +1.4. “Covered Software” +means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. + +1.5. “Incompatible With Secondary Licenses” +means + +that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or + +that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. + +1.6. “Executable Form” +means any form of the work other than Source Code Form. + +1.7. “Larger Work” +means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. + +1.8. “License” +means this document. + +1.9. “Licensable” +means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. + +1.10. “Modifications” +means any of the following: + +any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or + +any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor +means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. + +1.12. “Secondary License” +means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” +means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) +means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants and Conditions +2.1. Grants +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + +under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and + +under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. + +2.2. Effective Date +The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. + +2.3. Limitations on Grant Scope +The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: + +for any code that a Contributor has removed from Covered Software; or + +for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or + +under Patent Claims infringed by Covered Software in the absence of its Contributions. + +This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). + +2.4. Subsequent Licenses +No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). + +2.5. Representation +Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use +This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. + +3. Responsibilities +3.1. Distribution of Source Form +All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form +If You distribute Covered Software in Executable Form then: + +such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and + +You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work +You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). + +3.4. Notices +You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms +You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Termination +5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. + +6. Disclaimer of Warranty +Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. + +7. Limitation of Liability +Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation +Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous +This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. + +10. Versions of the License +10.1. New Versions +Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. + +10.2. Effect of New Versions +You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. + +10.3. Modified Versions +If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses +If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice +This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-protobuf b/distribution/src/release/licenses/LICENSE-protobuf similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-protobuf rename to distribution/src/release/licenses/LICENSE-protobuf diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-slf4j b/distribution/src/release/licenses/LICENSE-slf4j similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-slf4j rename to distribution/src/release/licenses/LICENSE-slf4j diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-woodstox-stax2-api b/distribution/src/release/licenses/LICENSE-woodstox-stax2-api similarity index 100% rename from java-chassis-distribution/src/release/licenses/LICENSE-woodstox-stax2-api rename to distribution/src/release/licenses/LICENSE-woodstox-stax2-api diff --git a/java-chassis-distribution/src/release/licenses/NOTICE-apache-commons-codec b/distribution/src/release/licenses/NOTICE-apache-commons-codec similarity index 100% rename from java-chassis-distribution/src/release/licenses/NOTICE-apache-commons-codec rename to distribution/src/release/licenses/NOTICE-apache-commons-codec diff --git a/java-chassis-distribution/src/release/licenses/NOTICE-netty b/distribution/src/release/licenses/NOTICE-netty similarity index 100% rename from java-chassis-distribution/src/release/licenses/NOTICE-netty rename to distribution/src/release/licenses/NOTICE-netty diff --git a/java-chassis-distribution/src/release/licenses/NOTICE-prometheus b/distribution/src/release/licenses/NOTICE-prometheus similarity index 100% rename from java-chassis-distribution/src/release/licenses/NOTICE-prometheus rename to distribution/src/release/licenses/NOTICE-prometheus diff --git a/distribution/src/release/licenses/NOTICE-protostuff b/distribution/src/release/licenses/NOTICE-protostuff new file mode 100644 index 00000000000..1f95779a7fb --- /dev/null +++ b/distribution/src/release/licenses/NOTICE-protostuff @@ -0,0 +1,27 @@ +============================================================== + protostuff + Copyright 2009 David Yu dyuproject@gmail.com +============================================================== + +protobuf is copyright Google inc unless otherwise noted. +It is licensed under the BSD license. + +jackson-core-asl is copyright FasterXml unless otherwise noted. +It is licensed under the apache 2.0 license. + +antlr is copyright Terence Parr unless otherwise noted. +It is licensed under the BSD license. + +stringtemplate is copyright Terence Parr unless otherwise noted. +It is licensed under the BSD license. + +velocity is licensed under the apache 2.0 license. + +B64Code.java is copyright Mort Bay Consulting Pty Ltd unless otherwise noted. +It is licensed under the apache 2.0 license. + +jarjar is copyright Google inc unless otherwise noted. +It is licensed under the apache 2.0 license. + +guava is copyright Google inc unless otherwise noted. +It is licensed under the apache 2.0 license. diff --git a/java-chassis-distribution/src/release/licenses/NOTICE-tomcat b/distribution/src/release/licenses/NOTICE-tomcat similarity index 100% rename from java-chassis-distribution/src/release/licenses/NOTICE-tomcat rename to distribution/src/release/licenses/NOTICE-tomcat diff --git a/dynamic-config/config-apollo/pom.xml b/dynamic-config/config-apollo/pom.xml index 321990a68e3..7cc03d182dd 100644 --- a/dynamic-config/config-apollo/pom.xml +++ b/dynamic-config/config-apollo/pom.xml @@ -22,7 +22,7 @@ dynamic-config org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 config-apollo @@ -40,9 +40,5 @@ org.springframework spring-web - - javax.validation - validation-api - diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloClient.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloClient.java new file mode 100644 index 00000000000..61c6a9c5c7d --- /dev/null +++ b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloClient.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.apollo; + +import static org.apache.servicecomb.config.apollo.ConfigurationAction.CREATE; +import static org.apache.servicecomb.config.apollo.ConfigurationAction.DELETE; +import static org.apache.servicecomb.config.apollo.ConfigurationAction.SET; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.config.apollo.ApolloDynamicPropertiesSource.UpdateHandler; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.google.common.annotations.VisibleForTesting; + +import io.netty.handler.codec.http.HttpResponseStatus; + +public class ApolloClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApolloClient.class); + + private static final Map originalConfigMap = new ConcurrentHashMap<>(); + + private static final ScheduledExecutorService EXECUTOR = Executors.newScheduledThreadPool(1); + + private final ApolloConfig apolloConfig; + + private final UpdateHandler updateHandler; + + private static RestTemplate rest = new RestTemplate(); + + public ApolloClient(UpdateHandler updateHandler, ApolloConfig apolloConfig) { + this.updateHandler = updateHandler; + this.apolloConfig = apolloConfig; + } + + @VisibleForTesting + static Map getOriginalConfigMap() { + return originalConfigMap; + } + + @VisibleForTesting + static void setRest(RestTemplate rest) { + ApolloClient.rest = rest; + } + + public void refreshApolloConfig() { + EXECUTOR.scheduleWithFixedDelay(new ConfigRefresh(apolloConfig.getServerUri()), + apolloConfig.getFirstRefreshInterval(), + apolloConfig.getRefreshInterval(), TimeUnit.SECONDS); + } + + class ConfigRefresh implements Runnable { + private final String serviceUri; + + ConfigRefresh(String serviceUris) { + this.serviceUri = serviceUris; + } + + @Override + public void run() { + try { + refreshConfig(); + } catch (Throwable e) { + LOGGER.error("client refresh thread exception ", e); + } + } + + @SuppressWarnings("unchecked") + void refreshConfig() { + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", "application/json;charset=UTF-8"); + headers.add("Authorization", apolloConfig.getToken()); + HttpEntity entity = new HttpEntity<>(headers); + ResponseEntity exchange = rest.exchange(composeAPI(), HttpMethod.GET, entity, String.class); + if (HttpResponseStatus.OK.code() == exchange.getStatusCode().value()) { + try { + Map body = JsonUtils.OBJ_MAPPER.readValue(exchange.getBody(), + new TypeReference>() { + }); + refreshConfigItems((Map) body.get("configurations")); + } catch (IOException e) { + LOGGER.error("JsonObject parse config center response error: ", e); + } + } else { + LOGGER.error("fetch configuration failed, error code:{} for {}", + exchange.getStatusCode().value(), + exchange.getBody()); + } + } + + private String composeAPI() { + String api = serviceUri + "/openapi/v1/envs/" + apolloConfig.getEnv() + + "/apps/" + apolloConfig.getServiceName() + + "/clusters/" + apolloConfig.getServerClusters() + + "/namespaces/" + apolloConfig.getNamespace() + + "/releases/latest"; + return api; + } + + private void refreshConfigItems(Map map) { + compareChangedConfig(originalConfigMap, map); + originalConfigMap.clear(); + originalConfigMap.putAll(map); + } + + void compareChangedConfig(Map before, Map after) { + Map itemsCreated = new HashMap<>(); + Map itemsDeleted = new HashMap<>(); + Map itemsModified = new HashMap<>(); + if (before == null || before.isEmpty()) { + updateHandler.handle(CREATE, after); + return; + } + if (after == null || after.isEmpty()) { + updateHandler.handle(DELETE, before); + return; + } + after.forEach((itemKey, itemValue) -> { + if (!before.containsKey(itemKey)) { + itemsCreated.put(itemKey, itemValue); + } else if (!itemValue.equals(before.get(itemKey))) { + itemsModified.put(itemKey, itemValue); + } + }); + for (String itemKey : before.keySet()) { + if (!after.containsKey(itemKey)) { + itemsDeleted.put(itemKey, ""); + } + } + updateHandler.handle(CREATE, itemsCreated); + updateHandler.handle(SET, itemsModified); + updateHandler.handle(DELETE, itemsDeleted); + } + } +} diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfig.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfig.java new file mode 100644 index 00000000000..97509b9ee15 --- /dev/null +++ b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfig.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.apollo; + +import org.springframework.core.env.Environment; + +public class ApolloConfig { + private static final String SERVER_URL_KEY = "apollo.config.serverUri"; + + private static final String SERVER_NAMESPACE = "apollo.config.namespace"; + + private static final String SERVER_ENV = "apollo.config.env"; + + private static final String SERVER_CLUSTERS = "apollo.config.clusters"; + + private static final String APOLLO_SERVICE_NAME = "apollo.config.serviceName"; + + private static final String TOKEN = "apollo.config.token"; + + private static final String REFRESH_INTERVAL = "apollo.config.refreshInterval"; + + private static final String FIRST_REFRESH_INTERVAL = "apollo.config.firstRefreshInterval"; + + private static final int DEFAULT_REFRESH_INTERVAL = 3; + + private static final int DEFAULT_FIRST_REFRESH_INTERVAL = 0; + + private final Environment environment; + + public ApolloConfig(Environment environment) { + this.environment = environment; + } + + public String getServiceName() { + return environment.getProperty(APOLLO_SERVICE_NAME); + } + + public String getServerUri() { + return environment.getProperty(SERVER_URL_KEY); + } + + public String getToken() { + return environment.getProperty(TOKEN); + } + + public String getEnv() { + return environment.getProperty(SERVER_ENV); + } + + public String getNamespace() { + return environment.getProperty(SERVER_NAMESPACE); + } + + public String getServerClusters() { + return environment.getProperty(SERVER_CLUSTERS); + } + + public int getRefreshInterval() { + return environment.getProperty(REFRESH_INTERVAL, int.class, DEFAULT_REFRESH_INTERVAL); + } + + public int getFirstRefreshInterval() { + return environment.getProperty(FIRST_REFRESH_INTERVAL, int.class, DEFAULT_FIRST_REFRESH_INTERVAL); + } +} diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfiguration.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfiguration.java new file mode 100644 index 00000000000..152f23962c2 --- /dev/null +++ b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloConfiguration.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.apollo; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ApolloConfiguration { + +} diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloDynamicPropertiesSource.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloDynamicPropertiesSource.java new file mode 100644 index 00000000000..4a1113283e0 --- /dev/null +++ b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ApolloDynamicPropertiesSource.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.apollo; + +import static org.apache.servicecomb.config.apollo.ConfigurationAction.CREATE; +import static org.apache.servicecomb.config.apollo.ConfigurationAction.DELETE; +import static org.apache.servicecomb.config.apollo.ConfigurationAction.SET; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.config.ConfigMapping; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +public class ApolloDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "apollo"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ApolloDynamicPropertiesSource.class); + + private final Map valueCache = new ConcurrentHashMap<>(); + + private final ApolloDynamicPropertiesSource.UpdateHandler updateHandler = + new ApolloDynamicPropertiesSource.UpdateHandler(); + + public ApolloDynamicPropertiesSource() { + } + + @Override + public int getOrder() { + return 300; + } + + private void init(Environment environment) { + ApolloConfig apolloConfig = new ApolloConfig(environment); + ApolloClient apolloClient = new ApolloClient(updateHandler, apolloConfig); + apolloClient.refreshApolloConfig(); + } + + public class UpdateHandler { + public void handle(ConfigurationAction action, Map config) { + if (config == null || config.isEmpty()) { + return; + } + Map configuration = ConfigMapping.getConvertedMap(config); + if (CREATE.equals(action)) { + valueCache.putAll(configuration); + } else if (SET.equals(action)) { + valueCache.putAll(configuration); + } else if (DELETE.equals(action)) { + configuration.keySet().forEach(valueCache::remove); + } else { + LOGGER.error("action: {} is invalid.", action.name()); + return; + } + LOGGER.warn("Config value cache changed: action:{}; item:{}", action.name(), configuration.keySet()); + } + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, valueCache); + } +} diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ConfigurationAction.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ConfigurationAction.java similarity index 94% rename from dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ConfigurationAction.java rename to dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ConfigurationAction.java index 5daf1972cfd..1a0047152b2 100644 --- a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ConfigurationAction.java +++ b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/apollo/ConfigurationAction.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.config.client; +package org.apache.servicecomb.config.apollo; public enum ConfigurationAction { CREATE, diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImpl.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImpl.java deleted file mode 100644 index 171cfb6e914..00000000000 --- a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImpl.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -import static com.netflix.config.WatchedUpdateResult.createIncremental; -import static org.apache.servicecomb.config.client.ConfigurationAction.CREATE; -import static org.apache.servicecomb.config.client.ConfigurationAction.DELETE; -import static org.apache.servicecomb.config.client.ConfigurationAction.SET; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.validation.constraints.NotNull; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.ConfigMapping; -import org.apache.servicecomb.config.client.ApolloClient; -import org.apache.servicecomb.config.client.ApolloConfig; -import org.apache.servicecomb.config.client.ConfigurationAction; -import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableMap; -import com.netflix.config.WatchedUpdateListener; -import com.netflix.config.WatchedUpdateResult; - -public class ApolloConfigurationSourceImpl implements ConfigCenterConfigurationSource { - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterConfigurationSource.class); - - private final Map valueCache = new ConcurrentHashMap<>(); - - private List listeners = new CopyOnWriteArrayList<>(); - - private static final String APOLLO_CONFIG_URL_KEY = "apollo.config.serverUri"; - - public ApolloConfigurationSourceImpl() { - } - - private final UpdateHandler updateHandler = new UpdateHandler(); - - @Override - public boolean isValidSource(Configuration localConfiguration) { - if (localConfiguration.getProperty(APOLLO_CONFIG_URL_KEY) == null) { - LOGGER.warn("Apollo configuration source is not configured!"); - return false; - } - return true; - } - - @Override - public void init(Configuration localConfiguration) { - ApolloConfig.setConcurrentCompositeConfiguration(localConfiguration); - init(); - } - - private void init() { - ApolloClient apolloClient = new ApolloClient(updateHandler); - apolloClient.refreshApolloConfig(); - } - - @Override - public void addUpdateListener(@NotNull WatchedUpdateListener watchedUpdateListener) { - listeners.add(watchedUpdateListener); - } - - @Override - public void removeUpdateListener(@NotNull WatchedUpdateListener watchedUpdateListener) { - listeners.remove(watchedUpdateListener); - } - - private void updateConfiguration(WatchedUpdateResult result) { - for (WatchedUpdateListener l : listeners) { - try { - l.updateConfiguration(result); - } catch (Throwable ex) { - LOGGER.error("Error in invoking WatchedUpdateListener", ex); - } - } - } - - @Override - public Map getCurrentData() throws Exception { - return valueCache; - } - - public List getCurrentListeners() { - return listeners; - } - - public class UpdateHandler { - public void handle(ConfigurationAction action, Map config) { - if (config == null || config.isEmpty()) { - return; - } - Map configuration = ConfigMapping.getConvertedMap(config); - if (CREATE.equals(action)) { - valueCache.putAll(configuration); - - updateConfiguration(createIncremental(ImmutableMap.copyOf(configuration), - null, - null)); - } else if (SET.equals(action)) { - valueCache.putAll(configuration); - - updateConfiguration(createIncremental(null, - ImmutableMap.copyOf(configuration), - null)); - } else if (DELETE.equals(action)) { - for (String itemKey : configuration.keySet()) { - valueCache.remove(itemKey); - } - updateConfiguration(createIncremental(null, - null, - ImmutableMap.copyOf(configuration))); - } else { - LOGGER.error("action: {} is invalid.", action.name()); - return; - } - LOGGER.warn("Config value cache changed: action:{}; item:{}", action.name(), configuration.keySet()); - } - } -} diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloClient.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloClient.java deleted file mode 100644 index 54a23fa5c31..00000000000 --- a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloClient.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import static org.apache.servicecomb.config.client.ConfigurationAction.CREATE; -import static org.apache.servicecomb.config.client.ConfigurationAction.DELETE; -import static org.apache.servicecomb.config.client.ConfigurationAction.SET; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.config.archaius.sources.ApolloConfigurationSourceImpl.UpdateHandler; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import com.fasterxml.jackson.core.type.TypeReference; - -import io.netty.handler.codec.http.HttpResponseStatus; - -public class ApolloClient { - - private static final Logger LOGGER = LoggerFactory.getLogger(ApolloClient.class); - - private static final ApolloConfig APOLLO_CONFIG = ApolloConfig.INSTANCE; - - private static final Map originalConfigMap = new ConcurrentHashMap<>(); - - private static final ScheduledExecutorService EXECUTOR = Executors.newScheduledThreadPool(1); - - private final int refreshInterval = APOLLO_CONFIG.getRefreshInterval(); - - private final int firstRefreshInterval = APOLLO_CONFIG.getFirstRefreshInterval(); - - private final String serviceUri = APOLLO_CONFIG.getServerUri(); - - private final String serviceName = APOLLO_CONFIG.getServiceName(); - - private final String token = APOLLO_CONFIG.getToken(); - - private final String env = APOLLO_CONFIG.getEnv(); - - private final String clusters = APOLLO_CONFIG.getServerClusters(); - - private final String namespace = APOLLO_CONFIG.getNamespace(); - - private final UpdateHandler updateHandler; - - private static RestTemplate rest = new RestTemplate(); - - public ApolloClient(UpdateHandler updateHandler) { - this.updateHandler = updateHandler; - } - - public void refreshApolloConfig() { - EXECUTOR - .scheduleWithFixedDelay(new ConfigRefresh(serviceUri), firstRefreshInterval, refreshInterval, TimeUnit.SECONDS); - } - - class ConfigRefresh implements Runnable { - private final String serviceUri; - - ConfigRefresh(String serviceUris) { - this.serviceUri = serviceUris; - } - - @Override - public void run() { - try { - refreshConfig(); - } catch (Exception e) { - - LOGGER.error("client refresh thread exception ", e); - } - } - - @SuppressWarnings("unchecked") - void refreshConfig() { - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Type", "application/json;charset=UTF-8"); - headers.add("Authorization", token); - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity exchange = rest.exchange(composeAPI(), HttpMethod.GET, entity, String.class); - if (HttpResponseStatus.OK.code() == exchange.getStatusCode().value()) { - try { - Map body = JsonUtils.OBJ_MAPPER.readValue(exchange.getBody(), - new TypeReference>() { - }); - refreshConfigItems((Map) body.get("configurations")); - } catch (IOException e) { - LOGGER.error("JsonObject parse config center response error: ", e); - } - } else { - LOGGER.error("fetch configuration failed, error code:{} for {}", - exchange.getStatusCodeValue(), - exchange.getBody()); - } - } - - private String composeAPI() { - String api = serviceUri + "/openapi/v1/envs/" + env + - "/apps/" + serviceName + - "/clusters/" + clusters + - "/namespaces/" + namespace + - "/releases/latest"; - return api; - } - - private void refreshConfigItems(Map map) { - compareChangedConfig(originalConfigMap, map); - originalConfigMap.clear(); - originalConfigMap.putAll(map); - } - - void compareChangedConfig(Map before, Map after) { - Map itemsCreated = new HashMap<>(); - Map itemsDeleted = new HashMap<>(); - Map itemsModified = new HashMap<>(); - if (before == null || before.isEmpty()) { - updateHandler.handle(CREATE, after); - return; - } - if (after == null || after.isEmpty()) { - updateHandler.handle(DELETE, before); - return; - } - for (String itemKey : after.keySet()) { - if (!before.containsKey(itemKey)) { - itemsCreated.put(itemKey, after.get(itemKey)); - } else if (!after.get(itemKey).equals(before.get(itemKey))) { - itemsModified.put(itemKey, after.get(itemKey)); - } - } - for (String itemKey : before.keySet()) { - if (!after.containsKey(itemKey)) { - itemsDeleted.put(itemKey, ""); - } - } - updateHandler.handle(CREATE, itemsCreated); - updateHandler.handle(SET, itemsModified); - updateHandler.handle(DELETE, itemsDeleted); - } - } -} - diff --git a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloConfig.java b/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloConfig.java deleted file mode 100644 index b8de462e3c6..00000000000 --- a/dynamic-config/config-apollo/src/main/java/org/apache/servicecomb/config/client/ApolloConfig.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import org.apache.commons.configuration.Configuration; - -public class ApolloConfig { - public static final ApolloConfig INSTANCE = new ApolloConfig(); - - private static Configuration finalConfig; - - private static final String SERVER_URL_KEY = "apollo.config.serverUri"; - - private static final String SERVER_NAMESPACE = "apollo.config.namespace"; - - private static final String SERVER_ENV = "apollo.config.env"; - - private static final String SERVER_CLUSTERS = "apollo.config.clusters"; - - private static final String APOLLO_SERVICE_NAME = "apollo.config.serviceName"; - - private static final String TOKEN = "apollo.config.token"; - - private static final String REFRESH_INTERVAL = "apollo.config.refreshInterval"; - - private static final String FIRST_REFRESH_INTERVAL = "apollo.config.firstRefreshInterval"; - - private static final int DEFAULT_REFRESH_INTERVAL = 3; - - private static final int DEFAULT_FIRST_REFRESH_INTERVAL = 0; - - private ApolloConfig() { - } - - public static void setConcurrentCompositeConfiguration(Configuration config) { - finalConfig = config; - } - - public Configuration getConcurrentCompositeConfiguration() { - return finalConfig; - } - - public String getServiceName() { - return finalConfig.getString(APOLLO_SERVICE_NAME); - } - - public String getServerUri() { - return finalConfig.getString(SERVER_URL_KEY); - } - - public String getToken() { - return finalConfig.getString(TOKEN); - } - - public String getEnv() { - return finalConfig.getString(SERVER_ENV); - } - - public String getNamespace() { - return finalConfig.getString(SERVER_NAMESPACE); - } - - public String getServerClusters() { - return finalConfig.getString(SERVER_CLUSTERS); - } - - public int getRefreshInterval() { - return finalConfig.getInt(REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL); - } - - public int getFirstRefreshInterval() { - return finalConfig.getInt(FIRST_REFRESH_INTERVAL, DEFAULT_FIRST_REFRESH_INTERVAL); - } -} diff --git a/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..aa0aae8be0b --- /dev/null +++ b/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.apollo.ApolloDynamicPropertiesSource diff --git a/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource b/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource deleted file mode 100644 index fa6f9b75892..00000000000 --- a/dynamic-config/config-apollo/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.config.archaius.sources.ApolloConfigurationSourceImpl diff --git a/dynamic-config/config-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dynamic-config/config-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..31e45053446 --- /dev/null +++ b/dynamic-config/config-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.config.apollo.ApolloConfiguration diff --git a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/apollo/ApolloClientTest.java b/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/apollo/ApolloClientTest.java new file mode 100644 index 00000000000..65bc6632c72 --- /dev/null +++ b/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/apollo/ApolloClientTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.apollo; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.config.apollo.ApolloClient.ConfigRefresh; +import org.apache.servicecomb.config.apollo.ApolloDynamicPropertiesSource.UpdateHandler; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +public class ApolloClientTest { + @BeforeAll + public static void setUpClass() { + + } + + @Test + public void refreshApolloConfig() { + ApolloConfig apolloConfig = Mockito.mock(ApolloConfig.class); + RestTemplate rest = Mockito.mock(RestTemplate.class); + ApolloClient.setRest(rest); + + ResponseEntity responseEntity = new ResponseEntity<>( + "{\"apollo\":\"mocked\", \"configurations\":{\"timeout\":1000}}", HttpStatus.OK); + Mockito.when(rest.exchange( + ArgumentMatchers.anyString(), + ArgumentMatchers.any(HttpMethod.class), + ArgumentMatchers.>any(), + ArgumentMatchers.>any())).thenReturn(responseEntity); + ApolloDynamicPropertiesSource impl = new ApolloDynamicPropertiesSource(); + UpdateHandler updateHandler = impl.new UpdateHandler(); + ApolloClient apolloClient = new ApolloClient(updateHandler, apolloConfig); + ConfigRefresh cr = apolloClient.new ConfigRefresh(apolloConfig.getServerUri()); + cr.run(); + + Assertions.assertEquals(1, ApolloClient.getOriginalConfigMap().size()); + } + + @Test + public void testCompareChangedConfig() { + ApolloConfig apolloConfig = Mockito.mock(ApolloConfig.class); + boolean status = true; + Map before = new HashMap<>(); + Map after = new HashMap<>(); + + ApolloDynamicPropertiesSource impl = new ApolloDynamicPropertiesSource(); + UpdateHandler updateHandler = impl.new UpdateHandler(); + ApolloClient apolloClient = new ApolloClient(updateHandler, apolloConfig); + + ConfigRefresh cr = apolloClient.new ConfigRefresh(""); + + try { + cr.compareChangedConfig(before, after); + } catch (Exception e) { + status = false; + } + Assertions.assertTrue(status); + + before.put("test", "testValue"); + try { + cr.compareChangedConfig(before, after); + } catch (Exception e) { + status = false; + } + Assertions.assertTrue(status); + + after.put("test", "testValue2"); + try { + cr.compareChangedConfig(before, after); + } catch (Exception e) { + status = false; + } + Assertions.assertTrue(status); + + try { + cr.compareChangedConfig(before, after); + } catch (Exception e) { + status = false; + } + Assertions.assertTrue(status); + } +} diff --git a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImplTest.java b/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImplTest.java deleted file mode 100644 index 6c8790d3536..00000000000 --- a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/archaius/sources/ApolloConfigurationSourceImplTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -import static org.apache.servicecomb.config.client.ConfigurationAction.CREATE; -import static org.apache.servicecomb.config.client.ConfigurationAction.DELETE; -import static org.apache.servicecomb.config.client.ConfigurationAction.SET; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.config.archaius.sources.ApolloConfigurationSourceImpl.UpdateHandler; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.WatchedUpdateListener; - -import mockit.Deencapsulation; - -public class ApolloConfigurationSourceImplTest { - @Test - public void testCreate() throws Exception { - - ApolloConfigurationSourceImpl apolloConfigurationSource = new ApolloConfigurationSourceImpl(); - apolloConfigurationSource.addUpdateListener(result -> Assert.assertTrue(!result.getAdded().isEmpty())); - UpdateHandler udateHandler = Deencapsulation.getField(apolloConfigurationSource, UpdateHandler.class); - Map createItems = new HashMap<>(); - createItems.put("testKey", "testValue"); - udateHandler.handle(CREATE, createItems); - } - - @Test - public void testUpdate() throws Exception { - - ApolloConfigurationSourceImpl apolloConfigurationSource = new ApolloConfigurationSourceImpl(); - apolloConfigurationSource.addUpdateListener(result -> Assert.assertTrue(!result.getChanged().isEmpty())); - UpdateHandler udateHandler = Deencapsulation.getField(apolloConfigurationSource, UpdateHandler.class); - Map updateItems = new HashMap<>(); - updateItems.put("testKey", "testValue"); - udateHandler.handle(SET, updateItems); - } - - @Test - public void testDelete() throws Exception { - ApolloConfigurationSourceImpl apolloConfigurationSource = new ApolloConfigurationSourceImpl(); - apolloConfigurationSource.addUpdateListener(result -> Assert.assertTrue(!result.getDeleted().isEmpty())); - UpdateHandler udateHandler = Deencapsulation.getField(apolloConfigurationSource, UpdateHandler.class); - Map deleteItems = new HashMap<>(); - deleteItems.put("testKey", "testValue"); - - apolloConfigurationSource.getCurrentData().put("testKey", "testValue"); - udateHandler.handle(DELETE, deleteItems); - Assert.assertTrue(apolloConfigurationSource.getCurrentData().isEmpty()); - } - - @Test - public void testRemoveUpdateListener() { - ApolloConfigurationSourceImpl apolloConfigurationSource = new ApolloConfigurationSourceImpl(); - WatchedUpdateListener watchedUpdateListener = Mockito.mock(WatchedUpdateListener.class); - apolloConfigurationSource.addUpdateListener(watchedUpdateListener); - apolloConfigurationSource.removeUpdateListener(watchedUpdateListener); - Assert.assertTrue(apolloConfigurationSource.getCurrentListeners().isEmpty()); - } -} diff --git a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloClientTest.java b/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloClientTest.java deleted file mode 100644 index 774356caf1c..00000000000 --- a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloClientTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.config.archaius.sources.ApolloConfigurationSourceImpl; -import org.apache.servicecomb.config.archaius.sources.ApolloConfigurationSourceImpl.UpdateHandler; -import org.apache.servicecomb.config.client.ApolloClient.ConfigRefresh; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Matchers; -import org.mockito.Mockito; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import mockit.Deencapsulation; - -public class ApolloClientTest { - @BeforeClass - public static void setUpClass() { - - ApolloConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - } - - @Test - public void refreshApolloConfig() { - ApolloConfig apolloConfig = ApolloConfig.INSTANCE; - RestTemplate rest = Mockito.mock(RestTemplate.class); - - ResponseEntity responseEntity = new ResponseEntity<>( - "{\"apollo\":\"mocked\", \"configurations\":{\"timeout\":1000}}", HttpStatus.OK); - Mockito.when(rest.exchange( - Matchers.anyString(), - Matchers.any(HttpMethod.class), - Matchers.>any(), - Matchers.>any())).thenReturn(responseEntity); - ApolloConfigurationSourceImpl impl = new ApolloConfigurationSourceImpl(); - UpdateHandler updateHandler = impl.new UpdateHandler(); - ApolloClient apolloClient = new ApolloClient(updateHandler); - Deencapsulation.setField(apolloClient, "rest", rest); - ConfigRefresh cr = apolloClient.new ConfigRefresh(apolloConfig.getServerUri()); - cr.run(); - - Map originMap = Deencapsulation.getField(apolloClient, "originalConfigMap"); - Assert.assertEquals(1, originMap.size()); - } - - @Test - public void testCompareChangedConfig() { - boolean status = true; - Map before = new HashMap<>(); - Map after = new HashMap<>(); - - ApolloConfigurationSourceImpl impl = new ApolloConfigurationSourceImpl(); - UpdateHandler updateHandler = impl.new UpdateHandler(); - ApolloClient apolloClient = new ApolloClient(updateHandler); - - ConfigRefresh cr = apolloClient.new ConfigRefresh(""); - - try { - Deencapsulation.invoke(cr, "compareChangedConfig", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - status = true; - before.put("test", "testValue"); - try { - Deencapsulation.invoke(cr, "compareChangedConfig", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - status = true; - after.put("test", "testValue2"); - try { - Deencapsulation.invoke(cr, "compareChangedConfig", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - status = true; - try { - Deencapsulation.invoke(cr, "compareChangedConfig", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } -} diff --git a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloConfigTest.java b/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloConfigTest.java deleted file mode 100644 index d96b5d894ec..00000000000 --- a/dynamic-config/config-apollo/src/test/java/org/apache/servicecomb/config/client/ApolloConfigTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import org.apache.servicecomb.config.ConfigUtil; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class ApolloConfigTest { - @BeforeClass - public static void setUpClass() { - ApolloConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - } - - @Test - public void getServiceName() { - ApolloConfig instance = ApolloConfig.INSTANCE; - Assert.assertEquals("apollo-test", instance.getServiceName()); - Assert.assertEquals("http://127.0.0.1:8070", instance.getServerUri()); - Assert.assertEquals("DEV", instance.getEnv()); - Assert.assertEquals("test-cluster", instance.getServerClusters()); - Assert.assertEquals("application", instance.getNamespace()); - Assert.assertEquals("xxx", instance.getToken()); - Assert.assertEquals(30, instance.getRefreshInterval()); - Assert.assertEquals(0, instance.getFirstRefreshInterval()); - } -} diff --git a/dynamic-config/config-apollo/src/test/resources/microservice.yaml b/dynamic-config/config-apollo/src/test/resources/microservice.yaml index 3b19383a224..4932794e5d7 100644 --- a/dynamic-config/config-apollo/src/test/resources/microservice.yaml +++ b/dynamic-config/config-apollo/src/test/resources/microservice.yaml @@ -40,12 +40,3 @@ servicecomb: address: 0.0.0.0:8080 highway: address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider - #executors: - #default: test - #Provider: - #server: test - #server.wrapParam: test \ No newline at end of file diff --git a/dynamic-config/config-cc/pom.xml b/dynamic-config/config-cc/pom.xml index 6444c99150a..0e8f6addcc6 100644 --- a/dynamic-config/config-cc/pom.xml +++ b/dynamic-config/config-cc/pom.xml @@ -21,7 +21,7 @@ dynamic-config org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -33,10 +33,6 @@ org.apache.servicecomb foundation-config - - org.apache.servicecomb - deployment - org.apache.servicecomb foundation-ssl @@ -45,12 +41,24 @@ org.apache.servicecomb foundation-vertx - io.vertx vertx-codegen provided + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + org.apache.servicecomb + config-center-client + - \ No newline at end of file + diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigCenterConfigurationSourceImpl.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigCenterConfigurationSourceImpl.java deleted file mode 100644 index 7fd362d2e86..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigCenterConfigurationSourceImpl.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -import static com.netflix.config.WatchedUpdateResult.createIncremental; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.deployment.Deployment; -import org.apache.servicecomb.deployment.DeploymentProvider; -import org.apache.servicecomb.config.ConfigMapping; -import org.apache.servicecomb.config.client.ConfigCenterClient; -import org.apache.servicecomb.config.client.ConfigCenterConfig; -import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.WatchedUpdateListener; -import com.netflix.config.WatchedUpdateResult; - -/** - * Created by on 2017/1/9. - */ -public class ConfigCenterConfigurationSourceImpl implements ConfigCenterConfigurationSource { - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterConfigurationSourceImpl.class); - - private final Map valueCache = Maps.newConcurrentMap(); - - private final List listeners = new CopyOnWriteArrayList<>(); - - private UpdateHandler updateHandler = new UpdateHandler(); - - private ConfigCenterClient configCenterClient; - - public ConfigCenterConfigurationSourceImpl() { - } - - @Override - public boolean isValidSource(Configuration localConfiguration) { - if (Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER) == null) { - return false; - } - return true; - } - - private void init() { - configCenterClient = new ConfigCenterClient(updateHandler); - configCenterClient.connectServer(); - } - - @Override - public void init(Configuration localConfiguration) { - ConfigCenterConfig.setConcurrentCompositeConfiguration((ConcurrentCompositeConfiguration) localConfiguration); - init(); - } - - @Override - public void destroy() { - if (configCenterClient == null) { - return; - } - - configCenterClient.destroy(); - } - - public void addUpdateListener(WatchedUpdateListener watchedUpdateListener) { - if (watchedUpdateListener != null) { - listeners.add(watchedUpdateListener); - } - } - - public void removeUpdateListener(WatchedUpdateListener watchedUpdateListener) { - if (watchedUpdateListener != null) { - listeners.remove(watchedUpdateListener); - } - } - - private void updateConfiguration(WatchedUpdateResult result) { - for (WatchedUpdateListener l : listeners) { - try { - l.updateConfiguration(result); - } catch (Throwable ex) { - LOGGER.error("Error in invoking WatchedUpdateListener", ex); - } - } - } - - public Map getCurrentData() - throws Exception { - return valueCache; - } - - public List getCurrentListeners() { - return listeners; - } - - public class UpdateHandler { - - public void handle(String action, Map parseConfigs) { - if (parseConfigs == null || parseConfigs.isEmpty()) { - return; - } - Map configuration = ConfigMapping.getConvertedMap(parseConfigs); - if ("create".equals(action)) { - valueCache.putAll(configuration); - updateConfiguration(createIncremental(ImmutableMap.copyOf(configuration), - null, - null)); - } else if ("set".equals(action)) { - valueCache.putAll(configuration); - updateConfiguration(createIncremental(null, ImmutableMap.copyOf(configuration), - null)); - } else if ("delete".equals(action)) { - for (String itemKey : configuration.keySet()) { - valueCache.remove(itemKey); - } - updateConfiguration(createIncremental(null, - null, - ImmutableMap.copyOf(configuration))); - } else { - LOGGER.error("action: {} is invalid.", action); - return; - } - LOGGER.warn("Config value cache changed: action:{}; item:{}", action, configuration.keySet()); - } - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfig.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfig.java new file mode 100644 index 00000000000..c1cf7c1b683 --- /dev/null +++ b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfig.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.cc; + +import java.util.Collections; +import java.util.List; + +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.foundation.vertx.VertxConst; +import org.springframework.core.env.Environment; + +public final class ConfigCenterConfig { + public static final String SSL_TAG = "cc.consumer"; + + private static final String ADDRESS = "servicecomb.config.client.serverUri"; + + private static final String DOMAIN_NAME = "servicecomb.config.client.domainName"; + + private static final String REFRESH_INTERVAL = "servicecomb.config.client.refresh_interval"; + + private static final String FIRST_PULL_REQUIRED = "servicecomb.config.client.firstPullRequired"; + + public static final String FILE_SOURCE = "servicecomb.config.client.fileSource"; + + private static final int DEFAULT_REFRESH_INTERVAL = 15000; + + private static final String CLIENT_CONNECT_TIMEOUT = "servicecomb.config.client.timeout.connect"; + + private static final String CLIENT_REQUEST_TIMEOUT = "servicecomb.config.client.timeout.request"; + + private static final String CLIENT_SOCKET_TIMEOUT = "servicecomb.config.client.timeout.socket"; + + private final Environment environment; + + public ConfigCenterConfig(Environment environment) { + this.environment = environment; + } + + public String getDomainName() { + return environment.getProperty(DOMAIN_NAME, "default"); + } + + public boolean firstPullRequired() { + return environment.getProperty(FIRST_PULL_REQUIRED, boolean.class, false); + } + + @SuppressWarnings("unchecked") + public List getFileSources() { + return environment.getProperty(FILE_SOURCE, List.class, Collections.emptyList()); + } + + public long getRefreshInterval() { + return environment.getProperty( + REFRESH_INTERVAL, long.class, (long) DEFAULT_REFRESH_INTERVAL); + } + + public Boolean isProxyEnable() { + return environment.getProperty(VertxConst.PROXY_ENABLE, boolean.class, false); + } + + public String getProxyHost() { + return environment.getProperty(VertxConst.PROXY_HOST, "127.0.0.1"); + } + + public int getProxyPort() { + return environment.getProperty(VertxConst.PROXY_PORT, int.class, 8080); + } + + public String getProxyUsername() { + return environment.getProperty(VertxConst.PROXY_USERNAME); + } + + public String getProxyPasswd() { + return environment.getProperty(VertxConst.PROXY_PASSWD); + } + + public List getServerUri() { + return ConfigUtil.parseArrayValue(environment.getProperty(ADDRESS, "")); + } + + public int getConnectTimeout() { + return environment.getProperty(CLIENT_CONNECT_TIMEOUT, int.class, 5000); + } + + public int getConnectionRequestTimeout() { + return environment.getProperty(CLIENT_REQUEST_TIMEOUT, int.class, 5000); + } + + public int getSocketTimeout() { + return environment.getProperty(CLIENT_SOCKET_TIMEOUT, int.class, 5000); + } +} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfiguration.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfiguration.java new file mode 100644 index 00000000000..672a5931faf --- /dev/null +++ b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterConfiguration.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.cc; + +import org.springframework.context.annotation.Bean; + +public class ConfigCenterConfiguration { + @Bean + public ConfigCenterInformationCollector configCenterInformationCollector() { + return new ConfigCenterInformationCollector(); + } +} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java new file mode 100644 index 00000000000..23c0a7af196 --- /dev/null +++ b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterDynamicPropertiesSource.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.cc; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.config.center.client.ConfigCenterAddressManager; +import org.apache.servicecomb.config.center.client.ConfigCenterClient; +import org.apache.servicecomb.config.center.client.ConfigCenterConfigurationChangedEvent; +import org.apache.servicecomb.config.center.client.ConfigCenterManager; +import org.apache.servicecomb.config.center.client.model.ConfigCenterConfiguration; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest; +import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse; +import org.apache.servicecomb.config.common.ConfigConverter; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import com.google.common.eventbus.Subscribe; + +public class ConfigCenterDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "config-center"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterDynamicPropertiesSource.class); + + private final Map data = new ConcurrentHashMapEx<>(); + + private ConfigConverter configConverter; + + public ConfigCenterDynamicPropertiesSource() { + } + + private void init(Environment environment) { + ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(environment); + configConverter = new ConfigConverter(configCenterConfig.getFileSources()); + + ConfigCenterAddressManager configCenterAddressManager = configCenterAddressManager(configCenterConfig, environment); + + HttpTransport httpTransport = createHttpTransport(configCenterAddressManager, + buildRequestConfig(configCenterConfig), environment, configCenterConfig); + ConfigCenterClient configCenterClient = new ConfigCenterClient(configCenterAddressManager, httpTransport); + EventManager.register(this); + + ConfigCenterConfiguration configCenterConfiguration = + createConfigCenterConfiguration(configCenterConfig); + + QueryConfigurationsRequest queryConfigurationsRequest = firstPull(configCenterConfig, configCenterClient, + environment, configCenterAddressManager); + + ConfigCenterManager configCenterManager = new ConfigCenterManager(configCenterClient, EventManager.getEventBus(), + configConverter, configCenterConfiguration, configCenterAddressManager); + configCenterManager.setQueryConfigurationsRequest(queryConfigurationsRequest); + configCenterManager.startConfigCenterManager(); + data.putAll(configConverter.getCurrentData()); + } + + private RequestConfig buildRequestConfig(ConfigCenterConfig config) { + RequestConfig.Builder builder = HttpTransportFactory.defaultRequestConfig(); + builder.setConnectTimeout(config.getConnectTimeout()); + builder.setConnectionRequestTimeout(config.getConnectionRequestTimeout()); + builder.setSocketTimeout(config.getSocketTimeout()); + return builder.build(); + } + + private QueryConfigurationsRequest firstPull(ConfigCenterConfig configCenterConfig, + ConfigCenterClient configCenterClient, Environment environment, + ConfigCenterAddressManager configCenterAddressManager) { + QueryConfigurationsRequest queryConfigurationsRequest = createQueryConfigurationsRequest(environment); + try { + QueryConfigurationsResponse response = configCenterClient + .queryConfigurations(queryConfigurationsRequest, configCenterAddressManager.address()); + if (response.isChanged()) { + configConverter.updateData(response.getConfigurations()); + queryConfigurationsRequest.setRevision(response.getRevision()); + } + } catch (Exception e) { + if (configCenterConfig.firstPullRequired()) { + throw e; + } + LOGGER.warn("first pull failed, and ignore {}", e.getMessage()); + } + return queryConfigurationsRequest; + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigCenterConfigurationChangedEvent event) { + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + data.putAll(event.getAdded()); + data.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> data.remove(k)); + EventManager.post(ConfigurationChangedEvent.createIncremental(event.getAdded(), + event.getUpdated(), event.getDeleted())); + } + + private QueryConfigurationsRequest createQueryConfigurationsRequest(Environment environment) { + QueryConfigurationsRequest request = new QueryConfigurationsRequest(); + request.setApplication(BootStrapProperties.readApplication(environment)); + request.setServiceName(BootStrapProperties.readServiceName(environment)); + request.setVersion(BootStrapProperties.readServiceVersion(environment)); + request.setEnvironment(BootStrapProperties.readServiceEnvironment(environment)); + // 需要设置为 null, 并且 query 参数为 revision=null 才会返回 revision 信息。 revision = 是不行的。 + request.setRevision(null); + return request; + } + + private ConfigCenterConfiguration createConfigCenterConfiguration( + ConfigCenterConfig configCenterConfig) { + return new ConfigCenterConfiguration().setRefreshIntervalInMillis(configCenterConfig.getRefreshInterval()); + } + + private HttpTransport createHttpTransport(ConfigCenterAddressManager configCenterAddressManager, + RequestConfig requestConfig, + Environment environment, ConfigCenterConfig configCenterConfig) { + List authHeaderProviders = SPIServiceUtils.getOrLoadSortedService(AuthHeaderProvider.class); + + if (configCenterConfig.isProxyEnable()) { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(requestConfig); + HttpHost proxy = new HttpHost(configCenterConfig.getProxyHost(), + configCenterConfig.getProxyPort(), "http"); // now only support http proxy + httpClientBuilder.setProxy(proxy); + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials(configCenterConfig.getProxyUsername(), + configCenterConfig.getProxyPasswd())); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(configCenterAddressManager.sslEnabled(), environment, ConfigCenterConfig.SSL_TAG), + getRequestAuthHeaderProvider(authHeaderProviders), httpClientBuilder); + } + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(configCenterAddressManager.sslEnabled(), environment, ConfigCenterConfig.SSL_TAG), + getRequestAuthHeaderProvider(authHeaderProviders), requestConfig); + } + + private static RequestAuthHeaderProvider getRequestAuthHeaderProvider(List authHeaderProviders) { + return signRequest -> { + String host = signRequest != null && signRequest.getEndpoint() != null ? signRequest.getEndpoint().getHost() : ""; + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.authHeaders(host))); + return headers; + }; + } + + private ConfigCenterAddressManager configCenterAddressManager(ConfigCenterConfig configCenterConfig, Environment environment) { + String region = environment.getProperty("servicecomb.datacenter.region"); + String availableZone = environment.getProperty("servicecomb.datacenter.availableZone"); + return new ConfigCenterAddressManager(configCenterConfig.getDomainName(), + configCenterConfig.getServerUri(), EventManager.getEventBus(), region, availableZone); + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, data); + } + + @Override + public int getOrder() { + return 200; + } +} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterInformationCollector.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterInformationCollector.java new file mode 100644 index 00000000000..ab91f368013 --- /dev/null +++ b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/ConfigCenterInformationCollector.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.cc; + +import org.apache.servicecomb.core.bootup.BootUpInformationCollector; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; +import org.springframework.lang.NonNull; + + +public class ConfigCenterInformationCollector implements BootUpInformationCollector, EnvironmentAware { + private ConfigCenterConfig configCenterConfig; + + @Override + public void setEnvironment(@NonNull Environment environment) { + this.configCenterConfig = new ConfigCenterConfig(environment); + } + + @Override + public String collect() { + return "Config Center: " + configCenterConfig.getServerUri(); + } + + @Override + public int getOrder() { + return 1; + } +} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/TransportUtils.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/TransportUtils.java new file mode 100644 index 00000000000..25a4dac0543 --- /dev/null +++ b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/cc/TransportUtils.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.cc; + +import static org.apache.servicecomb.foundation.ssl.SSLOption.DEFAULT_OPTION; + +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.springframework.core.env.Environment; + +public class TransportUtils { + public static SSLProperties createSSLProperties(boolean sslEnabled, Environment environment, String tag) { + SSLProperties sslProperties = new SSLProperties(); + sslProperties.setEnabled(sslEnabled); + + if (!sslEnabled) { + return sslProperties; + } + + SSLOption option = new SSLOption(); + option.setEngine(getStringProperty(environment, + DEFAULT_OPTION.getEngine(), + "ssl." + tag + ".engine", + "ssl.engine")); + option.setProtocols( + getStringProperty(environment, + DEFAULT_OPTION.getProtocols(), + "ssl." + tag + ".protocols", + "ssl.protocols")); + option.setCiphers( + getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".ciphers", "ssl.ciphers")); + option.setAuthPeer( + getBooleanProperty(environment, DEFAULT_OPTION.isAuthPeer(), "ssl." + tag + ".authPeer", "ssl.authPeer")); + option.setCheckCNHost( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNHost(), + "ssl." + tag + ".checkCN.host", + "ssl.checkCN.host")); + option.setCheckCNWhite( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNWhite(), + "ssl." + tag + ".checkCN.white", + "ssl.checkCN.white")); + option.setCheckCNWhiteFile(getStringProperty(environment, + DEFAULT_OPTION.getCiphers(), + "ssl." + tag + ".checkCN.white.file", + "ssl.checkCN.white.file")); + option.setAllowRenegotiate(getBooleanProperty(environment, + DEFAULT_OPTION.isAllowRenegotiate(), + "ssl." + tag + ".allowRenegotiate", + "ssl.allowRenegotiate")); + option.setStorePath( + getStringProperty(environment, + DEFAULT_OPTION.getStorePath(), + "ssl." + tag + ".storePath", + "ssl.storePath")); + option.setClientAuth( + getStringProperty(environment, + DEFAULT_OPTION.getClientAuth(), + "ssl." + tag + ".clientAuth", + "ssl.clientAuth")); + option.setTrustStore( + getStringProperty(environment, + DEFAULT_OPTION.getTrustStore(), + "ssl." + tag + ".trustStore", + "ssl.trustStore")); + option.setTrustStoreType(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreType(), + "ssl." + tag + ".trustStoreType", + "ssl.trustStoreType")); + option.setTrustStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreValue(), + "ssl." + tag + ".trustStoreValue", + "ssl.trustStoreValue")); + option.setKeyStore( + getStringProperty(environment, DEFAULT_OPTION.getKeyStore(), "ssl." + tag + ".keyStore", "ssl.keyStore")); + option.setKeyStoreType( + getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreType(), + "ssl." + tag + ".keyStoreType", + "ssl.keyStoreType")); + option.setKeyStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreValue(), + "ssl." + tag + ".keyStoreValue", + "ssl.keyStoreValue")); + option.setCrl(getStringProperty(environment, DEFAULT_OPTION.getCrl(), "ssl." + tag + ".crl", "ssl.crl")); + option.setSslCustomClass( + getStringProperty(environment, null, "ssl." + tag + ".sslCustomClass", "ssl.sslCustomClass")); + + sslProperties.setSslOption(option); + sslProperties.setSslCustom(SSLCustom.createSSLCustom(option.getSslCustomClass())); + return sslProperties; + } + + private static String getStringProperty(Environment environment, String defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key); + } + } + return defaultValue; + } + + private static boolean getBooleanProperty(Environment environment, boolean defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key, boolean.class, false); + } + } + return defaultValue; + } +} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterClient.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterClient.java deleted file mode 100644 index aabf1ef7522..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterClient.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.lang.StringUtils; -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl; -import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; -import org.apache.servicecomb.foundation.auth.SignRequest; -import org.apache.servicecomb.foundation.common.encrypt.Encryptions; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.ssl.SSLCustom; -import org.apache.servicecomb.foundation.ssl.SSLOption; -import org.apache.servicecomb.foundation.ssl.SSLOptionFactory; -import org.apache.servicecomb.foundation.vertx.AddressResolverConfig; -import org.apache.servicecomb.foundation.vertx.VertxTLSBuilder; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientPoolFactory; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.type.TypeReference; - -import io.netty.handler.codec.http.HttpResponseStatus; -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.CaseInsensitiveHeaders; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.WebSocket; -import io.vertx.core.http.impl.FrameType; -import io.vertx.core.http.impl.ws.WebSocketFrameImpl; -import io.vertx.core.net.ProxyOptions; - -/** - * Created by on 2016/5/17. - */ - -public class ConfigCenterClient { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterClient.class); - - private static final ConfigCenterConfig CONFIG_CENTER_CONFIG = ConfigCenterConfig.INSTANCE; - - private static final String SSL_KEY = "cc.consumer"; - - public static final String PROXY_KEY = "cc.consumer"; - - private static final long HEARTBEAT_INTERVAL = 30000; - - private static final long BOOTUP_WAIT_TIME = 10; - - private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - - private ScheduledExecutorService heartbeatTask = null; - - private int refreshMode = CONFIG_CENTER_CONFIG.getRefreshMode(); - - private int refreshInterval = CONFIG_CENTER_CONFIG.getRefreshInterval(); - - private int firstRefreshInterval = CONFIG_CENTER_CONFIG.getFirstRefreshInterval(); - - private int refreshPort = CONFIG_CENTER_CONFIG.getRefreshPort(); - - private String tenantName = CONFIG_CENTER_CONFIG.getTenantName(); - - private String serviceName = CONFIG_CENTER_CONFIG.getServiceName(); - - private String environment = CONFIG_CENTER_CONFIG.getEnvironment(); - - private MemberDiscovery memberDiscovery = new MemberDiscovery(CONFIG_CENTER_CONFIG.getServerUri()); - - private ConfigCenterConfigurationSourceImpl.UpdateHandler updateHandler; - - private ClientPoolManager clientMgr; - - private boolean isWatching = false; - - private final ServiceLoader authHeaderProviders = - ServiceLoader.load(AuthHeaderProvider.class); - - private URIConst uriConst = new URIConst(); - - public ConfigCenterClient(ConfigCenterConfigurationSourceImpl.UpdateHandler updateHandler) { - this.updateHandler = updateHandler; - } - - public void connectServer() { - if (refreshMode != 0 && refreshMode != 1) { - LOGGER.error("refreshMode must be 0 or 1."); - return; - } - ParseConfigUtils.getInstance().initWithUpdateHandler(updateHandler); - try { - deployConfigClient(); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - refreshMembers(memberDiscovery); - ConfigRefresh refreshTask = new ConfigRefresh(ParseConfigUtils.getInstance(), memberDiscovery); - refreshTask.run(true); - executor.scheduleWithFixedDelay(refreshTask, - firstRefreshInterval, - refreshInterval, - TimeUnit.MILLISECONDS); - } - - public void destroy() { - if (executor != null) { - executor.shutdown(); - executor = null; - } - - if (heartbeatTask != null) { - heartbeatTask.shutdown(); - heartbeatTask = null; - } - } - - private void refreshMembers(MemberDiscovery memberDiscovery) { - if (CONFIG_CENTER_CONFIG.getAutoDiscoveryEnabled()) { - String configCenter = memberDiscovery.getConfigServer(); - IpPort ipPort = NetUtils.parseIpPortFromURI(configCenter); - clientMgr.findThreadBindClientPool().runOnContext(client -> { - HttpClientRequest request = - client.get(ipPort.getPort(), ipPort.getHostOrIp(), uriConst.MEMBERS, rsp -> { - if (rsp.statusCode() == HttpResponseStatus.OK.code()) { - rsp.bodyHandler(buf -> { - memberDiscovery.refreshMembers(buf.toJsonObject()); - }); - } - }); - SignRequest signReq = createSignRequest(request.method().toString(), - configCenter + uriConst.MEMBERS, - new HashMap<>(), - null); - if (ConfigCenterConfig.INSTANCE.getToken() != null) { - request.headers().add("X-Auth-Token", ConfigCenterConfig.INSTANCE.getToken()); - } - authHeaderProviders.forEach(provider -> request.headers() - .addAll(provider.getSignAuthHeaders(signReq))); - request.exceptionHandler(e -> { - LOGGER.error("Fetch member from {} failed. Error message is [{}].", configCenter, e.getMessage()); - }); - request.end(); - }); - } - } - - private void deployConfigClient() throws InterruptedException { - VertxOptions vertxOptions = new VertxOptions(); - vertxOptions.setAddressResolverOptions(AddressResolverConfig.getAddressResover(SSL_KEY, - ConfigCenterConfig.INSTANCE.getConcurrentCompositeConfiguration())); - Vertx vertx = VertxUtils.getOrCreateVertxByName("config-center", vertxOptions); - - HttpClientOptions httpClientOptions = createHttpClientOptions(); - clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions)); - - DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(clientMgr, 1); - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); - } - - private HttpClientOptions createHttpClientOptions() { - HttpClientOptions httpClientOptions = new HttpClientOptions(); - if (ConfigCenterConfig.INSTANCE.isProxyEnable()) { - ProxyOptions proxy = new ProxyOptions() - .setHost(ConfigCenterConfig.INSTANCE.getProxyHost()) - .setPort(ConfigCenterConfig.INSTANCE.getProxyPort()) - .setUsername(ConfigCenterConfig.INSTANCE.getProxyUsername()) - .setPassword(Encryptions.decode(ConfigCenterConfig.INSTANCE.getProxyPasswd(), PROXY_KEY)); - httpClientOptions.setProxyOptions(proxy); - } - httpClientOptions.setConnectTimeout(CONFIG_CENTER_CONFIG.getConnectionTimeout()); - if (this.memberDiscovery.getConfigServer().toLowerCase().startsWith("https")) { - LOGGER.debug("config center client performs requests over TLS"); - SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory(SSL_KEY, - ConfigCenterConfig.INSTANCE.getConcurrentCompositeConfiguration()); - SSLOption sslOption; - if (factory == null) { - sslOption = SSLOption.buildFromYaml(SSL_KEY, - ConfigCenterConfig.INSTANCE.getConcurrentCompositeConfiguration()); - } else { - sslOption = factory.createSSLOption(); - } - SSLCustom sslCustom = SSLCustom.createSSLCustom(sslOption.getSslCustomClass()); - VertxTLSBuilder.buildHttpClientOptions(sslOption, sslCustom, httpClientOptions); - } - return httpClientOptions; - } - - class ConfigRefresh implements Runnable { - private ParseConfigUtils parseConfigUtils; - - private MemberDiscovery memberdis; - - ConfigRefresh(ParseConfigUtils parseConfigUtils, MemberDiscovery memberdis) { - this.parseConfigUtils = parseConfigUtils; - this.memberdis = memberdis; - } - - public void run(boolean wait) { - try { - String configCenter = memberdis.getConfigServer(); - if (refreshMode == 1) { - //make sure that revision is updated timely,wait sub thread to finish it's pull task - refreshConfig(configCenter, true); - } else if (!isWatching) { - // 重新监听时需要先加载,避免在断开期间丢失变更 - //we do not need worry about that the revision may not be updated timely, because we do not need - //revision info in the push mode. the config-center will push the changing to us - refreshConfig(configCenter, wait); - doWatch(configCenter); - } - } catch (Exception e) { - LOGGER.error("client refresh thread exception", e); - } - } - - // 具体动作 - @Override - public void run() { - run(false); - } - - // create watch and wait for done - public void doWatch(String configCenter) - throws UnsupportedEncodingException, InterruptedException { - CountDownLatch waiter = new CountDownLatch(1); - IpPort ipPort = NetUtils.parseIpPortFromURI(configCenter); - String url = uriConst.REFRESH_ITEMS + "?dimensionsInfo=" - + StringUtils.deleteWhitespace(URLEncoder.encode(serviceName, "UTF-8")); - Map headers = new HashMap<>(); - headers.put("x-domain-name", tenantName); - if (ConfigCenterConfig.INSTANCE.getToken() != null) { - headers.put("X-Auth-Token", ConfigCenterConfig.INSTANCE.getToken()); - } - headers.put("x-environment", environment); - - HttpClientWithContext vertxHttpClient = clientMgr.findThreadBindClientPool(); - vertxHttpClient.runOnContext(client -> { - Map authHeaders = new HashMap<>(); - authHeaderProviders.forEach(provider -> authHeaders.putAll(provider.getSignAuthHeaders( - createSignRequest(null, configCenter + url, headers, null)))); - - client.websocket(refreshPort, - ipPort.getHostOrIp(), - url, - new CaseInsensitiveHeaders().addAll(headers) - .addAll(authHeaders), - ws -> { - ws.exceptionHandler(e -> { - LOGGER.error("watch config read fail", e); - stopHeartBeatThread(); - isWatching = false; - }); - ws.closeHandler(v -> { - LOGGER.warn("watching config connection is closed accidentally"); - stopHeartBeatThread(); - isWatching = false; - }); - - ws.pongHandler(pong -> { - // ignore, just prevent NPE. - }); - ws.frameHandler(frame -> { - Buffer action = frame.binaryData(); - LOGGER.info("watching config recieved {}", action); - Map mAction = action.toJsonObject().getMap(); - if ("CREATE".equals(mAction.get("action"))) { - //event loop can not be blocked,we just keep nothing changed in push mode - refreshConfig(configCenter, false); - } else if ("MEMBER_CHANGE".equals(mAction.get("action"))) { - refreshMembers(memberdis); - } else { - parseConfigUtils.refreshConfigItemsIncremental(mAction); - } - }); - startHeartBeatThread(ws); - isWatching = true; - waiter.countDown(); - }, - e -> { - LOGGER.error( - "watcher connect to config center {} refresh port {} failed. Error message is [{}]", - configCenter, - refreshPort, - e.getMessage()); - waiter.countDown(); - }); - }); - waiter.await(); - } - - private void startHeartBeatThread(WebSocket ws) { - heartbeatTask = Executors.newScheduledThreadPool(1); - heartbeatTask.scheduleWithFixedDelay(() -> sendHeartbeat(ws), - HEARTBEAT_INTERVAL, - HEARTBEAT_INTERVAL, - TimeUnit.MILLISECONDS); - } - - private void stopHeartBeatThread() { - if (heartbeatTask != null) { - heartbeatTask.shutdownNow(); - } - } - - private void sendHeartbeat(WebSocket ws) { - try { - ws.writeFrame(new WebSocketFrameImpl(FrameType.PING)); - EventManager.post(new ConnSuccEvent()); - } catch (IllegalStateException e) { - EventManager.post(new ConnFailEvent("heartbeat fail, " + e.getMessage())); - LOGGER.error("heartbeat fail", e); - } - } - - public void refreshConfig(String configcenter, boolean wait) { - CountDownLatch latch = new CountDownLatch(1); - String encodeServiceName = ""; - try { - encodeServiceName = - URLEncoder.encode(StringUtils.deleteWhitespace(serviceName), StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - LOGGER.error("encode failed. Error message: {}", e.getMessage()); - encodeServiceName = StringUtils.deleteWhitespace(serviceName); - } - //just log in the debug level - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Updating remote config..."); - } - String path = uriConst.ITEMS + "?dimensionsInfo=" + encodeServiceName + "&revision=" - + ParseConfigUtils.getInstance().getCurrentVersionInfo(); - clientMgr.findThreadBindClientPool().runOnContext(client -> { - IpPort ipPort = NetUtils.parseIpPortFromURI(configcenter); - HttpClientRequest request = client.get(ipPort.getPort(), ipPort.getHostOrIp(), path, rsp -> { - if (rsp.statusCode() == HttpResponseStatus.OK.code()) { - rsp.bodyHandler(buf -> { - try { - parseConfigUtils - .refreshConfigItems(JsonUtils.OBJ_MAPPER.readValue(buf.toString(), - new TypeReference>>() { - })); - EventManager.post(new ConnSuccEvent()); - } catch (IOException e) { - EventManager.post(new ConnFailEvent( - "config update result parse fail " + e.getMessage())); - LOGGER.error("Config update from {} failed. Error message is [{}].", - configcenter, - e.getMessage()); - } - latch.countDown(); - }); - } else if (rsp.statusCode() == HttpResponseStatus.NOT_MODIFIED.code()) { - //nothing changed - EventManager.post(new ConnSuccEvent()); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Updating remote config is done. the revision {} has no change", - ParseConfigUtils.getInstance().getCurrentVersionInfo()); - } - latch.countDown(); - } else { - rsp.bodyHandler(buf -> { - LOGGER.error("Server error message is [{}].", buf); - latch.countDown(); - }); - EventManager.post(new ConnFailEvent("fetch config fail")); - LOGGER.error("Config update from {} failed.", configcenter); - } - }).setTimeout((BOOTUP_WAIT_TIME - 1) * 1000); - Map headers = new HashMap<>(); - headers.put("x-domain-name", tenantName); - if (ConfigCenterConfig.INSTANCE.getToken() != null) { - headers.put("X-Auth-Token", ConfigCenterConfig.INSTANCE.getToken()); - } - headers.put("x-environment", environment); - request.headers().addAll(headers); - authHeaderProviders.forEach(provider -> request.headers() - .addAll(provider.getSignAuthHeaders(createSignRequest(request.method().toString(), - configcenter + path, - headers, - null)))); - request.exceptionHandler(e -> { - EventManager.post(new ConnFailEvent("fetch config fail")); - LOGGER.error("Config update from {} failed. Error message is [{}].", - configcenter, - e.getMessage()); - latch.countDown(); - }); - request.end(); - }); - if (wait) { - try { - latch.await(BOOTUP_WAIT_TIME, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.warn(e.getMessage()); - } - } - } - } - - public static SignRequest createSignRequest(String method, String endpoint, Map headers, - InputStream content) { - SignRequest signReq = new SignRequest(); - try { - signReq.setEndpoint(new URI(endpoint)); - } catch (URISyntaxException e) { - LOGGER.warn("set uri failed, uri is {}, message: {}", endpoint, e.getMessage()); - } - - Map queryParams = new HashMap<>(); - if (endpoint.contains("?")) { - String parameters = endpoint.substring(endpoint.indexOf("?") + 1); - if (null != parameters && !"".equals(parameters)) { - String[] parameterarray = parameters.split("&"); - for (String p : parameterarray) { - String key = p.split("=")[0]; - String value = p.split("=")[1]; - if (!queryParams.containsKey(key)) { - queryParams.put(key, new String[] {value}); - } else { - List vals = new ArrayList<>(Arrays.asList(queryParams.get(key))); - vals.add(value); - queryParams.put(key, vals.toArray(new String[vals.size()])); - } - } - } - } - signReq.setQueryParams(queryParams); - - signReq.setHeaders(headers); - signReq.setHttpMethod(method); - signReq.setContent(content); - return signReq; - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterConfig.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterConfig.java deleted file mode 100644 index 3f570ba80bb..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConfigCenterConfig.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_SERVICECOMB_ENV; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.SERVICECOMB_ENV; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.deployment.Deployment; -import org.apache.servicecomb.deployment.DeploymentProvider; - -import com.google.common.base.Joiner; -import com.netflix.config.ConcurrentCompositeConfiguration; - -public final class ConfigCenterConfig { - public static final ConfigCenterConfig INSTANCE = new ConfigCenterConfig(); - - private static ConcurrentCompositeConfiguration finalConfig; - - private static final String AUTO_DISCOVERY_ENABLED = "servicecomb.service.registry.autodiscovery"; - - private static final String REFRESH_MODE = "servicecomb.config.client.refreshMode"; - - private static final String REFRESH_PORT = "servicecomb.config.client.refreshPort"; - - private static final String TENANT_NAME = "servicecomb.config.client.tenantName"; - - private static final String DOMAIN_NAME = "servicecomb.config.client.domainName"; - - private static final String TOKEN_NAME = "servicecomb.config.client.token"; - - private static final String URI_API_VERSION = "servicecomb.config.client.api.version"; - - private static final String REFRESH_INTERVAL = "servicecomb.config.client.refresh_interval"; - - private static final String FIRST_REFRESH_INTERVAL = "servicecomb.config.client.first_refresh_interval"; - - private static final String SERVICE_NAME = "service_description.name"; - - private static final String SERVICE_VERSION = "service_description.version"; - - private static final String APPLICATION_NAME = "APPLICATION_ID"; - - private static final String INSTANCE_TAGS = "instance_description.properties.tags"; - - public static final String PROXY_PRE_NAME = "servicecomb.proxy."; - - public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable"; - - public static final String PROXY_HOST = PROXY_PRE_NAME + "host"; - - public static final String PROXY_PORT = PROXY_PRE_NAME + "port"; - - public static final String PROXY_USERNAME = PROXY_PRE_NAME + "username"; - - public static final String PROXY_PASSWD = PROXY_PRE_NAME + "passwd"; - - private static final int DEFAULT_REFRESH_MODE = 0; - - private static final int DEFAULT_REFRESH_PORT = 30104; - - private static final int DEFAULT_REFRESH_INTERVAL = 30000; - - private static final int DEFAULT_FIRST_REFRESH_INTERVAL = 0; - - private static final int DEFAULT_TIMEOUT_IN_MS = 30000; - - private ConfigCenterConfig() { - } - - public static void setConcurrentCompositeConfiguration(ConcurrentCompositeConfiguration config) { - finalConfig = config; - } - - public ConcurrentCompositeConfiguration getConcurrentCompositeConfiguration() { - return finalConfig; - } - - public int getRefreshMode() { - return finalConfig.getInt(REFRESH_MODE, DEFAULT_REFRESH_MODE); - } - - public int getRefreshPort() { - return finalConfig.getInt(REFRESH_PORT, DEFAULT_REFRESH_PORT); - } - - public String getTenantName() { - return finalConfig.getString(TENANT_NAME, "default"); - } - - public String getDomainName() { - return finalConfig.getString(DOMAIN_NAME, "default"); - } - - public String getToken() { - return finalConfig.getString(TOKEN_NAME, null); - } - - public String getApiVersion() { - return finalConfig.getString(URI_API_VERSION, "v3"); - } - - public int getRefreshInterval() { - return finalConfig.getInt(REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL); - } - - public int getFirstRefreshInterval() { - return finalConfig.getInt(FIRST_REFRESH_INTERVAL, DEFAULT_FIRST_REFRESH_INTERVAL); - } - - public Boolean isProxyEnable() { - return finalConfig.getBoolean(PROXY_ENABLE, false); - } - - public String getProxyHost() { - return finalConfig.getString(PROXY_HOST, "127.0.0.1"); - } - - public int getProxyPort() { - return finalConfig.getInt(PROXY_PORT, 8080); - } - - public String getProxyUsername() { - return finalConfig.getString(PROXY_USERNAME, ""); - } - - public String getProxyPasswd() { - return finalConfig.getString(PROXY_PASSWD, ""); - } - - @SuppressWarnings("unchecked") - public String getServiceName() { - String service = finalConfig.getString(SERVICE_NAME); - String appName = finalConfig.getString(APPLICATION_NAME); - String tags; - if (appName != null) { - service = service + "@" + appName; - } - - String serviceVersion = finalConfig.getString(SERVICE_VERSION); - if (serviceVersion != null) { - service = service + "#" + serviceVersion; - } - - Object o = finalConfig.getProperty(INSTANCE_TAGS); - if (o == null) { - return service; - } - if (o instanceof List) { - tags = Joiner.on(",").join((List) o); - } else { - tags = o.toString(); - } - service += "!" + tags; - return service; - } - - public List getServerUri() { - return Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_CONFIG_CENTER).getAccessURL(); - } - - public boolean getAutoDiscoveryEnabled() { - return finalConfig.getBoolean(AUTO_DISCOVERY_ENABLED, false); - } - - public int getConnectionTimeout() { - return finalConfig.getInt("servicecomb.config.client.timeout.connection", DEFAULT_TIMEOUT_IN_MS); - } - - public String getEnvironment() { - return finalConfig.getString(SERVICECOMB_ENV, DEFAULT_SERVICECOMB_ENV); - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnFailEvent.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnFailEvent.java deleted file mode 100644 index b608fae35df..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnFailEvent.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -public class ConnFailEvent { - - private String msg; - - public ConnFailEvent(String msg) { - this.msg = msg; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnSuccEvent.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnSuccEvent.java deleted file mode 100644 index 54239ab790a..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ConnSuccEvent.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -public class ConnSuccEvent { - -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/MemberDiscovery.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/MemberDiscovery.java deleted file mode 100644 index cee4c046625..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/MemberDiscovery.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.Subscribe; - -import io.vertx.core.json.JsonObject; - -/** - * Created by on 2016/11/19. - */ -public class MemberDiscovery { - - private static final Logger LOGGER = LoggerFactory.getLogger(MemberDiscovery.class); - - private static final String SCHEMA_SEPRATOR = "://"; - - private List configServerAddresses = new ArrayList<>(); - - private Object lock = new Object(); - - private AtomicInteger counter = new AtomicInteger(0); - - public MemberDiscovery(List configCenterUri) { - if (configCenterUri != null && !configCenterUri.isEmpty()) { - configServerAddresses.addAll(configCenterUri); - } - Collections.shuffle(configServerAddresses); - EventManager.register(this); - } - - public String getConfigServer() { - synchronized (lock) { - if (configServerAddresses.isEmpty()) { - throw new IllegalStateException("Config center address is not available."); - } - int index = Math.abs(counter.get() % configServerAddresses.size()); - return configServerAddresses.get(index); - } - } - - @Subscribe - public void onConnFailEvent(ConnFailEvent e) { - counter.incrementAndGet(); - } - - public void refreshMembers(JsonObject members) { - List newServerAddresses = new ArrayList<>(); - members.getJsonArray("instances").forEach(m -> { - JsonObject instance = (JsonObject) m; - if ("UP".equals(instance.getString("status", "UP"))) { - String endpoint = instance.getJsonArray("endpoints").getString(0); - String scheme = instance.getBoolean("isHttps", false) ? "https" : "http"; - newServerAddresses.add(scheme + SCHEMA_SEPRATOR - + endpoint.substring(endpoint.indexOf(SCHEMA_SEPRATOR) + SCHEMA_SEPRATOR.length())); - } - }); - - synchronized (lock) { - this.configServerAddresses.clear(); - this.configServerAddresses.addAll(newServerAddresses); - Collections.shuffle(this.configServerAddresses); - } - LOGGER.info("New config center members: {}", this.configServerAddresses); - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ParseConfigUtils.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ParseConfigUtils.java deleted file mode 100644 index b51e0d75f54..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/ParseConfigUtils.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl.UpdateHandler; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.type.TypeReference; - -/** - * Created by on 2017/1/5. - */ -public class ParseConfigUtils { - - private static final Logger LOGGER = LoggerFactory.getLogger(ParseConfigUtils.class); - - private static final ParseConfigUtils INSTANCE = new ParseConfigUtils(); - - private LinkedHashMap> multiDimensionItems = new LinkedHashMap<>(); - - //it's dangerous to make flatItems public - private final Map flatItems = new HashMap<>(); - - private String currentVersionInfo = "default"; - - private UpdateHandler updateHandler; - - private Lock configLock = new ReentrantLock(); - - //for compatibility with other modules and JunitTest - public ParseConfigUtils(UpdateHandler updateHandler) { - this.updateHandler = updateHandler; - } - - private ParseConfigUtils() { - } - - public void initWithUpdateHandler(UpdateHandler updateHandler) { - if (updateHandler == null) { - LOGGER.error("when init ParseConfigUtils, updateHandler can not be null"); - } - this.updateHandler = updateHandler; - } - - /* - as the data is returned, we can block the thread at a short time. consider that if the multiple verticles were deployed - and if we use pull mode and push mode at the same time , we must share a common lock with all methods which would - change the config setting - */ - public void refreshConfigItems(Map> remoteItems) { - try { - configLock.lock(); - String oldRevision = currentVersionInfo; - currentVersionInfo = - remoteItems.getOrDefault("revision", new HashMap<>()).getOrDefault("version", "default").toString(); - //make sure the currentVersionInfo != "" - currentVersionInfo = currentVersionInfo.equals("") ? "default" : currentVersionInfo; - //the key revision is not the config setting - boolean newVersion = (remoteItems.remove("revision") != null); - multiDimensionItems.clear(); - multiDimensionItems.putAll(remoteItems); - doRefreshItems(); - if (newVersion) { - LOGGER.info("Updating remote config is done. revision has changed from {} to {}", oldRevision, - currentVersionInfo); - } - } finally { - configLock.unlock(); - } - } - - public static ParseConfigUtils getInstance() { - return INSTANCE; - } - - public String getCurrentVersionInfo() { - return this.currentVersionInfo; - } - - public void refreshConfigItemsIncremental(Map action) { - try { - configLock.lock(); - if ("UPDATE".equals(action.get("action"))) { - try { - multiDimensionItems.put((String) action.get("key"), JsonUtils.OBJ_MAPPER - .readValue(action.get("value").toString(), new TypeReference>() { - })); - } catch (IOException e) { - LOGGER.error("parse config change action fail"); - } - doRefreshItems(); - } else if ("DELETE".equals(action.get("action"))) { - multiDimensionItems.remove(action.get("key")); - doRefreshItems(); - } - } finally { - configLock.unlock(); - } - } - - private void doRefreshItems() { - Map freshFlatItems = mergeDimensionItems(multiDimensionItems); - notifyItemsChangedNeedRefresh(flatItems, freshFlatItems); - flatItems.clear(); - flatItems.putAll(freshFlatItems); - } - - private Map mergeDimensionItems(Map> items) { - Map flatMap = new HashMap<>(); - return items.values().stream().reduce(flatMap, (result, item) -> { - result.putAll(item); - return result; - }); - } - - private void notifyItemsChangedNeedRefresh(Map before, Map after) { - Map itemsCreated = new HashMap<>(); - Map itemsDeleted = new HashMap<>(); - Map itemsModified = new HashMap<>(); - if (before == null || before.isEmpty()) { - updateHandler.handle("create", after); - return; - } - if (after == null || after.isEmpty()) { - updateHandler.handle("delete", before); - return; - } - for (String itemKey : after.keySet()) { - if (!before.containsKey(itemKey)) { - itemsCreated.put(itemKey, after.get(itemKey)); - } else if (!after.get(itemKey).equals(before.get(itemKey))) { - itemsModified.put(itemKey, after.get(itemKey)); - } - } - for (String itemKey : before.keySet()) { - if (!after.containsKey(itemKey)) { - itemsDeleted.put(itemKey, ""); - } - } - updateHandler.handle("create", itemsCreated); - updateHandler.handle("set", itemsModified); - updateHandler.handle("delete", itemsDeleted); - } -} diff --git a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/URIConst.java b/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/URIConst.java deleted file mode 100644 index 14be6716305..00000000000 --- a/dynamic-config/config-cc/src/main/java/org/apache/servicecomb/config/client/URIConst.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -public class URIConst { - private final String DOMAIN_NAME = ConfigCenterConfig.INSTANCE.getDomainName(); - - private final String CURRENT_VERSION = ConfigCenterConfig.INSTANCE.getApiVersion(); - - private final String VERSION_V2 = "v2"; - - private final String PREFIX_V2 = "/configuration/v2"; - - private final String PREFIX_V3 = String.format("/v3/%s/configuration", DOMAIN_NAME); - - private final boolean isV2 = VERSION_V2.equals(CURRENT_VERSION); - - private final String CURRENT_PREFIX = isV2 ? PREFIX_V2 : PREFIX_V3; - - // v2 no prefix - public final String MEMBERS = isV2 ? "/members" : PREFIX_V3 + "/members"; - - // v2 has prefix - public final String REFRESH_ITEMS = CURRENT_PREFIX + "/refresh/items"; - - public final String ITEMS = CURRENT_PREFIX + "/items"; -} diff --git a/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..94d24b08be8 --- /dev/null +++ b/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.cc.ConfigCenterDynamicPropertiesSource diff --git a/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource b/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource deleted file mode 100644 index 10d2b83ab11..00000000000 --- a/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl \ No newline at end of file diff --git a/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector b/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector new file mode 100644 index 00000000000..9b7c91cf3d9 --- /dev/null +++ b/dynamic-config/config-cc/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.servicecomb.config.cc.ConfigCenterInformationCollector diff --git a/dynamic-config/config-cc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dynamic-config/config-cc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..febb8943865 --- /dev/null +++ b/dynamic-config/config-cc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.config.cc.ConfigCenterConfiguration diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/archaius/sources/TestConfigCenterConfigurationSource.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/archaius/sources/TestConfigCenterConfigurationSource.java deleted file mode 100644 index ec451274906..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/archaius/sources/TestConfigCenterConfigurationSource.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.config.archaius.sources; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.lang.reflect.FieldUtils; -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl.UpdateHandler; -import org.apache.servicecomb.config.client.ConfigCenterClient; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.WatchedUpdateListener; -import com.netflix.config.WatchedUpdateResult; - -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -/** - * Created by on 2017/1/12. - */ -public class TestConfigCenterConfigurationSource { - @Test - public void testCreate() throws Exception { - - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - configCenterSource.addUpdateListener(new WatchedUpdateListener() { - @Override - public void updateConfiguration(WatchedUpdateResult result) { - Assert.assertTrue(!result.getAdded().isEmpty()); - } - }); - UpdateHandler udateHandler = Deencapsulation.getField(configCenterSource, UpdateHandler.class); - Map addedItems = new HashMap<>(); - addedItems.put("testKey", "testValue"); - udateHandler.handle("create", addedItems); - } - - @Test - public void testUpdate() throws Exception { - - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - configCenterSource.addUpdateListener(new WatchedUpdateListener() { - @Override - public void updateConfiguration(WatchedUpdateResult result) { - Assert.assertTrue(!result.getChanged().isEmpty()); - } - }); - UpdateHandler udateHandler = Deencapsulation.getField(configCenterSource, UpdateHandler.class); - Map addedItems = new HashMap<>(); - addedItems.put("testKey", "testValue"); - udateHandler.handle("set", addedItems); - } - - @Test - public void testDelete() throws Exception { - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - configCenterSource.addUpdateListener(new WatchedUpdateListener() { - @Override - public void updateConfiguration(WatchedUpdateResult result) { - Assert.assertTrue(!result.getDeleted().isEmpty()); - } - }); - UpdateHandler udateHandler = Deencapsulation.getField(configCenterSource, UpdateHandler.class); - Map addedItems = new HashMap<>(); - addedItems.put("testKey", "testValue"); - - configCenterSource.getCurrentData().put("testKey", "testValue"); - udateHandler.handle("delete", addedItems); - Assert.assertTrue(configCenterSource.getCurrentData().isEmpty()); - } - - @Test - public void testRemoveUpdateListener() { - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - WatchedUpdateListener watchedUpdateListener = Mockito.mock(WatchedUpdateListener.class); - configCenterSource.addUpdateListener(watchedUpdateListener); - configCenterSource.removeUpdateListener(watchedUpdateListener); - Assert.assertTrue(configCenterSource.getCurrentListeners().isEmpty()); - } - - @Test - public void destroy_notInit() { - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - - // need not throw exception - configCenterSource.destroy(); - } - - @Test - public void destroy_inited() throws IllegalAccessException { - AtomicInteger count = new AtomicInteger(); - ConfigCenterClient configCenterClient = new MockUp() { - @Mock - void destroy() { - count.incrementAndGet(); - } - }.getMockInstance(); - ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - FieldUtils.writeDeclaredField(configCenterSource, "configCenterClient", configCenterClient, true); - - configCenterSource.destroy(); - - Assert.assertEquals(1, count.get()); - } -} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java new file mode 100644 index 00000000000..50d39bc19db --- /dev/null +++ b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterAddressManagerTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.cc; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.center.client.ConfigCenterAddressManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.google.common.eventbus.EventBus; + +class ConfigCenterAddressManagerTest { + private static final List addresses = new ArrayList<>(); + + private static ConfigCenterAddressManager addressManager1; + + private static ConfigCenterAddressManager addressManager2; + + @Test + public void addressManagerTest() throws NoSuchFieldException, IllegalAccessException { + addresses.add("http://127.0.0.1:30103"); + addresses.add("https://127.0.0.2:30103"); + addressManager1 = new ConfigCenterAddressManager("project", addresses, new EventBus(), "", ""); + addressManager2 = new ConfigCenterAddressManager(null, addresses, new EventBus(), "", ""); + Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager1, 0); + addressManagerField = addressManager2.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager2, 0); + + Assertions.assertNotNull(addressManager1); + Assertions.assertNotNull(addressManager2); + + List addresses = addressManager1.getAddresses(); + Assertions.assertEquals(2, addresses.size()); + Assertions.assertEquals("http://127.0.0.1:30103/v3/project", addresses.get(0)); + + Assertions.assertEquals("https://127.0.0.2:30103/v3/project", addressManager1.address()); + Assertions.assertEquals("http://127.0.0.1:30103/v3/project", addressManager1.address()); + Assertions.assertEquals("https://127.0.0.2:30103/v3/default", addressManager2.address()); + } + + @Test + public void onRefreshEndpointEvent() { + List addressAZ = new ArrayList<>(); + addressAZ.add("http://127.0.0.3:30100"); + List addressRG = new ArrayList<>(); + addressRG.add("http://127.0.0.4:30100"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", addressRG); + addressManager1 = new ConfigCenterAddressManager("project", addresses, new EventBus(), "", ""); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseConfigCenter"); + addressManager1.refreshEndpoint(event, "CseConfigCenter"); + + List availableZone = addressManager1.getAvailableZone(); + Assertions.assertEquals("http://127.0.0.3:30100/v3/project", availableZone.get(0)); + + List availableRegion = addressManager1.getAvailableRegion(); + Assertions.assertEquals("http://127.0.0.4:30100/v3/project", availableRegion.get(0)); + + Assertions.assertEquals("http://127.0.0.3:30100/v3/project", addressManager1.address()); + } +} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java new file mode 100644 index 00000000000..3298d95bb19 --- /dev/null +++ b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/cc/ConfigCenterConfigurationSourceImplTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.cc; + + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.center.client.ConfigCenterAddressManager; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class ConfigCenterConfigurationSourceImplTest { + @Test + void configAddressManagerTest() throws IllegalAccessException, NoSuchFieldException { + List addresses = new ArrayList<>(); + addresses.add("http://127.0.0.1:30103"); + addresses.add("http://127.0.0.2:30103"); + ConfigCenterAddressManager addressManager = new ConfigCenterAddressManager("test", addresses, + EventManager.getEventBus(), "", ""); + Field addressManagerField = addressManager.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager, 0); + Assertions.assertNotNull(addressManager); + + String address = addressManager.address(); + Assertions.assertEquals("http://127.0.0.2:30103/v3/test", address); + address = addressManager.address(); + Assertions.assertEquals("http://127.0.0.1:30103/v3/test", address); + + addressManager = new ConfigCenterAddressManager(null, addresses, EventManager.getEventBus(), "", ""); + addressManagerField = addressManager.getClass().getSuperclass().getDeclaredField("index"); + addressManagerField.setAccessible(true); + addressManagerField.set(addressManager, 0); + address = addressManager.address(); + Assertions.assertEquals("http://127.0.0.2:30103/v3/default", address); + } + + @Test + void onRefreshEndpointEventTest() { + List addresses = new ArrayList<>(); + addresses.add("http://127.0.0.1:30103"); + List addressAZ = new ArrayList<>(); + addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true"); + Map> zoneAndRegion = new HashMap<>(); + zoneAndRegion.put("sameZone", addressAZ); + zoneAndRegion.put("sameRegion", new ArrayList<>()); + RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseConfigCenter"); + ConfigCenterAddressManager addressManager = new ConfigCenterAddressManager("test", addresses, + EventManager.getEventBus(), "", ""); + addressManager.onRefreshEndpointEvent(event); + + List availableAZ = addressManager.getAvailableZone(); + Assertions.assertEquals("https://127.0.0.1:30100/v3/test", availableAZ.get(0)); + } +} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterClient.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterClient.java deleted file mode 100644 index 5c70ac4a280..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterClient.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl; -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl.UpdateHandler; -import org.apache.servicecomb.config.client.ConfigCenterClient.ConfigRefresh; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext.RunHandler; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import com.google.common.eventbus.Subscribe; - -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClient; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.WebSocket; -import io.vertx.core.json.JsonObject; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestConfigCenterClient { - @BeforeClass - public static void setUpClass() { - ConfigCenterConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - } - - @SuppressWarnings("unchecked") - @Test - public void testConnectServer() { - HttpClientRequest request = Mockito.mock(HttpClientRequest.class); - Mockito.when(request.method()).thenReturn(HttpMethod.GET); - Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap()); - Buffer rsp = Mockito.mock(Buffer.class); - Mockito.when(rsp.toJsonObject()).thenReturn(new JsonObject( - "{\"instances\":[{\"status\":\"UP\",\"endpoints\":[\"rest:0.0.0.0:30103\"],\"hostName\":\"125292-0.0.0.0\",\"serviceName\":\"configServer\",\"https\":false}]}")); - HttpClientResponse event = Mockito.mock(HttpClientResponse.class); - Mockito.when(event.bodyHandler(Mockito.any(Handler.class))).then(invocation -> { - Handler handler = invocation.getArgumentAt(0, Handler.class); - handler.handle(rsp); - return null; - }); - Mockito.when(event.statusCode()).thenReturn(200); - HttpClient httpClient = Mockito.mock(HttpClient.class); - Mockito.when( - httpClient.get(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.any(Handler.class))) - .then(invocation -> { - Handler handler = invocation.getArgumentAt(3, Handler.class); - handler.handle(event); - return request; - }); - new MockUp() { - @Mock - public void runOnContext(RunHandler handler) { - handler.run(httpClient); - } - }; - new MockUp() { - @Mock - public void refreshMembers(JsonObject members) { - Assert.assertTrue(members.size() == 1); - } - }; - UpdateHandler updateHandler = new ConfigCenterConfigurationSourceImpl().new UpdateHandler(); - ConfigCenterClient cc = new ConfigCenterClient(updateHandler); - cc.connectServer(); - } - - @Test - public void testConnectRefreshModeTwo() { - ConfigCenterClient cc2 = new ConfigCenterClient(null); - boolean status = false; - try { - Deencapsulation.setField(cc2, "refreshMode", 2); - cc2.connectServer(); - } catch (Exception e) { - status = true; - } - Assert.assertFalse(status); - } - - @Test - public void testConfigRefreshModeOne(@Mocked ClientPoolManager clientMgr, - @Mocked HttpClientWithContext httpClientWithContext) { - String version1 = refreshAndGetCurrentRevision(clientMgr, httpClientWithContext, 200, "huawei"); - //test the sdk get and change the latestRevision - Assert.assertEquals("huawei", version1); - String version2 = refreshAndGetCurrentRevision(clientMgr, httpClientWithContext, 304, "rkd"); - //test that when return code is 304, the sdk do not change the latestRevision - Assert.assertNotEquals("rkd", version2); - String version3 = refreshAndGetCurrentRevision(clientMgr, httpClientWithContext, 200, ""); - //make sure the current version is not "" - Assert.assertNotEquals("", version3); - } - - @SuppressWarnings("unchecked") - private String refreshAndGetCurrentRevision(ClientPoolManager clientMgr, - HttpClientWithContext httpClientWithContext, int statusCode, String version) { - - ConfigCenterConfigurationSourceImpl impl = new ConfigCenterConfigurationSourceImpl(); - UpdateHandler updateHandler = impl.new UpdateHandler(); - HttpClientRequest request = Mockito.mock(HttpClientRequest.class); - Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap()); - Buffer rsp = Mockito.mock(Buffer.class); - Mockito.when(rsp.toString()) - .thenReturn(String.format( - "{\"application\":{\"3\":\"2\",\"aa\":\"1\"},\"vmalledge\":{\"aa\":\"3\"},\"revision\": { \"version\": \"%s\"} }", - version)); - - HttpClientResponse httpClientResponse = Mockito.mock(HttpClientResponse.class); - Mockito.when(httpClientResponse.bodyHandler(Mockito.any(Handler.class))).then(invocation -> { - Handler handler = invocation.getArgumentAt(0, Handler.class); - handler.handle(rsp); - return null; - }); - Mockito.when(httpClientResponse.statusCode()).thenReturn(statusCode); - - HttpClient httpClient = Mockito.mock(HttpClient.class); - Mockito.when( - httpClient.get(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.any(Handler.class))) - .then(invocation -> { - Handler handler = invocation.getArgumentAt(3, Handler.class); - handler.handle(httpClientResponse); - return request; - }); - - new MockUp() { - @Mock - public void runOnContext(RunHandler handler) { - handler.run(httpClient); - } - }; - new Expectations() { - { - clientMgr.findThreadBindClientPool(); - result = httpClientWithContext; - } - }; - - ConfigCenterClient cc = new ConfigCenterClient(updateHandler); - Deencapsulation.setField(cc, "clientMgr", clientMgr); - ParseConfigUtils parseConfigUtils = new ParseConfigUtils(updateHandler); - MemberDiscovery memberdis = new MemberDiscovery(Arrays.asList("http://configcentertest:30103")); - ConfigRefresh refresh = cc.new ConfigRefresh(parseConfigUtils, memberdis); - Deencapsulation.setField(cc, "refreshMode", 1); - refresh.run(); - String currentVersionInfo = Deencapsulation.getField(parseConfigUtils, "currentVersionInfo").toString(); - return currentVersionInfo; - } - - @SuppressWarnings("unchecked") - @Test - public void testConfigRefreshModeZero(@Mocked ClientPoolManager clientMgr, - @Mocked HttpClientWithContext httpClientWithContext) { - ConfigCenterConfigurationSourceImpl impl = new ConfigCenterConfigurationSourceImpl(); - UpdateHandler updateHandler = impl.new UpdateHandler(); - HttpClientRequest request = Mockito.mock(HttpClientRequest.class); - Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap()); - Buffer rsp = Mockito.mock(Buffer.class); - Mockito.when(rsp.toString()) - .thenReturn("{\"application\":{\"2\":\"2\",\"aa\":\"1\"},\"vmalledge\":{\"aa\":\"3\"}}"); - - HttpClientResponse httpClientResponse = Mockito.mock(HttpClientResponse.class); - Mockito.when(httpClientResponse.bodyHandler(Mockito.any(Handler.class))).then(invocation -> { - Handler handler = invocation.getArgumentAt(0, Handler.class); - handler.handle(rsp); - return null; - }); - Mockito.when(httpClientResponse.statusCode()).thenReturn(200); - - Buffer buf = Mockito.mock(Buffer.class); - Mockito.when(buf.toJsonObject()).thenReturn(new JsonObject( - "{\"action\":\"UPDATE\",\"key\":\"vmalledge\",\"value\":\"{\\\"aa\\\":\\\"3\\\"}\"}")); - WebSocket websocket = Mockito.mock(WebSocket.class); - Mockito.when(websocket.handler(Mockito.any(Handler.class))).then(invocation -> { - Handler handler = invocation.getArgumentAt(0, Handler.class); - handler.handle(buf); - return websocket; - }); - HttpClient httpClient = Mockito.mock(HttpClient.class); - Mockito.when( - httpClient.get(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.any(Handler.class))) - .then(invocation -> { - Handler handler = invocation.getArgumentAt(3, Handler.class); - handler.handle(httpClientResponse); - return request; - }); - Mockito.when(httpClient.websocket(Mockito.anyInt(), - Mockito.anyString(), - Mockito.anyString(), - Mockito.any(MultiMap.class), - Mockito.any(Handler.class), - Mockito.any(Handler.class))) - .then(invocation -> { - Handler handler = invocation.getArgumentAt(4, Handler.class); - handler.handle(websocket); - return null; - }); - new MockUp() { - @Mock - public void runOnContext(RunHandler handler) { - handler.run(httpClient); - } - }; - new Expectations() { - { - clientMgr.findThreadBindClientPool(); - result = httpClientWithContext; - } - }; - - ConfigCenterClient cc = new ConfigCenterClient(updateHandler); - Deencapsulation.setField(cc, "clientMgr", clientMgr); - ParseConfigUtils parseConfigUtils = new ParseConfigUtils(updateHandler); - MemberDiscovery memberdis = new MemberDiscovery(Arrays.asList("http://configcentertest:30103")); - ConfigRefresh refresh = cc.new ConfigRefresh(parseConfigUtils, memberdis); - refresh.run(); - Map flatItems = Deencapsulation.getField(parseConfigUtils, "flatItems"); - Assert.assertEquals(2, flatItems.size()); - Deencapsulation.setField(cc, "refreshMode", 0); - refresh.run(); - } - - @SuppressWarnings("unchecked") - @Test - public void testConfigRefreshException(@Mocked ClientPoolManager clientMgr, - @Mocked HttpClientWithContext httpClientWithContext) { - ConfigCenterConfigurationSourceImpl impl = new ConfigCenterConfigurationSourceImpl(); - Map map = new HashMap<>(); - EventManager.register(new Object() { - @Subscribe - public void testMsg(Object event) { - if (event instanceof ConnFailEvent) { - map.put("result", "Fail event trigger"); - } - if (event instanceof ConnSuccEvent) { - map.put("result", "Succ event trigger"); - } - } - }); - UpdateHandler updateHandler = impl.new UpdateHandler(); - HttpClientRequest request = Mockito.mock(HttpClientRequest.class); - Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap()); - Buffer rsp = Mockito.mock(Buffer.class); - Mockito.when(rsp.toString()) - .thenReturn("{\"application\":{\"2\":\"2\",\"aa\":\"1\"},\"vmalledge\":{\"aa\":\"3\"}}"); - - HttpClientResponse event = Mockito.mock(HttpClientResponse.class); - Mockito.when(event.bodyHandler(Mockito.any(Handler.class))).then(invocation -> { - Handler handler = invocation.getArgumentAt(0, Handler.class); - handler.handle(rsp); - return null; - }); - Mockito.when(event.statusCode()).thenReturn(400); - Buffer buf = Mockito.mock(Buffer.class); - Mockito.when(buf.toJsonObject()).thenReturn(new JsonObject( - "{\"action\":\"UPDATE\",\"key\":\"vmalledge\",\"value\":\"{\\\"aa\\\":\\\"3\\\"}\"}")); - HttpClient httpClient = Mockito.mock(HttpClient.class); - Mockito.when( - httpClient.get(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.any(Handler.class))) - .then(invocation -> { - Handler handler = invocation.getArgumentAt(3, Handler.class); - handler.handle(event); - return request; - }); - new MockUp() { - @Mock - public void runOnContext(RunHandler handler) { - handler.run(httpClient); - } - }; - new Expectations() { - { - clientMgr.findThreadBindClientPool(); - result = httpClientWithContext; - } - }; - ConfigCenterClient cc = new ConfigCenterClient(updateHandler); - Deencapsulation.setField(cc, "clientMgr", clientMgr); - ParseConfigUtils parseConfigUtils = new ParseConfigUtils(updateHandler); - MemberDiscovery memberdis = new MemberDiscovery(Arrays.asList("http://configcentertest:30103")); - ConfigRefresh refresh = cc.new ConfigRefresh(parseConfigUtils, memberdis); - refresh.run(); - Assert.assertEquals("Fail event trigger", map.get("result")); - Mockito.when(event.statusCode()).thenReturn(200); - refresh.run(); - Assert.assertEquals("Succ event trigger", map.get("result")); - } - - @Test - public void destroy() { - ConfigCenterClient configCenterClient = new ConfigCenterClient(null); - ScheduledExecutorService executor = Deencapsulation.getField(configCenterClient, "executor"); - ScheduledExecutorService heartbeatTask = Executors.newScheduledThreadPool(1); - Deencapsulation.setField(configCenterClient, "heartbeatTask", heartbeatTask); - - Assert.assertFalse(executor.isShutdown()); - - configCenterClient.destroy(); - - Assert.assertTrue(executor.isShutdown()); - Assert.assertTrue(heartbeatTask.isShutdown()); - } -} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterConfig.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterConfig.java deleted file mode 100644 index 1624f5af8fb..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestConfigCenterConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.util.List; - -import org.apache.servicecomb.config.ConfigUtil; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestConfigCenterConfig { - @BeforeClass - public static void setUpClass() { - ConfigCenterConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - } - - @Test - public void getServerUri() { - List servers = ConfigCenterConfig.INSTANCE.getServerUri(); - Assert.assertEquals("https://172.16.8.7:30103", servers.get(0)); - Assert.assertEquals("https://172.16.8.7:30103", servers.get(1)); - } - - @Test - public void getEnvironment() { - Assert.assertEquals("testing", ConfigCenterConfig.INSTANCE.getEnvironment()); - System.setProperty("SERVICECOMB_ENV", "development"); - ConfigCenterConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - Assert.assertEquals("development", ConfigCenterConfig.INSTANCE.getEnvironment()); - } -} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestMemberDiscovery.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestMemberDiscovery.java deleted file mode 100644 index 23629022e85..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestMemberDiscovery.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import static org.junit.Assert.assertNotNull; - -import java.util.Arrays; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.vertx.core.json.JsonObject; - -public class TestMemberDiscovery { - @BeforeClass - public static void setUpClass() { - ConfigCenterConfig.setConcurrentCompositeConfiguration(ConfigUtil.createLocalConfig()); - } - - @Test - public void testGetConfigServerURIs() { - MemberDiscovery dc = new MemberDiscovery(ConfigCenterConfig.INSTANCE.getServerUri()); - assertNotNull(dc.getConfigServer()); - } - - @Test - public void testServerChange() { - MemberDiscovery dc = new MemberDiscovery(Arrays.asList("http://127.0.0.1:30103", "http://127.0.0.1:30104")); - String server1 = dc.getConfigServer(); - EventManager.post(new ConnFailEvent("connect failed.")); - String server2 = dc.getConfigServer(); - Assert.assertNotEquals(server1, server2); - EventManager.post(new ConnFailEvent("connect failed.")); - server2 = dc.getConfigServer(); - Assert.assertEquals(server1, server2); - - dc.refreshMembers(new JsonObject( - "{\"instances\":" - + "[{\"status\":\"UP\",\"endpoints\":[\"rest://0.0.0.0:30109\"],\"hostName\":\"125292-0.0.0.0\",\"serviceName\":\"configServer\",\"isHttps\":false}" - + ",{\"status\":\"UP\",\"endpoints\":[\"rest://0.0.0.0:30108\"],\"hostName\":\"125293-0.0.0.0\",\"serviceName\":\"configServer\",\"isHttps\":false}" - + "]}")); - server1 = dc.getConfigServer(); - EventManager.post(new ConnFailEvent("connect failed.")); - server2 = dc.getConfigServer(); - Assert.assertNotEquals(server1, server2); - EventManager.post(new ConnFailEvent("connect failed.")); - server2 = dc.getConfigServer(); - Assert.assertEquals(server1, server2); - } - - @Test - public void testDiscoverywithHttp() { - MemberDiscovery discoveryClient1 = new MemberDiscovery(null); - discoveryClient1.refreshMembers(new JsonObject( - "{\"instances\":[{\"status\":\"UP\",\"endpoints\":[\"rest://0.0.0.0:30103\"],\"hostName\":\"125292-0.0.0.0\",\"serviceName\":\"configServer\",\"isHttps\":false}]}")); - Assert.assertEquals("http://0.0.0.0:30103", discoveryClient1.getConfigServer()); - } - - @Test - public void testDiscoverywithHttps() { - MemberDiscovery discoveryClient1 = new MemberDiscovery(null); - discoveryClient1.refreshMembers(new JsonObject( - "{\"instances\":[{\"status\":\"UP\",\"endpoints\":[\"rest://0.0.0.0:30103\"],\"hostName\":\"125292-0.0.0.0\",\"serviceName\":\"configServer\",\"isHttps\":true}]}")); - Assert.assertEquals("https://0.0.0.0:30103", discoveryClient1.getConfigServer()); - } -} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestParseConfigUtils.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestParseConfigUtils.java deleted file mode 100644 index 2f70abe9e88..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestParseConfigUtils.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl; -import org.apache.servicecomb.config.archaius.sources.ConfigCenterConfigurationSourceImpl.UpdateHandler; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; - -/** - * @author - */ -public class TestParseConfigUtils { - - private ConfigCenterConfigurationSourceImpl configCenterSource = new ConfigCenterConfigurationSourceImpl(); - - private UpdateHandler uh = configCenterSource.new UpdateHandler(); - - private ParseConfigUtils pc = new ParseConfigUtils(uh); - - @Test - public void testNotifyItemsChangedNeedRefresh() { - - boolean status = true; - Map before = new HashMap<>(); - Map after = new HashMap<>(); - try { - Deencapsulation.invoke(pc, "notifyItemsChangedNeedRefresh", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - // Check with valid before object - status = true; - before.put("test", "testValue"); - try { - Deencapsulation.invoke(pc, "notifyItemsChangedNeedRefresh", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - // Check with valid after object - status = true; - after.put("test", "testValue2"); - try { - Deencapsulation.invoke(pc, "notifyItemsChangedNeedRefresh", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - - // Check with valid localItems object - status = true; - try { - Deencapsulation.invoke(pc, "notifyItemsChangedNeedRefresh", before, after); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } -} diff --git a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestURIConst.java b/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestURIConst.java deleted file mode 100644 index 8877624b0c2..00000000000 --- a/dynamic-config/config-cc/src/test/java/org/apache/servicecomb/config/client/TestURIConst.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.client; - -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestURIConst { - @Test - public void testURI_v2(final @Mocked ConfigCenterConfig config) { - new Expectations() { - { - config.getDomainName(); - result = "mytenant"; - config.getApiVersion(); - result = "v2"; - } - }; - - URIConst uriConst = new URIConst(); - Assert.assertEquals("/members", uriConst.MEMBERS); - Assert.assertEquals("/configuration/v2/refresh/items", uriConst.REFRESH_ITEMS); - Assert.assertEquals("/configuration/v2/items", uriConst.ITEMS); - } - - @Test - public void testURI_v3(final @Mocked ConfigCenterConfig config) { - new Expectations() { - { - config.getDomainName(); - result = "mytenant"; - config.getApiVersion(); - result = "v3"; - } - }; - - URIConst uriConst = new URIConst(); - Assert.assertEquals("/v3/mytenant/configuration/members", uriConst.MEMBERS); - Assert.assertEquals("/v3/mytenant/configuration/refresh/items", uriConst.REFRESH_ITEMS); - Assert.assertEquals("/v3/mytenant/configuration/items", uriConst.ITEMS); - } -} diff --git a/dynamic-config/config-consul/pom.xml b/dynamic-config/config-consul/pom.xml new file mode 100644 index 00000000000..af890c0e6ec --- /dev/null +++ b/dynamic-config/config-consul/pom.xml @@ -0,0 +1,54 @@ + + + + + 4.0.0 + + org.apache.servicecomb + dynamic-config + 3.4.0-SNAPSHOT + + + config-consul + Java Chassis::Dynamic Config::Consul + + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + java-chassis-core + + + org.kiwiproject + consul-client + + + com.google.code.gson + gson + + + diff --git a/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfig.java b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfig.java new file mode 100644 index 00000000000..57613037eb4 --- /dev/null +++ b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfig.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.consul; + +import org.springframework.core.env.Environment; + +public class ConsulConfig { + + public static final String CONSUL_CONFIG_PREFIX = "servicecomb.config.consul"; + + public static final String CONSUL_DEFAULT_ENVIRONMENT = "production"; + + public static final String PROPERTY_CONSUL_HOST = "servicecomb.config.consul.host"; + + public static final String PROPERTY_CONSUL_PORT = "servicecomb.config.consul.port"; + + public static final String PROPERTY_CONSUL_SCHEME = "servicecomb.config.consul.scheme"; + + public static final String PROPERTY_CONSUL_ACL_TOKEN = "servicecomb.config.consul.acl-token"; + + public static final String PROPERTY_CONSUL_WATCH_SECONDS = "servicecomb.config.consul.watch-seconds"; + + public static final String PROPERTY_INSTANCE_TAG = "servicecomb.config.consul.instance-tag"; + + public static final String PATH_ENVIRONMENT = "/servicecomb/config/environment/%s"; + + public static final String PATH_APPLICATION = "/servicecomb/config/application/%s/%s"; + + public static final String PATH_SERVICE = "/servicecomb/config/service/%s/%s/%s"; + + public static final String PATH_VERSION = "/servicecomb/config/version/%s/%s/%s/%s"; + + public static final String PATH_TAG = "/servicecomb/config/tag/%s/%s/%s/%s/%s"; + + private final Environment environment; + + public ConsulConfig(Environment environment) { + this.environment = environment; + } + + public String getConsulHost() { + return environment.getProperty(PROPERTY_CONSUL_HOST, String.class, "127.0.0.1"); + } + + public int getConsulPort() { + return environment.getProperty(PROPERTY_CONSUL_PORT, int.class, 8500); + } + + public String getConsulScheme() { + return environment.getProperty(PROPERTY_CONSUL_SCHEME); + } + + public String getConsulAclToken() { + return environment.getProperty(PROPERTY_CONSUL_ACL_TOKEN); + } + + public int getConsulWatchSeconds() { + return environment.getProperty(PROPERTY_CONSUL_WATCH_SECONDS, int.class, 8); + } + + public String getInstanceTag() { + return environment.getProperty(PROPERTY_INSTANCE_TAG); + } +} diff --git a/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigClient.java b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigClient.java new file mode 100644 index 00000000000..ae18e11ff48 --- /dev/null +++ b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigClient.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.consul; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.jetbrains.annotations.NotNull; +import org.kiwiproject.consul.Consul; +import org.kiwiproject.consul.KeyValueClient; +import org.kiwiproject.consul.cache.KVCache; +import org.kiwiproject.consul.model.kv.Value; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ByteArrayResource; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import static org.apache.servicecomb.config.consul.ConsulConfig.PATH_APPLICATION; +import static org.apache.servicecomb.config.consul.ConsulConfig.PATH_ENVIRONMENT; +import static org.apache.servicecomb.config.consul.ConsulConfig.PATH_SERVICE; +import static org.apache.servicecomb.config.consul.ConsulConfig.PATH_TAG; +import static org.apache.servicecomb.config.consul.ConsulConfig.PATH_VERSION; + +public class ConsulConfigClient { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulConfigClient.class); + + public class GetDataRunnable implements Runnable { + + private Map dataMap; + + private String path; + + public GetDataRunnable(String path, Map dataMap) { + this.dataMap = dataMap; + this.path = path; + } + + @Override + public void run() { + try { + if (path.equals("tagData")) { + tagData = dataMap; + } else if (path.equals("versionData")) { + versionData = dataMap; + } else if (path.equals("serviceData")) { + serviceData = dataMap; + } else if (path.equals("applicationData")) { + applicationData = dataMap; + } else { + environmentData = dataMap; + } + refreshConfigItems(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private ConsulDynamicPropertiesSource.UpdateHandler updateHandler; + + private ConsulConfig consulConfig; + + private Environment environment; + + private final Object lock = new Object(); + + private Consul consulClient; + + private KeyValueClient kvClient; + + private ConsulConfigProperties consulConfigProperties; + + private Map environmentData = new HashMap<>(); + + private Map applicationData = new HashMap<>(); + + private Map serviceData = new HashMap<>(); + + private Map versionData = new HashMap<>(); + + private Map tagData = new HashMap<>(); + + private Map allLast = new HashMap<>(); + + public ConsulConfigClient(ConsulDynamicPropertiesSource.UpdateHandler updateHandler, Environment environment, ConsulConfigProperties consulConfigProperties, Consul consulClient) { + this.updateHandler = updateHandler; + this.consulConfig = new ConsulConfig(environment); + this.environment = environment; + this.consulConfigProperties = consulConfigProperties; + this.consulClient = consulClient; + this.kvClient = consulClient.keyValueClient(); + } + + public void refreshConsulConfig() { + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ConsulConfig.CONSUL_DEFAULT_ENVIRONMENT; + } + addEnvironmentConfig(env); + addApplicationConfig(env); + addServiceConfig(env); + addVersionConfig(env); + addTagConfig(env); + + refreshConfigItems(); + } + + private void addTagConfig(String env) { + if (StringUtils.isBlank(consulConfig.getInstanceTag())) { + return; + } + String path = String.format(PATH_TAG, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment), + consulConfig.getInstanceTag()); + + this.tagData = parseData(path); + try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) { + cache.addListener(newValues -> { + Optional newValue = newValues.values().stream() + .filter(value -> value.getKey().equals(path)) + .findAny(); + + newValue.ifPresent(value -> { + Optional decodedValue = newValue.get().getValueAsString(); + decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("tagData", getValues(path))).start()); + }); + }); + cache.start(); + } + } + + private void addVersionConfig(String env) { + String path = String.format(PATH_VERSION, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment)); + + this.versionData = parseData(path); + try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) { + cache.addListener(newValues -> { + Optional newValue = newValues.values().stream() + .filter(value -> value.getKey().equals(path)) + .findAny(); + + newValue.ifPresent(value -> { + Optional decodedValue = newValue.get().getValueAsString(); + decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("versionData", getValues(path))).start()); + }); + }); + cache.start(); + } + } + + private void addServiceConfig(String env) { + String path = String.format(PATH_SERVICE, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment)); + + this.serviceData = parseData(path); + try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) { + cache.addListener(newValues -> { + Optional newValue = newValues.values().stream() + .filter(value -> value.getKey().equals(path)) + .findAny(); + + newValue.ifPresent(value -> { + Optional decodedValue = newValue.get().getValueAsString(); + decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("serviceData", getValues(path))).start()); + }); + }); + cache.start(); + } + } + + private void addApplicationConfig(String env) { + String path = String.format(PATH_APPLICATION, env, BootStrapProperties.readApplication(environment)); + this.applicationData = parseData(path); + try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) { + cache.addListener(newValues -> { + Optional newValue = newValues.values().stream() + .filter(value -> value.getKey().equals(path)) + .findAny(); + + newValue.ifPresent(value -> { + Optional decodedValue = newValue.get().getValueAsString(); + decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("applicationData", getValues(path))).start()); + }); + }); + cache.start(); + } + } + + private void addEnvironmentConfig(String env) { + String path = String.format(PATH_ENVIRONMENT, env); + + this.environmentData = parseData(path); + try (KVCache cache = KVCache.newCache(kvClient, path, consulConfig.getConsulWatchSeconds())) { + cache.addListener(newValues -> { + Optional newValue = newValues.values().stream() + .filter(value -> value.getKey().equals(path)) + .findAny(); + + newValue.ifPresent(value -> { + Optional decodedValue = newValue.get().getValueAsString(); + decodedValue.ifPresent(v -> new Thread(new GetDataRunnable("environmentData", getValues(path))).start()); + }); + }); + cache.start(); + } + } + + public Map parseData(String path) { + try { + return getValues(path); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + return new HashMap<>(); + } + + private Map getValues(String path) { + Map values = new HashMap<>(); + KeyValueClient keyValueClient = consulClient.keyValueClient(); + String decodedValue = keyValueClient.getValueAsString(path).orElseThrow(); + if (StringUtils.isBlank(decodedValue)) { + return values; + } + return getValues(path, decodedValue); + } + + private @NotNull Map getValues(String path, String decodedValue) { + Map values = new HashMap<>(); + if (path.endsWith(".yaml") || path.endsWith(".yml")) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(decodedValue.getBytes(StandardCharsets.UTF_8))); + values.putAll(toMap(yamlFactory.getObject())); + } else if (path.endsWith(".properties")) { + Properties properties = new Properties(); + try { + properties.load(new StringReader(decodedValue)); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + values.putAll(toMap(properties)); + } else { + values.put(path, decodedValue); + } + return values; + } + + private void refreshConfigItems() { + synchronized (lock) { + Map all = new HashMap<>(); + all.putAll(environmentData); + all.putAll(applicationData); + all.putAll(serviceData); + all.putAll(versionData); + all.putAll(tagData); + updateHandler.handle(all, allLast); + this.allLast = all; + } + } + + @SuppressWarnings("unchecked") + private Map toMap(Properties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + result.put(key, value); + } + return result; + } +} diff --git a/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigProperties.java b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigProperties.java new file mode 100644 index 00000000000..fe3a278678a --- /dev/null +++ b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulConfigProperties.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.consul; + +public class ConsulConfigProperties { + + private String host = "localhost"; + + private Integer port = 8500; + + private String scheme = "http"; + + private String aclToken; + + private Integer watchSeconds = 8; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getAclToken() { + return aclToken; + } + + public void setAclToken(String aclToken) { + this.aclToken = aclToken; + } + + public Integer getWatchSeconds() { + return watchSeconds; + } + + public void setWatchSeconds(Integer watchSeconds) { + this.watchSeconds = watchSeconds; + } +} diff --git a/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulDynamicPropertiesSource.java b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulDynamicPropertiesSource.java new file mode 100644 index 00000000000..9f0b3649249 --- /dev/null +++ b/dynamic-config/config-consul/src/main/java/org/apache/servicecomb/config/consul/ConsulDynamicPropertiesSource.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.consul; + +import com.google.common.net.HostAndPort; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.kiwiproject.consul.Consul; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ConsulDynamicPropertiesSource implements DynamicPropertiesSource { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDynamicPropertiesSource.class); + + public static final String SOURCE_NAME = "consul"; + + private final Map valueCache = new ConcurrentHashMap<>(); + + private ConsulConfigClient consulConfigClient; + + public ConsulDynamicPropertiesSource() { + } + + private final UpdateHandler updateHandler = new UpdateHandler(); + public class UpdateHandler { + public void handle(Map current, Map last) { + ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(current, last); + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + valueCache.putAll(event.getAdded()); + valueCache.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> valueCache.remove(k)); + EventManager.post(event); + } + } + + private ConsulConfigProperties consulConfigProperties(Environment environment) { + ConsulConfig consulConfig = new ConsulConfig(environment); + ConsulConfigProperties consulConfigProperties = new ConsulConfigProperties(); + consulConfigProperties.setHost(consulConfig.getConsulHost()); + consulConfigProperties.setPort(consulConfig.getConsulPort()); + consulConfigProperties.setScheme(consulConfig.getConsulScheme()); + consulConfigProperties.setAclToken(consulConfig.getConsulAclToken()); + consulConfigProperties.setWatchSeconds(consulConfig.getConsulWatchSeconds()); + return consulConfigProperties; + } + + private Consul consulClient(ConsulConfigProperties consulConfigProperties) { + Consul.Builder builder = Consul.builder().withHostAndPort(HostAndPort.fromParts(consulConfigProperties.getHost(), consulConfigProperties.getPort())); + if (StringUtils.isNotBlank(consulConfigProperties.getAclToken())) { + builder.withAclToken(consulConfigProperties.getAclToken()); + } + return builder.build(); + } + + private ConsulConfigClient consulConfigClient(Environment environment) { + ConsulConfigProperties consulConfigProperties = consulConfigProperties(environment); + Consul consulClient = consulClient(consulConfigProperties); + return new ConsulConfigClient(updateHandler, environment, consulConfigProperties, consulClient); + } + + @Override + public PropertySource create(Environment environment) { + try { + consulConfigClient = consulConfigClient(environment); + consulConfigClient.refreshConsulConfig(); + } catch (Exception e) { + throw new IllegalStateException("Set up consul config failed.", e); + } + return new MapPropertySource(SOURCE_NAME, valueCache); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/dynamic-config/config-consul/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-consul/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..7b1c73e1195 --- /dev/null +++ b/dynamic-config/config-consul/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.consul.ConsulDynamicPropertiesSource diff --git a/dynamic-config/config-etcd/pom.xml b/dynamic-config/config-etcd/pom.xml new file mode 100644 index 00000000000..8aa6b2cf963 --- /dev/null +++ b/dynamic-config/config-etcd/pom.xml @@ -0,0 +1,44 @@ + + + + + + + dynamic-config + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + config-etcd + Java Chassis::Dynamic Config::Zookeeper + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-vertx + + + io.etcd + jetcd-core + + + diff --git a/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdClient.java b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdClient.java new file mode 100644 index 00000000000..9a7743add07 --- /dev/null +++ b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdClient.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.etcd; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.etcd.EtcdDynamicPropertiesSource.UpdateHandler; +import org.apache.servicecomb.foundation.common.utils.MuteExceptionUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ByteArrayResource; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.Watch; +import io.etcd.jetcd.kv.GetResponse; +import io.etcd.jetcd.options.GetOption; +import io.etcd.jetcd.options.WatchOption; + +public class EtcdClient { + + public class GetDataRunnable implements Runnable { + + private Map dataMap; + + private EtcdClient etcdClient; + + private String path; + + public GetDataRunnable(Map dataMap, EtcdClient etcdClient, String path) { + this.dataMap = dataMap; + this.etcdClient = etcdClient; + this.path = path; + } + + @Override + public void run() { + try { + dataMap.clear(); + dataMap.putAll(etcdClient.parseData(path)); + refreshConfigItems(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdClient.class); + + public static final String PATH_ENVIRONMENT = "/servicecomb/config/environment/%s"; + + public static final String PATH_APPLICATION = "/servicecomb/config/application/%s/%s"; + + public static final String PATH_SERVICE = "/servicecomb/config/service/%s/%s/%s"; + + public static final String PATH_VERSION = "/servicecomb/config/version/%s/%s/%s/%s"; + + public static final String PATH_TAG = "/servicecomb/config/tag/%s/%s/%s/%s/%s"; + + private final UpdateHandler updateHandler; + + private final EtcdConfig etcdConfig; + + private final Environment environment; + + private final Object lock = new Object(); + + private Map environmentData = new HashMap<>(); + + private Map applicationData = new HashMap<>(); + + private Map serviceData = new HashMap<>(); + + private Map versionData = new HashMap<>(); + + private Map tagData = new HashMap<>(); + + private Map allLast = new HashMap<>(); + + private Client client; + + public EtcdClient(UpdateHandler updateHandler, Environment environment) { + this.updateHandler = updateHandler; + this.etcdConfig = new EtcdConfig(environment); + this.environment = environment; + } + + public void getClient() { + if (StringUtils.isEmpty(etcdConfig.getAuthInfo())) { + this.client = Client.builder().endpoints(etcdConfig.getConnectString()).build(); + } else { + String[] authInfo = etcdConfig.getAuthInfo().split(":"); + this.client = Client.builder().endpoints(etcdConfig.getConnectString()) + .user(ByteSequence.from(authInfo[0], StandardCharsets.UTF_8)) + .password(ByteSequence.from(authInfo[1], StandardCharsets.UTF_8)).build(); + } + } + + public void refreshEtcdConfig() throws Exception { + + getClient(); + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = EtcdConfig.ZOOKEEPER_DEFAULT_ENVIRONMENT; + } + addEnvironmentConfig(env); + addApplicationConfig(env); + addServiceConfig(env); + addVersionConfig(env); + addTagConfig(env); + + refreshConfigItems(); + } + + private void addTagConfig(String env) throws Exception { + if (StringUtils.isEmpty(etcdConfig.getInstanceTag())) { + return; + } + String path = String.format(PATH_TAG, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment), + etcdConfig.getInstanceTag()); + + ByteSequence prefixByteSeq = ByteSequence.from(path, StandardCharsets.UTF_8); + Watch watchClient = client.getWatchClient(); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> new Thread(new GetDataRunnable(tagData, this, path)).start()); + this.tagData = parseData(path); + } + + private void addVersionConfig(String env) throws Exception { + String path = String.format(PATH_VERSION, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment)); + + ByteSequence prefixByteSeq = ByteSequence.from(path, StandardCharsets.UTF_8); + Watch watchClient = client.getWatchClient(); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> new Thread(new GetDataRunnable(versionData, this, path)).start()); + this.versionData = parseData(path); + } + + private void addServiceConfig(String env) throws Exception { + String path = String.format(PATH_SERVICE, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment)); + + ByteSequence prefixByteSeq = ByteSequence.from(path, StandardCharsets.UTF_8); + Watch watchClient = client.getWatchClient(); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> new Thread(new GetDataRunnable(serviceData, this, path)).start()); + this.serviceData = parseData(path); + } + + private void addApplicationConfig(String env) throws Exception { + String path = String.format(PATH_APPLICATION, env, BootStrapProperties.readApplication(environment)); + + ByteSequence prefixByteSeq = ByteSequence.from(path, StandardCharsets.UTF_8); + Watch watchClient = client.getWatchClient(); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> new Thread(new GetDataRunnable(applicationData, this, path)).start()); + this.applicationData = parseData(path); + } + + private void addEnvironmentConfig(String env) throws Exception { + String path = String.format(PATH_ENVIRONMENT, env); + + ByteSequence prefixByteSeq = ByteSequence.from(path, StandardCharsets.UTF_8); + Watch watchClient = client.getWatchClient(); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> new Thread(new GetDataRunnable(environmentData, this, path)).start()); + this.environmentData = parseData(path); + } + + public Map parseData(String path) throws Exception { + + List endpointKv = getValuesByPrefix(path); + return getValues(path, endpointKv); + } + + private Map getValues(String path, List endpointKv) { + Map values = new HashMap<>(); + for (KeyValue keyValue : endpointKv) { + String key = new String(keyValue.getKey().getBytes(), StandardCharsets.UTF_8); + String value = new String(keyValue.getValue().getBytes(), StandardCharsets.UTF_8); + if (key.equals(path)) { + continue; + } + if (key.endsWith(".yaml") || key.endsWith(".yml")) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(value.getBytes(StandardCharsets.UTF_8))); + values.putAll(toMap(yamlFactory.getObject())); + } else if (key.endsWith(".properties")) { + Properties properties = new Properties(); + try { + properties.load(new StringReader(value)); + } catch (IOException e) { + LOGGER.error("load error"); + } + values.putAll(toMap(properties)); + } else { + values.put(key, value); + } + } + return values; + } + + private List getValuesByPrefix(String prefix) { + + CompletableFuture getFuture = client.getKVClient() + .get(ByteSequence.from(prefix, StandardCharsets.UTF_8), + GetOption.builder().withPrefix(ByteSequence.from(prefix, StandardCharsets.UTF_8)).build()); + GetResponse response = MuteExceptionUtil.builder().withLog("get kv by prefix error") + .executeCompletableFuture(getFuture); + return response.getKvs(); + } + + private void refreshConfigItems() { + synchronized (lock) { + Map all = new HashMap<>(); + all.putAll(environmentData); + all.putAll(applicationData); + all.putAll(serviceData); + all.putAll(versionData); + all.putAll(tagData); + updateHandler.handle(all, allLast); + this.allLast = all; + } + } + + @SuppressWarnings("unchecked") + private Map toMap(Properties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + result.put(key, value); + } + return result; + } +} diff --git a/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdConfig.java b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdConfig.java new file mode 100644 index 00000000000..ee04204c28a --- /dev/null +++ b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdConfig.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.etcd; + +import org.springframework.core.env.Environment; + +public class EtcdConfig { + public static final String ZOOKEEPER_DEFAULT_ENVIRONMENT = "production"; + + public static final String PROPERTY_CONNECT_STRING = "servicecomb.config.etcd.connectString"; + + public static final String PROPERTY_SESSION_TIMEOUT = "servicecomb.config.etcd.sessionTimeoutMillis"; + + public static final String PROPERTY_CONNECTION_TIMEOUT = "servicecomb.config.etcd.connectionTimeoutMills"; + + public static final String PROPERTY_AUTH_SCHEMA = "servicecomb.config.etcd.authenticationSchema"; + + public static final String PROPERTY_AUTH_INFO = "servicecomb.config.etcd.authenticationInfo"; + + public static final String PROPERTY_INSTANCE_TAG = "servicecomb.config.etcd.instanceTag"; + + private final Environment environment; + + public EtcdConfig(Environment environment) { + this.environment = environment; + } + + public String getConnectString() { + return environment.getProperty(PROPERTY_CONNECT_STRING, "http://127.0.0.1:2379"); + } + + public int getSessionTimeoutMillis() { + return environment.getProperty(PROPERTY_SESSION_TIMEOUT, int.class, 60000); + } + + public int getConnectionTimeoutMillis() { + return environment.getProperty(PROPERTY_CONNECTION_TIMEOUT, int.class, 1000); + } + + public String getAuthSchema() { + return environment.getProperty(PROPERTY_AUTH_SCHEMA); + } + + public String getAuthInfo() { + return environment.getProperty(PROPERTY_AUTH_INFO); + } + + public String getInstanceTag() { + return environment.getProperty(PROPERTY_INSTANCE_TAG); + } +} diff --git a/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdDynamicPropertiesSource.java b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdDynamicPropertiesSource.java new file mode 100644 index 00000000000..a86de892180 --- /dev/null +++ b/dynamic-config/config-etcd/src/main/java/org/apache/servicecomb/config/etcd/EtcdDynamicPropertiesSource.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.etcd; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +public class EtcdDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "etcd"; + + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdDynamicPropertiesSource.class); + + private final Map valueCache = new ConcurrentHashMap<>(); + + public EtcdDynamicPropertiesSource() { + } + + private final UpdateHandler updateHandler = new UpdateHandler(); + + private void init(Environment environment) { + EtcdClient etcdClient = new EtcdClient(updateHandler, environment); + try { + etcdClient.refreshEtcdConfig(); + } catch (Exception e) { + throw new IllegalStateException("Set up etcd config failed.", e); + } + } + + public class UpdateHandler { + public void handle(Map current, Map last) { + ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(current, last); + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + valueCache.putAll(event.getAdded()); + valueCache.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> valueCache.remove(k)); + EventManager.post(event); + } + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, valueCache); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/dynamic-config/config-etcd/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-etcd/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..d10124395fa --- /dev/null +++ b/dynamic-config/config-etcd/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.etcd.EtcdDynamicPropertiesSource diff --git a/dynamic-config/config-kie/pom.xml b/dynamic-config/config-kie/pom.xml new file mode 100644 index 00000000000..4bf61b5801f --- /dev/null +++ b/dynamic-config/config-kie/pom.xml @@ -0,0 +1,65 @@ + + + + + + + dynamic-config + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + config-kie + Java Chassis::Dynamic Config::Kie + + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-ssl + + + org.apache.servicecomb + foundation-vertx + + + io.vertx + vertx-codegen + provided + + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + org.apache.servicecomb + config-kie-client + + + diff --git a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfig.java b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfig.java new file mode 100644 index 00000000000..79e40786f8f --- /dev/null +++ b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfig.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie; + +import java.util.Collections; +import java.util.List; + +import org.apache.servicecomb.foundation.vertx.VertxConst; +import org.springframework.core.env.Environment; + +public class KieConfig { + public static final String SSL_TAG = "kie.consumer"; + + private static final String SERVER_URL_KEY = "servicecomb.kie.serverUri"; + + private static final String REFRESH_INTERVAL = "servicecomb.kie.refreshInterval"; + + private static final String FIRST_REFRESH_INTERVAL = "servicecomb.kie.firstRefreshInterval"; + + private static final String DOMAIN_NAME = "servicecomb.kie.domainName"; + + private static final String ENABLE_LONG_POLLING = "servicecomb.kie.enableLongPolling"; + + private static final String POLLING_WAIT_TIME = "servicecomb.kie.pollingWaitTime"; + + private static final String FIRST_PULL_REQUIRED = "servicecomb.kie.firstPullRequired"; + + private static final String CUSTOM_LABEL = "servicecomb.kie.customLabel"; + + private static final String CUSTOM_LABEL_VALUE = "servicecomb.kie.customLabelValue"; + + private static final String ENABLE_APP_CONFIG = "servicecomb.kie.enableAppConfig"; + + private static final String ENABLE_SERVICE_CONFIG = "servicecomb.kie.enableServiceConfig"; + + private static final String ENABLE_VERSION_CONFIG = "servicecomb.kie.enableVersionConfig"; + + private static final String ENABLE_CUSTOM_CONFIG = "servicecomb.kie.enableCustomConfig"; + + public static final String FILE_SOURCE = "servicecomb.config.client.fileSource"; + + private static final int DEFAULT_REFRESH_INTERVAL = 15000; + + private static final int DEFAULT_POLLING_WAIT_TIME = 10; + + private static final int DEFAULT_FIRST_REFRESH_INTERVAL = 0; + + private static final boolean DEFAULT_ENABLE_LONG_POLLING = true; + + private static final String CUSTOM_LABEL_DEFAULT = "public"; + + private static final String CUSTOM_LABEL_VALUE_DEFAULT = ""; + + private static final String CLIENT_CONNECT_TIMEOUT = "servicecomb.kie.client.timeout.connect"; + + private static final String CLIENT_REQUEST_TIMEOUT = "servicecomb.kie.client.timeout.request"; + + private static final String CLIENT_SOCKET_TIMEOUT = "servicecomb.kie.client.timeout.socket"; + + private final Environment environment; + + public KieConfig(Environment environment) { + this.environment = environment; + } + + @SuppressWarnings("unchecked") + public List getFileSources() { + return environment.getProperty(FILE_SOURCE, List.class, Collections.emptyList()); + } + + public String getDomainName() { + return environment.getProperty(DOMAIN_NAME, "default"); + } + + public String getServerUri() { + return environment.getProperty(SERVER_URL_KEY); + } + + public int getRefreshInterval() { + return environment.getProperty(REFRESH_INTERVAL, int.class, DEFAULT_REFRESH_INTERVAL); + } + + public int getFirstRefreshInterval() { + return environment.getProperty(FIRST_REFRESH_INTERVAL, int.class, DEFAULT_FIRST_REFRESH_INTERVAL); + } + + public boolean enableAppConfig() { + return environment.getProperty(ENABLE_APP_CONFIG, boolean.class, true); + } + + public boolean enableServiceConfig() { + return environment.getProperty(ENABLE_SERVICE_CONFIG, boolean.class, true); + } + + public boolean enableVersionConfig() { + return environment.getProperty(ENABLE_VERSION_CONFIG, boolean.class, true); + } + + public boolean enableCustomConfig() { + return environment.getProperty(ENABLE_CUSTOM_CONFIG, boolean.class, true); + } + + public boolean enableLongPolling() { + return environment.getProperty(ENABLE_LONG_POLLING, boolean.class, DEFAULT_ENABLE_LONG_POLLING); + } + + public int getPollingWaitTime() { + return environment.getProperty(POLLING_WAIT_TIME, int.class, DEFAULT_POLLING_WAIT_TIME); + } + + public boolean firstPullRequired() { + return environment.getProperty(FIRST_PULL_REQUIRED, boolean.class, false); + } + + public String getCustomLabel() { + return environment.getProperty(CUSTOM_LABEL, CUSTOM_LABEL_DEFAULT); + } + + public String getCustomLabelValue() { + return environment.getProperty(CUSTOM_LABEL_VALUE, CUSTOM_LABEL_VALUE_DEFAULT); + } + + public Boolean isProxyEnable() { + return environment.getProperty(VertxConst.PROXY_ENABLE, boolean.class, false); + } + + public String getProxyHost() { + return environment.getProperty(VertxConst.PROXY_HOST, "127.0.0.1"); + } + + public int getProxyPort() { + return environment.getProperty(VertxConst.PROXY_PORT, int.class, 8080); + } + + public String getProxyUsername() { + return environment.getProperty(VertxConst.PROXY_USERNAME); + } + + public String getProxyPasswd() { + return environment.getProperty(VertxConst.PROXY_PASSWD); + } + + public int getConnectTimeout() { + return environment.getProperty(CLIENT_CONNECT_TIMEOUT, int.class, 5000); + } + + public int getConnectionRequestTimeout() { + return environment.getProperty(CLIENT_REQUEST_TIMEOUT, int.class, 5000); + } + + public int getSocketTimeout() { + return environment.getProperty(CLIENT_SOCKET_TIMEOUT, int.class, 5000); + } +} diff --git a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfigConfiguration.java b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfigConfiguration.java new file mode 100644 index 00000000000..7b8e35bd6e4 --- /dev/null +++ b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieConfigConfiguration.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.kie; + +import org.apache.servicecomb.config.kie.collect.KieClientInformationCollector; +import org.springframework.context.annotation.Bean; + +public class KieConfigConfiguration { + @Bean + public KieClientInformationCollector kieClientInformationCollector() { + return new KieClientInformationCollector(); + } +} diff --git a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java new file mode 100644 index 00000000000..6683b84fb09 --- /dev/null +++ b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/KieDynamicPropertiesSource.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.kie; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.config.RequestConfig.Builder; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.config.common.ConfigConverter; +import org.apache.servicecomb.config.kie.client.KieClient; +import org.apache.servicecomb.config.kie.client.KieConfigManager; +import org.apache.servicecomb.config.kie.client.KieConfigurationChangedEvent; +import org.apache.servicecomb.config.kie.client.model.KieAddressManager; +import org.apache.servicecomb.config.kie.client.model.KieConfiguration; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import com.google.common.eventbus.Subscribe; + +public class KieDynamicPropertiesSource implements DynamicPropertiesSource { + private static final Logger LOGGER = LoggerFactory.getLogger(KieDynamicPropertiesSource.class); + + public static final String SOURCE_NAME = "kie"; + + private final Map data = new ConcurrentHashMapEx<>(); + + private KieConfigManager kieConfigManager; + + private ConfigConverter configConverter; + + public KieDynamicPropertiesSource() { + + } + + private void init(Environment environment) { + KieConfig kieConfig = new KieConfig(environment); + configConverter = new ConfigConverter(kieConfig.getFileSources()); + KieAddressManager kieAddressManager = configKieAddressManager(kieConfig, environment); + + RequestConfig.Builder requestBuilder = buildRequestConfigBuilder(kieConfig); + if (kieConfig.enableLongPolling() + && kieConfig.getPollingWaitTime() >= 0) { + requestBuilder.setConnectionRequestTimeout(kieConfig.getPollingWaitTime() * 2 * 1000); + requestBuilder.setSocketTimeout(kieConfig.getPollingWaitTime() * 2 * 1000); + } + HttpTransport httpTransport = createHttpTransport(kieAddressManager, requestBuilder.build(), + kieConfig, environment); + KieConfiguration kieConfiguration = createKieConfiguration(kieConfig, environment); + KieClient kieClient = new KieClient(kieAddressManager, httpTransport, kieConfiguration); + EventManager.register(this); + kieConfigManager = new KieConfigManager(kieClient, EventManager.getEventBus(), kieConfiguration, configConverter, + kieAddressManager); + kieConfigManager.firstPull(); + kieConfigManager.startConfigKieManager(); + data.putAll(configConverter.getCurrentData()); + } + + private Builder buildRequestConfigBuilder(KieConfig kieConfig) { + Builder builder = HttpTransportFactory.defaultRequestConfig(); + builder.setConnectTimeout(kieConfig.getConnectTimeout()); + builder.setConnectionRequestTimeout(kieConfig.getConnectionRequestTimeout()); + builder.setSocketTimeout(kieConfig.getSocketTimeout()); + return builder; + } + + @Subscribe + public void onConfigurationChangedEvent(KieConfigurationChangedEvent event) { + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + data.putAll(event.getAdded()); + data.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> data.remove(k)); + EventManager.post(ConfigurationChangedEvent.createIncremental(event.getAdded(), + event.getUpdated(), event.getDeleted())); + } + + private KieConfiguration createKieConfiguration(KieConfig kieConfig, Environment environment) { + return new KieConfiguration() + .setAppName(BootStrapProperties.readApplication(environment)) + .setServiceName(BootStrapProperties.readServiceName(environment)) + .setEnvironment(BootStrapProperties.readServiceEnvironment(environment)) + .setVersion(BootStrapProperties.readServiceVersion(environment)) + .setFirstPullRequired(kieConfig.firstPullRequired()) + .setCustomLabel(kieConfig.getCustomLabel()) + .setCustomLabelValue(kieConfig.getCustomLabelValue()) + .setEnableAppConfig(kieConfig.enableAppConfig()) + .setEnableCustomConfig(kieConfig.enableCustomConfig()) + .setEnableLongPolling(kieConfig.enableLongPolling()) + .setEnableServiceConfig(kieConfig.enableServiceConfig()) + .setEnableVersionConfig(kieConfig.enableVersionConfig()) + .setPollingWaitInSeconds(kieConfig.getPollingWaitTime()) + .setProject(kieConfig.getDomainName()) + .setRefreshIntervalInMillis(kieConfig.getRefreshInterval()); + } + + private HttpTransport createHttpTransport(KieAddressManager kieAddressManager, + RequestConfig requestConfig, KieConfig kieConfig, + Environment environment) { + List authHeaderProviders = SPIServiceUtils.getOrLoadSortedService(AuthHeaderProvider.class); + + if (kieConfig.isProxyEnable()) { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(requestConfig); + HttpHost proxy = new HttpHost(kieConfig.getProxyHost(), + kieConfig.getProxyPort(), "http"); // now only support http proxy + httpClientBuilder.setProxy(proxy); + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials(kieConfig.getProxyUsername(), + kieConfig.getProxyPasswd())); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(kieAddressManager.sslEnabled(), environment, KieConfig.SSL_TAG), + getRequestAuthHeaderProvider(authHeaderProviders), httpClientBuilder); + } + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(kieAddressManager.sslEnabled(), environment, KieConfig.SSL_TAG), + getRequestAuthHeaderProvider(authHeaderProviders), requestConfig); + } + + private static RequestAuthHeaderProvider getRequestAuthHeaderProvider(List authHeaderProviders) { + return signRequest -> { + String host = signRequest != null && signRequest.getEndpoint() != null ? signRequest.getEndpoint().getHost() : ""; + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.authHeaders(host))); + return headers; + }; + } + + private KieAddressManager configKieAddressManager(KieConfig kieConfig, Environment environment) { + String region = environment.getProperty("servicecomb.datacenter.region"); + String availableZone = environment.getProperty("servicecomb.datacenter.availableZone"); + return new KieAddressManager( + Arrays.asList(kieConfig.getServerUri().split(",")), EventManager.getEventBus(), region, availableZone); + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, data); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/TransportUtils.java b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/TransportUtils.java new file mode 100644 index 00000000000..8be7ec00c1a --- /dev/null +++ b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/TransportUtils.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie; + +import static org.apache.servicecomb.foundation.ssl.SSLOption.DEFAULT_OPTION; + +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.springframework.core.env.Environment; + +public class TransportUtils { + public static SSLProperties createSSLProperties(boolean sslEnabled, Environment environment, String tag) { + SSLProperties sslProperties = new SSLProperties(); + sslProperties.setEnabled(sslEnabled); + + if (!sslEnabled) { + return sslProperties; + } + + SSLOption option = new SSLOption(); + option.setEngine(getStringProperty(environment, + DEFAULT_OPTION.getEngine(), + "ssl." + tag + ".engine", + "ssl.engine")); + option.setProtocols( + getStringProperty(environment, + DEFAULT_OPTION.getProtocols(), + "ssl." + tag + ".protocols", + "ssl.protocols")); + option.setCiphers( + getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".ciphers", "ssl.ciphers")); + option.setAuthPeer( + getBooleanProperty(environment, DEFAULT_OPTION.isAuthPeer(), "ssl." + tag + ".authPeer", "ssl.authPeer")); + option.setCheckCNHost( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNHost(), + "ssl." + tag + ".checkCN.host", + "ssl.checkCN.host")); + option.setCheckCNWhite( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNWhite(), + "ssl." + tag + ".checkCN.white", + "ssl.checkCN.white")); + option.setCheckCNWhiteFile(getStringProperty(environment, + DEFAULT_OPTION.getCiphers(), + "ssl." + tag + ".checkCN.white.file", + "ssl.checkCN.white.file")); + option.setAllowRenegotiate(getBooleanProperty(environment, + DEFAULT_OPTION.isAllowRenegotiate(), + "ssl." + tag + ".allowRenegotiate", + "ssl.allowRenegotiate")); + option.setStorePath( + getStringProperty(environment, + DEFAULT_OPTION.getStorePath(), + "ssl." + tag + ".storePath", + "ssl.storePath")); + option.setClientAuth( + getStringProperty(environment, + DEFAULT_OPTION.getClientAuth(), + "ssl." + tag + ".clientAuth", + "ssl.clientAuth")); + option.setTrustStore( + getStringProperty(environment, + DEFAULT_OPTION.getTrustStore(), + "ssl." + tag + ".trustStore", + "ssl.trustStore")); + option.setTrustStoreType(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreType(), + "ssl." + tag + ".trustStoreType", + "ssl.trustStoreType")); + option.setTrustStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreValue(), + "ssl." + tag + ".trustStoreValue", + "ssl.trustStoreValue")); + option.setKeyStore( + getStringProperty(environment, DEFAULT_OPTION.getKeyStore(), "ssl." + tag + ".keyStore", "ssl.keyStore")); + option.setKeyStoreType( + getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreType(), + "ssl." + tag + ".keyStoreType", + "ssl.keyStoreType")); + option.setKeyStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreValue(), + "ssl." + tag + ".keyStoreValue", + "ssl.keyStoreValue")); + option.setCrl(getStringProperty(environment, DEFAULT_OPTION.getCrl(), "ssl." + tag + ".crl", "ssl.crl")); + option.setSslCustomClass( + getStringProperty(environment, null, "ssl." + tag + ".sslCustomClass", "ssl.sslCustomClass")); + + sslProperties.setSslOption(option); + sslProperties.setSslCustom(SSLCustom.createSSLCustom(option.getSslCustomClass())); + return sslProperties; + } + + private static String getStringProperty(Environment environment, String defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key); + } + } + return defaultValue; + } + + private static boolean getBooleanProperty(Environment environment, boolean defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key, boolean.class, false); + } + } + return defaultValue; + } +} diff --git a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/collect/KieClientInformationCollector.java b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/collect/KieClientInformationCollector.java new file mode 100644 index 00000000000..d689aaec2e1 --- /dev/null +++ b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/collect/KieClientInformationCollector.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.kie.collect; + +import org.apache.servicecomb.config.kie.KieConfig; +import org.apache.servicecomb.core.bootup.BootUpInformationCollector; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; +import org.springframework.lang.NonNull; + +public class KieClientInformationCollector implements BootUpInformationCollector, EnvironmentAware { + private KieConfig kieConfig; + + @Override + public void setEnvironment(@NonNull Environment environment) { + this.kieConfig = new KieConfig(environment); + } + + @Override + public String collect() { + return "Kie Center: " + kieConfig.getServerUri(); + } + + @Override + public int getOrder() { + return 2; + } +} diff --git a/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..1ff1d0d0bb4 --- /dev/null +++ b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.kie.KieDynamicPropertiesSource diff --git a/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector new file mode 100644 index 00000000000..4ff2984a1b2 --- /dev/null +++ b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.servicecomb.config.kie.collect.KieClientInformationCollector diff --git a/dynamic-config/config-kie/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dynamic-config/config-kie/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..347d30ccef4 --- /dev/null +++ b/dynamic-config/config-kie/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.config.kie.KieConfigConfiguration diff --git a/dynamic-config/config-kie/src/test/resources/microservice.yaml b/dynamic-config/config-kie/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..4928e22a60b --- /dev/null +++ b/dynamic-config/config-kie/src/test/resources/microservice.yaml @@ -0,0 +1,56 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +host.name: 172.16.8.7 +trace: + handler: + enabled: false + sampler: + percent: 0.5 + metric: + service: + enable: false +validate: + parameter: + enabled: true + returnValue: + enabled: true + apiInvoke: + enabled: true +shutDownHandler: + enabled: true + timeLimit: 30000 +eureka: + instance: + preferIpAddress: true + leaseRenewalIntervalInSeconds: 3 + leaseExpirationDurationInSeconds: 5 + client: + serviceUrl: + defaultZone: http://172.16.8.8:30100/ +servicecomb: + kie: + serverUri: https://172.16.8.7:30110 + service: + registry: + autodiscovery: true + refreshInterval: 3000 + firstRefreshInterval: 0 + +service_description: + name: testDemo + environment: testing diff --git a/dynamic-config/config-nacos/README.md b/dynamic-config/config-nacos/README.md new file mode 100644 index 00000000000..e09d8db761d --- /dev/null +++ b/dynamic-config/config-nacos/README.md @@ -0,0 +1,4 @@ +# Dynamic configurations implementation with [Nacos](https://github.com/alibaba/nacos) + +Read [developers guide](https://docs.servicecomb.io/java-chassis/zh_CN/config/general-config/) +for details. diff --git a/dynamic-config/config-nacos/pom.xml b/dynamic-config/config-nacos/pom.xml new file mode 100644 index 00000000000..395603f9fd6 --- /dev/null +++ b/dynamic-config/config-nacos/pom.xml @@ -0,0 +1,45 @@ + + + + + + + dynamic-config + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + config-nacos + Java Chassis::Dynamic Config::Nacos + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-vertx + + + + com.alibaba.nacos + nacos-client + + + diff --git a/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosClient.java b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosClient.java new file mode 100644 index 00000000000..de9527b17ab --- /dev/null +++ b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosClient.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.nacos; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.nacos.NacosDynamicPropertiesSource.UpdateHandler; +import org.apache.servicecomb.config.parser.Parser; +import org.springframework.core.env.Environment; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; + +public class NacosClient { + private final UpdateHandler updateHandler; + + private final NacosConfig nacosConfig; + + private final Environment environment; + + private final Object lock = new Object(); + + private Map application = new HashMap<>(); + + private Map service = new HashMap<>(); + + private Map version = new HashMap<>(); + + private Map profile = new HashMap<>(); + + private Map custom = new HashMap<>(); + + private Map allLast = new HashMap<>(); + + public NacosClient(UpdateHandler updateHandler, Environment environment) { + this.updateHandler = updateHandler; + this.nacosConfig = new NacosConfig(environment); + this.environment = environment; + } + + public void refreshNacosConfig() throws NacosException { + Properties properties = nacosProperties(environment, nacosConfig); + + ConfigService configService = NacosFactory.createConfigService(properties); + addApplicationConfig(configService); + addServiceConfig(configService); + addVersionConfig(configService); + addProfileConfig(configService); + addCustomConfig(configService); + + refreshConfigItems(); + } + + private void addApplicationConfig(ConfigService configService) throws NacosException { + String content = configService.getConfig(BootStrapProperties.readApplication(environment), + BootStrapProperties.readApplication(environment), 5000); + processApplicationConfig(content); + configService.addListener(BootStrapProperties.readApplication(environment), + BootStrapProperties.readApplication(environment), new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + processApplicationConfig(configInfo); + refreshConfigItems(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } + + private void processApplicationConfig(String content) { + if (StringUtils.isEmpty(content)) { + this.application = new HashMap<>(); + return; + } + Parser contentParser = Parser.findParser("yaml"); + this.application = contentParser.parse(content, "", false); + } + + private void addServiceConfig(ConfigService configService) throws NacosException { + String content = configService.getConfig(BootStrapProperties.readServiceName(environment), + BootStrapProperties.readApplication(environment), + 5000); + processServiceConfig(content); + configService.addListener(BootStrapProperties.readServiceName(environment), + BootStrapProperties.readApplication(environment), new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + processServiceConfig(configInfo); + refreshConfigItems(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } + + private void processServiceConfig(String content) { + if (StringUtils.isEmpty(content)) { + this.service = new HashMap<>(); + return; + } + Parser contentParser = Parser.findParser("yaml"); + this.service = contentParser.parse(content, "", false); + } + + private void addVersionConfig(ConfigService configService) throws NacosException { + String content = configService.getConfig( + BootStrapProperties.readServiceName(environment) + "-" + + BootStrapProperties.readServiceVersion(environment), + BootStrapProperties.readApplication(environment), + 5000); + processVersionConfig(content); + configService.addListener(BootStrapProperties.readServiceName(environment) + "-" + + BootStrapProperties.readServiceVersion(environment), + BootStrapProperties.readApplication(environment), new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + processVersionConfig(configInfo); + refreshConfigItems(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } + + private void processVersionConfig(String content) { + if (StringUtils.isEmpty(content)) { + this.version = new HashMap<>(); + return; + } + Parser contentParser = Parser.findParser("yaml"); + this.version = contentParser.parse(content, "", false); + } + + private void addProfileConfig(ConfigService configService) throws NacosException { + String profile = environment.getProperty("spring.profiles.active"); + if (StringUtils.isEmpty(profile)) { + return; + } + String content = configService.getConfig(BootStrapProperties.readServiceName(environment) + "-" + profile, + BootStrapProperties.readApplication(environment), 5000); + processProfileConfig(content); + configService.addListener(BootStrapProperties.readServiceName(environment) + "-" + profile, + BootStrapProperties.readApplication(environment), new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + processProfileConfig(configInfo); + refreshConfigItems(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } + + private void processProfileConfig(String content) { + if (StringUtils.isEmpty(content)) { + this.profile = new HashMap<>(); + return; + } + Parser contentParser = Parser.findParser("yaml"); + this.profile = contentParser.parse(content, "", false); + } + + private void addCustomConfig(ConfigService configService) throws NacosException { + if (StringUtils.isEmpty(nacosConfig.getDataId()) || StringUtils.isEmpty(nacosConfig.getGroup())) { + return; + } + String content = configService.getConfig(nacosConfig.getDataId(), + nacosConfig.getGroup(), 5000); + processCustomConfig(content); + configService.addListener(nacosConfig.getDataId(), + nacosConfig.getGroup(), new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + processCustomConfig(configInfo); + refreshConfigItems(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } + + private void processCustomConfig(String content) { + if (StringUtils.isEmpty(content)) { + this.custom = new HashMap<>(); + return; + } + Parser contentParser = Parser.findParser(nacosConfig.getContentType()); + String keyPrefix = nacosConfig.getGroup() + "." + + nacosConfig.getDataId(); + this.custom = contentParser.parse(content, keyPrefix, nacosConfig.getAddPrefix()); + } + + private void refreshConfigItems() { + synchronized (lock) { + Map all = new HashMap<>(); + all.putAll(application); + all.putAll(service); + all.putAll(version); + all.putAll(profile); + all.putAll(custom); + updateHandler.handle(all, allLast); + this.allLast = all; + } + } + + private static Properties nacosProperties(Environment environment, NacosConfig nacosConfig) { + Properties properties = new Properties(); + properties.put(NacosConfig.PROP_NAMESPACE, BootStrapProperties.readServiceEnvironment(environment)); + properties.put(NacosConfig.PROP_ADDRESS, nacosConfig.getServerAddr()); + if (nacosConfig.getUsername() != null) { + properties.put(NacosConfig.PROP_USERNAME, nacosConfig.getUsername()); + } + if (nacosConfig.getPassword() != null) { + properties.put(NacosConfig.PROP_PASSWORD, nacosConfig.getPassword()); + } + if (nacosConfig.getAccessKey() != null) { + properties.put(NacosConfig.PROP_ACCESS_KEY, nacosConfig.getAccessKey()); + } + if (nacosConfig.getSecretKey() != null) { + properties.put(NacosConfig.PROP_SECRET_KEY, nacosConfig.getSecretKey()); + } + return properties; + } +} diff --git a/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosConfig.java b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosConfig.java new file mode 100644 index 00000000000..8963bd75c2d --- /dev/null +++ b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosConfig.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.nacos; + +import org.springframework.core.env.Environment; + +public class NacosConfig { + public static final String PROPERTY_DATA_ID = "servicecomb.nacos.dataId"; + + public static final String PROPERTY_SERVER_ADDR = "servicecomb.nacos.serverAddr"; + + public static final String PROPERTY_GROUP = "servicecomb.nacos.group"; + + public static final String PROPERTY_ADD_PREFIX = "servicecomb.nacos.addPrefix"; + + public static final String PROPERTY_CONTENT_TYPE = "servicecomb.nacos.contentType"; + + public static final String PROPERTY_USERNAME = "servicecomb.nacos.username"; + + public static final String PROPERTY_PASSWORD = "servicecomb.nacos.password"; + + public static final String PROPERTY_ACCESS_KEY = "servicecomb.nacos.accessKey"; + + public static final String PROPERTY_SECRET_KEY = "servicecomb.nacos.secretKey"; + + public static final String PROP_NAMESPACE = "namespace"; + + public static final String PROP_ADDRESS = "serverAddr"; + + public static final String PROP_USERNAME = "username"; + + public static final String PROP_PASSWORD = "password"; + + public static final String PROP_ACCESS_KEY = "accessKey"; + + public static final String PROP_SECRET_KEY = "secretKey"; + + private final Environment environment; + + public NacosConfig(Environment environment) { + this.environment = environment; + } + + public String getServerAddr() { + return environment.getProperty(PROPERTY_SERVER_ADDR, "http://127.0.0.1:8848"); + } + + public String getDataId() { + return environment.getProperty(PROPERTY_DATA_ID); + } + + public String getGroup() { + return environment.getProperty(PROPERTY_GROUP); + } + + public String getUsername() { + return environment.getProperty(PROPERTY_USERNAME); + } + + public String getPassword() { + return environment.getProperty(PROPERTY_PASSWORD); + } + + public String getAccessKey() { + return environment.getProperty(PROPERTY_ACCESS_KEY); + } + + public String getSecretKey() { + return environment.getProperty(PROPERTY_SECRET_KEY); + } + + public String getContentType() { + return environment.getProperty(PROPERTY_CONTENT_TYPE, "yaml"); + } + + public boolean getAddPrefix() { + return environment.getProperty(PROPERTY_ADD_PREFIX, boolean.class, false); + } +} diff --git a/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosDynamicPropertiesSource.java b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosDynamicPropertiesSource.java new file mode 100644 index 00000000000..308b6337615 --- /dev/null +++ b/dynamic-config/config-nacos/src/main/java/org/apache/servicecomb/config/nacos/NacosDynamicPropertiesSource.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.nacos; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +public class NacosDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "nacos"; + + private static final Logger LOGGER = LoggerFactory.getLogger(NacosDynamicPropertiesSource.class); + + private final Map valueCache = new ConcurrentHashMap<>(); + + public NacosDynamicPropertiesSource() { + } + + private final UpdateHandler updateHandler = new UpdateHandler(); + + private void init(Environment environment) { + NacosClient nacosClient = new NacosClient(updateHandler, environment); + try { + nacosClient.refreshNacosConfig(); + } catch (Exception e) { + throw new IllegalStateException("Set up nacos config failed.", e); + } + } + + public class UpdateHandler { + public void handle(Map current, Map last) { + ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(current, last); + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + valueCache.putAll(event.getAdded()); + valueCache.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> valueCache.remove(k)); + EventManager.post(event); + } + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, valueCache); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/dynamic-config/config-nacos/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-nacos/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..f7b7e102457 --- /dev/null +++ b/dynamic-config/config-nacos/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.nacos.NacosDynamicPropertiesSource diff --git a/dynamic-config/config-nacos/src/test/resources/microservice.yaml b/dynamic-config/config-nacos/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..1b9666a84d4 --- /dev/null +++ b/dynamic-config/config-nacos/src/test/resources/microservice.yaml @@ -0,0 +1,35 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +APPLICATION_ID: nacostest +service_description: + name: nacos-test + version: 1.0.1 + +servicecomb: + service: + registry: + address: http://127.0.0.1:30100 + nacos: + serverAddr: 127.0.0.1:8848 + dataId: example + group: DEFAULT_GROUP + rest: + address: 0.0.0.0:8080 + highway: + address: 0.0.0.0:7070 diff --git a/dynamic-config/config-zookeeper/pom.xml b/dynamic-config/config-zookeeper/pom.xml new file mode 100644 index 00000000000..35fabec9591 --- /dev/null +++ b/dynamic-config/config-zookeeper/pom.xml @@ -0,0 +1,49 @@ + + + + + + + dynamic-config + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + config-zookeeper + Java Chassis::Dynamic Config::Zookeeper + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-vertx + + + + org.apache.curator + curator-framework + + + org.apache.curator + curator-recipes + + + diff --git a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java new file mode 100644 index 00000000000..407c577d4e5 --- /dev/null +++ b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java @@ -0,0 +1,281 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.zookeeper; + +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.CuratorCache; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.zookeeper.ZookeeperDynamicPropertiesSource.UpdateHandler; +import org.apache.zookeeper.server.auth.DigestLoginModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ByteArrayResource; + +public class ZookeeperClient { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperClient.class); + + public static final String PATH_ENVIRONMENT = "/servicecomb/config/environment/%s"; + + public static final String PATH_APPLICATION = "/servicecomb/config/application/%s/%s"; + + public static final String PATH_SERVICE = "/servicecomb/config/service/%s/%s/%s"; + + public static final String PATH_VERSION = "/servicecomb/config/version/%s/%s/%s/%s"; + + public static final String PATH_TAG = "/servicecomb/config/tag/%s/%s/%s/%s/%s"; + + private final UpdateHandler updateHandler; + + private final ZookeeperConfig zookeeperConfig; + + private final Environment environment; + + private final Object lock = new Object(); + + private Map environmentData = new HashMap<>(); + + private Map applicationData = new HashMap<>(); + + private Map serviceData = new HashMap<>(); + + private Map versionData = new HashMap<>(); + + private Map tagData = new HashMap<>(); + + private Map allLast = new HashMap<>(); + + + public ZookeeperClient(UpdateHandler updateHandler, Environment environment) { + this.updateHandler = updateHandler; + this.zookeeperConfig = new ZookeeperConfig(environment); + this.environment = environment; + } + + public void refreshZookeeperConfig() throws Exception { + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperConfig.getConnectString()) + .sessionTimeoutMs(zookeeperConfig.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperConfig.getAuthSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperConfig.getAuthInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperConfig.getAuthInfo().split(":"); + Configuration.setConfiguration(new ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + CuratorFramework client = builder.build(); + client.start(); + + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ZookeeperConfig.ZOOKEEPER_DEFAULT_ENVIRONMENT; + } + addEnvironmentConfig(env, client); + addApplicationConfig(env, client); + addServiceConfig(env, client); + addVersionConfig(env, client); + addTagConfig(env, client); + + refreshConfigItems(); + } + + private void addTagConfig(String env, CuratorFramework client) throws Exception { + if (StringUtils.isEmpty(zookeeperConfig.getInstanceTag())) { + return; + } + String path = String.format(PATH_TAG, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment), + zookeeperConfig.getInstanceTag()); + CuratorCache cache = CuratorCache.builder(client, path).build(); + cache.listenable().addListener((type, oldData, newData) -> { + try { + this.tagData = parseData(client, path); + refreshConfigItems(); + } catch (Exception e) { + LOGGER.error("process event failed", e); + } + }); + cache.start(); + this.tagData = parseData(client, path); + } + + private void addVersionConfig(String env, CuratorFramework client) throws Exception { + String path = String.format(PATH_VERSION, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment), + BootStrapProperties.readServiceVersion(environment)); + CuratorCache cache = CuratorCache.builder(client, path).build(); + cache.listenable().addListener((type, oldData, newData) -> { + try { + this.versionData = parseData(client, path); + refreshConfigItems(); + } catch (Exception e) { + LOGGER.error("process event failed", e); + } + }); + cache.start(); + this.versionData = parseData(client, path); + } + + private void addServiceConfig(String env, CuratorFramework client) throws Exception { + String path = String.format(PATH_SERVICE, env, + BootStrapProperties.readApplication(environment), + BootStrapProperties.readServiceName(environment)); + CuratorCache cache = CuratorCache.builder(client, path).build(); + cache.listenable().addListener((type, oldData, newData) -> { + try { + this.serviceData = parseData(client, path); + refreshConfigItems(); + } catch (Exception e) { + LOGGER.error("process event failed", e); + } + }); + cache.start(); + this.serviceData = parseData(client, path); + } + + private void addApplicationConfig(String env, CuratorFramework client) throws Exception { + String path = String.format(PATH_APPLICATION, env, BootStrapProperties.readApplication(environment)); + CuratorCache cache = CuratorCache.builder(client, path).build(); + cache.listenable().addListener((type, oldData, newData) -> { + try { + this.applicationData = parseData(client, path); + refreshConfigItems(); + } catch (Exception e) { + LOGGER.error("process event failed", e); + } + }); + cache.start(); + this.applicationData = parseData(client, path); + } + + private void addEnvironmentConfig(String env, CuratorFramework client) throws Exception { + String path = String.format(PATH_ENVIRONMENT, env); + CuratorCache cache = CuratorCache.builder(client, path).build(); + cache.listenable().addListener((type, oldData, newData) -> { + try { + this.environmentData = parseData(client, path); + refreshConfigItems(); + } catch (Exception e) { + LOGGER.error("process event failed", e); + } + }); + cache.start(); + this.environmentData = parseData(client, path); + } + + private Map parseData(CuratorFramework client, String path) throws Exception { + Map values = new HashMap<>(); + + if (client.checkExists().forPath(path) != null) { + client.getChildren().forPath(path).stream().sorted().forEach(item -> { + try { + byte[] data = client.getData().forPath(path + "/" + item); + if (item.endsWith(".yaml") || item.endsWith(".yml")) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(data)); + values.putAll(toMap(yamlFactory.getObject())); + } else if (item.endsWith(".properties")) { + Properties properties = new Properties(); + properties.load(new StringReader(new String(data, StandardCharsets.UTF_8))); + values.putAll(toMap(properties)); + } else { + values.put(item, new String(data, StandardCharsets.UTF_8)); + } + } catch (Exception e) { + LOGGER.error("", e); + } + }); + } + + return values; + } + + private void refreshConfigItems() { + synchronized (lock) { + Map all = new HashMap<>(); + all.putAll(environmentData); + all.putAll(applicationData); + all.putAll(serviceData); + all.putAll(versionData); + all.putAll(tagData); + updateHandler.handle(all, allLast); + this.allLast = all; + } + } + + @SuppressWarnings("unchecked") + private Map toMap(Properties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + result.put(key, value); + } + return result; + } +} diff --git a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java new file mode 100644 index 00000000000..307ef7f0d55 --- /dev/null +++ b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.zookeeper; + +import org.springframework.core.env.Environment; + +public class ZookeeperConfig { + public static final String ZOOKEEPER_DEFAULT_ENVIRONMENT = "production"; + + public static final String PROPERTY_CONNECT_STRING = "servicecomb.config.zk.connect-string"; + + public static final String PROPERTY_SESSION_TIMEOUT = "servicecomb.config.zk.session-timeout-millis"; + + public static final String PROPERTY_CONNECTION_TIMEOUT = "servicecomb.config.zk.connection-timeout-mills"; + + public static final String PROPERTY_AUTH_SCHEMA = "servicecomb.config.zk.authentication-schema"; + + public static final String PROPERTY_AUTH_INFO = "servicecomb.config.zk.authentication-info"; + + public static final String PROPERTY_INSTANCE_TAG = "servicecomb.config.zk.instance-tag"; + + private final Environment environment; + + public ZookeeperConfig(Environment environment) { + this.environment = environment; + } + + public String getConnectString() { + return environment.getProperty(PROPERTY_CONNECT_STRING, "127.0.0.1:2181"); + } + + public int getSessionTimeoutMillis() { + return environment.getProperty(PROPERTY_SESSION_TIMEOUT, int.class, 60000); + } + + public int getConnectionTimeoutMillis() { + return environment.getProperty(PROPERTY_CONNECTION_TIMEOUT, int.class, 1000); + } + + public String getAuthSchema() { + return environment.getProperty(PROPERTY_AUTH_SCHEMA); + } + + public String getAuthInfo() { + return environment.getProperty(PROPERTY_AUTH_INFO); + } + + public String getInstanceTag() { + return environment.getProperty(PROPERTY_INSTANCE_TAG); + } +} diff --git a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperDynamicPropertiesSource.java b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperDynamicPropertiesSource.java new file mode 100644 index 00000000000..a971ea5845f --- /dev/null +++ b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperDynamicPropertiesSource.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.zookeeper; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.DynamicPropertiesSource; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +public class ZookeeperDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "zookeeper"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperDynamicPropertiesSource.class); + + private final Map valueCache = new ConcurrentHashMap<>(); + + public ZookeeperDynamicPropertiesSource() { + } + + private final UpdateHandler updateHandler = new UpdateHandler(); + + private void init(Environment environment) { + ZookeeperClient zookeeperClient = new ZookeeperClient(updateHandler, environment); + try { + zookeeperClient.refreshZookeeperConfig(); + } catch (Exception e) { + throw new IllegalStateException("Set up zookeeper config failed.", e); + } + } + + public class UpdateHandler { + public void handle(Map current, Map last) { + ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(current, last); + LOGGER.info("Dynamic configuration changed: {}", event.getChanged()); + valueCache.putAll(event.getAdded()); + valueCache.putAll(event.getUpdated()); + event.getDeleted().forEach((k, v) -> valueCache.remove(k)); + EventManager.post(event); + } + } + + @Override + public PropertySource create(Environment environment) { + init(environment); + return new MapPropertySource(SOURCE_NAME, valueCache); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/dynamic-config/config-zookeeper/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/dynamic-config/config-zookeeper/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..7b3b32c721d --- /dev/null +++ b/dynamic-config/config-zookeeper/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.zookeeper.ZookeeperDynamicPropertiesSource diff --git a/dynamic-config/pom.xml b/dynamic-config/pom.xml index 5eb2a3ac050..d5777cd654c 100644 --- a/dynamic-config/pom.xml +++ b/dynamic-config/pom.xml @@ -23,8 +23,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default 4.0.0 @@ -34,6 +34,11 @@ config-apollo config-cc + config-nacos + config-kie + config-zookeeper + config-etcd + config-consul diff --git a/edge/edge-core/pom.xml b/edge/edge-core/pom.xml index 1c73a92e9d8..0a75f8e33c6 100644 --- a/edge/edge-core/pom.xml +++ b/edge/edge-core/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb edge - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT edge-core Java Chassis::Edge::Core @@ -31,7 +31,10 @@ org.apache.servicecomb transport-rest-vertx - + + org.apache.servicecomb + handler-loadbalance + io.vertx vertx-codegen @@ -39,13 +42,13 @@ - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test @@ -58,5 +61,10 @@ swagger-generator-jaxrs test + + org.mockito + mockito-inline + test + diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/AbstractEdgeDispatcher.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/AbstractEdgeDispatcher.java index 5c7ad05f780..c29c066b800 100644 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/AbstractEdgeDispatcher.java +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/AbstractEdgeDispatcher.java @@ -17,13 +17,17 @@ package org.apache.servicecomb.edge.core; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.apache.servicecomb.transport.rest.vertx.AbstractVertxHttpDispatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; + import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; @@ -33,11 +37,28 @@ public abstract class AbstractEdgeDispatcher extends AbstractVertxHttpDispatcher protected void onFailure(RoutingContext context) { LOGGER.error("edge server failed.", context.failure()); HttpServerResponse response = context.response(); + if (response.closed() || response.ended()) { + return; + } + if (context.failure() instanceof InvocationException) { InvocationException exception = (InvocationException) context.failure(); response.setStatusCode(exception.getStatusCode()); - response.setStatusMessage(exception.getErrorData().toString()); - response.end(); + response.setStatusMessage(exception.getReasonPhrase()); + if (null == exception.getErrorData()) { + response.end(); + return; + } + + String responseBody; + try { + responseBody = RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(exception.getErrorData()); + response.putHeader("Content-Type", MediaType.APPLICATION_JSON); + } catch (JsonProcessingException e) { + responseBody = exception.getErrorData().toString(); + response.putHeader("Content-Type", MediaType.TEXT_PLAIN); + } + response.end(responseBody); } else { response.setStatusCode(Status.BAD_GATEWAY.getStatusCode()); response.setStatusMessage(Status.BAD_GATEWAY.getReasonPhrase()); diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CommonHttpEdgeDispatcher.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CommonHttpEdgeDispatcher.java new file mode 100644 index 00000000000..0f7e59bb0d2 --- /dev/null +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CommonHttpEdgeDispatcher.java @@ -0,0 +1,249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.edge.core; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationItem; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationLoader; +import org.apache.servicecomb.common.rest.route.Utils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.apache.servicecomb.loadbalance.ExtensionsManager; +import org.apache.servicecomb.loadbalance.LoadBalanceFilter; +import org.apache.servicecomb.loadbalance.LoadBalancer; +import org.apache.servicecomb.loadbalance.RuleExt; +import org.apache.servicecomb.loadbalance.ServiceCombServer; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.transport.rest.client.Http2TransportHttpClientOptionsSPI; +import org.apache.servicecomb.transport.rest.client.HttpTransportHttpClientOptionsSPI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.Subscribe; + +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.RequestOptions; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; + +/** + * This dispatcher forwards requests to any http servers, includes java-chassis providers and other, + * provided the server is registered to service center. + * + * This dispatcher using loadbalance handler to choose the target server. So any functions + * provided by loadbalancer handler is available, excluding retrying. + */ +public class CommonHttpEdgeDispatcher extends AbstractEdgeDispatcher { + private static final Logger LOG = LoggerFactory.getLogger(CommonHttpEdgeDispatcher.class); + + private static final String KEY_ENABLED = "servicecomb.http.dispatcher.edge.http.enabled"; + + private static final String KEY_ORDER = "servicecomb.http.dispatcher.edge.http.order"; + + private static final String KEY_PATTERN = "servicecomb.http.dispatcher.edge.http.pattern"; + + private static final String PATTERN_ANY = "/(.*)"; + + private static final String KEY_MAPPING_PREFIX = "servicecomb.http.dispatcher.edge.http.mappings"; + + private final Map loadBalancerMap = new ConcurrentHashMapEx<>(); + + private Map configurations = new HashMap<>(); + + private Environment environment; + + public CommonHttpEdgeDispatcher() { + + } + + // though this is an SPI, but add as beans. + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + if (this.enabled()) { + loadConfigurations(); + } + } + + // Maybe future change to beans + protected DiscoveryTree getDiscoveryTree() { + return BeanUtils.getBean(DiscoveryTree.class); + } + + // Maybe future change to beans + protected Environment getEnvironment() { + return BeanUtils.getBean(Environment.class); + } + + // Maybe future change to beans + protected ExtensionsManager getExtensionsManager() { + return BeanUtils.getBean(ExtensionsManager.class); + } + + @Override + public int getOrder() { + return LegacyPropertyFactory.getIntProperty(KEY_ORDER, 40_000); + } + + @Override + public boolean enabled() { + return environment.getProperty(KEY_ENABLED, boolean.class, false); + } + + @Override + public void init(Router router) { + String pattern = environment.getProperty(KEY_PATTERN, PATTERN_ANY); + router.routeWithRegex(pattern).failureHandler(this::onFailure).handler(this::onRequest); + } + + private void loadConfigurations() { + configurations = URLMappedConfigurationLoader.loadConfigurations(environment, KEY_MAPPING_PREFIX); + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(KEY_MAPPING_PREFIX)) { + loadConfigurations(); + break; + } + } + } + + protected void onRequest(RoutingContext context) { + URLMappedConfigurationItem configurationItem = findConfigurationItem(context.request().uri()); + if (configurationItem == null) { + context.next(); + return; + } + + String uri = Utils.findActualPath(context.request().uri(), configurationItem.getPrefixSegmentCount()); + + Invocation invocation = new Invocation() { + @Override + public String getConfigTransportName() { + return "rest"; + } + + @Override + public String getMicroserviceName() { + return configurationItem.getMicroserviceName(); + } + }; + + LoadBalancer loadBalancer = getOrCreateLoadBalancer(invocation, configurationItem.getMicroserviceName() + ); + ServiceCombServer server = loadBalancer.chooseServer(invocation); + if (server == null) { + LOG.warn("no available server for service {}", configurationItem.getMicroserviceName()); + serverNotReadyResponse(context); + return; + } + + URIEndpointObject endpointObject = new URIEndpointObject(server.getEndpoint().getEndpoint()); + + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setHost(endpointObject.getHostOrIp()) + .setPort(endpointObject.getPort()) + .setSsl(endpointObject.isSslEnabled()) + .setMethod(context.request().method()) + .setURI(uri); + + HttpClient httpClient; + if (endpointObject.isHttp2Enabled()) { + httpClient = HttpClients.getClient(Http2TransportHttpClientOptionsSPI.CLIENT_NAME, false).getHttpClient(); + } else { + httpClient = HttpClients.getClient(HttpTransportHttpClientOptionsSPI.CLIENT_NAME, false).getHttpClient(); + } + + context.request().pause(); + + httpClient + .request(requestOptions).compose(httpClientRequest -> { + context.request().headers() + .forEach((header) -> httpClientRequest.headers().set(header.getKey(), header.getValue())); + + context.request().resume(); + context.request().handler(httpClientRequest::write); + context.request().endHandler((v) -> httpClientRequest.end()); + + return httpClientRequest.response().compose(httpClientResponse -> { + context.response().setStatusCode(httpClientResponse.statusCode()); + httpClientResponse.headers() + .forEach((header) -> context.response().headers().set(header.getKey(), header.getValue())); + httpClientResponse.handler(this.responseHandler(context)); + httpClientResponse.endHandler((v) -> context.response().end()); + return Future.succeededFuture(); + }); + }).onFailure(failure -> { + LOG.warn("send request to target {}:{} failed, cause {}", endpointObject.getHostOrIp(), endpointObject.getPort(), + failure.getMessage()); + serverNotReadyResponse(context); + }); + } + + private void serverNotReadyResponse(RoutingContext context) { + context.response().setStatusCode(503); + context.response().setStatusMessage("service not ready"); + context.response().end(); + } + + protected Handler responseHandler(RoutingContext routingContext) { + return data -> routingContext.response().write(data); + } + + protected LoadBalancer getOrCreateLoadBalancer(Invocation invocation, String microserviceName) { + DiscoveryContext context = new DiscoveryContext(); + context.setInputParameters(invocation); + VersionedCache serversVersionedCache = getDiscoveryTree().discovery(context, + BootStrapProperties.readApplication(environment), + microserviceName); + invocation.addLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST, serversVersionedCache.data()); + return loadBalancerMap + .computeIfAbsent(microserviceName, name -> createLoadBalancer(microserviceName)); + } + + private LoadBalancer createLoadBalancer(String microserviceName) { + RuleExt rule = getExtensionsManager().createLoadBalancerRule(microserviceName); + return new LoadBalancer(rule, microserviceName); + } + + private URLMappedConfigurationItem findConfigurationItem(String path) { + for (URLMappedConfigurationItem item : configurations.values()) { + if (item.getPattern().matcher(path).matches()) { + return item; + } + } + return null; + } +} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CompatiblePathVersionMapper.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CompatiblePathVersionMapper.java deleted file mode 100644 index fc032415687..00000000000 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/CompatiblePathVersionMapper.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import java.util.Map; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.serviceregistry.version.VersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleUtils; -import org.springframework.util.StringUtils; - -public class CompatiblePathVersionMapper { - // v1 -> 1.0.0-2.0.0 - // v2 -> 2.0.0-3.0.0 - private Map mapper = new ConcurrentHashMapEx<>(); - - public VersionRule getOrCreate(String pathVersion) { - return mapper.computeIfAbsent(pathVersion, pv -> { - return createVersionRule(pathVersion); - }); - } - - // v + number - protected VersionRule createVersionRule(String pathVersion) { - if (StringUtils.isEmpty(pathVersion) || Character.toUpperCase(pathVersion.charAt(0)) != 'V') { - throw new ServiceCombException( - String.format("pathVersion \"%s\" is invalid, format must be v+number or V+number.", pathVersion)); - } - - int number = 0; - try { - number = Integer.parseInt(pathVersion.substring(1)); - } catch (NumberFormatException e) { - throw new ServiceCombException( - String.format("pathVersion \"%s\" is invalid, format must be v+number or V+number.", pathVersion), e); - } - - if (number < 0 || number > Short.MAX_VALUE) { - throw new ServiceCombException( - String.format("pathVersion \"%s\" is invalid, version range is [0, %d].", pathVersion, Short.MAX_VALUE)); - } - - if (number == Short.MAX_VALUE) { - return VersionRuleUtils.getOrCreate(String.format("%d.0.0+", number)); - } - - return VersionRuleUtils.getOrCreate(String.format("%d.0.0-%d.0.0", number, number + 1)); - } -} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/DefaultEdgeDispatcher.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/DefaultEdgeDispatcher.java index 20ecb21ccc1..56108a8cf1a 100644 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/DefaultEdgeDispatcher.java +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/DefaultEdgeDispatcher.java @@ -17,71 +17,94 @@ package org.apache.servicecomb.edge.core; -import java.util.Map; - -import com.netflix.config.DynamicPropertyFactory; - +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.common.rest.route.Utils; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; +import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +import io.vertx.codegen.annotations.Nullable; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; /** * Provide an easy mapping dispatcher that starts with a common prefix pattern. */ public class DefaultEdgeDispatcher extends AbstractEdgeDispatcher { + private static final String KEY_ENABLED = "servicecomb.http.dispatcher.edge.default.enabled"; - private static final String KEY_PREFIX = "servicecomb.http.dispatcher.edge.default.prefix"; + private static final String KEY_ORDER = "servicecomb.http.dispatcher.edge.default.order"; - private static final String KEY_WITH_VERSION = "servicecomb.http.dispatcher.edge.default.withVersion"; + private static final String KEY_PREFIX = "servicecomb.http.dispatcher.edge.default.prefix"; private static final String KEY_PREFIX_SEGMENT_COUNT = "servicecomb.http.dispatcher.edge.default.prefixSegmentCount"; - private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); + public static final String MICROSERVICE_NAME = "param0"; - private String prefix; + private int prefixSegmentCount; - private boolean withVersion; + private Environment environment; - private int prefixSegmentCount; + // though this is an SPI, but add as beans. + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } @Override public int getOrder() { - return 20000; + // can not use environment, add as beans is later than instantiate SPI + return LegacyPropertyFactory.getIntProperty(KEY_ORDER, 20_000); } @Override public boolean enabled() { - return DynamicPropertyFactory.getInstance().getBooleanProperty(KEY_ENABLED, false).get(); + return environment.getProperty(KEY_ENABLED, boolean.class, false); } @Override public void init(Router router) { - prefix = DynamicPropertyFactory.getInstance().getStringProperty(KEY_PREFIX, "api").get(); - withVersion = DynamicPropertyFactory.getInstance().getBooleanProperty(KEY_WITH_VERSION, true).get(); - prefixSegmentCount = DynamicPropertyFactory.getInstance().getIntProperty(KEY_PREFIX_SEGMENT_COUNT, 1).get(); - String regex; - if (withVersion) { - regex = "/" + prefix + "/([^\\\\/]+)/([^\\\\/]+)/(.*)"; - } else { - regex = "/" + prefix + "/([^\\\\/]+)/(.*)"; - } - router.routeWithRegex(regex).handler(CookieHandler.create()); + String prefix = environment.getProperty(KEY_PREFIX, "api"); + prefixSegmentCount = environment.getProperty(KEY_PREFIX_SEGMENT_COUNT, int.class, 1); + String regex = generateRouteRegex(prefix, false); + + // cookies handler are enabled by default start from 3.8.3 router.routeWithRegex(regex).handler(createBodyHandler()); router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); } + @VisibleForTesting + String generateRouteRegex(String prefix, boolean withVersion) { + String version = withVersion ? "/([^\\\\/]+)" : ""; + return String.format("/%s/([^\\\\/]+)%s/(.*)", prefix, version); + } + protected void onRequest(RoutingContext context) { - Map pathParams = context.pathParams(); - String microserviceName = pathParams.get("param0"); + String microserviceName = extractMicroserviceName(context); String path = Utils.findActualPath(context.request().path(), prefixSegmentCount); - EdgeInvocation edgeInvocation = new EdgeInvocation(); - if (withVersion) { - String pathVersion = pathParams.get("param1"); - edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); - } - edgeInvocation.init(microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); + requestByFilter(context, microserviceName, path); + } + + @Nullable + private String extractMicroserviceName(RoutingContext context) { + return context.pathParam(MICROSERVICE_NAME); + } + + protected void requestByFilter(RoutingContext context, String microserviceName, String path) { + HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); + HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); + InvocationCreator creator = new EdgeInvocationCreator(context, requestEx, responseEx, + microserviceName, path); + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } } diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderFilter.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderFilter.java new file mode 100644 index 00000000000..92594e6157a --- /dev/null +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeAddHeaderFilter.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.edge.core; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.transport.rest.client.RestClientTransportContext; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.Subscribe; + +public class EdgeAddHeaderFilter extends AbstractFilter implements EdgeFilter { + public static final String NAME = "edge-add-headers"; + + private static final String PREFIX = "servicecomb.edge.filter.addHeader"; + + private static final String KEY_HEADERS = PREFIX + ".allowedHeaders"; + + private final Environment environment; + + private List publicHeaders = new ArrayList<>(); + + public EdgeAddHeaderFilter(Environment environment) { + this.environment = environment; + init(); + EventManager.register(this); + } + + @Subscribe + @SuppressWarnings("unused") + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(PREFIX)) { + init(); + break; + } + } + } + + private void init() { + String publicHeaderStr = environment.getProperty(KEY_HEADERS); + if (StringUtils.isEmpty(publicHeaderStr)) { + return; + } + publicHeaders = Arrays.asList(publicHeaderStr.split(",")); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.RESTFUL.equals(transport); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1995; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (publicHeaders.isEmpty()) { + return nextNode.onFilter(invocation); + } + + RestClientTransportContext transportContext = invocation.getTransportContext(); + HttpServletRequestEx oldRequest = invocation.getRequestEx(); + publicHeaders.forEach(key -> { + String value = oldRequest.getHeader(key); + if (StringUtils.isNotEmpty(value)) { + transportContext.getHttpClientRequest().putHeader(key, value); + } + }); + + return nextNode.onFilter(invocation); + } +} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeBootListener.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeBootListener.java index 55ee39261ad..144dc2c6224 100644 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeBootListener.java +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeBootListener.java @@ -17,41 +17,18 @@ package org.apache.servicecomb.edge.core; -import org.apache.commons.configuration.Configuration; import org.apache.servicecomb.core.BootListener; import org.apache.servicecomb.core.executor.ExecutorManager; -import org.apache.servicecomb.transport.rest.client.TransportClientConfig; import org.apache.servicecomb.transport.rest.vertx.TransportConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import com.netflix.config.DynamicPropertyFactory; - -@Component public class EdgeBootListener implements BootListener { - private static final Logger LOGGER = LoggerFactory.getLogger(EdgeBootListener.class); - @Override public void onBootEvent(BootEvent event) { if (!EventType.BEFORE_PRODUCER_PROVIDER.equals(event.getEventType())) { return; } - TransportClientConfig.setRestTransportClientCls(EdgeRestTransportClient.class); TransportConfig.setRestServerVerticle(EdgeRestServerVerticle.class); - - String defaultExecutor = DynamicPropertyFactory.getInstance() - .getStringProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, null) - .get(); - if (defaultExecutor != null) { - LOGGER.info("Edge service default executor is {}.", defaultExecutor); - return; - } - - // change default to reactive mode - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.setProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, ExecutorManager.EXECUTOR_REACTIVE); - LOGGER.info("Set ReactiveExecutor to be edge service default executor."); + ExecutorManager.setExecutorDefault(ExecutorManager.EXECUTOR_REACTIVE); } } diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeCoreConfiguration.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeCoreConfiguration.java new file mode 100644 index 00000000000..6fa0457c7fc --- /dev/null +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeCoreConfiguration.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.edge.core; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class EdgeCoreConfiguration { + @Bean + public EdgeBootListener scbEdgeBootListener() { + return new EdgeBootListener(); + } + + @Bean + public EdgeAddHeaderFilter scbEdgeAddHeaderFilter(Environment environment) { + return new EdgeAddHeaderFilter(environment); + } +} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocation.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocation.java deleted file mode 100644 index fb885a5daeb..00000000000 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocation.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import java.util.List; - -import org.apache.servicecomb.common.rest.AbstractRestInvocation; -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.provider.consumer.ReactiveResponseExecutor; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; -import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; - -import io.vertx.core.Vertx; -import io.vertx.ext.web.RoutingContext; - -public class EdgeInvocation extends AbstractRestInvocation { - public static final String EDGE_INVOCATION_CONTEXT = "edgeInvocationContext"; - - protected String microserviceName; - - protected MicroserviceVersionRule microserviceVersionRule; - - protected MicroserviceVersionMeta latestMicroserviceVersionMeta; - - protected ReferenceConfig referenceConfig; - - protected String versionRule = DefinitionConst.VERSION_RULE_ALL; - - protected RoutingContext routingContext; - - public void init(String microserviceName, RoutingContext context, String path, - List httpServerFilters) { - this.microserviceName = microserviceName; - this.requestEx = new VertxServerRequestToHttpServletRequest(context, path); - this.responseEx = new VertxServerResponseToHttpServletResponse(context.response()); - this.routingContext = context; - this.httpServerFilters = httpServerFilters; - requestEx.setAttribute(RestConst.REST_REQUEST, requestEx); - } - - public void edgeInvoke() { - findMicroserviceVersionMeta(); - findRestOperation(latestMicroserviceVersionMeta.getMicroserviceMeta()); - - scheduleInvocation(); - } - - protected void findMicroserviceVersionMeta() { - String versionRule = chooseVersionRule(); - - String appId = RegistryUtils.getAppId(); - int idxAt = microserviceName.indexOf(org.apache.servicecomb.serviceregistry.api.Const.APP_SERVICE_SEPARATOR); - if (idxAt != -1) { - appId = microserviceName.substring(0, idxAt); - } - - microserviceVersionRule = RegistryUtils.getServiceRegistry() - .getAppManager() - .getOrCreateMicroserviceVersionRule(appId, microserviceName, versionRule); - latestMicroserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - - if (latestMicroserviceVersionMeta == null) { - throw new ServiceCombException( - String.format("Failed to find latest MicroserviceVersionMeta, appId=%s, microserviceName=%s, versionRule=%s.", - appId, - microserviceName, - versionRule)); - } - } - - public void setVersionRule(String versionRule) { - this.versionRule = versionRule; - } - - // another possible rule: - // path is: /msName/version/..... - // version in path is v1 or v2 and so on - // map version to VersionRule: - // v1->1.0.0-2.0.0 - // v2->2.0.0-3.0.0 - // that means if a(1.x.x) bigger then b(1.y.y), then a compatible to b - // but a(2.x.x) not compatible to b - protected String chooseVersionRule() { - // this will use all instance of the microservice - // and this required all new version compatible to old version - return versionRule; - } - - @Override - protected OperationLocator locateOperation(ServicePathManager servicePathManager) { - return servicePathManager.consumerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod()); - } - - @Override - protected void createInvocation() { - ReferenceConfig referenceConfig = new ReferenceConfig(); - referenceConfig.setMicroserviceVersionRule(microserviceVersionRule); - referenceConfig.setTransport(Const.ANY_TRANSPORT); - - this.invocation = InvocationFactory.forConsumer(referenceConfig, - restOperationMeta.getOperationMeta(), - null); - this.invocation.setSync(false); - this.invocation.setEdge(true); - this.invocation.getHandlerContext().put(EDGE_INVOCATION_CONTEXT, Vertx.currentContext()); - this.invocation.setResponseExecutor(new ReactiveResponseExecutor()); - this.routingContext.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - } -} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocationCreator.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocationCreator.java new file mode 100644 index 00000000000..309548a5b38 --- /dev/null +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeInvocationCreator.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.edge.core; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.common.rest.RestVertxProducerInvocationCreator; +import org.apache.servicecomb.common.rest.locator.OperationLocator; +import org.apache.servicecomb.common.rest.locator.ServicePathManager; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; + +import io.vertx.core.Vertx; +import io.vertx.ext.web.RoutingContext; + +public class EdgeInvocationCreator extends RestVertxProducerInvocationCreator { + public static final String EDGE_INVOCATION_CONTEXT = "edgeInvocationContext"; + + protected final String microserviceName; + + protected final String path; + + protected MicroserviceReferenceConfig microserviceReferenceConfig; + + public EdgeInvocationCreator(RoutingContext routingContext, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, + String microserviceName, String path) { + // Set endpoint before load balance because edge service will use RESTFUL transport filters. + super(routingContext, null, + SCBEngine.getInstance().getTransportManager().findTransport(CoreConst.RESTFUL).getEndpoint(), + requestEx, responseEx); + + this.microserviceName = microserviceName; + this.path = path; + } + + @Override + public CompletableFuture createAsync() { + return createMicroserviceReferenceConfig() + .thenCompose(v -> super.createAsync()); + } + + protected CompletableFuture createMicroserviceReferenceConfig() { + return SCBEngine.getInstance() + .getOrCreateReferenceConfigAsync(microserviceName) + .thenAccept(mrc -> { + this.microserviceReferenceConfig = mrc; + this.microserviceMeta = mrc.getMicroserviceMeta(); + }); + } + + @Override + protected OperationLocator locateOperation(ServicePathManager servicePathManager) { + return servicePathManager.consumerLocateOperation(path, requestEx.getMethod()); + } + + @Override + protected Invocation createInstance() { + ReferenceConfig referenceConfig = microserviceReferenceConfig + .createReferenceConfig(restOperationMeta.getOperationMeta()); + + Invocation invocation = InvocationFactory.forConsumer(referenceConfig, + restOperationMeta.getOperationMeta(), + restOperationMeta.getOperationMeta().buildBaseConsumerRuntimeType(), + null); + invocation.setSync(false); + invocation.setEdge(); + invocation.setEndpoint(endpoint); // ensure transport name is correct + invocation.addLocalContext(EDGE_INVOCATION_CONTEXT, Vertx.currentContext()); + + return invocation; + } +} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestServerVerticle.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestServerVerticle.java index a7d7529aa32..5135bf5d4fb 100644 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestServerVerticle.java +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestServerVerticle.java @@ -16,15 +16,11 @@ */ package org.apache.servicecomb.edge.core; -import org.apache.servicecomb.transport.rest.client.RestTransportClient; import org.apache.servicecomb.transport.rest.vertx.RestServerVerticle; public class EdgeRestServerVerticle extends RestServerVerticle { @Override public void start() throws Exception { super.start(); - - RestTransportClient restClient = (RestTransportClient) config().getValue(RestTransportClient.class.getName()); - restClient.getClientMgr().findClientPool(false, context); } } diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestTransportClient.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestTransportClient.java deleted file mode 100644 index bfac38676dc..00000000000 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/EdgeRestTransportClient.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.edge.core; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.transport.rest.client.RestTransportClient; - -import io.vertx.core.Context; - -public class EdgeRestTransportClient extends RestTransportClient { - @Override - protected HttpClientWithContext findHttpClientPool(Invocation invocation) { - Context invocationContext = (Context) invocation.getHandlerContext().get(EdgeInvocation.EDGE_INVOCATION_CONTEXT); - return clientMgr.findClientPool(invocation.isSync(), invocationContext); - } -} diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/URLMappedEdgeDispatcher.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/URLMappedEdgeDispatcher.java index f8c16950150..d4e456c098f 100644 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/URLMappedEdgeDispatcher.java +++ b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/URLMappedEdgeDispatcher.java @@ -18,150 +18,143 @@ package org.apache.servicecomb.edge.core; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.regex.Pattern; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.DynamicPropertyFactory; +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationItem; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationLoader; +import org.apache.servicecomb.common.rest.route.Utils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; +import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse; +import org.apache.servicecomb.transport.rest.vertx.RestBodyHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.Subscribe; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; +import io.vertx.ext.web.handler.PlatformHandler; /** * Provide a URL mapping based dispatcher. Users configure witch URL patterns dispatch to a target service. */ public class URLMappedEdgeDispatcher extends AbstractEdgeDispatcher { - class ConfigurationItem { - String microserviceName; - - String versionRule; - - int prefixSegmentCount; - - Pattern pattern; - - String stringPattern; - } - - private static final Logger LOG = LoggerFactory.getLogger(URLMappedEdgeDispatcher.class); + public static final String CONFIGURATION_ITEM = "URLMappedConfigurationItem"; private static final String PATTERN_ANY = "/(.*)"; - private static final String KEY_ENABLED = "servicecomb.http.dispatcher.edge.url.enabled"; - - private static final String KEY_MAPPING_PREIX = "servicecomb.http.dispatcher.edge.url.mappings"; + private static final String KEY_ORDER = "servicecomb.http.dispatcher.edge.url.order"; - private static final String KEY_MAPPING_PATH = ".path"; + private static final String KEY_ENABLED = "servicecomb.http.dispatcher.edge.url.enabled"; - private static final String KEY_MAPPING_SERVICE_NAME = "servicecomb.http.dispatcher.edge.url.mappings.%s.microserviceName"; + private static final String KEY_PATTERN = "servicecomb.http.dispatcher.edge.url.pattern"; - private static final String KEY_MAPPING_VERSION_RULE = "servicecomb.http.dispatcher.edge.url.mappings.%s.versionRule"; + private static final String KEY_MAPPING_PREFIX = "servicecomb.http.dispatcher.edge.url.mappings"; - private static final String KEY_MAPPING_PREFIX_SEGMENT_COUNT = "servicecomb.http.dispatcher.edge.url.mappings.%s.prefixSegmentCount"; + private Map configurations = new HashMap<>(); - private Map configurations = new HashMap<>(); + private Environment environment; public URLMappedEdgeDispatcher() { - if(this.enabled()) { + EventManager.register(this); + } + + // though this is an SPI, but add as beans. + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + if (this.enabled()) { loadConfigurations(); } } + @VisibleForTesting + public Map getConfigurations() { + return configurations; + } + @Override public int getOrder() { - return 30000; + return LegacyPropertyFactory.getIntProperty(KEY_ORDER, 30_000); } @Override public boolean enabled() { - return DynamicPropertyFactory.getInstance().getBooleanProperty(KEY_ENABLED, false).get(); + return environment.getProperty(KEY_ENABLED, boolean.class, false); } @Override public void init(Router router) { - router.routeWithRegex(PATTERN_ANY).handler(CookieHandler.create()); - router.routeWithRegex(PATTERN_ANY).handler(createBodyHandler()); - router.routeWithRegex(PATTERN_ANY).failureHandler(this::onFailure).handler(this::onRequest); + // cookies handler are enabled by default start from 3.8.3 + String pattern = environment.getProperty(KEY_PATTERN, PATTERN_ANY); + router.routeWithRegex(pattern).failureHandler(this::onFailure) + .handler((PlatformHandler) URLMappedEdgeDispatcher.this::preCheck) + .handler(createBodyHandler()) + .handler(this::onRequest); } private void loadConfigurations() { - ConcurrentCompositeConfiguration config = (ConcurrentCompositeConfiguration) DynamicPropertyFactory - .getBackingConfigurationSource(); - loadConfigurations(config); - config.addConfigurationListener(event -> { - if (event.getPropertyName().startsWith(KEY_MAPPING_PREIX)) { - LOG.info("Map rule have been changed. Reload configurations. Event=" + event.getType()); - loadConfigurations(config); - } - }); + configurations = URLMappedConfigurationLoader.loadConfigurations(environment, KEY_MAPPING_PREFIX); } - private void loadConfigurations(ConcurrentCompositeConfiguration config) { - Map configurations = new HashMap<>(); - Iterator configsItems = config.getKeys(KEY_MAPPING_PREIX); - while (configsItems.hasNext()) { - String pathKey = configsItems.next(); - if (pathKey.endsWith(KEY_MAPPING_PATH)) { - ConfigurationItem configurationItem = new ConfigurationItem(); - String pattern = DynamicPropertyFactory.getInstance() - .getStringProperty(pathKey, null).get(); - if (StringUtils.isEmpty(pattern)) { - continue; - } - configurationItem.pattern = Pattern.compile(pattern); - configurationItem.stringPattern = pattern; - String pathKeyItem = pathKey - .substring(KEY_MAPPING_PREIX.length() + 1, pathKey.length() - KEY_MAPPING_PATH.length()); - configurationItem.microserviceName = DynamicPropertyFactory.getInstance() - .getStringProperty(String.format(KEY_MAPPING_SERVICE_NAME, pathKeyItem), null).get(); - if (StringUtils.isEmpty(configurationItem.microserviceName)) { - continue; - } - configurationItem.prefixSegmentCount = DynamicPropertyFactory.getInstance() - .getIntProperty(String.format(KEY_MAPPING_PREFIX_SEGMENT_COUNT, pathKeyItem), 0).get(); - configurationItem.versionRule = DynamicPropertyFactory.getInstance() - .getStringProperty(String.format(KEY_MAPPING_VERSION_RULE, pathKeyItem), "0.0.0+").get(); - configurations.put(pathKeyItem, configurationItem); + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(KEY_MAPPING_PREFIX)) { + loadConfigurations(); + break; } } - this.configurations = configurations; - logConfigurations(); } - private void logConfigurations() { - for (String key : this.configurations.keySet()) { - ConfigurationItem item = this.configurations.get(key); - LOG.info("config item: key=" + key + ";pattern=" + item.stringPattern + ";service=" + item.microserviceName - + ";versionRule=" + item.versionRule); + protected void preCheck(RoutingContext context) { + URLMappedConfigurationItem configurationItem = findConfigurationItem(context.request().path()); + if (configurationItem == null) { + // by pass body handler flag + context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.TRUE); + context.next(); + return; } + context.put(CONFIGURATION_ITEM, configurationItem); + context.next(); } protected void onRequest(RoutingContext context) { - ConfigurationItem configurationItem = findConfigurationItem(context.request().path()); - if (configurationItem == null) { + Boolean bypass = context.get(RestBodyHandler.BYPASS_BODY_HANDLER); + if (Boolean.TRUE.equals(bypass)) { + // clear flag + context.put(RestBodyHandler.BYPASS_BODY_HANDLER, Boolean.FALSE); context.next(); return; } - String path = Utils.findActualPath(context.request().path(), configurationItem.prefixSegmentCount); + URLMappedConfigurationItem configurationItem = context.get(CONFIGURATION_ITEM); - EdgeInvocation edgeInvocation = new EdgeInvocation(); - if (configurationItem.versionRule != null) { - edgeInvocation.setVersionRule(configurationItem.versionRule); - } - edgeInvocation.init(configurationItem.microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); + String path = Utils.findActualPath(context.request().path(), configurationItem.getPrefixSegmentCount()); + + requestByFilter(context, configurationItem, path); + } + + protected void requestByFilter(RoutingContext context, URLMappedConfigurationItem configurationItem, String path) { + HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); + HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); + InvocationCreator creator = new EdgeInvocationCreator(context, requestEx, responseEx, + configurationItem.getMicroserviceName(), path); + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } - private ConfigurationItem findConfigurationItem(String path) { - for (ConfigurationItem item : configurations.values()) { - if (item.pattern.matcher(path).matches()) { + private URLMappedConfigurationItem findConfigurationItem(String path) { + for (URLMappedConfigurationItem item : configurations.values()) { + if (item.getPattern().matcher(path).matches()) { return item; } } diff --git a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/Utils.java b/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/Utils.java deleted file mode 100644 index 9bbefb9f0d1..00000000000 --- a/edge/edge-core/src/main/java/org/apache/servicecomb/edge/core/Utils.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -/** - * Commonly used methods in this package. - */ -public final class Utils { - private Utils() { - - } - - /** - * Get the actual path without prefix - * @param path full path - * @param pathIndex the index of / that after prefix - * @return actual path - */ - public static String findActualPath(String path, int pathIndex) { - if (pathIndex <= 0) { - return path; - } - - int fromIndex = 0; - int counter = pathIndex; - char[] chars = path.toCharArray(); - for (int i = 0; i < chars.length; i++) { - if (chars[i] == '/') { - if (--counter < 0) { - fromIndex = i; - break; - } - } - } - return fromIndex > 0 ? path.substring(fromIndex) : ""; - } -} diff --git a/edge/edge-core/src/main/resources/META-INF/microservice.yaml b/edge/edge-core/src/main/resources/META-INF/microservice.yaml new file mode 100644 index 00000000000..a456c2868b2 --- /dev/null +++ b/edge/edge-core/src/main/resources/META-INF/microservice.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb-config-order: -500 + +servicecomb: + context: + # do not decode invocation context for edge service by default + decodeInvocationContext: false diff --git a/edge/edge-core/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/edge/edge-core/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher index d81bb22579c..6a672cefffd 100644 --- a/edge/edge-core/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher +++ b/edge/edge-core/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher @@ -16,4 +16,5 @@ # org.apache.servicecomb.edge.core.DefaultEdgeDispatcher -org.apache.servicecomb.edge.core.URLMappedEdgeDispatcher \ No newline at end of file +org.apache.servicecomb.edge.core.URLMappedEdgeDispatcher +org.apache.servicecomb.edge.core.CommonHttpEdgeDispatcher diff --git a/edge/edge-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/edge/edge-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..aa087dba015 --- /dev/null +++ b/edge/edge-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.edge.core.EdgeCoreConfiguration diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestAbstractEdgeDispatcher.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestAbstractEdgeDispatcher.java index b675045cb77..bbeceff2292 100644 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestAbstractEdgeDispatcher.java +++ b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestAbstractEdgeDispatcher.java @@ -17,23 +17,17 @@ package org.apache.servicecomb.edge.core; -import java.util.HashMap; -import java.util.Map; - +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestAbstractEdgeDispatcher { - class AbstractEdgeDispatcherForTest extends AbstractEdgeDispatcher { + static class AbstractEdgeDispatcherForTest extends AbstractEdgeDispatcher { @Override public int getOrder() { return 0; @@ -44,53 +38,26 @@ public void init(Router router) { } } - @Test - public void onFailure(@Mocked RoutingContext context) { - Map map = new HashMap<>(); - HttpServerResponse response = new MockUp() { - @Mock - HttpServerResponse setStatusCode(int statusCode) { - map.put("code", statusCode); - return null; - } + public void onFailure() { + RoutingContext context = Mockito.mock(RoutingContext.class); - @Mock - HttpServerResponse setStatusMessage(String statusMessage) { - map.put("msg", statusMessage); - return null; - } - }.getMockInstance(); + HttpServerResponse response = Mockito.mock(HttpServerResponse.class); - new Expectations() { - { - context.failure(); - returns(new Error("failed"), null); - context.response(); - result = response; - } - }; + Mockito.when(context.response()).thenReturn(response); + Mockito.when(context.failure()).thenReturn(new RuntimeExceptionWithoutStackTrace("failed")); AbstractEdgeDispatcherForTest dispatcher = new AbstractEdgeDispatcherForTest(); dispatcher.onFailure(context); - Assert.assertEquals(502, map.get("code")); - Assert.assertEquals("Bad Gateway", map.get("msg")); + Mockito.verify(response).setStatusMessage("Bad Gateway"); + Mockito.verify(response).setStatusCode(502); - new Expectations() { - { - context.failure(); - returns(new InvocationException(401, "unauthorized", "unauthorized"), - new InvocationException(401, "unauthorized", "unauthorized")); - context.response(); - result = response; - } - }; + Mockito.when(context.failure()).thenReturn(new InvocationException(401, "unauthorized", "unauthorized")); dispatcher = new AbstractEdgeDispatcherForTest(); dispatcher.onFailure(context); - - Assert.assertEquals(401, map.get("code")); - Assert.assertEquals("unauthorized", map.get("msg")); + Mockito.verify(response).setStatusMessage("unauthorized"); + Mockito.verify(response).setStatusCode(401); } } diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestCompatiblePathVersionMapper.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestCompatiblePathVersionMapper.java deleted file mode 100644 index 871c25d418b..00000000000 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestCompatiblePathVersionMapper.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.serviceregistry.version.VersionRule; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class TestCompatiblePathVersionMapper { - CompatiblePathVersionMapper mapper = new CompatiblePathVersionMapper(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void getOrCreate() { - VersionRule versionRule = mapper.getOrCreate("v1"); - - Assert.assertEquals("1.0.0.0-2.0.0.0", versionRule.getVersionRule()); - } - - @Test - public void createVersionRule_empty() { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is("pathVersion \"\" is invalid, format must be v+number or V+number.")); - - mapper.getOrCreate(""); - } - - @Test - public void createVersionRule_invalidFormat() { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is("pathVersion \"a1\" is invalid, format must be v+number or V+number.")); - - mapper.getOrCreate("a1"); - } - - @Test - public void createVersionRule_invalidNumber() { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is("pathVersion \"va\" is invalid, format must be v+number or V+number.")); - - mapper.getOrCreate("va"); - } - - @Test - public void createVersionRule_tooSmall() { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is("pathVersion \"v-1\" is invalid, version range is [0, 32767].")); - - mapper.getOrCreate("v-1"); - } - - @Test - public void createVersionRule_tooBig() { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is("pathVersion \"v32768\" is invalid, version range is [0, 32767].")); - - mapper.getOrCreate("v32768"); - } - - @Test - public void createVersionRule_32767() { - VersionRule versionRule = mapper.getOrCreate("v32767"); - - Assert.assertEquals("32767.0.0.0+", versionRule.getVersionRule()); - } -} diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestDefaultEdgeDispatcher.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestDefaultEdgeDispatcher.java deleted file mode 100644 index e74f13aed3d..00000000000 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestDefaultEdgeDispatcher.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.Handler; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.Route; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestDefaultEdgeDispatcher { - @Before - public void setUp() { - - } - - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - @SuppressWarnings("unchecked") - public void testOnRequest(@Mocked Router router, @Mocked Route route - , @Mocked RoutingContext context - , @Mocked HttpServerRequest requst - , @Mocked EdgeInvocation invocation) { - DefaultEdgeDispatcher dispatcher = new DefaultEdgeDispatcher(); - Map pathParams = new HashMap<>(); - pathParams.put("param0", "testService"); - pathParams.put("param1", "v1"); - - new Expectations() { - { - router.routeWithRegex("/api/([^\\\\/]+)/([^\\\\/]+)/(.*)"); - result = route; - route.handler((Handler) any); - result = route; - route.failureHandler((Handler) any); - result = route; - context.pathParams(); - result = pathParams; - context.request(); - result = requst; - requst.path(); - result = "/api/testService/v1/hello"; - invocation.setVersionRule("1.0.0.0-2.0.0.0"); - invocation.init("testService", context, "/testService/v1/hello", - Deencapsulation.getField(dispatcher, "httpServerFilters")); - invocation.edgeInvoke(); - } - }; - dispatcher.init(router); - Assert.assertEquals(dispatcher.enabled(), false); - Assert.assertEquals(Utils.findActualPath("/api/test", 1), "/test"); - Assert.assertEquals(dispatcher.getOrder(), 20000); - - dispatcher.onRequest(context); - // assert done in expectations. - } -} diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeBootListener.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeBootListener.java deleted file mode 100644 index 992aad06c70..00000000000 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeBootListener.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import org.apache.servicecomb.core.BootListener.BootEvent; -import org.apache.servicecomb.core.BootListener.EventType; -import org.apache.servicecomb.core.executor.ExecutorManager; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.netflix.config.DynamicPropertyFactory; - -public class TestEdgeBootListener { - EdgeBootListener listener = new EdgeBootListener(); - - BootEvent bootEvent = new BootEvent(); - - @Before - public void setup() { - ArchaiusUtils.resetConfig(); - } - - @After - public void teardown() { - ArchaiusUtils.resetConfig(); - System.clearProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT); - } - - @Test - public void onBootEvent_ignore() { - System.setProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, ExecutorManager.EXECUTOR_DEFAULT); - - bootEvent.setEventType(EventType.AFTER_CONSUMER_PROVIDER); - listener.onBootEvent(bootEvent); - - Assert.assertEquals(ExecutorManager.EXECUTOR_DEFAULT, - DynamicPropertyFactory.getInstance().getStringProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, null).get()); - } - - @Test - public void onBootEvent_accept_notChange() { - System.setProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, ExecutorManager.EXECUTOR_DEFAULT); - - bootEvent.setEventType(EventType.BEFORE_PRODUCER_PROVIDER); - listener.onBootEvent(bootEvent); - - Assert.assertEquals(ExecutorManager.EXECUTOR_DEFAULT, - DynamicPropertyFactory.getInstance().getStringProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, null).get()); - } - - @Test - public void onBootEvent_change() { - bootEvent.setEventType(EventType.BEFORE_PRODUCER_PROVIDER); - listener.onBootEvent(bootEvent); - - Assert.assertEquals(ExecutorManager.EXECUTOR_REACTIVE, - DynamicPropertyFactory.getInstance().getStringProperty(ExecutorManager.KEY_EXECUTORS_DEFAULT, null).get()); - } -} diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeInvocation.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeInvocation.java deleted file mode 100644 index 538e97900a2..00000000000 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestEdgeInvocation.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.edge.core; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.common.rest.locator.OperationLocator; -import org.apache.servicecomb.common.rest.locator.ServicePathManager; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.provider.consumer.ReactiveResponseExecutor; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import io.vertx.core.Context; -import io.vertx.core.impl.VertxImpl; -import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestEdgeInvocation { - String microserviceName = "ms"; - - @Mocked - RoutingContext routingContext; - - @Mocked - Context context; - - List httpServerFilters = Collections.emptyList(); - - MicroserviceMeta microserviceMeta = new MicroserviceMeta("app:ms"); - - MicroserviceVersionRule microserviceVersionRule = new MicroserviceVersionRule(microserviceMeta.getAppId(), - microserviceMeta.getName(), DefinitionConst.VERSION_RULE_LATEST); - - ReferenceConfig referenceConfig = new ReferenceConfig(); - - EdgeInvocation edgeInvocation = new EdgeInvocation(); - - HttpServletRequestEx requestEx; - - HttpServletResponseEx responseEx; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setup() { - new Expectations(VertxImpl.class) { - { - VertxImpl.context(); - result = context; - } - }; - - referenceConfig.setMicroserviceVersionRule(microserviceVersionRule); - referenceConfig.setTransport("rest"); - - edgeInvocation.init(microserviceName, routingContext, "/base", httpServerFilters); - - requestEx = Deencapsulation.getField(edgeInvocation, "requestEx"); - responseEx = Deencapsulation.getField(edgeInvocation, "responseEx"); - } - - @Test - public void edgeInvoke(@Mocked MicroserviceVersionMeta microserviceVersionMeta) { - new Expectations() { - { - microserviceVersionRule.getLatestMicroserviceVersion(); - result = microserviceVersionMeta; - microserviceVersionMeta.getMicroserviceMeta(); - result = microserviceMeta; - } - }; - - Map result = new LinkedHashMap<>(); - edgeInvocation = new EdgeInvocation() { - @Override - protected void findMicroserviceVersionMeta() { - result.put("findMicroserviceVersionMeta", true); - } - - @Override - protected void findRestOperation(MicroserviceMeta microserviceMeta) { - result.put("findRestOperation", true); - } - - @Override - protected void scheduleInvocation() { - result.put("scheduleInvocation", true); - } - }; - edgeInvocation.latestMicroserviceVersionMeta = microserviceVersionMeta; - - edgeInvocation.edgeInvoke(); - - Assert.assertTrue(result.get("findMicroserviceVersionMeta")); - Assert.assertTrue(result.get("findRestOperation")); - Assert.assertTrue(result.get("scheduleInvocation")); - } - - @Test - public void findMicroserviceVersionMetaNullLatestVersion(@Mocked AppManager appManager, - @Mocked MicroserviceVersionRule microserviceVersionRule, @Mocked ServiceRegistry serviceRegistry) { - String versionRule = DefinitionConst.VERSION_RULE_ALL; - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAppManager(); - result = appManager; - RegistryUtils.getAppId(); - result = "app"; - appManager.getOrCreateMicroserviceVersionRule("app", microserviceName, versionRule); - result = microserviceVersionRule; - microserviceVersionRule.getLatestMicroserviceVersion(); - result = null; - } - }; - - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers - .is("Failed to find latest MicroserviceVersionMeta, appId=app, microserviceName=ms, versionRule=0.0.0+.")); - - edgeInvocation.findMicroserviceVersionMeta(); - } - - @Test - public void findMicroserviceVersionMetaNormal(@Mocked AppManager appManager, - @Mocked MicroserviceVersionRule microserviceVersionRule, - @Mocked MicroserviceVersionMeta latestMicroserviceVersionMeta, - @Mocked ServiceRegistry serviceRegistry) { - String versionRule = DefinitionConst.VERSION_RULE_ALL; - microserviceName = "app:ms"; - edgeInvocation.microserviceName = microserviceName; - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAppManager(); - result = appManager; - RegistryUtils.getAppId(); - result = "app"; - appManager.getOrCreateMicroserviceVersionRule("app", microserviceName, versionRule); - result = microserviceVersionRule; - microserviceVersionRule.getLatestMicroserviceVersion(); - result = latestMicroserviceVersionMeta; - } - }; - - edgeInvocation.findMicroserviceVersionMeta(); - - Assert.assertSame(latestMicroserviceVersionMeta, edgeInvocation.latestMicroserviceVersionMeta); - } - - @Test - public void chooseVersionRule_default() { - Assert.assertEquals(DefinitionConst.VERSION_RULE_ALL, edgeInvocation.chooseVersionRule()); - } - - @Test - public void chooseVersionRule_set() { - String versionRule = "1.0.0"; - edgeInvocation.setVersionRule(versionRule); - - Assert.assertEquals(versionRule, edgeInvocation.chooseVersionRule()); - } - - @Test - public void locateOperation(@Mocked ServicePathManager servicePathManager, - @Mocked OperationLocator operationLocator) { - new Expectations() { - { - servicePathManager.consumerLocateOperation(anyString, anyString); - result = operationLocator; - } - }; - - Assert.assertSame(operationLocator, edgeInvocation.locateOperation(servicePathManager)); - } - - @Test - public void createInvocation(@Mocked MicroserviceVersionMeta microserviceVersionMeta, - @Mocked MicroserviceVersionRule microserviceVersionRule, @Mocked RestOperationMeta restOperationMeta, - @Mocked Microservice microservice) { - edgeInvocation.latestMicroserviceVersionMeta = microserviceVersionMeta; - edgeInvocation.microserviceVersionRule = microserviceVersionRule; - Deencapsulation.setField(edgeInvocation, "restOperationMeta", restOperationMeta); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getMicroservice(); - result = microservice; - } - }; - - edgeInvocation.createInvocation(); - Invocation invocation = Deencapsulation.getField(edgeInvocation, "invocation"); - Assert.assertThat(invocation.getResponseExecutor(), Matchers.instanceOf(ReactiveResponseExecutor.class)); - Assert.assertFalse(invocation.isSync()); - Assert.assertTrue(invocation.isEdge()); - Assert.assertSame(context, invocation.getHandlerContext().get(EdgeInvocation.EDGE_INVOCATION_CONTEXT)); - } - - @Test - public void testSetRoutingContext() { - Assert.assertSame(this.routingContext, edgeInvocation.routingContext); - } -} diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestURLMappedEdgeDispatcher.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestURLMappedEdgeDispatcher.java index 353051ce137..046adfaa3a2 100644 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestURLMappedEdgeDispatcher.java +++ b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestURLMappedEdgeDispatcher.java @@ -17,85 +17,104 @@ package org.apache.servicecomb.edge.core; +import java.util.HashMap; import java.util.Map; -import org.apache.servicecomb.edge.core.URLMappedEdgeDispatcher.ConfigurationItem; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationItem; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.transport.rest.vertx.RestBodyHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; -import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; public class TestURLMappedEdgeDispatcher { - @Before + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + + @BeforeEach public void setUp() throws Exception { - Log4jUtils.init(); } - @After + @AfterEach public void tearDown() { - ArchaiusUtils.resetConfig(); } @Test - public void testConfigurations(@Mocked RoutingContext context - , @Mocked HttpServerRequest requst - , @Mocked EdgeInvocation invocation) { - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.enabled", true); - + public void testConfigurations() { + EnumerablePropertySource propertySource = Mockito.mock(EnumerablePropertySource.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + }); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.enabled", boolean.class, false)) + .thenReturn(true); URLMappedEdgeDispatcher dispatcher = new URLMappedEdgeDispatcher(); - Map items = Deencapsulation - .getField(dispatcher, "configurations"); - Assert.assertEquals(items.size(), 0); + dispatcher.setEnvironment(environment); + Map items = dispatcher.getConfigurations(); + Assertions.assertEquals(items.size(), 0); - new Expectations() { - { - context.next(); - } - }; + RoutingContext context = Mockito.mock(RoutingContext.class); + Mockito.when(context.get(RestBodyHandler.BYPASS_BODY_HANDLER)).thenReturn(Boolean.TRUE); dispatcher.onRequest(context); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.path", "/a/b/c/.*"); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.microserviceName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.prefixSegmentCount", 2); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.versionRule", "2.0.0+"); - items = Deencapsulation.getField(dispatcher, "configurations"); - Assert.assertEquals(items.size(), 1); - ConfigurationItem item = items.get("service1"); - Assert.assertEquals(item.microserviceName, "serviceName"); - Assert.assertEquals(item.prefixSegmentCount, 2); - Assert.assertEquals(item.stringPattern, "/a/b/c/.*"); - Assert.assertEquals(item.versionRule, "2.0.0+"); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.http.dispatcher.edge.url.mappings.service1.path", + "servicecomb.http.dispatcher.edge.url.mappings.service1.microserviceName", + "servicecomb.http.dispatcher.edge.url.mappings.service1.prefixSegmentCount", + "servicecomb.http.dispatcher.edge.url.mappings.service1.versionRule" + }); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.path")) + .thenReturn("/a/b/c/.*"); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.microserviceName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.prefixSegmentCount", + int.class, 0)) + .thenReturn(2); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service1.versionRule", + "0.0.0+")) + .thenReturn("2.0.0+"); + Map latest = new HashMap<>(); + latest.put("servicecomb.http.dispatcher.edge.url.mappings.service1.path", "/a/b/c/.*"); + dispatcher.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service2.versionRule", "2.0.0+"); - ArchaiusUtils.setProperty("servicecomb.http.dispatcher.edge.url.mappings.service3.path", "/b/c/d/.*"); - items = Deencapsulation.getField(dispatcher, "configurations"); - Assert.assertEquals(items.size(), 1); - item = items.get("service1"); - Assert.assertEquals(item.microserviceName, "serviceName"); - Assert.assertEquals(item.prefixSegmentCount, 2); - Assert.assertEquals(item.stringPattern, "/a/b/c/.*"); - Assert.assertEquals(item.versionRule, "2.0.0+"); + items = dispatcher.getConfigurations(); + Assertions.assertEquals(items.size(), 1); + URLMappedConfigurationItem item = items.get("service1"); + Assertions.assertEquals(item.getMicroserviceName(), "serviceName"); + Assertions.assertEquals(item.getPrefixSegmentCount(), 2); + Assertions.assertEquals(item.getStringPattern(), "/a/b/c/.*"); + Assertions.assertEquals(item.getVersionRule(), "2.0.0+"); - new Expectations() { - { - context.request(); - result = requst; - requst.path(); - result = "/a/b/c/d/e"; - invocation.setVersionRule("2.0.0+"); - invocation.init("serviceName", context, "/c/d/e", - Deencapsulation.getField(dispatcher, "httpServerFilters")); - invocation.edgeInvoke(); - } - }; - dispatcher.onRequest(context); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.http.dispatcher.edge.url.mappings.service1.path", + "servicecomb.http.dispatcher.edge.url.mappings.service1.microserviceName", + "servicecomb.http.dispatcher.edge.url.mappings.service1.prefixSegmentCount", + "servicecomb.http.dispatcher.edge.url.mappings.service1.versionRule", + "servicecomb.http.dispatcher.edge.url.mappings.service2.versionRule", + "servicecomb.http.dispatcher.edge.url.mappings.service3.path" + }); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service2.versionRule")) + .thenReturn("2.0.0+"); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.edge.url.mappings.service3.path")) + .thenReturn("/b/c/d/.*"); + + latest = new HashMap<>(); + latest.put("servicecomb.http.dispatcher.edge.url.mappings.service3.path", "/a/b/c/.*"); + dispatcher.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); + + items = dispatcher.getConfigurations(); + Assertions.assertEquals(items.size(), 1); + item = items.get("service1"); + Assertions.assertEquals(item.getMicroserviceName(), "serviceName"); + Assertions.assertEquals(item.getPrefixSegmentCount(), 2); + Assertions.assertEquals(item.getStringPattern(), "/a/b/c/.*"); + Assertions.assertEquals(item.getVersionRule(), "2.0.0+"); } } diff --git a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestUtils.java b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestUtils.java index c92373fb35f..38e8fa837d5 100644 --- a/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestUtils.java +++ b/edge/edge-core/src/test/java/org/apache/servicecomb/edge/core/TestUtils.java @@ -17,17 +17,18 @@ package org.apache.servicecomb.edge.core; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.common.rest.route.Utils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestUtils { @Test - public void testUtisl() { - Assert.assertEquals(Utils.findActualPath("/a/b/c", -1), "/a/b/c"); - Assert.assertEquals(Utils.findActualPath("/a/b/c", 0), "/a/b/c"); - Assert.assertEquals(Utils.findActualPath("/a/b/c", 1), "/b/c"); - Assert.assertEquals(Utils.findActualPath("/a/b/c", 2), "/c"); - Assert.assertEquals(Utils.findActualPath("/a/b/c", 3), ""); - Assert.assertEquals(Utils.findActualPath("/a/b/c", 100), ""); + public void testUtils() { + Assertions.assertEquals("/a/b/c", Utils.findActualPath("/a/b/c", -1)); + Assertions.assertEquals("/a/b/c", Utils.findActualPath("/a/b/c", 0)); + Assertions.assertEquals("/b/c", Utils.findActualPath("/a/b/c", 1)); + Assertions.assertEquals("/c", Utils.findActualPath("/a/b/c", 2)); + Assertions.assertEquals("", Utils.findActualPath("/a/b/c", 3)); + Assertions.assertEquals("", Utils.findActualPath("/a/b/c", 100)); } } diff --git a/edge/pom.xml b/edge/pom.xml index 49d150075e9..e11f4e088b6 100644 --- a/edge/pom.xml +++ b/edge/pom.xml @@ -22,8 +22,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default edge Java Chassis::Edge diff --git a/etc/checkstyle-eclipse.xml b/etc/checkstyle-eclipse.xml deleted file mode 100644 index 956816ecd20..00000000000 --- a/etc/checkstyle-eclipse.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/etc/checkstyle-suppressions.xml b/etc/checkstyle-suppressions.xml deleted file mode 100644 index 802285ff829..00000000000 --- a/etc/checkstyle-suppressions.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/etc/checkstyle.xml b/etc/checkstyle.xml deleted file mode 100644 index 546932fe309..00000000000 --- a/etc/checkstyle.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/etc/findbugs-exclude.xml b/etc/findbugs-exclude.xml deleted file mode 100644 index 8bacf38dc84..00000000000 --- a/etc/findbugs-exclude.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/etc/releaseNotes.md b/etc/releaseNotes.md deleted file mode 100644 index ecc431c9e66..00000000000 --- a/etc/releaseNotes.md +++ /dev/null @@ -1,34 +0,0 @@ -## Release Notes - -## Apache ServiceComb Java-Chassis (Incubating) 1.0.0-m1 - -### Major improvements: - - - Java Chassis can now use Apollo as configuration center. Users can now -change configurations like load balancing policy and those changes will -come into effect on the fly. -See [here](http://servicecomb.apache.org/users/dynamic-config/) for more -details. - - - Metrics was re-factored. We now uses events for collecting invocation data -instead of Hystrix. This reduces the performance penalty of computing -metrics. -Metrics can now be fetched via '/metrics' using HTTP. -See [here](http://servicecomb.apache.org/users/metrics-in-1.0.0-m1/) for -more details. - -### Other Noticeable Changes: - -- The Java Chassis libraries are now under group "org.apache.servicecomb". -- We provide out of the box metrics support now. Prometheus is supported. -- Configuration center was re-factored and moved out from foundation. -Support for Apollo was added. -- Users can now use Object type for calling services. -- Users can now use Generics for calling services. -- Better integration with Spring MVC. -- Upgraded to zipkin2 internally, Java Chassis can now work with zipkin -server v1 and v2. -- We are in the process of supporting reactive programming. Pojo consumer -and provider now supports CompletableFuture. - -### For more detailed information please checkout [here](https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12321626&version=12342351) diff --git a/foundations/foundation-common/pom.xml b/foundations/foundation-common/pom.xml index 48925464b6c..2f5a18878b4 100644 --- a/foundations/foundation-common/pom.xml +++ b/foundations/foundation-common/pom.xml @@ -20,13 +20,17 @@ 4.0.0 org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT foundations foundation-common Java Chassis::Foundations::Common + + com.sun.activation + jakarta.activation + com.fasterxml.jackson.dataformat jackson-dataformat-xml @@ -47,17 +51,19 @@ org.slf4j slf4j-api - - log4j - log4j - org.apache.httpcomponents httpclient + + + commons-logging + commons-logging + + - javax.ws.rs - javax.ws.rs-api + jakarta.ws.rs + jakarta.ws.rs-api commons-io @@ -68,22 +74,52 @@ guava - javax.servlet - javax.servlet-api + com.google.guava + failureaccess + + + + jakarta.servlet + jakarta.servlet-api + org.apache.commons commons-lang3 - org.slf4j - slf4j-log4j12 - test + org.apache.servicecomb + foundation-spi + org.apache.servicecomb foundation-test-scaffolding + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + io.vertx + vertx-core + + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.jmockit + jmockit + test + diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java deleted file mode 100644 index 313c19ee5ba..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.auth; - -import java.util.HashMap; -import java.util.Map; - -public interface AuthHeaderProvider { - default Map authHeaders() { - return new HashMap<>(0); - } - - default Map getSignAuthHeaders(SignRequest request) { - return authHeaders(); - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/Cipher.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/Cipher.java new file mode 100644 index 00000000000..3912ce38bda --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/Cipher.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.auth; + +public interface Cipher { + String name(); + + char[] decrypt(char[] encrypted); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/DefaultCipher.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/DefaultCipher.java new file mode 100644 index 00000000000..62cb24df37a --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/DefaultCipher.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.auth; + +public final class DefaultCipher implements Cipher { + public static final String CIPHER_NAME = "default"; + + private static final DefaultCipher INSTANCE = new DefaultCipher(); + + public static DefaultCipher getInstance() { + return INSTANCE; + } + + private DefaultCipher() { + } + + @Override + public String name() { + return CIPHER_NAME; + } + + @Override + public char[] decrypt(char[] encrypted) { + return encrypted; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/FoundationCommonAuthConfiguration.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/FoundationCommonAuthConfiguration.java new file mode 100644 index 00000000000..7faea74a3b5 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/FoundationCommonAuthConfiguration.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.auth; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FoundationCommonAuthConfiguration { + public ShaAKSKCipher scbShaAKSKCipher() { + return new ShaAKSKCipher(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/ShaAKSKCipher.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/ShaAKSKCipher.java new file mode 100644 index 00000000000..ee857e64464 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/ShaAKSKCipher.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.auth; + +public class ShaAKSKCipher implements Cipher { + public static final String CIPHER_NAME = "ShaAKSKCipher"; + + @Override + public String name() { + return CIPHER_NAME; + } + + @Override + public char[] decrypt(char[] encrypted) { + return encrypted; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/DynamicObject.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/DynamicObject.java new file mode 100644 index 00000000000..0bdf703315f --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/DynamicObject.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; + +public class DynamicObject { + protected Map dynamic = new HashMap<>(); + + @JsonAnyGetter + public Map getDynamic() { + return dynamic; + } + + @SuppressWarnings("unchecked") + public T getDynamic(String key) { + return (T) dynamic.get(key); + } + + public void setDynamic(Map dynamic) { + this.dynamic = dynamic; + } + + @JsonAnySetter + public DynamicObject putDynamic(String key, Object value) { + this.dynamic.put(key, value); + return this; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Holder.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Holder.java new file mode 100644 index 00000000000..9e9752c6a30 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Holder.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common; + +// do not use javax.xml.ws.Holder, use this one. Because JDK 11 above do not have jakarta.ws.Holder +public final class Holder { + + /** + * The value contained in the holder. + */ + public T value; + + /** + * Creates a new holder with a null value. + */ + public Holder() { + } + + /** + * Create a new holder with the specified value. + * + * @param value The value to be stored in the holder. + */ + public Holder(T value) { + this.value = value; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/LegacyPropertyFactory.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/LegacyPropertyFactory.java new file mode 100644 index 00000000000..ada58bdf3e7 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/LegacyPropertyFactory.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common; + +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Provider a convenient way to get property value in static context. + * + * NOTE: This way is not commented and only for legacy code without too much refactoring. + * And make sure to use this class when spring bean context is already initialized. + */ +public class LegacyPropertyFactory { + private static Environment environment; + + public LegacyPropertyFactory(Environment environment) { + LegacyPropertyFactory.environment = environment; + } + + @VisibleForTesting + public static void setEnvironment(Environment environment) { + LegacyPropertyFactory.environment = environment; + } + + public static T getProperty(String key, Class targetType) { + return environment.getProperty(key, targetType); + } + + public static T getProperty(String key, Class targetType, T defaultValue) { + return environment.getProperty(key, targetType, defaultValue); + } + + public static boolean getBooleanProperty(String key, boolean defaultValue) { + return environment.getProperty(key, boolean.class, defaultValue); + } + + public static int getIntProperty(String key, int defaultValue) { + return environment.getProperty(key, int.class, defaultValue); + } + + public static long getLongProperty(String key, long defaultValue) { + return environment.getProperty(key, long.class, defaultValue); + } + + public static String getStringProperty(String key) { + return environment.getProperty(key); + } + + public static String getStringProperty(String key, String defaultValue) { + return environment.getProperty(key, defaultValue); + } + + public static Environment getEnvironment() { + return environment; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/NamedThreadFactory.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/NamedThreadFactory.java index c6be9c1e0db..3b79c9c8e1a 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/NamedThreadFactory.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/NamedThreadFactory.java @@ -43,7 +43,9 @@ public NamedThreadFactory(String prefix) { */ @Override public Thread newThread(Runnable r) { - return new Thread(r, prefix + "-" + threadNumber.getAndIncrement()); + Thread thread = new Thread(r, prefix + "-" + threadNumber.getAndIncrement()); + thread.setDaemon(true); + return thread; } public String getPrefix() { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/ParameterizedTypeUtil.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/ParameterizedTypeUtil.java new file mode 100644 index 00000000000..025c08acbf3 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/ParameterizedTypeUtil.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Utility class for creating ParameterizedType. + */ +public class ParameterizedTypeUtil implements ParameterizedType { + private final Type[] actualTypeArguments; + + private final Class rawType; + + private ParameterizedTypeUtil(Class rawType, Type[] actualTypeArguments) { + this.actualTypeArguments = actualTypeArguments; + this.rawType = rawType; + } + + public static ParameterizedType make(Class rawType, Type... actualTypeArguments) { + return new ParameterizedTypeUtil(rawType, actualTypeArguments); + } + + @Override + public Type[] getActualTypeArguments() { + return this.actualTypeArguments; + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } + + @Override + public boolean equals(Object o) { + if (o instanceof ParameterizedType that) { + + if (this == that) { + return true; + } + + Type thatRawType = that.getRawType(); + + return Objects.equals(rawType, thatRawType) && + Arrays.equals(actualTypeArguments, that.getActualTypeArguments()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Arrays.hashCode(actualTypeArguments) ^ + Objects.hashCode(rawType); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(rawType.getName()); + + if (actualTypeArguments != null) { + StringJoiner sj = new StringJoiner(", ", "<", ">"); + sj.setEmptyValue(""); + for (Type t : actualTypeArguments) { + sj.add(t.getTypeName()); + } + sb.append(sj); + } + + return sb.toString(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/RegisterManager.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/RegisterManager.java index d2933cff2bc..80cf768a22d 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/RegisterManager.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/RegisterManager.java @@ -27,13 +27,17 @@ public class RegisterManager { private static final Logger LOGGER = LoggerFactory.getLogger(RegisterManager.class); - private String name; + private final String name; private String registerErrorFmt = "Not allow register repeat data, name=%s, key=%s"; - private Map objMap = new ConcurrentHashMap<>(); + private final Map objMap = new ConcurrentHashMap<>(); - private Object lockObj = new Object(); + private final Object lockObj = new Object(); + + protected Map getObjMap() { + return objMap; + } public RegisterManager(String name) { this.name = name; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/VendorExtensions.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/VendorExtensions.java new file mode 100644 index 00000000000..270a883d0f0 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/VendorExtensions.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common; + +import java.util.Map; +import java.util.function.Function; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; + +public class VendorExtensions { + private final Map store = new ConcurrentHashMapEx<>(); + + public Map getStore() { + return store; + } + + @SuppressWarnings("unchecked") + public V get(Object key) { + return (V) store.get(key); + } + + public void put(Object key, Object value) { + store.put(key, value); + } + + @SuppressWarnings("unchecked") + public V computeIfAbsent(Object key, Function mappingFunction) { + return (V) store.computeIfAbsent(key, mappingFunction); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/Version.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Version.java similarity index 95% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/Version.java rename to foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Version.java index 3ec9753d4fc..e09ad62e0ef 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/Version.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/Version.java @@ -15,11 +15,11 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.version; +package org.apache.servicecomb.foundation.common; import java.util.Objects; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; // short version is enough public class Version implements Comparable { @@ -50,7 +50,7 @@ public Version(String version) { } if (versions.length < 4) { - versions = (String[]) ArrayUtils.addAll(versions, ZERO); + versions = ArrayUtils.addAll(versions, ZERO); } this.major = parseNumber("major", version, versions[0]); this.minor = parseNumber("minor", version, versions[1]); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnum.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnum.java new file mode 100644 index 00000000000..982e913fefe --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnum.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.base; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonValue; + +public abstract class DynamicEnum { + private final T value; + + @JsonIgnore + private boolean dynamic = false; + + public DynamicEnum(T value) { + this.value = value; + } + + @JsonValue + public T getValue() { + return value; + } + + @JsonIgnore + public boolean isStatic() { + return !dynamic; + } + + public boolean isDynamic() { + return dynamic; + } + + public DynamicEnum setDynamic(boolean dynamic) { + this.dynamic = dynamic; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DynamicEnum that = (DynamicEnum) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnumCache.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnumCache.java new file mode 100644 index 00000000000..74d27cdbc3a --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/DynamicEnumCache.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.base; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DynamicEnumCache> { + private static final Logger LOGGER = LoggerFactory.getLogger(DynamicEnumCache.class); + + private final Class cls; + + private final Map values; + + /** + * + * @param cls + */ + private final Constructor constructor; + + public DynamicEnumCache(Class cls) { + try { + this.cls = cls; + this.constructor = initFactory(); + this.values = initValues(); + } catch (Exception e) { + throw new IllegalStateException("failed to init dynamic enum, class=" + cls.getName(), e); + } + } + + private Constructor initFactory() throws NoSuchMethodException { + ParameterizedType superClass = (ParameterizedType) cls.getGenericSuperclass(); + Class argument = (Class) superClass.getActualTypeArguments()[0]; + return cls.getConstructor(argument); + } + + @SuppressWarnings("unchecked") + private Map initValues() { + Map values = new LinkedHashMap<>(); + EnumUtils.findEnumFields(cls) + .map(field -> (T) EnumUtils.readEnum(field)) + .forEach(oneEnum -> values.put(oneEnum.getValue(), oneEnum)); + return Collections.unmodifiableMap(values); + } + + public T fromValue(Object value) { + if (value == null) { + return null; + } + + T instance = values.get(value); + if (instance != null) { + return instance; + } + + try { + // do not cache unknown value to avoid attach + // if need to cache unknown value, should avoid cache too many values + instance = constructor.newInstance(value); + instance.setDynamic(true); + return instance; + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + LOGGER.error("failed to create enum, class={}, value={}.", cls.getName(), value); + return null; + } + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/EnumUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/EnumUtils.java new file mode 100644 index 00000000000..b25bcfa1504 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/EnumUtils.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.base; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.stream.Stream; + +public interface EnumUtils { + @SuppressWarnings("unchecked") + static T readEnum(Field enumField) { + try { + return (T) enumField.get(null); + } catch (IllegalAccessException e) { + throw new IllegalStateException("failed to read enum, field=" + enumField, e); + } + } + + static boolean isEnumField(Class cls, Field field) { + return Modifier.isStatic(field.getModifiers()) && cls.equals(field.getType()); + } + + static Stream findEnumFields(Class cls) { + return Arrays.stream(cls.getFields()) + .filter(field -> isEnumField(cls, field)); + } + + static boolean isDynamicEnum(Type cls) { + return cls instanceof DynamicEnum; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/ServiceCombConstants.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/ServiceCombConstants.java index a4f32733c87..aedae7c1a86 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/ServiceCombConstants.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/base/ServiceCombConstants.java @@ -18,25 +18,6 @@ package org.apache.servicecomb.foundation.common.base; public interface ServiceCombConstants { - - String CONFIG_APPLICATION_ID_KEY = "APPLICATION_ID"; - - String CONFIG_SERVICE_DESCRIPTION_KEY = "service_description"; - - String CONFIG_MICROSERVICE_NAME_KEY = "name"; - - String CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY = CONFIG_SERVICE_DESCRIPTION_KEY + "." + CONFIG_MICROSERVICE_NAME_KEY; - - String CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY = CONFIG_SERVICE_DESCRIPTION_KEY + ".version"; - - String CONFIG_QUALIFIED_MICROSERVICE_ROLE_KEY = CONFIG_SERVICE_DESCRIPTION_KEY + ".role"; - - String CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY = CONFIG_SERVICE_DESCRIPTION_KEY + ".description"; - - String DEFAULT_MICROSERVICE_NAME = "defaultMicroservice"; - - String DEFAULT_APPLICATION_ID = "defaultApplicationId"; - String CONFIG_TRACING_COLLECTOR_ADDRESS = "servicecomb.tracing.collector.address"; String CONFIG_TRACING_COLLECTOR_API_V1 = "v1"; @@ -45,27 +26,21 @@ public interface ServiceCombConstants { String CONFIG_TRACING_COLLECTOR_API_VERSION = "servicecomb.tracing.collector.apiVersion"; - String CONFIG_TRACING_ENABLED_KEY = "servicecomb.tracing.enabled"; - String CONFIG_TRACING_COLLECTOR_PATH = "/api/{0}/spans"; String DEFAULT_TRACING_COLLECTOR_ADDRESS = "http://127.0.0.1:9411"; - String CONFIG_SERVICECOMB_PREFIX = "servicecomb."; - - String CONFIG_CSE_PREFIX = "cse."; - - String CONFIG_KEY_SPLITER = "_"; + String CONFIG_KEY_SPLITTER = "_"; String CONFIG_FRAMEWORK_DEFAULT_NAME = "servicecomb-java-chassis"; String CONFIG_DEFAULT_REGISTER_BY = "SDK"; - String SERVICECOMB_ENV = "service_description.environment"; + String DEVELOPMENT_SERVICECOMB_ENV = "development"; - String DEFAULT_SERVICECOMB_ENV = ""; + String SERVICE_MAPPING = "SERVICE_MAPPING"; - String DEVELOPMENT_SERVICECOMB_ENV = "development"; + String VERSION_MAPPING = "VERSION_MAPPING"; - String PRODUCTION_SERVICECOMB_ENV = "production"; + String APP_MAPPING = "APP_MAPPING"; } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/cache/VersionedCache.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/cache/VersionedCache.java index 6580174861e..b30e13862b4 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/cache/VersionedCache.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/cache/VersionedCache.java @@ -30,7 +30,7 @@ interface IsEmpty { boolean isEmpty(); } - protected int cacheVersion; + protected volatile int cacheVersion; // an optional name protected String name; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/concurrency/SuppressedRunnableWrapper.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/concurrency/SuppressedRunnableWrapper.java new file mode 100644 index 00000000000..edd3ba2f845 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/concurrency/SuppressedRunnableWrapper.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.concurrency; + +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A wrapper for {@link Runnable}. + * All the exceptions thrown from {@link Runnable#run()} are caught and handled. + */ +public class SuppressedRunnableWrapper implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(SuppressedRunnableWrapper.class); + + private final Runnable target; + + private final Consumer errorHandler; + + public SuppressedRunnableWrapper(Runnable runnable) { + this(runnable, null); + } + + public SuppressedRunnableWrapper(Runnable runnable, Consumer errorHandler) { + this.target = runnable; + this.errorHandler = errorHandler; + } + + @Override + public void run() { + try { + target.run(); + } catch (Throwable e) { + handleError(e); + } + } + + private void handleError(Throwable e) { + if (null == errorHandler) { + LOGGER.error("task {} execute error!", target, e); + return; + } + errorHandler.accept(e); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/ConfigMgr.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/ConfigMgr.java deleted file mode 100644 index 78b7905e251..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/ConfigMgr.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.foundation.common.config.impl.IncConfigs; -import org.apache.servicecomb.foundation.common.config.impl.IncConfigs.IncConfig; -import org.apache.servicecomb.foundation.common.config.impl.PropertiesLoader; -import org.apache.servicecomb.foundation.common.config.impl.XmlLoader; -import org.apache.servicecomb.foundation.common.config.impl.XmlLoaderUtils; -import org.springframework.core.io.Resource; - -public class ConfigMgr { - public static final ConfigMgr INSTANCE = new ConfigMgr(); - - private Map configMap = new ConcurrentHashMap<>(); - - private Map configLoaderMap; - - /** - * 扫描所有的*.inc.config.xml - * 根据配置初始化所有的loader - */ - public void init() throws Exception { - List resArr = - PaaSResourceUtils.getSortedResources("classpath*:config/config.inc.xml", ".inc.xml"); - IncConfigs incConfigs = new IncConfigs(); - incConfigs.setPropertiesList(new ArrayList<>()); - incConfigs.setXmlList(new ArrayList<>()); - for (Resource resource : resArr) { - IncConfigs tmp = XmlLoaderUtils.load(resource, IncConfigs.class); - if (tmp.getPropertiesList() != null) { - incConfigs.getPropertiesList().addAll(tmp.getPropertiesList()); - } - if (tmp.getXmlList() != null) { - incConfigs.getXmlList().addAll(tmp.getXmlList()); - } - } - - configLoaderMap = new HashMap<>(); - for (IncConfig incConfig : incConfigs.getPropertiesList()) { - PropertiesLoader loader = (PropertiesLoader) configLoaderMap.get(incConfig.getId()); - if (loader != null) { - loader.getLocationPatternList().addAll(incConfig.getPathList()); - continue; - } - - configLoaderMap.put(incConfig.getId(), new PropertiesLoader(incConfig.getPathList())); - } - - for (IncConfig incConfig : incConfigs.getXmlList()) { - XmlLoader loader = (XmlLoader) configLoaderMap.get(incConfig.getId()); - if (loader != null) { - loader.getLocationPatternList().addAll(incConfig.getPathList()); - continue; - } - configLoaderMap.put(incConfig.getId(), new XmlLoader(incConfig.getPathList())); - } - } - - @SuppressWarnings("unchecked") - public T getConfig(String configId) throws Exception { - T config = (T) configMap.get(configId); - if (config != null) { - return config; - } - - if (configLoaderMap == null) { - init(); - } - - ConfigLoader loader = configLoaderMap.get(configId); - if (loader == null) { - throw new RuntimeException("can not find config for " + configId); - } - - config = (T) loader.load(); - configMap.put(configId, config); - return config; - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSPropertyPlaceholderConfigurer.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSPropertyPlaceholderConfigurer.java deleted file mode 100644 index b308d556b51..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSPropertyPlaceholderConfigurer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config; - -import java.io.IOException; -import java.util.Properties; - -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; - -public class PaaSPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { - - // 以逗号分隔 - private String configId; - - public void setConfigId(String configId) { - this.configId = configId; - } - - @Override - protected void loadProperties(Properties props) throws IOException { - for (String id : configId.split(",")) { - try { - Properties config = ConfigMgr.INSTANCE.getConfig(id); - props.putAll(config); - } catch (Exception e) { - throw new IOException(e); - } - } - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSResourceUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSResourceUtils.java index 6ca10e63b26..fe11a3fe763 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSResourceUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/PaaSResourceUtils.java @@ -20,27 +20,20 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.List; import java.util.Properties; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Unmarshaller; - +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.common.config.impl.PropertiesLoader; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.StringUtils; -import org.w3c.dom.Document; + public class PaaSResourceUtils extends org.springframework.util.ResourceUtils { public static final String PROPERTIES_SUFFIX = ".properties"; - public static final String XML_SUFFIX = ".xml"; - - private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); /** * 失败,则返回空数组 @@ -76,34 +69,31 @@ public static List getResources(String... locationPatterns) { * 此时,还分多个,是不合适的 */ public static void sortResources(List resList, String suffix) { - resList.sort(new Comparator() { - @Override - public int compare(Resource o1, Resource o2) { - try { - // jar的优先级比较低 - if (isJarURL(o1.getURL()) && isFileURL(o2.getURL())) { - return -1; - } - - // 干掉后缀,再排序 - String name1 = o1.getFilename(); - String name2 = o2.getFilename(); - - //Resource.getFilename接口会返回null,当路径的文件名不存在时 - //配置文件一定存在,并且Resource有合法的文件名,name1和name2不可能为空, - //这里做判断是为了处理CodeDEX报的null引用 - if (StringUtils.isEmpty(name1) || StringUtils.isEmpty(name2)) { - throw new IOException( - String.format("Resource %s or %s is not a file", o1.getURI(), o2.getURI())); - } - - name1 = name1.substring(0, name1.length() - suffix.length()); - name2 = name2.substring(0, name2.length() - suffix.length()); - - return name1.compareTo(name2); - } catch (IOException e) { - throw new RuntimeException(e); + resList.sort((o1, o2) -> { + try { + // jar的优先级比较低 + if (isJarURL(o1.getURL()) && isFileURL(o2.getURL())) { + return -1; } + + // 干掉后缀,再排序 + String name1 = o1.getFilename(); + String name2 = o2.getFilename(); + + //Resource.getFilename接口会返回null,当路径的文件名不存在时 + //配置文件一定存在,并且Resource有合法的文件名,name1和name2不可能为空, + //这里做判断是为了处理CodeDEX报的null引用 + if (StringUtils.isEmpty(name1) || StringUtils.isEmpty(name2)) { + throw new IOException( + String.format("Resource %s or %s is not a file", o1.getURI(), o2.getURI())); + } + + name1 = name1.substring(0, name1.length() - suffix.length()); + name2 = name2.substring(0, name2.length() - suffix.length()); + + return name1.compareTo(name2); + } catch (IOException e) { + throw new RuntimeException(e); } }); } @@ -112,10 +102,6 @@ public static void sortProperties(List resList) { sortResources(resList, PROPERTIES_SUFFIX); } - public static void sortXmls(List resList) { - sortResources(resList, XML_SUFFIX); - } - public static List getSortedResources(String locationPattern, String suffix) { if (StringUtils.isEmpty(locationPattern)) { throw new RuntimeException("Resource path must not be null or empty"); @@ -132,7 +118,7 @@ public static List getSortedResources(String locationPattern, String s return resList; } - public static List getSortedPorperties(String locationPattern) { + public static List getSortedProperties(String locationPattern) { return getSortedResources(locationPattern, PROPERTIES_SUFFIX); } @@ -140,24 +126,4 @@ public static Properties loadMergedProperties(String locationPattern) throws Exc PropertiesLoader loader = new PropertiesLoader(Arrays.asList(locationPattern)); return loader.load(); } - - public static List getSortedXmls(String locationPattern) { - return getSortedResources(locationPattern, XML_SUFFIX); - } - - @SuppressWarnings("unchecked") - public static T loadConfigAs(String configId, Class clazz) throws Exception { - Object config = ConfigMgr.INSTANCE.getConfig(configId); - if (Properties.class.isInstance(config)) { - return (T) JsonUtils.convertValue(config, clazz); - } - - if (Document.class.isInstance(config)) { - JAXBContext jaxbContext = JAXBContext.newInstance(clazz); - Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); - return (T) jaxbUnmarshaller.unmarshal((Document) config, clazz).getValue(); - } - - throw new Exception("not support"); - } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IdXmlLoader.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IdXmlLoader.java deleted file mode 100644 index 786cec6b157..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IdXmlLoader.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config.impl; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -public class IdXmlLoader extends XmlLoader { - private Map idMap = new HashMap<>(); - - public IdXmlLoader(List locationPatternList) { - super(locationPatternList); - } - - public IdXmlLoader(List locationPatternList, String suffix) { - super(locationPatternList, suffix); - } - - @Override - protected Element findAndSetExist(Element ele) { - String id = ele.getAttribute("id"); - if (StringUtils.isEmpty(id)) { - throw new RuntimeException("id not allow be empty"); - } - - Element existEle = idMap.get(id); - if (existEle == null) { - idMap.put(id, ele); - return null; - } - - return existEle; - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IncConfigs.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IncConfigs.java deleted file mode 100644 index a1b2ed3ec30..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/IncConfigs.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config.impl; - -import java.util.List; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; - -@JacksonXmlRootElement(localName = "configs") -public class IncConfigs { - - public static class IncConfig { - @JacksonXmlProperty(isAttribute = true) - private String id; - - @JacksonXmlProperty(isAttribute = true) - private String loader; - - @JacksonXmlProperty(localName = "path") - @JacksonXmlElementWrapper(useWrapping = false) - private List pathList; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getLoader() { - return loader; - } - - public void setLoader(String loader) { - this.loader = loader; - } - - public List getPathList() { - return pathList; - } - - public void setPathList(List pathList) { - this.pathList = pathList; - } - } - - @JacksonXmlProperty(localName = "properties") - @JacksonXmlElementWrapper(useWrapping = false) - private List propertiesList; - - @JacksonXmlProperty(localName = "xml") - @JacksonXmlElementWrapper(useWrapping = false) - private List xmlList; - - public List getPropertiesList() { - return propertiesList; - } - - public void setPropertiesList(List propertiesList) { - this.propertiesList = propertiesList; - } - - public List getXmlList() { - return xmlList; - } - - public void setXmlList(List xmlList) { - this.xmlList = xmlList; - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PaaSPropertiesLoaderUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PaaSPropertiesLoaderUtils.java index b31901bd12a..a12eca5ae3a 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PaaSPropertiesLoaderUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PaaSPropertiesLoaderUtils.java @@ -21,9 +21,10 @@ import java.util.List; import java.util.Properties; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.common.config.PaaSResourceUtils; import org.springframework.core.io.Resource; -import org.springframework.util.StringUtils; + public class PaaSPropertiesLoaderUtils extends org.springframework.core.io.support.PropertiesLoaderUtils { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PropertiesLoader.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PropertiesLoader.java index 1590ba143bf..ae4500e8aef 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PropertiesLoader.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/PropertiesLoader.java @@ -25,7 +25,7 @@ import org.springframework.core.io.Resource; public class PropertiesLoader extends AbstractLoader { - private List foundResList = new ArrayList<>(); + private final List foundResList = new ArrayList<>(); public PropertiesLoader(List locationPatternList) { super(locationPatternList); @@ -40,7 +40,7 @@ public List getFoundResList() { public T load() throws Exception { Properties props = new Properties(); for (String locationPattern : locationPatternList) { - List resList = PaaSResourceUtils.getSortedPorperties(locationPattern); + List resList = PaaSResourceUtils.getSortedProperties(locationPattern); foundResList.addAll(resList); PaaSPropertiesLoaderUtils.fillAllProperties(props, resList); } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoader.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoader.java deleted file mode 100644 index 254b1eda3d0..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoader.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config.impl; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.config.PaaSResourceUtils; -import org.springframework.core.io.Resource; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * 无逻辑append xml - */ -public class XmlLoader extends AbstractLoader { - - private String suffix; - - public XmlLoader(List locationPatternList) { - this(locationPatternList, PaaSResourceUtils.XML_SUFFIX); - } - - public XmlLoader(List locationPatternList, String suffix) { - super(locationPatternList); - this.suffix = suffix; - } - - @SuppressWarnings("unchecked") - @Override - public T load() throws Exception { - Document doc = XmlLoaderUtils.newDoc(); - Element root = null; - for (String locationPattern : locationPatternList) { - List resList = PaaSResourceUtils.getSortedResources(locationPattern, suffix); - for (Resource res : resList) { - Document tmpDoc = XmlLoaderUtils.load(res); - Element tmpRoot = tmpDoc.getDocumentElement(); - - if (root == null) { - root = (Element) doc.importNode(tmpRoot, false); - doc.appendChild(root); - } - - NodeList nodeList = tmpRoot.getChildNodes(); - for (int idx = 0; idx < nodeList.getLength(); idx++) { - Node child = nodeList.item(idx); - - if (!Element.class.isInstance(child)) { - continue; - } - - Element clone = (Element) doc.importNode(child, true); - Element exist = findAndSetExist(clone); - if (exist == null) { - root.appendChild(clone); - continue; - } - - // merge attr and children - XmlLoaderUtils.mergeElement(clone, exist); - } - } - } - return (T) doc; - } - - protected Element findAndSetExist(Element ele) { - return null; - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoaderUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoaderUtils.java index af0393409e4..8d2a4b98c1e 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoaderUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/config/impl/XmlLoaderUtils.java @@ -38,7 +38,7 @@ public final class XmlLoaderUtils { private XmlLoaderUtils() { } - private static ObjectMapper xmlMapper = new XmlMapper(); + private static final ObjectMapper xmlMapper = new XmlMapper(); @SuppressWarnings("unchecked") public static T load(Resource res, Class cls) throws Exception { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java index 1f100c14849..3539764406d 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/AlarmEvent.java @@ -31,5 +31,5 @@ public Type getType() { public enum Type { OPEN, CLOSE - }; + } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EnableExceptionPropagation.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EnableExceptionPropagation.java new file mode 100644 index 00000000000..744ebb94a26 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EnableExceptionPropagation.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.event; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * do not suppress exception + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface EnableExceptionPropagation { +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EventManager.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EventManager.java index 6e59293f474..50b474050d9 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EventManager.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/EventManager.java @@ -17,12 +17,16 @@ package org.apache.servicecomb.foundation.common.event; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + import com.google.common.eventbus.EventBus; /** * EventManager for chassis events * */ +@Configuration public class EventManager { public static EventBus eventBus = new SimpleEventBus(); @@ -50,4 +54,9 @@ public static void post(Object event) { public static void unregister(Object listener) { eventBus.unregister(listener); } + + @Bean + public EventBus scbEventBus() { + return eventBus; + } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleEventBus.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleEventBus.java index 1dfbd97ef76..49602a2de58 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleEventBus.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleEventBus.java @@ -18,6 +18,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -62,10 +63,11 @@ public void unregister(Object instance) { } } + @Override public void post(Object event) { // cache always reset after register/unregister // so cache always match latest subscribersMap at last - // te worst scenes is invoke collectSubscriberForEvent multiple times, no problem + // the worst scenes is invoke collectSubscriberForEvent multiple times, no problem List subscribers = subscribersCache .computeIfAbsent(event.getClass(), this::collectSubscriberForEvent); for (SimpleSubscriber subscriber : subscribers) { @@ -87,6 +89,8 @@ private List collectSubscriberForEvent(Class eventClass) { } } } + + subscribersForEvent.sort(Comparator.comparingInt(SimpleSubscriber::getOrder)); return subscribersForEvent; } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java index e83a6bd21d1..990ca304dcf 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.foundation.common.event; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.function.Consumer; import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; @@ -28,9 +29,13 @@ public class SimpleSubscriber { private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSubscriber.class); - private Object instance; + private final Object instance; - private Method method; + private final Method method; + + private int order; + + private final boolean enableExceptionPropagation; // generated from method private Consumer lambda; @@ -41,15 +46,26 @@ public SimpleSubscriber(Object instance, Method method) { this.instance = instance; this.method = method; - method.setAccessible(true); + enableExceptionPropagation = method.getAnnotation(EnableExceptionPropagation.class) != null; + SubscriberOrder subscriberOrder = method.getAnnotation(SubscriberOrder.class); + if (subscriberOrder != null) { + order = subscriberOrder.value(); + } + try { lambda = LambdaMetafactoryUtils.createLambda(instance, method, Consumer.class); } catch (Throwable throwable) { - LOGGER.warn("Failed to create lambda for method: {}, fallback to reflect.", method); + // because enhance LambdaMetafactoryUtils to support ALL_MODES by reflect + // never run into this branch. + // otherwise create a listener instance of anonymous class will run into this branch + LOGGER.warn("Failed to create lambda for method: {}, fallback to reflect.", method, throwable); + + checkAccess(method); lambda = event -> { try { method.invoke(instance, event); } catch (Throwable e) { + LOGGER.warn("Failed to call event listener {}.", method.getName()); throw new IllegalStateException(e); } }; @@ -61,6 +77,19 @@ public SimpleSubscriber(Object instance, Method method) { } } + private static void checkAccess(Method method) { + // This check is not accurate. Most of time package visible and protected access can be ignored, so simply do this. + if (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { + throw new IllegalStateException( + String.format( + "The event handler must be a public accessible method. NOTICE: " + + "this is change from 2.0 and using higher version of JDK. " + + "Declaring class is %s, method is %s", + method.getDeclaringClass().getName(), + method.getName())); + } + } + public Object getInstance() { return instance; } @@ -69,8 +98,19 @@ public Method getMethod() { return method; } + public int getOrder() { + return order; + } + public void dispatchEvent(Object event) { - dispatcher.accept(event); + try { + dispatcher.accept(event); + } catch (Throwable e) { + if (enableExceptionPropagation) { + throw e; + } + LOGGER.error("Event process should not throw exception when @EnableExceptionPropagation not set. ", e); + } } private void syncDispatch(Object event) { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SubscriberOrder.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SubscriberOrder.java new file mode 100644 index 00000000000..2232ac5dd99 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SubscriberOrder.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.event; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * order of subscriber
+ * lower values will run first + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SubscriberOrder { + int value() default 0; +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatus.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatus.java index 15489ba95a9..45806dcc53f 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatus.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatus.java @@ -16,9 +16,9 @@ */ package org.apache.servicecomb.foundation.common.http; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.Status.Family; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status.Family; +import jakarta.ws.rs.core.Response.StatusType; public class HttpStatus implements StatusType { public static boolean isSuccess(int code) { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusManager.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusManager.java index b2ec5a75472..8a995f74389 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusManager.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusManager.java @@ -19,13 +19,13 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; public class HttpStatusManager { - private Map statusMap = new ConcurrentHashMap<>(); + private final Map statusMap = new ConcurrentHashMap<>(); public HttpStatusManager() { for (Status status : Status.values()) { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusUtils.java index 4dac0e4259b..3c4693c9eab 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpStatusUtils.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.foundation.common.http; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; public final class HttpStatusUtils { private static final HttpStatusManager MGR = new HttpStatusManager(); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java index 0c77d19b8bd..626cb136030 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java @@ -20,9 +20,9 @@ import java.net.URI; import java.net.URISyntaxException; -import org.springframework.util.StringUtils; import com.google.common.net.UrlEscapers; +import org.apache.commons.lang3.StringUtils; public final class HttpUtils { private HttpUtils() { @@ -33,7 +33,6 @@ private HttpUtils() { * @param headerValue example: attachment;filename=a.txt * */ - // public static String parseParamFromHeaderValue(String headerValue, String paramName) { if (StringUtils.isEmpty(headerValue)) { return null; @@ -44,9 +43,8 @@ public static String parseParamFromHeaderValue(String headerValue, String paramN if (idx == -1) { continue; } - - if (paramName.equalsIgnoreCase(value.substring(0, idx))) { - return value.substring(idx + 1); + if (paramName.equalsIgnoreCase(value.substring(0, idx).trim())) { + return value.substring(idx + 1).replaceAll("\"", "").trim(); } } return null; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/log/AbstractMarker.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/log/AbstractMarker.java new file mode 100644 index 00000000000..15128c19bce --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/log/AbstractMarker.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.log; + +import java.util.Collections; +import java.util.Iterator; + +import org.slf4j.Marker; + +public abstract class AbstractMarker implements Marker { + private static final long serialVersionUID = -1L; + + @Override + public void add(Marker reference) { + + } + + @Override + public boolean remove(Marker reference) { + return false; + } + + @Deprecated + @Override + public boolean hasChildren() { + return false; + } + + @Override + public boolean hasReferences() { + return false; + } + + @SuppressWarnings("unchecked") + @Override + public Iterator iterator() { + return Collections.EMPTY_LIST.iterator(); + } + + @Override + public boolean contains(Marker other) { + return false; + } + + @Override + public boolean contains(String name) { + return false; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/IpPort.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/IpPort.java index d8515eea13a..66aae3ebca7 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/IpPort.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/IpPort.java @@ -22,9 +22,9 @@ import com.google.common.base.Objects; public class IpPort { - private String hostOrIp; + private volatile String hostOrIp; - private int port; + private volatile int port; private volatile InetSocketAddress socketAddress; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java index 30f8e29db34..fd8cc1f7a29 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java @@ -29,14 +29,23 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; + public final class NetUtils { private static final Logger LOGGER = LoggerFactory.getLogger(NetUtils.class); + private static final String IPV4_KEY = "_v4"; + + private static final String IPV6_KEY = "_v6"; + + private static final String PREFERRED_INTERFACE = "eth"; + // one interface can bind to multiple address // we only save one ip for each interface name. // eg: @@ -47,34 +56,42 @@ public final class NetUtils { // eth0:1 -> ip3 // on interface name conflict, all data saved - // key is network interface name + // key is network interface name and type private static Map allInterfaceAddresses = new HashMap<>(); private static String hostName; private static String hostAddress; + private static String hostAddressIpv6; + static { doGetHostNameAndHostAddress(); } private static void doGetHostNameAndHostAddress() { try { - doGetIpv4AddressFromNetworkInterface(); + doGetAddressFromNetworkInterface(); // getLocalHost will throw exception in some docker image and sometimes will do a hostname lookup and time consuming InetAddress localHost = InetAddress.getLocalHost(); hostName = localHost.getHostName(); - if ((localHost.isAnyLocalAddress() || localHost.isLoopbackAddress() || localHost.isMulticastAddress()) - && !allInterfaceAddresses.isEmpty()) { - InetAddress availabelAddress = allInterfaceAddresses.values().iterator().next(); - hostAddress = availabelAddress.getHostAddress(); - LOGGER.warn("cannot find a proper host address, choose {}, may not be correct.", hostAddress); - } else { + LOGGER.info("localhost hostName={}, hostAddress={}.", hostName, localHost.getHostAddress()); + + if (!isLocalAddress(localHost)) { + if (Inet6Address.class.isInstance(localHost)) { + hostAddressIpv6 = trimIpv6(localHost.getHostAddress()); + hostAddress = tryGetHostAddressFromNetworkInterface(false, localHost); + LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6); + return; + } hostAddress = localHost.getHostAddress(); + hostAddressIpv6 = trimIpv6(tryGetHostAddressFromNetworkInterface(true, localHost)); + LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6); + return; } - - LOGGER.info( - "add host name from localhost:" + hostName + ",host address:" + hostAddress); + hostAddressIpv6 = trimIpv6(tryGetHostAddressFromNetworkInterface(true, localHost)); + hostAddress = tryGetHostAddressFromNetworkInterface(false, localHost); + LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6); } catch (Exception e) { LOGGER.error("got exception when trying to get addresses:", e); if (allInterfaceAddresses.size() >= 1) { @@ -82,10 +99,32 @@ private static void doGetHostNameAndHostAddress() { // get host name will do a reverse name lookup and is time consuming hostName = entry.getHostName(); hostAddress = entry.getHostAddress(); - LOGGER.info( - "add host name from interfaces:" + hostName + ",host address:" + hostAddress); + LOGGER.info("add host name from interfaces:" + hostName + ",host address:" + hostAddress); + } + } + } + + private static String tryGetHostAddressFromNetworkInterface(boolean isIpv6, InetAddress localhost) { + InetAddress result = null; + for (Entry entry : allInterfaceAddresses.entrySet()) { + if (isIpv6 && entry.getKey().endsWith(IPV6_KEY)) { + result = entry.getValue(); + if (entry.getKey().startsWith(PREFERRED_INTERFACE)) { + return result.getHostAddress(); + } + } else if (!isIpv6 && entry.getKey().endsWith(IPV4_KEY)) { + result = entry.getValue(); + if (entry.getKey().startsWith(PREFERRED_INTERFACE)) { + return result.getHostAddress(); + } } } + + if (result == null) { + return localhost.getHostAddress(); + } + + return result.getHostAddress(); } private NetUtils() { @@ -95,61 +134,119 @@ private NetUtils() { * docker环境中,有时无法通过InetAddress.getLocalHost()获取 ,会报unknown host Exception, system error * 此时,通过遍历网卡接口的方式规避,出来的数据不一定对 */ - private static void doGetIpv4AddressFromNetworkInterface() throws SocketException { - Enumeration iterNetwork = NetworkInterface.getNetworkInterfaces(); + private static void doGetAddressFromNetworkInterface() throws SocketException { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); - while (iterNetwork.hasMoreElements()) { - NetworkInterface network = iterNetwork.nextElement(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface network = networkInterfaces.nextElement(); if (!network.isUp() || network.isLoopback() || network.isVirtual()) { continue; } - Enumeration iterAddress = network.getInetAddresses(); - while (iterAddress.hasMoreElements()) { - InetAddress address = iterAddress.nextElement(); + Enumeration addresses = network.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress address = addresses.nextElement(); - if (address.isAnyLocalAddress() || address.isLoopbackAddress() || address.isMulticastAddress() - || Inet6Address.class.isInstance(address)) { + if (isLocalAddress(address)) { continue; } - if (Inet4Address.class.isInstance(address)) { - LOGGER.info( - "add network interface name:" + network.getName() + ",host address:" + address.getHostAddress()); - allInterfaceAddresses.put(network.getName(), address); + if (address instanceof Inet4Address) { + LOGGER.info("add ipv4 network interface:" + network.getName() + ",host address:" + address.getHostAddress()); + allInterfaceAddresses.put(network.getName() + IPV4_KEY, address); + } else if (address instanceof Inet6Address) { + LOGGER.info("add ipv6 network interface:" + network.getName() + ",host address:" + address.getHostAddress()); + allInterfaceAddresses.put(network.getName() + IPV6_KEY, address); } } } } + private static String trimIpv6(String hostAddress) { + int index = hostAddress.indexOf("%"); + if (index >= 0) { + return hostAddress.substring(0, index); + } + return hostAddress; + } + + private static boolean isLocalAddress(InetAddress address) { + return address.isAnyLocalAddress() || address.isLoopbackAddress() || address.isMulticastAddress(); + } + /** - * address ip:port格式 + * The format of address should be {@code IPv4:port} or {@code [IPv6]:port}, or {@code host:port}, + * or you will not get expected result. + * + * Note that the IPv6 address should be wrapped by square brackets. + * @return IpPort parsed from input param, or {@code null} if the param is null. */ public static IpPort parseIpPort(String address) { if (address == null) { return null; } - int idx = address.indexOf(':'); - if (idx == -1) { - return null; + URI uri = URI.create("http://" + address); + return parseIpPort(uri, true); + } + + /** + * Parse a {@link URI} into an {@link IpPort}. + * + *

+ * A uri without port is allowed, in which case the port will be inferred from the scheme. {@code http} is 80, and + * {@code https} is 443. + *

+ *

+ * The host of the {@code uri} should not be null, or it will be treated as an illegal param, + * and an {@link IllegalArgumentException} will be thrown. + *

+ */ + public static IpPort parseIpPort(URI uri) { + return parseIpPort(uri, false); + } + + /** + * Parse a {@link URI} into an {@link IpPort} + * @param uri a uri representing {@link IpPort} + * @param ignorePortUndefined whether the port should be inferred from scheme, when the port part of {@code uri} is {@code -1}. + * If {@code true} the undefined port is ignored; + * otherwise a port will be inferred from scheme: {@code http} is 80, and {@code https} is 443. + */ + public static IpPort parseIpPort(URI uri, boolean ignorePortUndefined) { + if (null == uri.getHost()) { + // if the format of address is legal but the value is out of range, URI#create(String) will not throw exception + // but return a URI with null host. + throw new IllegalArgumentException("Illegal uri: [" + uri + "]"); + } + + IpPort ipPort = new IpPort(uri.getHost(), uri.getPort()); + if (-1 != ipPort.getPort() || ignorePortUndefined) { + return ipPort; } - String hostOrIp = address.substring(0, idx); - int port = Integer.parseInt(address.substring(idx + 1)); - return new IpPort(hostOrIp, port); + if (uri.getScheme().equals("http")) { + ipPort.setPort(80); + } + if (uri.getScheme().equals("https")) { + ipPort.setPort(443); + } + + return ipPort; } + /** + * @param uriAddress the address containing IP and port info. + * @return IpPort parsed from input param, or {@code null} if the param is null. + */ public static IpPort parseIpPortFromURI(String uriAddress) { if (uriAddress == null) { return null; } try { - URI uri = new URI(uriAddress); - String authority = uri.getAuthority(); - return parseIpPort(uri.getScheme(), authority); + return parseIpPort(new URI(uriAddress)); } catch (URISyntaxException e) { return null; } @@ -159,23 +256,13 @@ public static IpPort parseIpPort(String scheme, String authority) { if (authority == null) { return null; } - int idx = authority.indexOf(':'); - if (idx != -1) { - return parseIpPort(authority); - } - if (scheme.equals("http")) { - return new IpPort(authority, 80); - } - if (scheme.equals("https")) { - return new IpPort(authority, 443); - } - return null; + return parseIpPort(URI.create(scheme + "://" + authority)); } /** * 对于配置为0.0.0.0的地址,let it go * schema, e.g. http - * adddress, e.g 0.0.0.0:8080 + * address, e.g 0.0.0.0:8080 * return 实际监听的地址 */ public static String getRealListenAddress(String schema, String address) { @@ -184,11 +271,9 @@ public static String getRealListenAddress(String schema, String address) { } try { URI originalURI = new URI(schema + "://" + address); - IpPort ipPort = NetUtils.parseIpPort(originalURI.getAuthority()); - if (ipPort == null) { - LOGGER.error("address {} is not valid.", address); - return null; - } + // validate original url + NetUtils.parseIpPort(originalURI); + return originalURI.toString(); } catch (URISyntaxException e) { LOGGER.error("address {} is not valid.", address); @@ -205,6 +290,11 @@ public static String getHostName() { return hostName; } + @VisibleForTesting + static void resetHostName() { + hostName = null; + } + public static String getHostAddress() { //If failed to get host address ,micro-service will registry failed //So I add retry mechanism @@ -214,6 +304,15 @@ public static String getHostAddress() { return hostAddress; } + public static String getIpv6HostAddress() { + //If failed to get host address ,micro-service will registry failed + //So I add retry mechanism + if (hostAddressIpv6 == null) { + doGetHostNameAndHostAddress(); + } + return hostAddressIpv6; + } + public static InetAddress getInterfaceAddress(String interfaceName) { return allInterfaceAddresses.get(interfaceName); } @@ -238,7 +337,7 @@ public static boolean canTcpListen(InetAddress address, int port) { public static String humanReadableBytes(long bytes) { int unit = 1024; if (bytes < unit) { - return bytes + ""; + return String.valueOf(bytes); } int exp = (int) (Math.log(bytes) / Math.log(unit)); char pre = "KMGTPE".charAt(exp - 1); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java index 4c46e14f4da..78b633c1183 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java @@ -35,37 +35,43 @@ public class URIEndpointObject extends IpPort { private static final String PROTOCOL_KEY = "protocol"; + private static final String WEBSOCKET_ENABLED_KEY = "websocketEnabled"; + private static final String HTTP2 = "http2"; - private boolean sslEnabled; + private final boolean sslEnabled; private boolean http2Enabled; - private Map> querys; + private boolean websocketEnabled; + + private final Map> queries; + + private final String schema; public URIEndpointObject(String endpoint) { URI uri = URI.create(endpoint); + schema = uri.getScheme(); setHostOrIp(uri.getHost()); if (uri.getPort() < 0) { // do not use default port throw new IllegalArgumentException("port not specified."); } setPort(uri.getPort()); - querys = splitQuery(uri); + queries = splitQuery(uri); sslEnabled = Boolean.parseBoolean(getFirst(SSL_ENABLED_KEY)); - String httpversion = getFirst(PROTOCOL_KEY); - if (httpversion != null && httpversion.equals(HTTP2)) { + websocketEnabled = Boolean.parseBoolean(getFirst(WEBSOCKET_ENABLED_KEY)); + String httpVersion = getFirst(PROTOCOL_KEY); + if (HTTP2.equals(httpVersion)) { http2Enabled = true; } } public static Map> splitQuery(URI uri) { final Map> queryPairs = new LinkedHashMap<>(); - List pairs = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8.name()); + List pairs = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8); for (NameValuePair pair : pairs) { - List list = queryPairs.computeIfAbsent(pair.getName(), name -> { - return new ArrayList<>(); - }); + List list = queryPairs.computeIfAbsent(pair.getName(), name -> new ArrayList<>()); list.add(pair.getValue()); } return queryPairs; @@ -75,16 +81,24 @@ public boolean isSslEnabled() { return sslEnabled; } + public boolean isWebsocketEnabled() { + return websocketEnabled; + } + public boolean isHttp2Enabled() { return http2Enabled; } + public String getSchema() { + return this.schema; + } + public List getQuery(String key) { - return querys.get(key); + return queries.get(key); } public String getFirst(String key) { - List values = querys.get(key); + List values = queries.get(key); // it's impossible that values is not null and size is 0 if (values == null) { return null; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/AbstractPart.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/AbstractPart.java index 653d0f909e3..0c849a5d83a 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/AbstractPart.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/AbstractPart.java @@ -22,11 +22,12 @@ import java.util.Collection; import javax.activation.MimetypesFileTypeMap; -import javax.servlet.http.Part; -import javax.ws.rs.core.MediaType; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.MediaType; public class AbstractPart implements Part { - private static MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(); + private static final MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(); protected String name; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePart.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePart.java index ef290479760..1bd9ddfd952 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePart.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePart.java @@ -18,14 +18,14 @@ package org.apache.servicecomb.foundation.common.part; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import org.apache.commons.io.FileUtils; public class FilePart extends AbstractPart implements FilePartForSend { - private File file; + private final File file; private boolean deleteAfterFinished; @@ -41,7 +41,7 @@ public FilePart(String name, File file) { @Override public InputStream getInputStream() throws IOException { - return new FileInputStream(file); + return Files.newInputStream(file.toPath()); } @Override diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePartForSend.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePartForSend.java index f86e696a66e..b2252361997 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePartForSend.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/FilePartForSend.java @@ -16,7 +16,7 @@ */ package org.apache.servicecomb.foundation.common.part; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; public interface FilePartForSend extends Part { boolean isDeleteAfterFinished(); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/ResourcePart.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/ResourcePart.java index ff07e896ac8..cb00e5dd00c 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/ResourcePart.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/part/ResourcePart.java @@ -23,7 +23,7 @@ import org.springframework.core.io.Resource; public class ResourcePart extends AbstractPart { - private Resource resource; + private final Resource resource; public ResourcePart(String name, Resource resource) { this.name = name; diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/spring/PaasNamespaceHandler.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/spring/PaasNamespaceHandler.java index 5b65bf7edcd..f434818df84 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/spring/PaasNamespaceHandler.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/spring/PaasNamespaceHandler.java @@ -50,10 +50,10 @@ public void init() { String className = entry.getValue().toString(); try { Class clazz = Class.forName(className); - Object instance = clazz.newInstance(); + Object instance = clazz.getDeclaredConstructor().newInstance(); registerBeanDefinitionParser(entry.getKey().toString(), (BeanDefinitionParser) instance); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + } catch (ReflectiveOperationException e) { // 类找不到,说明没部署相应的jar包,这不一定是错误 // 可能是业务就选择不部署相应的jar包 // 所以只是打印个info日志 diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/AbstractRestObjectMapper.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AbstractRestObjectMapper.java similarity index 80% rename from common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/AbstractRestObjectMapper.java rename to foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AbstractRestObjectMapper.java index 1f64d3d0543..5069e6a3986 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/AbstractRestObjectMapper.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AbstractRestObjectMapper.java @@ -15,17 +15,20 @@ * limitations under the License. */ -package org.apache.servicecomb.common.rest.codec; +package org.apache.servicecomb.foundation.common.utils; -import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; public abstract class AbstractRestObjectMapper extends ObjectMapper { private static final long serialVersionUID = 189026839992490564L; - public AbstractRestObjectMapper(JsonFactory jsonFactory) { - super(jsonFactory); + public AbstractRestObjectMapper() { + super(); } - abstract public String convertToString(Object value) throws Exception; + public AbstractRestObjectMapper(RestObjectMapper src) { + super(src); + } + + public abstract String convertToString(Object value) throws Exception; } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AsyncUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AsyncUtils.java new file mode 100644 index 00000000000..25219038097 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/AsyncUtils.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; + +import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; + +public final class AsyncUtils { + private AsyncUtils() { + } + + public static CompletableFuture tryCatchSupplier(Supplier supplier) { + try { + T value = supplier.get(); + return CompletableFuture.completedFuture(value); + } catch (Throwable e) { + return completeExceptionally(e); + } + } + + public static CompletableFuture tryCatchSupplierFuture(Supplier> supplier) { + try { + return supplier.get(); + } catch (Throwable e) { + return completeExceptionally(e); + } + } + + public static CompletableFuture completeExceptionally(Throwable throwable) { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(throwable); + return future; + } + + /** + * throws {@code exception} as RuntimeException. + * + * @param exception exception which will be rethrow + */ + public static RuntimeException rethrow(Throwable exception) { + if (exception instanceof RuntimeException) { + return (RuntimeException) exception; + } + return new ServiceCombException("Not declared exception", exception); + } + + public static T toSync(CompletableFuture future) { + try { + return future.get(); + } catch (ExecutionException executionException) { + throw rethrow(executionException.getCause()); + } catch (Throwable e) { + throw rethrow(e); + } + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java index 103ac79e0d5..bc6a648b361 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java @@ -17,66 +17,21 @@ package org.apache.servicecomb.foundation.common.utils; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; -import org.apache.commons.lang3.StringUtils; -import org.springframework.aop.TargetClassAware; +import org.springframework.aop.framework.AopProxyUtils; import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; public final class BeanUtils { - public static final String DEFAULT_BEAN_RESOURCE = "classpath*:META-INF/spring/*.bean.xml"; - - public static final String SCB_SCAN_PACKAGE = "scb-scan-package"; - - private static final String SCB_PACKAGE = "org.apache.servicecomb"; - private static ApplicationContext context; private BeanUtils() { } - public static void init() { - init(DEFAULT_BEAN_RESOURCE); - } - - - public static void init(String... configLocations) { - prepareServiceCombScanPackage(); - - context = new ClassPathXmlApplicationContext(configLocations); - } - - public static void prepareServiceCombScanPackage() { - Set scanPackags = new LinkedHashSet<>(); - // add exists settings - String exists = System.getProperty(SCB_SCAN_PACKAGE); - if (exists != null) { - for (String exist : exists.trim().split(",")) { - if (!exist.isEmpty()) { - scanPackags.add(exist.trim()); - } - } - } - - // ensure servicecomb package exist - scanPackags.add(SCB_PACKAGE); - - // add main class package - Class mainClass = JvmUtils.findMainClass(); - if (mainClass != null) { - String pkg = mainClass.getPackage().getName(); - if (!pkg.startsWith(SCB_PACKAGE)) { - scanPackags.add(pkg); - } - } - - // finish - System.setProperty(SCB_SCAN_PACKAGE, StringUtils.join(scanPackags, ",")); - } - public static ApplicationContext getContext() { return context; } @@ -93,11 +48,45 @@ public static T getBean(String name) { return (T) context.getBean(name); } + public static Map getBeansOfType(Class type) { + if (context == null) { + // for some test case + return Collections.emptyMap(); + } + return context.getBeansOfType(type); + } + + public static T getBean(Class type) { + if (context == null) { + // for some test case + return null; + } + return context.getBean(type); + } + + /** + * Get the implemented class of the given instance + * @param bean the instance to get implemented class from + * @return the implemented class (if the checked class is proxied, return the ultimate target class) + * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass + */ public static Class getImplClassFromBean(Object bean) { - if (TargetClassAware.class.isInstance(bean)) { - return ((TargetClassAware) bean).getTargetClass(); + return AopProxyUtils.ultimateTargetClass(bean); + } + + public static void addBeans(Class cls, List exists) { + if (context == null) { + return; } - return bean.getClass(); + for (T instance : exists) { + context.getAutowireCapableBeanFactory().autowireBean(instance); + } + for (T bean : context.getBeansOfType(cls).values()) { + if (bean.enabled()) { + exists.add(bean); + } + } + exists.sort(Comparator.comparingInt(SPIOrder::getOrder)); } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ClassLoaderScopeContext.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ClassLoaderScopeContext.java new file mode 100644 index 00000000000..c977b762fda --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ClassLoaderScopeContext.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.annotations.VisibleForTesting; + +/** +* class loader scope property is used when users run java-chassis in an class loader separated environment. +* +* For examples, deploy two war's to web container, or deploy two bundles in an OSGI container. +* +* Now java chassis not testing this feature carefully, but we will support users doing so. +* +* users who using this feature can feed back your problems in issues. +* +*/ +public class ClassLoaderScopeContext { + + private static final Map CLASS_LOADER_SCOPE_CONTEXT = new HashMap<>(); + + public static void setClassLoaderScopeProperty(String key, String value) { + CLASS_LOADER_SCOPE_CONTEXT.put(key, value); + } + + public static String getClassLoaderScopeProperty(String key) { + return CLASS_LOADER_SCOPE_CONTEXT.get(key); + } + + @VisibleForTesting + public static void clearClassLoaderScopeProperty() { + CLASS_LOADER_SCOPE_CONTEXT.clear(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ConditionWaiter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ConditionWaiter.java new file mode 100644 index 00000000000..4641ca3d233 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ConditionWaiter.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +public class ConditionWaiter { + private final AtomicReference dataReference; + + private final AtomicBoolean isComplete; + + private final long sleepDuration; + + private final TimeUnit timeUnit; + + private final ExecutorService executorService; + + public ConditionWaiter(T initialData, long sleepDuration, TimeUnit timeUnit) { + this.dataReference = new AtomicReference<>(initialData); + this.isComplete = new AtomicBoolean(false); + this.sleepDuration = sleepDuration; + this.timeUnit = timeUnit; + this.executorService = Executors.newSingleThreadExecutor(); + } + + public T waitForCompletion() { + while (!isComplete.get()) { + SleepUtil.sleep(sleepDuration, timeUnit); + } + return dataReference.get(); + } + + public void setData(T newData) { + dataReference.set(newData); + } + + public void executeTaskAsync(Callable task) { + CompletableFuture.supplyAsync(() -> { + try { + return task.call(); + } catch (Exception e) { + throw new RuntimeException("Task execution failed", e); + } + }, executorService).thenAccept(result -> { + setData(result); + isComplete.set(true); + }); + } + + public static class SleepUtil { + public static void sleep(long duration, TimeUnit timeUnit) { + try { + timeUnit.sleep(duration); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println("Thread was interrupted during sleep!"); + } + } + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FilePerm.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FilePerm.java index 7ffaa173aac..979841f1523 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FilePerm.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FilePerm.java @@ -84,7 +84,7 @@ private FilePerm() { */ public static final int FILE_PERM_MASK = 511; - private static AclEntryPermission[] permList = new AclEntryPermission[] { + private static final AclEntryPermission[] permList = new AclEntryPermission[] { AclEntryPermission.READ_DATA, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_NAMED_ATTRS, diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FortifyUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FortifyUtils.java index c88415ad754..63234af5ab4 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FortifyUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/FortifyUtils.java @@ -36,9 +36,9 @@ */ public final class FortifyUtils { - private static Method getMessageMethod; + private static final Method getMessageMethod; - private static Method printStackTraceMethod; + private static final Method printStackTraceMethod; static { try { @@ -83,7 +83,7 @@ public static String getErrorInfo(Throwable e) { } public static String getErrorInfo(Throwable e, boolean isPrintMsg) { - StringBuffer error = new StringBuffer(System.lineSeparator()); + StringBuilder error = new StringBuilder(System.lineSeparator()); error.append("Exception: ").append(e.getClass().getName()).append("; "); if (isPrintMsg) { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/GenericsUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/GenericsUtils.java new file mode 100644 index 00000000000..d872236082e --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/GenericsUtils.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +public final class GenericsUtils { + /** + * check if XXX.class is generic type. see TestGenericsUtils for details meaning. + * This method is provided for API compatibility for RestTemplate. Following code: + *

+ *{@code + * List>> response = consumers.getSCBRestTemplate() + * postForObject("/testListObjectParam", request, List.class); + * } + * + * should work for versions of 1.*. This is because java-chassis can read type info from swaggers. + *

+ * Start from 2.x, the best practise to write this code is to use ParameterizedTypeReference provided by RestTemplate + * exchange method. + */ + public static boolean isGenericResponseType(Type type) { + if (type instanceof ParameterizedType) { + return false; + } + if (type instanceof Class) { + return ((Class) type).getTypeParameters().length > 0; + } + return true; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/IOUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/IOUtils.java new file mode 100644 index 00000000000..ce57bbb4f84 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/IOUtils.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.io.Closeable; + +import org.apache.commons.lang3.StringUtils; + +public class IOUtils { + @SuppressWarnings("deprecation") + public static void closeQuietly(final Closeable closeable) { + org.apache.commons.io.IOUtils.closeQuietly(closeable); + } + + public static String anonymousPath(String path) { + if (StringUtils.isEmpty(path)) { + return path; + } + StringBuilder result = new StringBuilder(); + char separator = path.contains("/") ? '/' : '\\'; + char[] tokens = path.toCharArray(); + boolean byPass = false; + boolean fileName = true; + for (int i = tokens.length - 1; i >= 0; i--) { + if (tokens[i] == separator) { + fileName = false; + byPass = false; + result.append(separator); + continue; + } + if (!byPass || fileName) { + result.append(tokens[i]); + byPass = true; + } + } + return result.reverse().toString(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java index 52f9aa5b1fe..07269d6830f 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java @@ -21,33 +21,20 @@ import java.io.InputStream; import java.io.OutputStream; -import javax.servlet.http.Part; - -import org.apache.servicecomb.foundation.common.utils.json.JavaxServletPartDeserializer; -import org.apache.servicecomb.foundation.common.utils.json.JavaxServletPartSerializer; - import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; public final class JsonUtils { public static final ObjectMapper OBJ_MAPPER; + private static final ObjectMapper UNICODE_OBJ_MAPPER; static { - OBJ_MAPPER = new ObjectMapper(); - OBJ_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - OBJ_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); - - SimpleModule partDeserializeModule = new SimpleModule("partDeserializeModule", - new Version(0, 0, 1, null, "javax.servlet", "javax.servlet-api") - ); - partDeserializeModule.addSerializer(Part.class, new JavaxServletPartSerializer()); - partDeserializeModule.addDeserializer(Part.class, new JavaxServletPartDeserializer()); - OBJ_MAPPER.registerModule(partDeserializeModule); + OBJ_MAPPER = new RestObjectMapper(); + + UNICODE_OBJ_MAPPER = OBJ_MAPPER.copy(); + UNICODE_OBJ_MAPPER.enable(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature()); } private JsonUtils() { @@ -73,10 +60,18 @@ public static String writeValueAsString(Object value) throws JsonProcessingExcep return OBJ_MAPPER.writeValueAsString(value); } + public static String writeUnicodeValueAsString(Object value) throws JsonProcessingException { + return UNICODE_OBJ_MAPPER.writeValueAsString(value); + } + public static T convertValue(Object fromValue, Class toValueType) { return OBJ_MAPPER.convertValue(fromValue, toValueType); } + public static T convertValue(Object fromValue, JavaType toValueType) { + return OBJ_MAPPER.convertValue(fromValue, toValueType); + } + public static void writeValue(OutputStream out, Object value) throws IOException { OBJ_MAPPER.writeValue(out, value); } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java index e6315e9f316..6ed60ff0afc 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java @@ -22,6 +22,7 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,24 +40,55 @@ private JvmUtils() { /** * - * @return main class or null, never throw exception + * @return main class or null, never throw exception. + * Note that this method does not ensure that the scbMainClass can be returned correctly in the some scene. + */ + public static Class findMainClassByStackTrace() { + String mainClass = null; + StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); + if (stackTrace != null && stackTrace.length > 0) { + for (StackTraceElement stackTraceElement : stackTrace) { + if ("main".equals(stackTraceElement.getMethodName())) { + mainClass = stackTraceElement.getClassName(); + break; + } + } + } + if (StringUtils.isEmpty(mainClass)) { + LOGGER.info("Can't found main class by stackTrace."); + return null; + } + try { + Class cls = Class.forName(mainClass); + LOGGER.info("Found main class \"{}\" by stackTrace.", mainClass); + return cls; + } catch (Throwable e) { + LOGGER.warn("\"{}\" is not a valid class.", mainClass, e); + return null; + } + } + + /** + * + * @return main class or null, never throw exception. + * Note that this method does not ensure that the scbMainClass can be returned correctly in the some scene,like "mvn spring-boot:run". */ public static Class findMainClass() { + //Get the mainClass from the call stack + String mainClass = null; // 1.run with java -cp ...... // command is main class and args // 2.run with java -jar ...... // command is jar file name and args String command = System.getProperty(SUN_JAVA_COMMAND); - if (command == null || command.isEmpty()) { - return null; + if (StringUtils.isNotEmpty(command)) { + String mainClassOrJar = command.trim().split(" ")[0]; + mainClass = readFromJar(mainClassOrJar); } - - String mainClassOrJar = command.trim().split(" ")[0]; - String mainClass = readFromJar(mainClassOrJar); - if (mainClass == null || mainClass.isEmpty()) { + if (StringUtils.isEmpty(mainClass)) { + LOGGER.info("Can't found main class by manifest."); return null; } - try { Class cls = Class.forName(mainClass); LOGGER.info("Found main class \"{}\".", mainClass); @@ -78,6 +110,10 @@ private static String readFromJar(String mainClassOrJar) { URL url = new URL(manifestUri); try (InputStream inputStream = url.openStream()) { Manifest manifest = new Manifest(inputStream); + String startClass = manifest.getMainAttributes().getValue("Start-Class"); + if (StringUtils.isNotEmpty(startClass)) { + return startClass; + } return manifest.getMainAttributes().getValue("Main-Class"); } } catch (Throwable e) { @@ -103,4 +139,4 @@ public static ClassLoader correctClassLoader(ClassLoader classLoader) { public static ClassLoader findClassLoader() { return correctClassLoader(null); } -} \ No newline at end of file +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairEntry.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairEntry.java new file mode 100644 index 00000000000..be31df199a4 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairEntry.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.security.PrivateKey; +import java.security.PublicKey; + +public final class KeyPairEntry { + + private final PrivateKey privateKey; + + private final PublicKey publicKey; + + private final String publicKeyEncoded; + + public KeyPairEntry(PrivateKey privateKey, PublicKey publicKey, String publicKeyEncoded) { + this.privateKey = privateKey; + this.publicKey = publicKey; + this.publicKeyEncoded = publicKeyEncoded; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public String getPublicKeyEncoded() { + return publicKeyEncoded; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairUtils.java new file mode 100644 index 00000000000..91fed2ce1c8 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/KeyPairUtils.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KeyPairUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(KeyPairUtils.class); + + private static final String KEY_GENERATOR_ALGORITHM = LegacyPropertyFactory.getStringProperty( + "servicecomb.publicKey.accessControl.keyGeneratorAlgorithm", "RSA"); + + private static final String SIGN_ALG = LegacyPropertyFactory.getStringProperty( + "servicecomb.publicKey.accessControl.signAlgorithm", "SHA256withRSA"); + + private static final int KEY_SIZE = LegacyPropertyFactory.getIntProperty( + "servicecomb.publicKey.accessControl.keySize", 2048); + + private static final Base64.Encoder encoder = Base64.getEncoder(); + + private static final Base64.Decoder decoder = Base64.getDecoder(); + + private static KeyFactory kf = null; + + static { + + try { + kf = KeyFactory.getInstance(KEY_GENERATOR_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + LOGGER.error("init keyfactory error"); + } + } + + public static KeyPairEntry generateALGKeyPair() { + try { + KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(KEY_GENERATOR_ALGORITHM); + keyGenerator.initialize(KEY_SIZE, new SecureRandom()); + KeyPair keyPair = keyGenerator.generateKeyPair(); + PublicKey pubKey = keyPair.getPublic(); + PrivateKey privKey = keyPair.getPrivate(); + return new KeyPairEntry(privKey, pubKey, encoder.encodeToString(pubKey.getEncoded())); + } catch (NoSuchAlgorithmException e) { + LOGGER.error("generate rsa keypair failed"); + throw new IllegalStateException("perhaps error occurred on jre"); + } + } + + /** + * if has performance problem ,change Signature to ThreadLocal instance + */ + public static String sign(String content, PrivateKey privateKey) + throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { + Signature signature = Signature.getInstance(SIGN_ALG); + signature.initSign(privateKey); + signature.update(content.getBytes(StandardCharsets.UTF_8)); + byte[] signByte = signature.sign(); + return encoder.encodeToString(signByte); + } + + /** + * + * if has performance problem ,change Signature to ThreadLocal instance + * @param publicKey public key after base64 encode + * @param sign 签名 + * @param content original content + * @return verify result + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + * @throws InvalidKeyException + * @throws SignatureException + */ + public static boolean verify(String publicKey, String sign, String content) + throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { + if (null == kf) { + throw new NoSuchAlgorithmException(KEY_GENERATOR_ALGORITHM + " KeyFactory not available"); + } + byte[] bytes = decoder.decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); + PublicKey pubKey = kf.generatePublic(keySpec); + Signature signature = Signature.getInstance(SIGN_ALG); + signature.initVerify(pubKey); + signature.update(content.getBytes(StandardCharsets.UTF_8)); + return signature.verify(decoder.decode(sign)); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaMetafactoryUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaMetafactoryUtils.java index ef182091e4a..32ba59014e0 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaMetafactoryUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaMetafactoryUtils.java @@ -25,17 +25,65 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; - +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.bean.BoolGetter; +import org.apache.servicecomb.foundation.common.utils.bean.BoolSetter; +import org.apache.servicecomb.foundation.common.utils.bean.ByteGetter; +import org.apache.servicecomb.foundation.common.utils.bean.ByteSetter; +import org.apache.servicecomb.foundation.common.utils.bean.CharGetter; +import org.apache.servicecomb.foundation.common.utils.bean.CharSetter; +import org.apache.servicecomb.foundation.common.utils.bean.DoubleGetter; +import org.apache.servicecomb.foundation.common.utils.bean.DoubleSetter; +import org.apache.servicecomb.foundation.common.utils.bean.FloatGetter; +import org.apache.servicecomb.foundation.common.utils.bean.FloatSetter; import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.common.utils.bean.ShortGetter; +import org.apache.servicecomb.foundation.common.utils.bean.ShortSetter; + +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; public final class LambdaMetafactoryUtils { - private static Lookup lookup = MethodHandles.lookup(); + private static final Lookup LOOKUP = MethodHandles.lookup(); + + private static final Map, Class> GETTER_MAP = new HashMap<>(); + + private static final Map, Class> SETTER_MAP = new HashMap<>(); + + static { + initGetterSetterMap(); + } + + private static void initGetterSetterMap() { + GETTER_MAP.put(boolean.class, BoolGetter.class); + GETTER_MAP.put(byte.class, ByteGetter.class); + GETTER_MAP.put(char.class, CharGetter.class); + GETTER_MAP.put(short.class, ShortGetter.class); + GETTER_MAP.put(int.class, IntGetter.class); + GETTER_MAP.put(long.class, LongGetter.class); + GETTER_MAP.put(float.class, FloatGetter.class); + GETTER_MAP.put(double.class, DoubleGetter.class); + + SETTER_MAP.put(boolean.class, BoolSetter.class); + SETTER_MAP.put(byte.class, ByteSetter.class); + SETTER_MAP.put(char.class, CharSetter.class); + SETTER_MAP.put(short.class, ShortSetter.class); + SETTER_MAP.put(int.class, IntSetter.class); + SETTER_MAP.put(long.class, LongSetter.class); + SETTER_MAP.put(float.class, FloatSetter.class); + SETTER_MAP.put(double.class, DoubleSetter.class); + } private LambdaMetafactoryUtils() { } - protected static Method findAbstractMethod(Class functionalInterface) { + private static Method findAbstractMethod(Class functionalInterface) { for (Method method : functionalInterface.getMethods()) { if ((method.getModifiers() & Modifier.ABSTRACT) != 0) { return method; @@ -45,68 +93,149 @@ protected static Method findAbstractMethod(Class functionalInterface) { return null; } - public static T createLambda(Object instance, Method instanceMethod, Class functionalIntfCls) - throws Throwable { - Method intfMethod = findAbstractMethod(functionalIntfCls); - MethodHandle methodHandle = lookup.unreflect(instanceMethod); - - MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); - MethodType instanceMethodType = MethodType - .methodType(instanceMethod.getReturnType(), instanceMethod.getParameterTypes()); - CallSite callSite = LambdaMetafactory.metafactory( - lookup, - intfMethod.getName(), - MethodType.methodType(functionalIntfCls, instance.getClass()), - intfMethodType, - methodHandle, - instanceMethodType); - - //noinspection unchecked - return (T) callSite.getTarget().bindTo(instance).invoke(); + @SuppressWarnings("unchecked") + public static T createLambda(Object instance, Method instanceMethod, Class functionalIntfCls) { + try { + Method intfMethod = findAbstractMethod(functionalIntfCls); + MethodHandle methodHandle = LOOKUP.unreflect(instanceMethod); + + MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); + MethodType instanceMethodType = MethodType + .methodType(instanceMethod.getReturnType(), instanceMethod.getParameterTypes()); + CallSite callSite = LambdaMetafactory.metafactory( + LOOKUP, + intfMethod.getName(), + MethodType.methodType(functionalIntfCls, instance.getClass()), + intfMethodType, + methodHandle, + instanceMethodType); + + return (T) callSite.getTarget().bindTo(instance).invoke(); + } catch (Throwable e) { + throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e); + } + } + + @SuppressWarnings("unchecked") + public static T createLambda(Method instanceMethod, Class functionalIntfCls) { + if (Modifier.isNative(instanceMethod.getModifiers())) { + // fix "Failed to create lambda from public final native java.lang.Class java.lang.Object.getClass()" + return null; + } + try { + Method intfMethod = findAbstractMethod(functionalIntfCls); + MethodHandle methodHandle = LOOKUP.unreflect(instanceMethod); + + MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); + + // the return type of fluent setter is object instead of void, but we can assume the return type is void. it doesn't matter + MethodType instanceMethodType = MethodType + .methodType(intfMethod.getReturnType(), methodHandle.type().parameterList()); + CallSite callSite = LambdaMetafactory.metafactory( + LOOKUP, + intfMethod.getName(), + MethodType.methodType(functionalIntfCls), + intfMethodType, + methodHandle, + instanceMethodType); + + return (T) callSite.getTarget().invoke(); + } catch (Throwable e) { + throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e); + } } - public static T createLambda(Method instanceMethod, Class functionalIntfCls) - throws Throwable { - Method intfMethod = findAbstractMethod(functionalIntfCls); - MethodHandle methodHandle = lookup.unreflect(instanceMethod); - - MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); - MethodType instanceMethodType = methodHandle.type(); - CallSite callSite = LambdaMetafactory.metafactory( - lookup, - intfMethod.getName(), - MethodType.methodType(functionalIntfCls), - intfMethodType, - methodHandle, - instanceMethodType); - - //noinspection unchecked - return (T) callSite.getTarget().invoke(); + public static T createGetter(Method getMethod) { + Class getterCls = GETTER_MAP.getOrDefault(getMethod.getReturnType(), Getter.class); + return createLambda(getMethod, getterCls); } - public static Getter createGetter(Method getMethod) throws Throwable { + @SuppressWarnings("unchecked") + public static Getter createObjectGetter(Method getMethod) { return createLambda(getMethod, Getter.class); } + public static Getter createObjectGetter(BeanPropertyDefinition propertyDefinition) { + if (propertyDefinition.hasGetter()) { + return createObjectGetter(propertyDefinition.getGetter().getAnnotated()); + } + + return createGetter(propertyDefinition.getField().getAnnotated()); + } + // slower than reflect directly - public static Getter createGetter(Field field) { - field.setAccessible(true); + @SuppressWarnings("unchecked") + public static Getter createGetter(Field field) { + checkAccess(field); return instance -> { try { - return field.get(instance); + return (F) field.get(instance); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }; } - public static Setter createSetter(Method setMethod) throws Throwable { - return createLambda(setMethod, Setter.class); + private static void checkAccess(Field field) { + // This check is not accurate. Most of time package visible and protected access can be ignored, so simply do this. + if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) { + throw new IllegalStateException( + String.format("Can not access field, a public field or accessor is required." + + "Declaring class is %s, field is %s", + field.getDeclaringClass().getName(), + field.getName())); + } + } + + public static T createSetter(Method setMethod) { + Class setterCls = SETTER_MAP.getOrDefault(setMethod.getParameterTypes()[0], Setter.class); + return createLambda(setMethod, setterCls); + } + + // just for avoid java 9~11 bug: https://bugs.openjdk.java.net/browse/JDK-8174983 + // otherwise can be replaced by: createLambda(setMethod, Setter.class) + @SuppressWarnings("unchecked") + public static Setter createObjectSetter(Method setMethod) { + Object setter = createSetter(setMethod); + if (setter instanceof BoolSetter) { + return (Instance, value) -> ((BoolSetter) setter).set(Instance, (boolean) value); + } + if (setter instanceof ByteSetter) { + return (Instance, value) -> ((ByteSetter) setter).set(Instance, (byte) value); + } + if (setter instanceof CharSetter) { + return (Instance, value) -> ((CharSetter) setter).set(Instance, (char) value); + } + if (setter instanceof DoubleSetter) { + return (Instance, value) -> ((DoubleSetter) setter).set(Instance, (double) value); + } + if (setter instanceof FloatSetter) { + return (Instance, value) -> ((FloatSetter) setter).set(Instance, (float) value); + } + if (setter instanceof IntSetter) { + return (Instance, value) -> ((IntSetter) setter).set(Instance, (int) value); + } + if (setter instanceof LongSetter) { + return (Instance, value) -> ((LongSetter) setter).set(Instance, (long) value); + } + if (setter instanceof ShortSetter) { + return (Instance, value) -> ((ShortSetter) setter).set(Instance, (short) value); + } + + return (Setter) setter; + } + + public static Setter createObjectSetter(BeanPropertyDefinition propertyDefinition) { + if (propertyDefinition.hasSetter()) { + return createObjectSetter(propertyDefinition.getSetter().getAnnotated()); + } + + return createSetter(propertyDefinition.getField().getAnnotated()); } // slower than reflect directly - public static Setter createSetter(Field field) { - field.setAccessible(true); + public static Setter createSetter(Field field) { + checkAccess(field); return (instance, value) -> { try { field.set(instance, value); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaUtils.java new file mode 100644 index 00000000000..09265d57e2e --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/LambdaUtils.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.util.function.Consumer; + +public class LambdaUtils { + + public static Consumer ignoreException(Consumer consumer) { + return item -> { + try { + consumer.accept(item); + } catch (Throwable e) { + } + }; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/Log4jUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/Log4jUtils.java deleted file mode 100644 index 9e95fcab31a..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/Log4jUtils.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.utils; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.stream.Collectors; - -import org.apache.commons.io.FileUtils; -import org.apache.log4j.PropertyConfigurator; -import org.apache.servicecomb.foundation.common.config.impl.PropertiesLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; - -public final class Log4jUtils { - - private static final String MERGED_FILE = "merged.log4j.properties"; - - public static final String OUTPUT_CONFIG_ENABLED = "log4j.logger.outputConfig.enabled"; - - public static final String OUTPUT_CONFIG_ENABLED_TRUE = "true"; - - // spring boot的包装中会重复调用init,需要规避一下 - private static boolean inited = false; - - private static final Object LOCK = new Object(); - - private Log4jUtils() { - } - - public static void init() throws Exception { - init(Arrays.asList("classpath*:config/base/log4j.properties", "classpath*:config/log4j.properties")); - } - - public static void init(String locationPattern) throws Exception { - init(Arrays.asList(locationPattern)); - } - - public static void init(List locationPatterns) throws Exception { - if (inited) { - return; - } - - synchronized (LOCK) { - if (inited) { - return; - } - - PropertiesLoader loader = new PropertiesLoader(locationPatterns); - Properties properties = loader.load(); - if (properties.isEmpty()) { - throw new Exception("can not find resource " + locationPatterns); - } - - PropertyConfigurator.configure(properties); - inited = true; - - if (OUTPUT_CONFIG_ENABLED_TRUE.equals( - properties.getProperty(OUTPUT_CONFIG_ENABLED, OUTPUT_CONFIG_ENABLED_TRUE))) { - // If the property file with the highest priority is on a hard disk(not in a jar package) - // and we have write access, output the merged property file for the purpose of debugging - outputFile(loader.getFoundResList(), properties); - } - } - } - - private static void outputFile(List resList, - Properties properties) throws IOException { - //不可以作为class的变量初始化,因为在outputFile前一句log机制才初始化完成的 - //must create org.slf4j.impl.Log4jLoggerAdapter by LoggerExtFactory - //in order to redefine Log4jLoggerAdapter before other class load Log4jLoggerAdapter - Logger log = LoggerFactory.getLogger(Log4jUtils.class); - - String content = genFileContext(resList, properties); - //不打印配置信息,有密钥等敏感信息 - //log.info("Merged log4j:\n{}", content); - - Resource res = resList.get(resList.size() - 1); - // 不能直接使用res.getFile,因为jar里面的资源,getFile会抛异常 - File file = new File(res.getURL().getPath()); - if (!file.getParentFile().canWrite()) { - log.error("Can not output {},because can not write to directory of file {}", - MERGED_FILE, - res.getURL().getPath()); - return; - } - - File mergedfile = new File(res.getFile().getParentFile(), MERGED_FILE); - FileUtils.writeStringToFile(mergedfile, content); - log.info("Write merged log4j config file to {}", mergedfile.getAbsolutePath()); - } - - private static String genFileContext(List resList, Properties properties) throws IOException { - List> entryList = properties.entrySet() - .stream() - .sorted(new Comparator>() { - @Override - public int compare(Entry o1, Entry o2) { - return o1.getKey().toString().compareTo(o2.getKey().toString()); - } - }) - .collect(Collectors.toList()); - - StringBuilder sb = new StringBuilder(); - for (Resource res : resList) { - sb.append("#").append(res.getURL().getPath()).append("\n"); - } - for (Entry entry : entryList) { - sb.append(entry.getKey()).append("=").append(entry.getValue()).append("\n"); - } - return sb.toString(); - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java new file mode 100644 index 00000000000..25bf4cb4610 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014 Red Hat, Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * The Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php + * + * You may elect to redistribute this code under either of these licenses. + * + */ + +/* + * Forked from https://github.com/vert-x3/vertx-web/blob/927ed057ddc028eb09a168db621de3d72fd85ed4/vertx-web/src/main/java/io/vertx/ext/web/impl/Utils.java + * Because we uses getSortedAcceptableMimeTypes method which is removed by vertx. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.regex.Pattern; + +public class MimeTypesUtils { + private static final Pattern COMMA_SPLITTER = Pattern.compile(" *, *"); + + private static final Pattern SEMICOLON_SPLITTER = Pattern.compile(" *; *"); + + private static final Pattern EQUAL_SPLITTER = Pattern.compile(" *= *"); + + private static final Comparator ACCEPT_X_COMPARATOR = (o1, o2) -> Float.compare(getQuality(o2), getQuality(o1)); + + private static float getQuality(String s) { + if (s == null) { + return 0; + } + + String[] params = SEMICOLON_SPLITTER.split(s); + for (int i = 1; i < params.length; i++) { + String[] q = EQUAL_SPLITTER.split(params[1]); + if ("q".equals(q[0])) { + return Float.parseFloat(q[1]); + } + } + return 1; + } + + public static List getSortedAcceptableMimeTypes(String acceptHeader) { + // accept anything when accept is not present + if (acceptHeader == null) { + return Collections.emptyList(); + } + + // parse + String[] items = COMMA_SPLITTER.split(acceptHeader); + // sort on quality + Arrays.sort(items, ACCEPT_X_COMPARATOR); + + List list = new ArrayList<>(items.length); + + for (String item : items) { + // find any ; e.g.: "application/json;q=0.8" + int space = item.indexOf(';'); + + if (space != -1) { + list.add(item.substring(0, space)); + } else { + list.add(item); + } + } + + return list; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MuteExceptionUtil.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MuteExceptionUtil.java new file mode 100644 index 00000000000..334ae13808f --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/MuteExceptionUtil.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MuteExceptionUtil { + + public interface FunctionWithException { + R apply(T t) throws Exception; + } + + public interface FunctionWithDoubleParam { + R apply(T1 t1, T2 t2) throws Exception; + } + + private static final Logger LOGGER = LoggerFactory.getLogger(MuteExceptionUtil.class); + + public static class MuteExceptionUtilBuilder { + + private String logMessage; + + private Object[] customMessageParams; + + public MuteExceptionUtilBuilder withLog(String message, Object... params) { + this.logMessage = message; + this.customMessageParams = params; + return this; + } + + private String getLogMessage(String defaultMessage) { + return logMessage != null ? logMessage : defaultMessage; + } + + public R executeFunction(FunctionWithException function, T t) { + try { + return function.apply(t); + } catch (Exception e) { + LOGGER.error(getLogMessage("execute Function failure..."), customMessageParams, e); + return null; + } + } + + public T executeSupplier(Supplier supplier) { + try { + return supplier.get(); + } catch (Exception e) { + LOGGER.error(getLogMessage("execute Supplier failure..."), customMessageParams, e); + return null; + } + } + + public T executeCompletableFuture(CompletableFuture completableFuture) { + try { + return completableFuture.get(); + } catch (Exception e) { + LOGGER.error(getLogMessage("execute CompletableFuture failure..."), customMessageParams, e); + return null; + } + } + + public R executeFunctionWithDoubleParam(FunctionWithDoubleParam function, T1 t1, T2 t2) { + try { + return function.apply(t1, t2); + } catch (Exception e) { + LOGGER.error(getLogMessage("execute FunctionWithDoubleParam failure..."), customMessageParams, e); + return null; + } + } + } + + public static MuteExceptionUtilBuilder builder() { + return new MuteExceptionUtilBuilder(); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/PartUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/PartUtils.java new file mode 100644 index 00000000000..61bbf442e11 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/PartUtils.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.io.File; +import java.io.InputStream; + +import org.apache.servicecomb.foundation.common.part.FilePart; +import org.apache.servicecomb.foundation.common.part.InputStreamPart; +import org.apache.servicecomb.foundation.common.part.ResourcePart; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; + +import jakarta.servlet.http.Part; + +public final class PartUtils { + private PartUtils() { + } + + public static Part getSinglePart(String name, Object value) { + if (value == null) { + return null; + } + + if (value instanceof Part) { + return (Part) value; + } + + if (value instanceof InputStream) { + return new InputStreamPart(name, (InputStream) value); + } + + if (value instanceof Resource) { + return new ResourcePart(name, (Resource) value); + } + + if (value instanceof File) { + return new FilePart(name, (File) value); + } + + if (value instanceof byte[]) { + return new ResourcePart(name, new ByteArrayResource((byte[]) value)); + } + + throw new IllegalStateException( + String.format("File input parameter of %s could be %s / %s / %s / byte[] or %s, but got %s.", + name, + Part.class.getName(), + InputStream.class.getName(), + Resource.class.getName(), + File.class.getName(), + value.getClass().getName())); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAKeyPairEntry.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAKeyPairEntry.java deleted file mode 100644 index dd1b442a100..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAKeyPairEntry.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.common.utils; - -import java.security.PrivateKey; -import java.security.PublicKey; - -public final class RSAKeyPairEntry { - - private PrivateKey privateKey; - - private PublicKey publicKey; - - private String publicKeyEncoded; - - public RSAKeyPairEntry(PrivateKey privateKey, PublicKey publicKey, String publicKeyEncoded) { - this.privateKey = privateKey; - this.publicKey = publicKey; - this.publicKeyEncoded = publicKeyEncoded; - } - - public PrivateKey getPrivateKey() { - return privateKey; - } - - public PublicKey getPublicKey() { - return publicKey; - } - - public String getPublicKeyEncoded() { - return publicKeyEncoded; - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAUtils.java deleted file mode 100644 index 0cded9129c4..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RSAUtils.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.common.utils; - -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RSAUtils { - - private final static Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class); - - private final static String RSA_ALG = "RSA"; - - private final static String SIGN_ALG = "SHA256withRSA"; - - private final static int KEY_SIZE = 2048; - - private static Base64.Encoder encoder = Base64.getEncoder(); - - private static Base64.Decoder decoder = Base64.getDecoder(); - - private static KeyFactory kf = null; - - static { - - try { - kf = KeyFactory.getInstance(RSA_ALG); - } catch (NoSuchAlgorithmException e) { - LOGGER.error("init keyfactory error"); - } - } - - public static RSAKeyPairEntry generateRSAKeyPair() { - try { - KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(RSA_ALG); - keyGenerator.initialize(KEY_SIZE, new SecureRandom()); - KeyPair keyPair = keyGenerator.generateKeyPair(); - PublicKey pubKey = keyPair.getPublic(); - PrivateKey privKey = keyPair.getPrivate(); - return new RSAKeyPairEntry(privKey, pubKey, encoder.encodeToString(pubKey.getEncoded())); - } catch (NoSuchAlgorithmException e) { - LOGGER.error("generate rsa keypair faild"); - throw new IllegalStateException("perhaps error occurred on jre"); - } - } - - /** - * if has performance problem ,change Signature to ThreadLocal instance - */ - public static String sign(String content, PrivateKey privateKey) - throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException { - Signature signature = Signature.getInstance(SIGN_ALG); - signature.initSign(privateKey); - signature.update(content.getBytes()); - byte[] signByte = signature.sign(); - return encoder.encodeToString(signByte); - } - - /** - * - * if has performance problem ,change Signature to ThreadLocal instance - * @param publicKey public key after base64 encode - * @param sign 签名 - * @param content original content - * @return verify result - * @throws NoSuchAlgorithmException - * @throws InvalidKeySpecException - * @throws InvalidKeyException - * @throws SignatureException - */ - public static boolean verify(String publicKey, String sign, String content) - throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { - if (null == kf) { - throw new NoSuchAlgorithmException(RSA_ALG + " KeyFactory not available"); - } - byte[] bytes = decoder.decode(publicKey); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); - PublicKey pubKey = kf.generatePublic(keySpec); - Signature signature = Signature.getInstance(SIGN_ALG); - signature.initVerify(pubKey); - signature.update(content.getBytes()); - return signature.verify(decoder.decode(sign)); - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ReflectUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ReflectUtils.java index 921ceae4999..1b4d3f1ca1a 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ReflectUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ReflectUtils.java @@ -17,20 +17,19 @@ package org.apache.servicecomb.foundation.common.utils; +import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import org.apache.commons.lang3.reflect.FieldUtils; import org.springframework.util.ReflectionUtils; -public final class ReflectUtils { - private static final Field MODIFIERS_FIELD = - ReflectionUtils.findField(Field.class, "modifiers"); - - static { - MODIFIERS_FIELD.setAccessible(true); - } +import com.google.common.reflect.TypeToken; +public final class ReflectUtils { private ReflectUtils() { } @@ -42,9 +41,6 @@ public static void setField(Object instance, String fieldName, Object value) { public static void setField(Class cls, Object instance, String fieldName, Object value) { Field field = ReflectionUtils.findField(cls, fieldName); try { - if ((field.getModifiers() & Modifier.FINAL) != 0) { - MODIFIERS_FIELD.setInt(field, field.getModifiers() & ~Modifier.FINAL); - } field.setAccessible(true); field.set(instance, value); } catch (Exception e) { @@ -62,4 +58,39 @@ public static Method findMethod(Class cls, String methodName) { return null; } + + @SuppressWarnings("unchecked") + public static Class getFieldArgument(Class genericCls, String fieldName) { + try { + Type generic = FieldUtils.getField(genericCls, fieldName).getGenericType(); + TypeToken token = TypeToken.of(genericCls).resolveType(generic); + Type fieldType = token.getType(); + Type argument = ((ParameterizedType) fieldType).getActualTypeArguments()[0]; + if (argument instanceof GenericArrayType) { + return (Class) TypeToken.of(argument).getRawType(); + } + + return (Class) argument; + } catch (Throwable e) { + throw new IllegalStateException("Failed to get generic argument.", e); + } + } + + @SuppressWarnings("unchecked") + public static T constructArrayType(Class cls) { + return (T) Array.newInstance(cls, 0).getClass(); + } + + public static Class getClassByName(String clsName) { + try { + return Class.forName(clsName); + } catch (ClassNotFoundException e) { + ClassLoader classLoader = JvmUtils.correctClassLoader(null); + try { + return classLoader.loadClass(clsName); + } catch (ClassNotFoundException e1) { + return null; + } + } + } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ResourceUtil.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ResourceUtil.java new file mode 100644 index 00000000000..037900d9a7a --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/ResourceUtil.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public final class ResourceUtil { + + private ResourceUtil() { + } + + /** + * Search the specified location in classpath, and returns the resources with the specified suffix. + */ + public static List findResourcesBySuffix(String resourceLocation, String fileNameSuffix) + throws IOException, URISyntaxException { + return findResources(resourceLocation, path -> path.toString().endsWith(fileNameSuffix)); + } + + /** + * Search the specified location in classpath, all the resources found are collected and returned. + */ + public static List findResources(String resourceLocation) throws IOException, URISyntaxException { + return findResources(resourceLocation, p -> true); + } + + /** + * Search the specified location in classpath, which can be a directory or the exact file location, + * and returns a list of URIs pointing to the matched resources. + * + * @param resourceLocation in which location the resources are searched + * @param filter to pick out those matched resources + */ + public static List findResources(String resourceLocation, Predicate filter) + throws IOException, URISyntaxException { + ArrayList result = new ArrayList<>(); + + Enumeration dirURLs = JvmUtils.findClassLoader().getResources(resourceLocation); + while (dirURLs.hasMoreElements()) { + URL dirURL = dirURLs.nextElement(); + if ("file".equals(dirURL.getProtocol())) { + Path dirPath = Paths.get(dirURL.toURI()); + collectResourcesFromPath(dirPath, filter, result); + continue; + } + + try (FileSystem fileSystem = FileSystems.newFileSystem(dirURL.toURI(), Collections.emptyMap())) { + Path dirPath = fileSystem.getPath(resourceLocation); + if (Files.exists(dirPath)) { + // normal jar files like : xxx.jar!/resourceLocation + collectResourcesFromPath(dirPath, filter, result); + } else { + // spring boot fat jar files like : xxx.jar!/BOOT-INF/!classes/resourceLocation + dirPath = fileSystem.getPath("BOOT-INF", "classes", resourceLocation); + if (Files.exists(dirPath)) { + collectResourcesFromPath(dirPath, filter, result); + } + } + } + } + + return result; + } + + private static void collectResourcesFromPath(Path path, Predicate filter, Collection resources) + throws IOException { + try (Stream dirContentTraversalStream = Files.walk(path)) { + dirContentTraversalStream + .filter(filter) + .map(Path::toUri) + .forEach(resources::add); + } + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RestObjectMapper.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RestObjectMapper.java new file mode 100644 index 00000000000..edc6095878f --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RestObjectMapper.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser.Feature; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import io.vertx.core.json.JsonObject; + +public class RestObjectMapper extends AbstractRestObjectMapper { + + private static class JsonObjectSerializer extends JsonSerializer { + @Override + public void serialize(JsonObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + jgen.writeObject(value.getMap()); + } + } + + private static final long serialVersionUID = -8158869347066287575L; + + private static final JavaType STRING_JAVA_TYPE = TypeFactory.defaultInstance().constructType(String.class); + + public RestObjectMapper() { + super(); + getFactory().disable(Feature.AUTO_CLOSE_SOURCE); + // Enable features that can tolerance errors and not enable those make more constraints for compatible reasons. + // Developers can use validation api to do more checks. + disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + // no view annotations shouldn't be included in JSON + this._deserializationConfig = this._deserializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION); + this._serializationConfig = this._serializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION); + disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); + enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); + + SimpleModule module = new SimpleModule(); + // custom types + module.addSerializer(JsonObject.class, new JsonObjectSerializer()); + registerModule(module); + registerModule(new JavaTimeModule()); + } + + public RestObjectMapper(RestObjectMapper src) { + super(src); + } + @Override + public RestObjectMapper copy() { + this._checkInvalidCopy(RestObjectMapper.class); + return new RestObjectMapper(this); + } + + @Override + public String convertToString(Object value) throws Exception { + return convertValue(value, STRING_JAVA_TYPE); + } + + @Override + @SuppressWarnings("unchecked") + public T convertValue(Object fromValue, JavaType toValueType) throws IllegalArgumentException { + // After jackson 2.10.*, will by pass the following check when convert value. But this is useful + // for java chassis applications and do not need to convert to keep performance. So add the check here.(conversion is + // not necessary and will cause some trouble in some user applications that depend on this) + if (fromValue == null) { + return null; + } else { + Class targetType = toValueType.getRawClass(); + if (targetType != Object.class + && !toValueType.hasGenericTypes() + && targetType.isAssignableFrom(fromValue.getClass())) { + return (T) fromValue; + } + } + + return super.convertValue(fromValue, toValueType); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RollingFileAppenderExt.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RollingFileAppenderExt.java deleted file mode 100644 index 70dd285f62c..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/RollingFileAppenderExt.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.utils; - -import java.io.File; -import java.io.IOException; - -import org.apache.log4j.RollingFileAppender; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.spi.LoggingEvent; - -/** - * 扩展增加2个功能:1. 设置文件权限;2. 文件删除后重建。 - */ -public class RollingFileAppenderExt extends RollingFileAppender { - private File currentFile; - - private boolean append; - - private String logPermission; - - public String getLogPermission() { - return logPermission; - } - - public void setLogPermission(String logPermission) { - this.logPermission = logPermission; - } - - @Override - public void setFile(String file) { - super.setFile(file); - } - - @Override - public void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { - this.append = append; - currentFile = new File(fileName); - createCurrentFile(); - super.setFile(fileName, append, bufferedIO, bufferSize); - } - - @Override - protected void subAppend(LoggingEvent event) { - // create a new file when file deleted - if (!currentFile.exists()) { - try { - setFile(fileName, append, bufferedIO, bufferSize); - } catch (IOException e) { - LogLog.error("", e); - } - } - super.subAppend(event); - } - - protected void createCurrentFile() throws IOException { - if (!currentFile.exists()) { - File parent = currentFile.getParentFile(); - if (parent != null && !parent.exists()) { - parent.mkdirs(); - } - currentFile.createNewFile(); - } - FilePerm.setFilePerm(currentFile, logPermission); - } -} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/StringBuilderUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/StringBuilderUtils.java index 0a57a983870..08a723eb7ec 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/StringBuilderUtils.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/StringBuilderUtils.java @@ -23,4 +23,10 @@ private StringBuilderUtils() { public static void appendLine(StringBuilder sb, String fmt, Object... args) { sb.append(String.format(fmt, args)).append("\n"); } + + public static StringBuilder deleteLast(StringBuilder sb, int count) { + int min = Math.min(sb.length(), count); + sb.setLength(sb.length() - min); + return sb; + } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TimeUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TimeUtils.java new file mode 100644 index 00000000000..476c3901c0b --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TimeUtils.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.time.Clock; + +public final class TimeUtils { + private TimeUtils() { + } + + private static final Clock systemDefaultZoneClock = Clock.systemDefaultZone(); + + /** + * @return Singleton system default zone clock + */ + public static Clock getSystemDefaultZoneClock() { + return systemDefaultZoneClock; + } + + +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TypesUtil.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TypesUtil.java new file mode 100644 index 00000000000..5f72a1db26b --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/TypesUtil.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * common utils to convert java types. + */ +public class TypesUtil { + private static final Map, Class> PRIMITIVE_TO_WRAPPER = new HashMap<>(); + + static { + PRIMITIVE_TO_WRAPPER.put(byte.class, Byte.class); + PRIMITIVE_TO_WRAPPER.put(short.class, Short.class); + PRIMITIVE_TO_WRAPPER.put(int.class, Integer.class); + PRIMITIVE_TO_WRAPPER.put(long.class, Long.class); + PRIMITIVE_TO_WRAPPER.put(float.class, Float.class); + PRIMITIVE_TO_WRAPPER.put(double.class, Double.class); + PRIMITIVE_TO_WRAPPER.put(boolean.class, Boolean.class); + PRIMITIVE_TO_WRAPPER.put(char.class, Character.class); + } + + + private static final Map, Class> WRAPPER_TO_PRIMITIVE = new HashMap<>(); + + static { + WRAPPER_TO_PRIMITIVE.put(Byte.class, byte.class); + WRAPPER_TO_PRIMITIVE.put(Short.class, short.class); + WRAPPER_TO_PRIMITIVE.put(Integer.class, int.class); + WRAPPER_TO_PRIMITIVE.put(Long.class, long.class); + WRAPPER_TO_PRIMITIVE.put(Float.class, float.class); + WRAPPER_TO_PRIMITIVE.put(Double.class, double.class); + WRAPPER_TO_PRIMITIVE.put(Boolean.class, boolean.class); + WRAPPER_TO_PRIMITIVE.put(Character.class, char.class); + } + + public static final JavaType PRIMITIVE_BYTE = TypeFactory.defaultInstance().constructType(byte.class); + + public static final JavaType PRIMITIVE_SHORT = TypeFactory.defaultInstance().constructType(short.class); + + public static final JavaType PRIMITIVE_INT = TypeFactory.defaultInstance().constructType(int.class); + + public static final JavaType PRIMITIVE_LONG = TypeFactory.defaultInstance().constructType(long.class); + + public static final JavaType PRIMITIVE_FLOAT = TypeFactory.defaultInstance().constructType(float.class); + + public static final JavaType PRIMITIVE_DOUBLE = TypeFactory.defaultInstance().constructType(double.class); + + public static final JavaType PRIMITIVE_BOOLEAN = TypeFactory.defaultInstance().constructType(boolean.class); + + public static final JavaType PRIMITIVE_CHAR = TypeFactory.defaultInstance().constructType(char.class); + + public static final JavaType PRIMITIVE_WRAPPER_BYTE = TypeFactory.defaultInstance().constructType(Byte.class); + + public static final JavaType PRIMITIVE_WRAPPER_SHORT = TypeFactory.defaultInstance().constructType(Short.class); + + public static final JavaType PRIMITIVE_WRAPPER_INT = TypeFactory.defaultInstance().constructType(Integer.class); + + public static final JavaType PRIMITIVE_WRAPPER_LONG = TypeFactory.defaultInstance().constructType(Long.class); + + public static final JavaType PRIMITIVE_WRAPPER_FLOAT = TypeFactory.defaultInstance().constructType(Float.class); + + public static final JavaType PRIMITIVE_WRAPPER_DOUBLE = TypeFactory.defaultInstance().constructType(Double.class); + + public static final JavaType PRIMITIVE_WRAPPER_BOOLEAN = TypeFactory.defaultInstance().constructType(Boolean.class); + + public static final JavaType PRIMITIVE_WRAPPER_CHAR = TypeFactory.defaultInstance().constructType(Character.class); + + + private static final Map PRIMITIVE_TO_WRAPPER_JAVATYPE = new HashMap<>(); + + static { + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_BYTE, PRIMITIVE_WRAPPER_BYTE); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_SHORT, PRIMITIVE_WRAPPER_SHORT); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_INT, PRIMITIVE_WRAPPER_INT); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_LONG, PRIMITIVE_WRAPPER_LONG); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_FLOAT, PRIMITIVE_WRAPPER_FLOAT); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_DOUBLE, PRIMITIVE_WRAPPER_DOUBLE); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_BOOLEAN, PRIMITIVE_WRAPPER_BOOLEAN); + PRIMITIVE_TO_WRAPPER_JAVATYPE.put(PRIMITIVE_CHAR, PRIMITIVE_WRAPPER_CHAR); + } + + private static final Map WRAPPER_TO_PRIMITIVE_JAVATYPE = new HashMap<>(); + + static { + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_BYTE, PRIMITIVE_BYTE); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_SHORT, PRIMITIVE_SHORT); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_INT, PRIMITIVE_INT); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_LONG, PRIMITIVE_LONG); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_FLOAT, PRIMITIVE_FLOAT); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_DOUBLE, PRIMITIVE_DOUBLE); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_BOOLEAN, PRIMITIVE_BOOLEAN); + WRAPPER_TO_PRIMITIVE_JAVATYPE.put(PRIMITIVE_WRAPPER_CHAR, PRIMITIVE_CHAR); + } + + public static Class primitiveTypeToWrapper(Class primitiveType) { + return PRIMITIVE_TO_WRAPPER.get(primitiveType); + } + + public static Class wrapperTypeToPrimitive(Class wrapperType) { + return WRAPPER_TO_PRIMITIVE.get(wrapperType); + } + + public static JavaType primitiveJavaTypeToWrapper(JavaType primitiveType) { + return PRIMITIVE_TO_WRAPPER_JAVATYPE.get(primitiveType); + } + + public static JavaType wrapperJavaTypeToPrimitive(JavaType wrapperType) { + return WRAPPER_TO_PRIMITIVE_JAVATYPE.get(wrapperType); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArrayGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArrayGetter.java new file mode 100644 index 00000000000..6bdda6ea66f --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArrayGetter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public class ArrayGetter implements Getter { + private final int idx; + + public ArrayGetter(int idx) { + this.idx = idx; + } + + @Override + public T get(T[] instance) { + return instance[idx]; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArraySetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArraySetter.java new file mode 100644 index 00000000000..4df87f8a273 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ArraySetter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public class ArraySetter implements Setter { + private final int idx; + + public ArraySetter(int idx) { + this.idx = idx; + } + + @Override + public void set(T[] instance, T value) { + instance[idx] = value; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolGetter.java new file mode 100644 index 00000000000..11e0a3c753e --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface BoolGetter { + boolean get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolSetter.java new file mode 100644 index 00000000000..8cbacb56ca7 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/BoolSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface BoolSetter { + void set(T instance, boolean value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteGetter.java new file mode 100644 index 00000000000..c4bab67d346 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface ByteGetter { + byte get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteSetter.java new file mode 100644 index 00000000000..952d06b0723 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ByteSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface ByteSetter { + void set(T instance, byte value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharGetter.java new file mode 100644 index 00000000000..2e09c988701 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface CharGetter { + char get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharSetter.java new file mode 100644 index 00000000000..e022fa34354 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/CharSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface CharSetter { + void set(T instance, char value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleGetter.java new file mode 100644 index 00000000000..5349c4ccbb3 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface DoubleGetter { + double get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleSetter.java new file mode 100644 index 00000000000..c39a8024502 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/DoubleSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface DoubleSetter { + void set(T instance, double value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatGetter.java new file mode 100644 index 00000000000..405d233a8bf --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface FloatGetter { + float get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatSetter.java new file mode 100644 index 00000000000..7d4b75a34b9 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/FloatSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface FloatSetter { + void set(T instance, float value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Getter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Getter.java index 15ea1d9cb6e..1fa0fb22947 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Getter.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Getter.java @@ -16,6 +16,6 @@ */ package org.apache.servicecomb.foundation.common.utils.bean; -public interface Getter { - Object get(Object instance); +public interface Getter { + F get(C instance); } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntGetter.java new file mode 100644 index 00000000000..b7aaf2991e8 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface IntGetter { + int get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntSetter.java new file mode 100644 index 00000000000..0a0425e3ca1 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/IntSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface IntSetter { + void set(T instance, int value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongGetter.java new file mode 100644 index 00000000000..8f4d68dd3e7 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface LongGetter { + long get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongSetter.java new file mode 100644 index 00000000000..a0ba4f9e723 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/LongSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface LongSetter { + void set(T instance, long value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapGetter.java index 0766e9959ab..84039d3595a 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapGetter.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapGetter.java @@ -18,16 +18,15 @@ import java.util.Map; -public class MapGetter implements Getter { - private Object key; +public class MapGetter implements Getter, V> { + private final K key; - public MapGetter(Object key) { + public MapGetter(K key) { this.key = key; } - @SuppressWarnings("unchecked") @Override - public Object get(Object instance) { - return ((Map) instance).get(key); + public V get(Map instance) { + return instance.get(key); } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapSetter.java index 216a0510fc1..872d00a63a4 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapSetter.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/MapSetter.java @@ -18,16 +18,15 @@ import java.util.Map; -public class MapSetter implements Setter { - private Object key; +public class MapSetter implements Setter, V> { + private final K key; - public MapSetter(Object key) { + public MapSetter(K key) { this.key = key; } - @SuppressWarnings("unchecked") @Override - public void set(Object instance, Object value) { - ((Map) instance).put(key, value); + public void set(Map instance, V value) { + instance.put(key, value); } } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Setter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Setter.java index c612b6922ff..bf79d2c8439 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Setter.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/Setter.java @@ -16,6 +16,6 @@ */ package org.apache.servicecomb.foundation.common.utils.bean; -public interface Setter { - void set(Object instance, Object value); +public interface Setter { + void set(C instance, F value); } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortGetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortGetter.java new file mode 100644 index 00000000000..bea64f4e33e --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortGetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface ShortGetter { + short get(T instance); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortSetter.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortSetter.java new file mode 100644 index 00000000000..db741cb047c --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/bean/ShortSetter.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.bean; + +public interface ShortSetter { + void set(T instance, short value); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java index 98b489f9c12..5b4f80b9ddb 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java @@ -19,12 +19,12 @@ import java.io.IOException; -import javax.servlet.http.Part; - import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import jakarta.servlet.http.Part; + public class JavaxServletPartDeserializer extends JsonDeserializer { @Override public Part deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java index 34d247e3eaf..c964241b42c 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java @@ -19,14 +19,15 @@ import java.io.IOException; -import javax.servlet.http.Part; - import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.util.TokenBuffer; +import jakarta.servlet.http.Part; + +// 什么情况下用? public class JavaxServletPartSerializer extends StdSerializer { private static final long serialVersionUID = 348443113789878443L; @@ -40,7 +41,7 @@ protected JavaxServletPartSerializer(Class t) { @Override public void serialize(Part value, JsonGenerator gen, SerializerProvider provider) throws IOException { - final ObjectCodec preservedCodec = ((TokenBuffer) gen).asParser().getCodec(); + ObjectCodec preservedCodec = ((TokenBuffer) gen).asParser().getCodec(); // set codec as null to avoid recursive dead loop // JsonGenerator is instantiated for each serialization, so there should be no thread safe issue gen.setCodec(null); diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/PartModule.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/PartModule.java new file mode 100644 index 00000000000..5c3b8a53bd6 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/PartModule.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils.json; + +import org.apache.servicecomb.foundation.common.utils.SPIOrder; + +import com.fasterxml.jackson.databind.module.SimpleModule; + +import jakarta.servlet.http.Part; + +public class PartModule extends SimpleModule implements SPIOrder { + private static final long serialVersionUID = 4201325332650814739L; + + public PartModule() { + super("javax-servlet-part"); + + addSerializer(Part.class, new JavaxServletPartSerializer()); + addDeserializer(Part.class, new JavaxServletPartDeserializer()); + } + + @Override + public Object getTypeId() { + return getModuleName(); + } + + @Override + public int getOrder() { + return Short.MAX_VALUE; + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/Keypair4Auth.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/Keypair4Auth.java new file mode 100644 index 00000000000..a3172419465 --- /dev/null +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/Keypair4Auth.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.token; + +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * 进程级别公私钥对 + * + */ +public class Keypair4Auth { + + private Keypair4Auth() { + } + + private PrivateKey privateKey; + + private PublicKey publicKey; + + private String publicKeyEncoded; + + + public PrivateKey getPrivateKey() { + return privateKey; + } + + + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + } + + + public PublicKey getPublicKey() { + return publicKey; + } + + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } + + + public String getPublicKeyEncoded() { + return publicKeyEncoded; + } + + + public void setPublicKeyEncoded(String publicKeyEncoded) { + this.publicKeyEncoded = publicKeyEncoded; + } + + public static Keypair4Auth INSTANCE = new Keypair4Auth(); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/RSAKeypair4Auth.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/RSAKeypair4Auth.java deleted file mode 100644 index b95cbf32a3e..00000000000 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/token/RSAKeypair4Auth.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.token; - -import java.security.PrivateKey; -import java.security.PublicKey; - -/** - * 进程级别公私钥对 - * - */ -public class RSAKeypair4Auth { - - private RSAKeypair4Auth() { - } - - private PrivateKey privateKey; - - private PublicKey publicKey; - - private String publicKeyEncoded; - - - public PrivateKey getPrivateKey() { - return privateKey; - } - - - public void setPrivateKey(PrivateKey privateKey) { - this.privateKey = privateKey; - } - - - public PublicKey getPublicKey() { - return publicKey; - } - - - public void setPublicKey(PublicKey publicKey) { - this.publicKey = publicKey; - } - - - public String getPublicKeyEncoded() { - return publicKeyEncoded; - } - - - public void setPublicKeyEncoded(String publicKeyEncoded) { - this.publicKeyEncoded = publicKeyEncoded; - } - - public static RSAKeypair4Auth INSTANCE = new RSAKeypair4Auth(); -} diff --git a/foundations/foundation-common/src/main/resources/META-INF/mime.types b/foundations/foundation-common/src/main/resources/META-INF/mime.types index 3e85536f857..eec38ecd549 100644 --- a/foundations/foundation-common/src/main/resources/META-INF/mime.types +++ b/foundations/foundation-common/src/main/resources/META-INF/mime.types @@ -154,4 +154,3 @@ application/x-x509-ca-cert cacert application/x-x509-server-cert scert application/x-x509-user-cert ucert application/x-x509-email-cert ecert - diff --git a/foundations/foundation-common/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.common.encrypt.Encryption b/foundations/foundation-common/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.common.encrypt.Encryption index 0e40feb3d0f..f954930aa71 100644 --- a/foundations/foundation-common/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.common.encrypt.Encryption +++ b/foundations/foundation-common/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.common.encrypt.Encryption @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.foundation.common.encrypt.NoEncryption \ No newline at end of file +org.apache.servicecomb.foundation.common.encrypt.NoEncryption diff --git a/foundations/foundation-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/foundations/foundation-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..de62f3b7eb0 --- /dev/null +++ b/foundations/foundation-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,19 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.foundation.auth.FoundationCommonAuthConfiguration +org.apache.servicecomb.foundation.common.event.EventManager diff --git a/foundations/foundation-common/src/main/resources/config/base/log4j.properties b/foundations/foundation-common/src/main/resources/config/base/log4j.properties deleted file mode 100644 index 83de4e47594..00000000000 --- a/foundations/foundation-common/src/main/resources/config/base/log4j.properties +++ /dev/null @@ -1,39 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -##log4j DEBUG < INFO < WARN < ERROR < FATAL -log4j.rootLogger=INFO,paas,stdout -paas.logs.dir=./ -paas.logs.file=cse.log - -#if not set runLogger level ,log4Utils.init will meet a null point error -log4j.logger.runLogger=INFO - -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%p] %m %l%n - -log4j.appender.paas=org.apache.servicecomb.foundation.common.utils.RollingFileAppenderExt -log4j.appender.paas.file=${paas.logs.dir}${paas.logs.file} -log4j.appender.paas.MaxFileSize=20MB -log4j.appender.paas.MaxBackupIndex=10 -log4j.appender.paas.layout=org.apache.log4j.PatternLayout -log4j.appender.paas.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS/zzz}][%t][%p]%m %l%n -log4j.appender.paas.logPermission=rw------- - -# do not print configuration content -log4j.logger.com.netflix.config.DynamicPropertyUpdater=OFF diff --git a/foundations/foundation-common/src/main/resources/config/config.inc.xml b/foundations/foundation-common/src/main/resources/config/config.inc.xml deleted file mode 100644 index 0aa422a2d18..00000000000 --- a/foundations/foundation-common/src/main/resources/config/config.inc.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - classpath*:config/config.properties - - diff --git a/foundations/foundation-common/src/test/java/com/google/common/eventbus/TestEventBus.java b/foundations/foundation-common/src/test/java/com/google/common/eventbus/TestEventBus.java deleted file mode 100644 index 8e2231ada13..00000000000 --- a/foundations/foundation-common/src/test/java/com/google/common/eventbus/TestEventBus.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.common.eventbus; - -import java.util.ArrayList; -import java.util.List; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestEventBus { - private EventBus eventBus = new EventBus(); - - private List events = new ArrayList<>(); - - class SubscriberForTest { - @Subscribe - @AllowConcurrentEvents - public void s1(Integer event) { - events.add(event); - } - - @Subscribe - public void s2(String event) { - events.add(event); - } - } - - @Test - public void unregister() { - Object obj = new SubscriberForTest(); - - eventBus.register(obj); - eventBus.unregister(obj); - } - - @Test - public void oneSubscriber() { - Object obj = new SubscriberForTest(); - - eventBus.register(obj); - - eventBus.post(0.1); - eventBus.post(1); - eventBus.post("str"); - Assert.assertThat(events, Matchers.contains(1, "str")); - - eventBus.unregister(obj); - - events.clear(); - eventBus.post(0.1); - eventBus.post(1); - eventBus.post("str"); - Assert.assertThat(events, Matchers.empty()); - } - - @Test - public void twoSubscriber() { - Object obj1 = new SubscriberForTest(); - Object obj2 = new SubscriberForTest(); - - eventBus.register(obj1); - eventBus.register(obj2); - - eventBus.post(0.1); - eventBus.post(1); - eventBus.post("str"); - Assert.assertThat(events, Matchers.contains(1, 1, "str", "str")); - - events.clear(); - eventBus.unregister(obj1); - eventBus.post(0.1); - eventBus.post(1); - eventBus.post("str"); - Assert.assertThat(events, Matchers.contains(1, "str")); - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/DynamicObjectTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/DynamicObjectTest.java new file mode 100644 index 00000000000..6867124543b --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/DynamicObjectTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import io.vertx.core.json.Json; +import io.vertx.core.json.jackson.DatabindCodec; + +class DynamicObjectTest { + @Test + void should_support_json_encode_decode() { + Map map = new HashMap<>(); + map.put("k", "v"); + + DynamicObject dynamicObject = DatabindCodec.mapper().convertValue(map, DynamicObject.class); + + assertThat(dynamicObject.getDynamic()).isNotSameAs(map); + assertThat(dynamicObject.getDynamic()).isEqualTo(map); + assertThat(Json.encode(dynamicObject)).isEqualTo("{\"k\":\"v\"}"); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/base/DynamicEnumTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/base/DynamicEnumTest.java new file mode 100644 index 00000000000..836be565147 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/base/DynamicEnumTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.base; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonCreator; + +import io.vertx.core.json.Json; +import io.vertx.core.json.jackson.DatabindCodec; + +class DynamicEnumTest { + static final String UNKNOWN_COLOR = "\"UNKNOWN-COLOR\""; + + static class Color extends DynamicEnum { + public static final Color RED = new Color("RED"); + + public static final Color BLUE = new Color("BLUE"); + + private static final DynamicEnumCache CACHE = new DynamicEnumCache<>(Color.class); + + public Color(String value) { + super(value); + } + + @JsonCreator + public static Color fromValue(String value) { + return CACHE.fromValue(value); + } + } + + static class ColorModel { + public Color color; + } + + @Test + void should_be_dynamic_for_unknown_value() { + Color color = Color.fromValue("unknown"); + assertThat(color.isDynamic()).isTrue(); + assertThat(color.isStatic()).isFalse(); + } + + @Test + void should_be_static_for_known_value() { + Color color = Color.fromValue("RED"); + assertThat(color.isDynamic()).isFalse(); + assertThat(color.isStatic()).isTrue(); + } + + @Test + void should_encode() { + assertThat(Json.encode(Color.RED)).isEqualTo("\"RED\""); + } + + @Test + void should_be_null_when_convert_from_null() { + assertThat(DatabindCodec.mapper().convertValue(null, Color.class)).isNull(); + } + + @Test + void should_be_null_when_decode_from_null() { + ColorModel model = Json.decodeValue(Json.encode(new ColorModel()), ColorModel.class); + assertThat(model.color).isNull(); + } + + @Test + void should_decode_from_known_value() { + Color color = Json.decodeValue(Json.encode(Color.RED), Color.class); + assertThat(color).isEqualTo(Color.RED); + } + + @Test + void should_decode_from_unknown_value() { + Color color = Json.decodeValue(UNKNOWN_COLOR, Color.class); + assertThat(color).isEqualTo(Color.fromValue("UNKNOWN-COLOR")); + } + + @Test + void should_not_cache_unknown_value() { + Color value1 = Json.decodeValue(UNKNOWN_COLOR, Color.class); + Color value2 = Json.decodeValue(UNKNOWN_COLOR, Color.class); + assertThat(value1).isNotSameAs(value2); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/cache/TestVersionedCache.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/cache/TestVersionedCache.java index b2909374474..cdfe99f57b8 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/cache/TestVersionedCache.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/cache/TestVersionedCache.java @@ -20,28 +20,27 @@ import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Assert; -import org.junit.Test; - import mockit.Deencapsulation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestVersionedCache { - private static AtomicInteger VERSION = Deencapsulation.getField(VersionedCache.class, "VERSION"); + private static final AtomicInteger VERSION = Deencapsulation.getField(VersionedCache.class, "VERSION"); @Test public void construct() { VersionedCache cache = new VersionedCache(); - Assert.assertNull(cache.data()); - Assert.assertNull(cache.arrayData()); - Assert.assertTrue(cache.isEmpty()); + Assertions.assertNull(cache.data()); + Assertions.assertNull(cache.arrayData()); + Assertions.assertTrue(cache.isEmpty()); } @Test public void autoCacheVersion() { VersionedCache cache = new VersionedCache().autoCacheVersion(); - Assert.assertEquals(VERSION.get(), cache.cacheVersion()); + Assertions.assertEquals(VERSION.get(), cache.cacheVersion()); } @Test @@ -49,14 +48,14 @@ public void setCacheVersion() { VersionedCache parent = new VersionedCache().autoCacheVersion(); VersionedCache cache = new VersionedCache().cacheVersion(parent.cacheVersion()); - Assert.assertEquals(parent.cacheVersion(), cache.cacheVersion()); + Assertions.assertEquals(parent.cacheVersion(), cache.cacheVersion()); } @Test public void setName() { VersionedCache cache = new VersionedCache().name("n"); - Assert.assertEquals("n", cache.name()); + Assertions.assertEquals("n", cache.name()); } @Test @@ -64,31 +63,31 @@ public void setSubName() { VersionedCache parent = new VersionedCache().name("parent"); VersionedCache child = new VersionedCache().subName(parent, "child"); - Assert.assertEquals("parent/child", child.name()); + Assertions.assertEquals("parent/child", child.name()); } @Test public void setMapData() { VersionedCache cache = new VersionedCache().data(Collections.emptyMap()); - Assert.assertSame(Collections.emptyMap(), cache.data()); - Assert.assertSame(Collections.emptyMap(), cache.mapData()); - Assert.assertTrue(cache.isEmpty()); + Assertions.assertSame(Collections.emptyMap(), cache.data()); + Assertions.assertSame(Collections.emptyMap(), cache.mapData()); + Assertions.assertTrue(cache.isEmpty()); cache.data(Collections.singletonMap("k", "v")); - Assert.assertFalse(cache.isEmpty()); + Assertions.assertFalse(cache.isEmpty()); } @Test public void setCollectionData() { VersionedCache cache = new VersionedCache().data(Collections.emptyList()); - Assert.assertSame(Collections.emptyList(), cache.data()); - Assert.assertSame(Collections.emptyList(), cache.collectionData()); - Assert.assertTrue(cache.isEmpty()); + Assertions.assertSame(Collections.emptyList(), cache.data()); + Assertions.assertSame(Collections.emptyList(), cache.collectionData()); + Assertions.assertTrue(cache.isEmpty()); cache.data(Collections.singletonList("v")); - Assert.assertFalse(cache.isEmpty()); + Assertions.assertFalse(cache.isEmpty()); } @Test @@ -96,24 +95,24 @@ public void setArrayData() { Object[] array = Collections.emptyList().toArray(); VersionedCache cache = new VersionedCache().data(array); - Assert.assertSame(array, cache.data()); - Assert.assertSame(array, cache.arrayData()); - Assert.assertTrue(cache.isEmpty()); + Assertions.assertSame(array, cache.data()); + Assertions.assertSame(array, cache.arrayData()); + Assertions.assertTrue(cache.isEmpty()); cache.data(new String[] {"a", "b"}); - Assert.assertFalse(cache.isEmpty()); + Assertions.assertFalse(cache.isEmpty()); } @Test public void setCommonData() { VersionedCache cache = new VersionedCache().data(null); - Assert.assertNull(cache.data()); - Assert.assertNull(cache.arrayData()); - Assert.assertTrue(cache.isEmpty()); + Assertions.assertNull(cache.data()); + Assertions.assertNull(cache.arrayData()); + Assertions.assertTrue(cache.isEmpty()); cache.data("a"); - Assert.assertFalse(cache.isEmpty()); + Assertions.assertFalse(cache.isEmpty()); } @Test @@ -121,9 +120,9 @@ public void isExpired() { VersionedCache cacheOld = new VersionedCache().autoCacheVersion(); VersionedCache cacheNew = new VersionedCache().autoCacheVersion(); - Assert.assertTrue(cacheOld.isExpired(cacheNew)); - Assert.assertFalse(cacheOld.isExpired(cacheOld)); - Assert.assertFalse(cacheNew.isExpired(cacheOld)); + Assertions.assertTrue(cacheOld.isExpired(cacheNew)); + Assertions.assertFalse(cacheOld.isExpired(cacheOld)); + Assertions.assertFalse(cacheNew.isExpired(cacheOld)); } @Test @@ -132,7 +131,7 @@ public void isSameVersion() { VersionedCache cacheNew = new VersionedCache().autoCacheVersion(); VersionedCache cacheSame = new VersionedCache().cacheVersion(cacheNew.cacheVersion()); - Assert.assertFalse(cacheOld.isSameVersion(cacheNew)); - Assert.assertTrue(cacheSame.isSameVersion(cacheNew)); + Assertions.assertFalse(cacheOld.isSameVersion(cacheNew)); + Assertions.assertTrue(cacheSame.isSameVersion(cacheNew)); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/concurrency/RunnableWrapperTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/concurrency/RunnableWrapperTest.java new file mode 100644 index 00000000000..79581ef3985 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/concurrency/RunnableWrapperTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.concurrency; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RunnableWrapperTest { + /** + * {@link SuppressedRunnableWrapper} should ensure that any {@link Throwable} thrown from {@link Runnable} + * should not interrupt the scheduled tasks. + */ + @Test + public void run() { + ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); + CountDownLatch countDownLatch = new CountDownLatch(3); + + try { + scheduledThreadPoolExecutor.scheduleAtFixedRate( + new SuppressedRunnableWrapper( + () -> { + countDownLatch.countDown(); + switch ((int) countDownLatch.getCount()) { + case 2: + throw new Error("Normal case, this is a mocked error"); + case 1: + throw new IllegalStateException("Normal case, this is a mocked exception"); + default: + } + } + ), + 1, + 1, + TimeUnit.MILLISECONDS); + + countDownLatch.await(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + System.out.println("get an InterruptedException! " + e.getMessage()); + e.printStackTrace(); + } finally { + scheduledThreadPoolExecutor.shutdownNow(); + } + + Assertions.assertEquals(0, countDownLatch.getCount()); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/config/TestConfig.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/config/TestConfig.java deleted file mode 100644 index 1fc157e73ac..00000000000 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/config/TestConfig.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.config; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import org.apache.servicecomb.foundation.common.config.impl.IdXmlLoader; -import org.apache.servicecomb.foundation.common.config.impl.PaaSPropertiesLoaderUtils; -import org.apache.servicecomb.foundation.common.config.impl.XmlLoader; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.context.ApplicationContext; -import org.springframework.core.io.Resource; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -public class TestConfig { - private static final int TEST_PROP_LIST_SIZE = 2; - - private static ApplicationContext context; - - @Test - public void loadMergedProperties() throws Exception { - Properties prop = ConfigMgr.INSTANCE.getConfig("pTest"); - Assert.assertEquals("0", prop.get("1")); - Assert.assertEquals("1", prop.get("1.1")); - Assert.assertEquals("2", prop.get("1.2")); - } - - @Test - public void testBean() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - BeanProp bp = (BeanProp) BeanUtils.getBean("beanProp"); - Assert.assertEquals("2", bp.getTest()); - } - - @Test - public void testBeanContext() { - BeanUtils.setContext(context); - Assert.assertEquals(context, BeanUtils.getContext()); - } - - @Test - public void testConvertProperties() throws Exception { - BeanProp bp = PaaSResourceUtils.loadConfigAs("pTest", BeanProp.class); - Assert.assertEquals("2", bp.getTest()); - } - - @Test - public void testConvertXml() throws Exception { - Object ret = PaaSResourceUtils.loadConfigAs("xTest", BeanProp.class); - BeanProp bp = (BeanProp) ret; - Assert.assertEquals("test value", bp.getTest()); - } - - @Test - public void testXml() throws Exception { - List locationPatternList = new ArrayList<>(); - locationPatternList.add("classpath*:config/config.test.inc.xml"); - ConfigLoader loader = new XmlLoader(locationPatternList, ".inc.xml"); - Document doc = loader.load(); - - Element root = doc.getDocumentElement(); - Assert.assertEquals("configs", root.getNodeName()); - - { - NodeList propList = root.getElementsByTagName("properties"); - Assert.assertEquals(2, propList.getLength()); - - { - Element prop = (Element) propList.item(0); - Assert.assertEquals("pTest", prop.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathList = prop.getElementsByTagName("path"); - Assert.assertEquals(1, pathList.getLength()); - Assert.assertEquals("classpath*:config/test.properties", pathList.item(0).getTextContent()); - } - - { - Element prop = (Element) propList.item(1); - Assert.assertEquals("pTest", prop.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathList = prop.getElementsByTagName("path"); - Assert.assertEquals(1, pathList.getLength()); - Assert.assertEquals("classpath*:config/test.ext.properties", - pathList.item(0).getTextContent()); - } - } - - { - NodeList xmlList = root.getElementsByTagName("xml"); - Assert.assertEquals(2, xmlList.getLength()); - - { - Element xml = (Element) xmlList.item(0); - Assert.assertEquals("xTest", xml.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathList = xml.getElementsByTagName("path"); - Assert.assertEquals(1, pathList.getLength()); - Assert.assertEquals("classpath*:config/test.xml", pathList.item(0).getTextContent()); - } - - { - Element xml = (Element) xmlList.item(1); - Assert.assertEquals("xTest", xml.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathList = xml.getElementsByTagName("path"); - Assert.assertEquals(1, pathList.getLength()); - Assert.assertEquals("classpath*:config/test.ext.xml", pathList.item(0).getTextContent()); - } - } - } - - @Test - public void testIdXml() throws Exception { - List locationPatternList = new ArrayList<>(); - locationPatternList.add("classpath*:config/config.test.inc.xml"); - ConfigLoader loader = new IdXmlLoader(locationPatternList, ".inc.xml"); - Document doc = loader.load(); - - Element root = doc.getDocumentElement(); - Assert.assertEquals("configs", root.getNodeName()); - - NodeList propList = root.getElementsByTagName("properties"); - Assert.assertEquals(1, propList.getLength()); - - Element prop = (Element) propList.item(0); - Assert.assertEquals("pTest", prop.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathListProp = prop.getElementsByTagName("path"); - Assert.assertEquals(TEST_PROP_LIST_SIZE, pathListProp.getLength()); - Assert.assertEquals("classpath*:config/test.properties", pathListProp.item(0).getTextContent()); - Assert.assertEquals("classpath*:config/test.ext.properties", pathListProp.item(1).getTextContent()); - - NodeList xmlList = root.getElementsByTagName("xml"); - Assert.assertEquals(1, xmlList.getLength()); - - Element xml = (Element) xmlList.item(0); - Assert.assertEquals("xTest", xml.getAttributes().getNamedItem("id").getNodeValue()); - - NodeList pathListXml = xml.getElementsByTagName("path"); - Assert.assertEquals(TEST_PROP_LIST_SIZE, pathListXml.getLength()); - Assert.assertEquals("classpath*:config/test.xml", pathListXml.item(0).getTextContent()); - Assert.assertEquals("classpath*:config/test.ext.xml", pathListXml.item(1).getTextContent()); - } - - @Test - public void testPaaSResourceUtils() throws Exception { - List oList = PaaSResourceUtils.getSortedXmls("test.xml"); - Assert.assertNotEquals(null, oList); - Assert.assertNotEquals(null, PaaSResourceUtils.loadMergedProperties("config/test.properties")); - PaaSResourceUtils.sortProperties(oList); - PaaSResourceUtils.sortXmls(oList); - Assert.assertNotEquals(null, PaaSPropertiesLoaderUtils.loadMergedProperties("config/test.properties")); - try { - PaaSPropertiesLoaderUtils.fillMergedProperties(new Properties(), ""); - } catch (Exception e) { - Assert.assertEquals(true, (e.getMessage()).contains("Resource path must not be null or empty")); - } - try { - PaaSPropertiesLoaderUtils.fillMergedProperties(new Properties(), "tes.kunle"); - } catch (Exception e) { - Assert.assertEquals(true, (e.getMessage()).contains("Resource path must ends with")); - } - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/encrypt/TestEncryptions.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/encrypt/TestEncryptions.java index 74bb90b760a..35090bad520 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/encrypt/TestEncryptions.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/encrypt/TestEncryptions.java @@ -17,11 +17,11 @@ package org.apache.servicecomb.foundation.common.encrypt; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestEncryptions { - class MyEncryption implements Encryption { + static class MyEncryption implements Encryption { @Override public char[] decode(char[] encrypted, String tags) { @@ -42,24 +42,24 @@ public char[] encode(char[] plain, String tags) { @Test public void testEncryptions() { - Assert.assertEquals(Encryptions.decode((String) null, ""), null); - Assert.assertEquals(Encryptions.decode("abcd", ""), "abcd"); - Assert.assertEquals(Encryptions.decode("abcd", null), "abcd"); - Assert.assertEquals(Encryptions.encode((String) null, ""), null); - Assert.assertEquals(Encryptions.encode("abcd", ""), "abcd"); - Assert.assertEquals(Encryptions.decode("abcd", null), "abcd"); + Assertions.assertNull(Encryptions.decode((String) null, "")); + Assertions.assertEquals(Encryptions.decode("abcd", ""), "abcd"); + Assertions.assertEquals(Encryptions.decode("abcd", null), "abcd"); + Assertions.assertNull(Encryptions.encode((String) null, "")); + Assertions.assertEquals(Encryptions.encode("abcd", ""), "abcd"); + Assertions.assertEquals(Encryptions.decode("abcd", null), "abcd"); } @Test public void testEncryptionsMy() { Encryption old = Encryptions.getEncryption(); Encryptions.setEncryption(new MyEncryption()); - Assert.assertEquals(Encryptions.decode((String) null, ""), null); - Assert.assertEquals(Encryptions.decode("abcd", ""), "abcd"); - Assert.assertEquals(Encryptions.decode("abcd", null), null); - Assert.assertEquals(Encryptions.encode((String) null, ""), null); - Assert.assertEquals(Encryptions.encode("abcd", ""), "abcd"); - Assert.assertEquals(Encryptions.encode("abcd", null), null); + Assertions.assertNull(Encryptions.decode((String) null, "")); + Assertions.assertEquals(Encryptions.decode("abcd", ""), "abcd"); + Assertions.assertNull(Encryptions.decode("abcd", null)); + Assertions.assertNull(Encryptions.encode((String) null, "")); + Assertions.assertEquals(Encryptions.encode("abcd", ""), "abcd"); + Assertions.assertNull(Encryptions.encode("abcd", null)); Encryptions.setEncryption(old); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventBus.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventBus.java new file mode 100644 index 00000000000..68cac748436 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventBus.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.event; + +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; + +import com.google.common.eventbus.AllowConcurrentEvents; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import org.junit.jupiter.api.Test; + +public class TestEventBus { + private final EventBus eventBus = new SimpleEventBus(); + + private final List events = new ArrayList<>(); + + public static class SubscriberForTest { + private final List events; + + public SubscriberForTest(List events) { + this.events = events; + } + @Subscribe + @AllowConcurrentEvents + public void s1(Integer event) { + events.add(event); + } + + @Subscribe + public void s2(String event) { + events.add(event); + } + } + + public static class SubscriberWithOrderForTest { + private final List events; + + public SubscriberWithOrderForTest(List events) { + this.events = events; + } + + @Subscribe + @SubscriberOrder(100) + public void s1(String event) { + events.add("s1:" + event); + } + + @Subscribe + @SubscriberOrder(-100) + public void s2(String event) { + events.add("s2:" + event); + } + } + + @Test + public void order() { + eventBus.register(new SubscriberWithOrderForTest(events)); + + eventBus.post("value"); + MatcherAssert.assertThat(events, Matchers.contains("s2:value", "s1:value")); + } + + @Test + public void unregister() { + Object obj = new SubscriberForTest(events); + + eventBus.register(obj); + eventBus.unregister(obj); + } + + @Test + public void oneSubscriber() { + Object obj = new SubscriberForTest(events); + + eventBus.register(obj); + + eventBus.post(0.1); + eventBus.post(1); + eventBus.post("str"); + MatcherAssert.assertThat(events, Matchers.contains(1, "str")); + + eventBus.unregister(obj); + + events.clear(); + eventBus.post(0.1); + eventBus.post(1); + eventBus.post("str"); + MatcherAssert.assertThat(events, Matchers.empty()); + } + + @Test + public void twoSubscriber() { + Object obj1 = new SubscriberForTest(events); + Object obj2 = new SubscriberForTest(events); + + eventBus.register(obj1); + eventBus.register(obj2); + + eventBus.post(0.1); + eventBus.post(1); + eventBus.post("str"); + MatcherAssert.assertThat(events, Matchers.contains(1, 1, "str", "str")); + + events.clear(); + eventBus.unregister(obj1); + eventBus.post(0.1); + eventBus.post(1); + eventBus.post("str"); + MatcherAssert.assertThat(events, Matchers.contains(1, "str")); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventManager.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventManager.java index 6073a41f45f..736a933159b 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventManager.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/event/TestEventManager.java @@ -17,14 +17,11 @@ package org.apache.servicecomb.foundation.common.event; -import java.util.stream.Collectors; - import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; import com.google.common.eventbus.Subscribe; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestEventManager { private int objCount = 0; @@ -35,27 +32,51 @@ public void test(Object listener) { EventManager.register(listener); EventManager.post("a"); EventManager.post(1); - Assert.assertEquals(2, objCount); - Assert.assertEquals(1, iCount); + Assertions.assertEquals(2, objCount); + Assertions.assertEquals(1, iCount); EventManager.unregister(listener); EventManager.post("a"); EventManager.post(1); - Assert.assertEquals(2, objCount); - Assert.assertEquals(1, iCount); + Assertions.assertEquals(2, objCount); + Assertions.assertEquals(1, iCount); } @Test - public void lambda() { + public void normalListener() { LogCollector collector = new LogCollector(); test(this); - Assert.assertTrue(collector.getEvents().isEmpty()); - collector.teardown(); + Assertions.assertTrue(collector.getEvents().isEmpty()); // ensure no warning logs + collector.tearDown(); + } + + @Test + public void anonymousListener() { + LogCollector collector = new LogCollector(); + Object listener = new Object() { + @Subscribe + private void onObject(Object obj) { + objCount++; + } + + @Subscribe + void onInt(Integer obj) { + iCount++; + } + }; + try { + test(listener); + Assertions.fail(); + } catch (IllegalStateException e) { + Assertions.assertTrue(true); + } + + collector.tearDown(); } @Test - public void reflect() { + public void anonymousListenerPublic() { LogCollector collector = new LogCollector(); Object listener = new Object() { @Subscribe @@ -68,13 +89,16 @@ public void onInt(Integer obj) { iCount++; } }; - test(listener); - Assert.assertThat(collector.getEvents().stream().map(e -> e.getMessage()).collect(Collectors.toList()), - Matchers.containsInAnyOrder( - "Failed to create lambda for method: public void org.apache.servicecomb.foundation.common.event.TestEventManager$1.onObject(java.lang.Object), fallback to reflect.", - "Failed to create lambda for method: public void org.apache.servicecomb.foundation.common.event.TestEventManager$1.onInt(java.lang.Integer), fallback to reflect.")); - - collector.teardown(); + try { + test(listener); + Assertions.fail(); + } catch (IllegalStateException e) { + Assertions.assertTrue(true); + } + + // ensure logs: "LOGGER.warn("Failed to create lambda for method: {}, fallback to reflect.", method, throwable);" + Assertions.assertFalse(collector.getEvents().isEmpty()); + collector.tearDown(); } @Subscribe @@ -87,4 +111,3 @@ public void onInt(Integer obj) { iCount++; } } - diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatus.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatus.java index 71e6eb46d59..b48ceeb4ee0 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatus.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatus.java @@ -17,41 +17,40 @@ package org.apache.servicecomb.foundation.common.http; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.Status.Family; - -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status.Family; public class TestHttpStatus { @Test public void testIsSuccessCode() { - Assert.assertTrue(HttpStatus.isSuccess(200)); - Assert.assertFalse(HttpStatus.isSuccess(300)); + Assertions.assertTrue(HttpStatus.isSuccess(200)); + Assertions.assertFalse(HttpStatus.isSuccess(300)); } @Test public void testIsSuccessType() { - Assert.assertTrue(HttpStatus.isSuccess(Status.OK)); - Assert.assertFalse(HttpStatus.isSuccess(Status.BAD_REQUEST)); + Assertions.assertTrue(HttpStatus.isSuccess(Status.OK)); + Assertions.assertFalse(HttpStatus.isSuccess(Status.BAD_REQUEST)); } @Test public void testGetStatusCode() { HttpStatus status = new HttpStatus(200, "ok"); - Assert.assertEquals(200, status.getStatusCode()); + Assertions.assertEquals(200, status.getStatusCode()); } @Test public void testGetFamily() { HttpStatus status = new HttpStatus(200, "ok"); - Assert.assertEquals(Family.familyOf(200), status.getFamily()); + Assertions.assertEquals(Family.familyOf(200), status.getFamily()); } @Test public void testGetReasonPhrase() { HttpStatus status = new HttpStatus(200, "ok"); - Assert.assertEquals("ok", status.getReasonPhrase()); + Assertions.assertEquals("ok", status.getReasonPhrase()); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatusUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatusUtils.java index ac546524109..87776b326ef 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatusUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpStatusUtils.java @@ -17,39 +17,32 @@ package org.apache.servicecomb.foundation.common.http; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestHttpStatusUtils { HttpStatusManager mgr = new HttpStatusManager(); StatusType st; - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Test public void testStandard() { st = HttpStatusUtils.getOrCreateByStatusCode(200); - Assert.assertEquals(200, st.getStatusCode()); + Assertions.assertEquals(200, st.getStatusCode()); } @Test public void testNotStandard() { st = mgr.getOrCreateByStatusCode(250); - Assert.assertEquals(250, st.getStatusCode()); + Assertions.assertEquals(250, st.getStatusCode()); } @Test public void testAddRepeat() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("repeated status code: 200")); - - mgr.addStatusType(new HttpStatus(200, "ok")); + IllegalStateException illegalStateException = Assertions.assertThrows(IllegalStateException.class, + () -> mgr.addStatusType(new HttpStatus(200, "ok"))); + Assertions.assertEquals("repeated status code: 200", illegalStateException.getMessage()); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java index 43587fcfb4c..113df2905f1 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java @@ -18,94 +18,80 @@ import java.net.URISyntaxException; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestHttpUtils { - @Rule - public ExpectedException expectedException = ExpectedException.none(); @Test public void parseParamFromHeaderValue_normal() { - Assert.assertEquals("v", HttpUtils.parseParamFromHeaderValue("xx;k=v", "k")); - } - - @Test - public void parseParamFromHeaderValue_normal_ignoreCase() { - Assert.assertEquals("v", HttpUtils.parseParamFromHeaderValue("xx;K=v", "k")); + Assertions.assertEquals("a", HttpUtils.parseParamFromHeaderValue("key1=a;key2=b", "key1")); + Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=a;key2= b", "key2")); + Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=a; key2=b", "key2")); + Assertions.assertEquals("a", HttpUtils.parseParamFromHeaderValue("key1=\"a\";key2=\"b\"", "key1")); + Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=\"a\";key2=\" b\"", "key2")); + Assertions.assertEquals("b", HttpUtils.parseParamFromHeaderValue("key1=\"a\"; key2=\"b\"", "key2")); + Assertions.assertEquals("b c.txt", HttpUtils.parseParamFromHeaderValue("key1=\"a\"; key2=\"b c.txt\"", "key2")); } @Test public void parseParamFromHeaderValue_null() { - Assert.assertNull(HttpUtils.parseParamFromHeaderValue(null, "k")); - } - - @Test - public void parseParamFromHeaderValue_noKv() { - Assert.assertNull(HttpUtils.parseParamFromHeaderValue("xx", "k")); + Assertions.assertNull(HttpUtils.parseParamFromHeaderValue(null, "key")); + Assertions.assertNull(HttpUtils.parseParamFromHeaderValue("key1=a; key2=b", "key")); } @Test - public void parseParamFromHeaderValue_noV() { - Assert.assertEquals("", HttpUtils.parseParamFromHeaderValue("xx;k=", "k")); - } - - @Test - public void parseParamFromHeaderValue_keyNotFound() { - Assert.assertNull(HttpUtils.parseParamFromHeaderValue("xx;k=", "kk")); + public void parseParamFromHeaderValue_emptyStr() { + Assertions.assertEquals("", HttpUtils.parseParamFromHeaderValue("key1=a; key2=", "key2")); } @Test public void uriEncode_null() { - Assert.assertEquals("", HttpUtils.uriEncodePath(null)); + Assertions.assertEquals("", HttpUtils.uriEncodePath(null)); } @Test public void uriDecode_null() { - Assert.assertNull(HttpUtils.uriDecodePath(null)); + Assertions.assertNull(HttpUtils.uriDecodePath(null)); } @Test public void uriEncode_chineseAndSpace() { String encoded = HttpUtils.uriEncodePath("测 试"); - Assert.assertEquals("%E6%B5%8B%20%E8%AF%95", encoded); - Assert.assertEquals("测 试", HttpUtils.uriDecodePath(encoded)); + Assertions.assertEquals("%E6%B5%8B%20%E8%AF%95", encoded); + Assertions.assertEquals("测 试", HttpUtils.uriDecodePath(encoded)); } @Test public void uriEncode_failed() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage(Matchers.is("uriEncode failed, path=\":\".")); - expectedException.expectCause(Matchers.instanceOf(URISyntaxException.class)); - - HttpUtils.uriEncodePath(":"); + IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class, + () -> HttpUtils.uriEncodePath(":")); + Assertions.assertEquals("uriEncode failed, path=\":\".", illegalArgumentException.getMessage()); + Assertions.assertTrue(illegalArgumentException.getCause() instanceof URISyntaxException); } @Test public void uriEncode_plus() { String encoded = HttpUtils.uriEncodePath("a+b"); - Assert.assertEquals("a+b", encoded); - Assert.assertEquals("a+b", HttpUtils.uriDecodePath(encoded)); + Assertions.assertEquals("a+b", encoded); + Assertions.assertEquals("a+b", HttpUtils.uriDecodePath(encoded)); } @Test public void uriEncode_encodeEntirePath() { String encoded = HttpUtils.uriEncodePath("a%%'+b/def"); - Assert.assertEquals("a%25%25'+b/def", encoded); + Assertions.assertEquals("a%25%25'+b/def", encoded); } @Test public void pathParamEncode() { - Assert.assertEquals("a+b", HttpUtils.encodePathParam("a+b")); - Assert.assertEquals("a%25b", HttpUtils.encodePathParam("a%b")); - Assert.assertEquals("a%25%25b", HttpUtils.encodePathParam("a%%b")); - Assert.assertEquals("%3C%20%3E'%22%EF%BC%88)&%2F%20%20", HttpUtils.encodePathParam("< >'\"()&/ ")); - Assert.assertEquals("%E6%B5%8B%20%E8%AF%95", HttpUtils.encodePathParam("测 试")); + Assertions.assertEquals("a+b", HttpUtils.encodePathParam("a+b")); + Assertions.assertEquals("a%25b", HttpUtils.encodePathParam("a%b")); + Assertions.assertEquals("a%25%25b", HttpUtils.encodePathParam("a%%b")); + Assertions.assertEquals("%3C%20%3E'%22%EF%BC%88)&%2F%20%20", HttpUtils.encodePathParam("< >'\"()&/ ")); + Assertions.assertEquals("%E6%B5%8B%20%E8%AF%95", HttpUtils.encodePathParam("测 试")); } /** @@ -114,82 +100,80 @@ public void pathParamEncode() { */ @Test public void pathParamEncode_SafeChar() { - Assert.assertEquals("-._~!$'()*,;&=@:+", HttpUtils.encodePathParam("-._~!$'()*,;&=@:+")); + Assertions.assertEquals("-._~!$'()*,;&=@:+", HttpUtils.encodePathParam("-._~!$'()*,;&=@:+")); } @Test public void uriDecode_failed() { - expectedException.expect(IllegalArgumentException.class); - expectedException - .expectMessage(Matchers.is("uriDecode failed, path=\":\".")); - expectedException.expectCause(Matchers.instanceOf(URISyntaxException.class)); - - HttpUtils.uriDecodePath(":"); + IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class, + () -> HttpUtils.uriDecodePath(":")); + Assertions.assertEquals("uriDecode failed, path=\":\".", illegalArgumentException.getMessage()); + Assertions.assertTrue(illegalArgumentException.getCause() instanceof URISyntaxException); } @Test public void parseFileNameFromHeaderValue() { String fileName = "测 试.txt"; String encoded = HttpUtils.uriEncodePath(fileName); - Assert.assertEquals(fileName, HttpUtils.parseFileNameFromHeaderValue("xx;filename=" + encoded)); + Assertions.assertEquals(fileName, HttpUtils.parseFileNameFromHeaderValue("xx;filename=" + encoded)); } @Test public void parseFileNameFromHeaderValue_defaultName() { - Assert.assertEquals("default", HttpUtils.parseFileNameFromHeaderValue("xx")); + Assertions.assertEquals("default", HttpUtils.parseFileNameFromHeaderValue("xx")); } @Test public void parseFileNameFromHeaderValue_ignorePath() { - Assert.assertEquals("a.txt", HttpUtils.parseFileNameFromHeaderValue("xx;filename=../../a.txt")); + Assertions.assertEquals("a.txt", HttpUtils.parseFileNameFromHeaderValue("xx;filename=../../a.txt")); } @Test public void getCharsetFromContentType_noContentType() { String character = HttpUtils.getCharsetFromContentType(null); - Assert.assertNull(character); + Assertions.assertNull(character); } @Test public void getCharsetFromContentType_noCharset() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON); - Assert.assertNull(character); + Assertions.assertNull(character); } @Test public void getCharsetFromContentType_noSemicolonEnd() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=utf-8"); - Assert.assertEquals("utf-8", character); + Assertions.assertEquals("utf-8", character); } @Test public void getCharsetFromContentType_semicolonEnd() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=utf-8;"); - Assert.assertEquals("utf-8", character); + Assertions.assertEquals("utf-8", character); } @Test public void getCharsetFromContentType_needTrim() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset= utf-8 ;"); - Assert.assertEquals("utf-8", character); + Assertions.assertEquals("utf-8", character); } @Test public void getCharsetFromContentType_quotationMarks() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=\"utf-8\";"); - Assert.assertEquals("utf-8", character); + Assertions.assertEquals("utf-8", character); } @Test public void getCharsetFromContentType_quotationMarks_needTrim() { String character = HttpUtils.getCharsetFromContentType(MediaType.APPLICATION_JSON + ";charset=\" utf-8 \";"); - Assert.assertEquals("utf-8", character); + Assertions.assertEquals("utf-8", character); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestIpPort.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestIpPort.java index fcd18bb8f6b..9194515cb28 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestIpPort.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestIpPort.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.foundation.common.net; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestIpPort { @Test @@ -27,12 +27,12 @@ public void testIpPort() { inst1.setHostOrIp("localhost"); inst1.setPort(3333); IpPort inst2 = new IpPort("localhost", 3333); - Assert.assertEquals(inst1.getHostOrIp(), inst2.getHostOrIp()); - Assert.assertEquals(inst1.getPort(), inst2.getPort()); - Assert.assertEquals(inst1.getSocketAddress().getHostName(), inst2.getSocketAddress().getHostName()); - Assert.assertEquals(inst1, inst1); - Assert.assertEquals(inst1, inst2); - Assert.assertEquals(inst1.toString(), "localhost:3333"); - Assert.assertNotEquals(inst1, new Object()); + Assertions.assertEquals(inst1.getHostOrIp(), inst2.getHostOrIp()); + Assertions.assertEquals(inst1.getPort(), inst2.getPort()); + Assertions.assertEquals(inst1.getSocketAddress().getHostName(), inst2.getSocketAddress().getHostName()); + Assertions.assertEquals(inst1, inst1); + Assertions.assertEquals(inst1, inst2); + Assertions.assertEquals(inst1.toString(), "localhost:3333"); + Assertions.assertNotEquals(inst1, new Object()); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java index 15e157fc8e8..dd13d96d4c6 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java @@ -22,50 +22,121 @@ import java.net.ServerSocket; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import mockit.Deencapsulation; public class TestNetUtils { + @Test + public void testFindProperHostAddress() { + NetUtils.resetHostName(); + String result = NetUtils.getHostName(); + System.out.println(result); + Assertions.assertNotNull(result); + + result = NetUtils.getHostAddress(); + System.out.println(result); + Assertions.assertNotNull(result); + + result = NetUtils.getIpv6HostAddress(); + System.out.println(result); + if (result != null) { + Assertions.assertFalse(result.contains("%")); + } + } + @Test public void testIpPort() { IpPort oIPPort = new IpPort("10.145.154.45", 8080); - Assert.assertEquals("10.145.154.45", oIPPort.getHostOrIp()); - Assert.assertEquals(8080, oIPPort.getPort()); + Assertions.assertEquals("10.145.154.45", oIPPort.getHostOrIp()); + Assertions.assertEquals(8080, oIPPort.getPort()); oIPPort.setPort(9090); - Assert.assertEquals(9090, oIPPort.getPort()); - Assert.assertNotEquals(null, oIPPort.getSocketAddress()); + Assertions.assertEquals(9090, oIPPort.getPort()); + Assertions.assertNotEquals(null, oIPPort.getSocketAddress()); + } + + @Test + public void testNetUtils() { + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("127.0.0.1:8080").getHostOrIp()); + Assertions.assertEquals(8080, NetUtils.parseIpPort("127.0.0.1:8080").getPort()); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("127.0.0.1").getHostOrIp()); + Assertions.assertEquals(-1, NetUtils.parseIpPort("127.0.0.1").getPort()); + Assertions.assertNull(NetUtils.parseIpPort((String) null)); + Assertions.assertNull(NetUtils.parseIpPortFromURI(null)); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPortFromURI("rest://127.0.0.1:8080").getHostOrIp()); + Assertions.assertEquals(8080, NetUtils.parseIpPortFromURI("http://127.0.0.1:8080").getPort()); + Assertions.assertEquals(80, NetUtils.parseIpPortFromURI("http://127.0.0.1").getPort()); + Assertions.assertEquals(8080, NetUtils.parseIpPortFromURI("https://127.0.0.1:8080").getPort()); + Assertions.assertEquals(443, NetUtils.parseIpPortFromURI("https://127.0.0.1").getPort()); + + Assertions.assertEquals(30000, NetUtils.parseIpPort("http", "127.0.0.1:30000").getPort()); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("http", "127.0.0.1:30000").getHostOrIp()); + Assertions.assertEquals(30000, NetUtils.parseIpPort("https", "127.0.0.1:30000").getPort()); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("https", "127.0.0.1:30000").getHostOrIp()); + Assertions.assertEquals(80, NetUtils.parseIpPort("http", "127.0.0.1").getPort()); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("http", "127.0.0.1").getHostOrIp()); + Assertions.assertEquals(443, NetUtils.parseIpPort("https", "127.0.0.1").getPort()); + Assertions.assertEquals("127.0.0.1", NetUtils.parseIpPort("https", "127.0.0.1").getHostOrIp()); + Assertions.assertNull(NetUtils.parseIpPort("http", null)); + + checkException(v -> NetUtils.parseIpPort("127.0.0.18080")); + checkException(v -> NetUtils.parseIpPortFromURI("ss")); } @Test - public void testNetutils() { - Assert.assertEquals("127.0.0.1", NetUtils.parseIpPort("127.0.0.1:8080").getHostOrIp()); - Assert.assertEquals(8080, NetUtils.parseIpPort("127.0.0.1:8080").getPort()); - Assert.assertEquals(null, NetUtils.parseIpPort(null)); - Assert.assertEquals(null, NetUtils.parseIpPort("127.0.0.18080")); - Assert.assertEquals(null, NetUtils.parseIpPortFromURI(null)); - Assert.assertEquals(null, NetUtils.parseIpPortFromURI("ss")); - Assert.assertEquals("127.0.0.1", NetUtils.parseIpPortFromURI("rest://127.0.0.1:8080").getHostOrIp()); - Assert.assertEquals(8080, NetUtils.parseIpPortFromURI("http://127.0.0.1:8080").getPort()); - Assert.assertEquals(80, NetUtils.parseIpPortFromURI("http://127.0.0.1").getPort()); - Assert.assertEquals(8080, NetUtils.parseIpPortFromURI("https://127.0.0.1:8080").getPort()); - Assert.assertEquals(443, NetUtils.parseIpPortFromURI("https://127.0.0.1").getPort()); + public void testNetUtilsIPv6() { + Assertions.assertEquals("[::1]", NetUtils.parseIpPort("[::1]:8080").getHostOrIp()); + Assertions.assertEquals("[::]", NetUtils.parseIpPort("[::]:8080").getHostOrIp()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPort("[fe80::f816:3eff:feda:38cd%eth0]:8080").getHostOrIp()); + Assertions.assertEquals("[fe80::38f7:44b8:8ab1:468%16]", + NetUtils.parseIpPort("[fe80::38f7:44b8:8ab1:468%16]:8080").getHostOrIp()); + Assertions.assertEquals(8080, NetUtils.parseIpPort("[::1]:8080").getPort()); + Assertions.assertEquals(8080, NetUtils.parseIpPort("[::]:8080").getPort()); + Assertions.assertEquals(8080, NetUtils.parseIpPort("[fe80::f816:3eff:feda:38cd%eth0]:8080").getPort()); + Assertions.assertEquals(8080, NetUtils.parseIpPort("[fe80::38f7:44b8:8ab1:468%16]:8080").getPort()); + + Assertions.assertEquals("[::1]", NetUtils.parseIpPortFromURI("rest://[::1]:8080").getHostOrIp()); + Assertions.assertEquals("[::]", NetUtils.parseIpPortFromURI("rest://[::]:8080").getHostOrIp()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPortFromURI("rest://[fe80::f816:3eff:feda:38cd%eth0]:8080").getHostOrIp()); + Assertions.assertEquals("[fe80::38f7:44b8:8ab1:468%16]", + NetUtils.parseIpPortFromURI("rest://[fe80::38f7:44b8:8ab1:468%16]:8080").getHostOrIp()); + Assertions.assertEquals(8080, NetUtils.parseIpPortFromURI("rest://[::1]:8080").getPort()); + Assertions.assertEquals(80, NetUtils.parseIpPortFromURI("http://[::1]").getPort()); + Assertions.assertEquals(8080, NetUtils.parseIpPortFromURI("https://[::1]:8080").getPort()); + Assertions.assertEquals(443, NetUtils.parseIpPortFromURI("https://[::1]").getPort()); + + Assertions.assertEquals(30000, NetUtils.parseIpPort("http", "[fe80::f816:3eff:feda:38cd%eth0]:30000").getPort()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPort("http", "[fe80::f816:3eff:feda:38cd%eth0]:30000").getHostOrIp()); + Assertions.assertEquals(30000, NetUtils.parseIpPort("https", "[fe80::f816:3eff:feda:38cd%eth0]:30000").getPort()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPort("https", "[fe80::f816:3eff:feda:38cd%eth0]:30000").getHostOrIp()); + Assertions.assertEquals(80, NetUtils.parseIpPort("http", "[fe80::f816:3eff:feda:38cd%eth0]").getPort()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPort("http", "[fe80::f816:3eff:feda:38cd%eth0]").getHostOrIp()); + Assertions.assertEquals(443, NetUtils.parseIpPort("https", "[fe80::f816:3eff:feda:38cd%eth0]").getPort()); + Assertions.assertEquals("[fe80::f816:3eff:feda:38cd%eth0]", + NetUtils.parseIpPort("https", "[fe80::f816:3eff:feda:38cd%eth0]").getHostOrIp()); } @Test public void testFullOperation() { - Assert.assertNotNull(NetUtils.getHostAddress()); - Assert.assertNotNull(NetUtils.getHostName()); + Assertions.assertNotNull(NetUtils.getHostAddress()); + Assertions.assertNotNull(NetUtils.getHostName()); } @Test public void testGetRealListenAddress() { - Assert.assertNull(NetUtils.getRealListenAddress("http", null)); - Assert.assertNull(NetUtils.getRealListenAddress("http:1", "1.1.1.1:8080")); - Assert.assertEquals("http://1.1.1.1:8080", NetUtils.getRealListenAddress("http", "1.1.1.1:8080")); + Assertions.assertNull(NetUtils.getRealListenAddress("http", null)); + Assertions.assertEquals("http://1.1.1.1:8080", NetUtils.getRealListenAddress("http", "1.1.1.1:8080")); + + checkException(v -> NetUtils.getRealListenAddress("http:1", "1.1.1.1:8080")); } @Test @@ -77,14 +148,14 @@ public void testNetworkInterface() { newValue.put("eth100", addr); Deencapsulation.setField(NetUtils.class, "allInterfaceAddresses", newValue); - Assert.assertEquals(addr, NetUtils.getInterfaceAddress("eth100")); - Assert.assertEquals(addr, NetUtils.ensureGetInterfaceAddress("eth100")); + Assertions.assertEquals(addr, NetUtils.getInterfaceAddress("eth100")); + Assertions.assertEquals(addr, NetUtils.ensureGetInterfaceAddress("eth100")); try { NetUtils.ensureGetInterfaceAddress("xxx"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (IllegalArgumentException e) { - Assert.assertEquals("Can not find address for interface name: xxx", e.getMessage()); + Assertions.assertEquals("Can not find address for interface name: xxx", e.getMessage()); } Deencapsulation.setField(NetUtils.class, "allInterfaceAddresses", org); @@ -94,7 +165,7 @@ public void testNetworkInterface() { public void testCanTcpListenNo() throws IOException { InetAddress address = InetAddress.getByName("127.0.0.1"); try (ServerSocket ss = new ServerSocket(0, 0, address)) { - Assert.assertFalse(NetUtils.canTcpListen(address, ss.getLocalPort())); + Assertions.assertFalse(NetUtils.canTcpListen(address, ss.getLocalPort())); } } @@ -105,57 +176,66 @@ public void testCanTcpListenYes() throws IOException { int port = ss.getLocalPort(); ss.close(); - Assert.assertTrue(NetUtils.canTcpListen(address, port)); + Assertions.assertTrue(NetUtils.canTcpListen(address, port)); } @Test - public void humanReadableBytes() throws IOException { - Assert.assertEquals("0", NetUtils.humanReadableBytes(0L)); - Assert.assertEquals("1", NetUtils.humanReadableBytes(1L)); - Assert.assertEquals("1023", NetUtils.humanReadableBytes(1023L)); - - Assert.assertEquals("1.000K", NetUtils.humanReadableBytes(1024L)); - Assert.assertEquals("1.001K", NetUtils.humanReadableBytes(1025L)); - Assert.assertEquals("1023.999K", NetUtils.humanReadableBytes(1024L * 1024 - 1)); - - Assert.assertEquals("1.000M", NetUtils.humanReadableBytes(1024L * 1024)); - Assert.assertEquals("1.000M", NetUtils.humanReadableBytes(1024L * 1024 + 1)); - Assert.assertEquals("1.001M", NetUtils.humanReadableBytes(1024L * 1024 + 1024)); - Assert.assertEquals("1023.999M", NetUtils.humanReadableBytes(1024L * 1024 * 1024 - 1024)); - Assert.assertEquals("1024.000M", NetUtils.humanReadableBytes(1024L * 1024 * 1024 - 1)); - Assert.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024)); - Assert.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 + 1)); - Assert.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 + 1024)); - Assert.assertEquals("1023.999G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 - 1024 * 1024)); - Assert.assertEquals("1024.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 - 1024)); - Assert.assertEquals("1.000T", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024)); - Assert.assertEquals("1.001T", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 + 1024 * 1024 * 1024)); - Assert.assertEquals("1023.999T", + public void humanReadableBytes() { + Assertions.assertEquals("0", NetUtils.humanReadableBytes(0L)); + Assertions.assertEquals("1", NetUtils.humanReadableBytes(1L)); + Assertions.assertEquals("1023", NetUtils.humanReadableBytes(1023L)); + + Assertions.assertEquals("1.000K", NetUtils.humanReadableBytes(1024L)); + Assertions.assertEquals("1.001K", NetUtils.humanReadableBytes(1025L)); + Assertions.assertEquals("1023.999K", NetUtils.humanReadableBytes(1024L * 1024 - 1)); + + Assertions.assertEquals("1.000M", NetUtils.humanReadableBytes(1024L * 1024)); + Assertions.assertEquals("1.000M", NetUtils.humanReadableBytes(1024L * 1024 + 1)); + Assertions.assertEquals("1.001M", NetUtils.humanReadableBytes(1024L * 1024 + 1024)); + Assertions.assertEquals("1023.999M", NetUtils.humanReadableBytes(1024L * 1024 * 1024 - 1024)); + Assertions.assertEquals("1024.000M", NetUtils.humanReadableBytes(1024L * 1024 * 1024 - 1)); + Assertions.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024)); + Assertions.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 + 1)); + Assertions.assertEquals("1.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 + 1024)); + Assertions.assertEquals("1023.999G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 - 1024 * 1024)); + Assertions.assertEquals("1024.000G", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 - 1024)); + Assertions.assertEquals("1.000T", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024)); + Assertions.assertEquals("1.001T", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 + 1024 * 1024 * 1024)); + Assertions.assertEquals("1023.999T", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 - 1024L * 1024 * 1024)); - Assert.assertEquals("1.000P", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024)); - Assert.assertEquals("1.001P", + Assertions.assertEquals("1.000P", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024)); + Assertions.assertEquals("1.001P", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 + 1024L * 1024 * 1024 * 1024)); - Assert.assertEquals("1023.999P", + Assertions.assertEquals("1023.999P", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024 - 1024L * 1024 * 1024 * 1024)); - Assert.assertEquals("1.000E", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024)); - Assert.assertEquals("1.001E", + Assertions.assertEquals("1.000E", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024)); + Assertions.assertEquals("1.001E", NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024 + 1024L * 1024 * 1024 * 1024 * 1024)); - Assert.assertEquals("8.000E", NetUtils.humanReadableBytes(Long.MAX_VALUE)); + Assertions.assertEquals("8.000E", NetUtils.humanReadableBytes(Long.MAX_VALUE)); } @Test public void testGetHostName() { - Assert.assertNotEquals(null, NetUtils.getHostName()); + Assertions.assertNotEquals(null, NetUtils.getHostName()); Deencapsulation.setField(NetUtils.class, "hostName", null); - Assert.assertNotEquals(null, NetUtils.getHostName()); + Assertions.assertNotEquals(null, NetUtils.getHostName()); } @Test public void testGetHostAddress() { - Assert.assertNotEquals(null, NetUtils.getHostAddress()); + Assertions.assertNotEquals(null, NetUtils.getHostAddress()); Deencapsulation.setField(NetUtils.class, "hostAddress", null); - Assert.assertNotEquals(null, NetUtils.getHostAddress()); + Assertions.assertNotEquals(null, NetUtils.getHostAddress()); + } + + public void checkException(Consumer testedBehavior) { + try { + testedBehavior.accept(null); + Assertions.fail("IllegalArgumentException is expected!"); + } catch (Exception e) { + Assertions.assertEquals(IllegalArgumentException.class, e.getClass()); + } } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestURIEndpointObject.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestURIEndpointObject.java index 5f7f4d418f8..dc3323fecc3 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestURIEndpointObject.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestURIEndpointObject.java @@ -23,36 +23,40 @@ import java.util.List; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; - import mockit.Deencapsulation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestURIEndpointObject { @Test public void testRestEndpointObject() { URIEndpointObject obj = new URIEndpointObject("http://127.0.2.0:8080"); - Assert.assertEquals("127.0.2.0", obj.getHostOrIp()); - Assert.assertEquals(8080, obj.getPort()); - Assert.assertFalse(obj.isSslEnabled()); + Assertions.assertEquals("127.0.2.0", obj.getHostOrIp()); + Assertions.assertEquals(8080, obj.getPort()); + Assertions.assertFalse(obj.isSslEnabled()); obj = new URIEndpointObject("http://127.0.2.0:8080?sslEnabled=true"); - Assert.assertEquals("127.0.2.0", obj.getHostOrIp()); - Assert.assertEquals(8080, obj.getPort()); - Assert.assertTrue(obj.isSslEnabled()); - Assert.assertNull(obj.getFirst("notExist")); + Assertions.assertEquals("127.0.2.0", obj.getHostOrIp()); + Assertions.assertEquals(8080, obj.getPort()); + Assertions.assertTrue(obj.isSslEnabled()); + Assertions.assertNull(obj.getFirst("notExist")); obj = new URIEndpointObject("http://127.0.2.0:8080?sslEnabled=true&protocol=http2"); - Assert.assertEquals("127.0.2.0", obj.getHostOrIp()); - Assert.assertEquals(8080, obj.getPort()); - Assert.assertTrue(obj.isSslEnabled()); - Assert.assertTrue(obj.isHttp2Enabled()); - Assert.assertNull(obj.getFirst("notExist")); + Assertions.assertEquals("127.0.2.0", obj.getHostOrIp()); + Assertions.assertEquals(8080, obj.getPort()); + Assertions.assertTrue(obj.isSslEnabled()); + Assertions.assertTrue(obj.isHttp2Enabled()); + Assertions.assertNull(obj.getFirst("notExist")); + + obj = new URIEndpointObject("rest://127.0.2.0:8080?urlPrefix=%2Froot"); + Assertions.assertEquals("127.0.2.0", obj.getHostOrIp()); + Assertions.assertEquals(8080, obj.getPort()); + Assertions.assertEquals("/root", obj.getQuery("urlPrefix").get(0)); } - @Test(expected = IllegalArgumentException.class) + @Test public void testRestEndpointObjectException() { - new URIEndpointObject("http://127.0.2.0"); + Assertions.assertThrows(IllegalArgumentException.class, () -> new URIEndpointObject("http://127.0.2.0")); } @Test @@ -61,16 +65,16 @@ public void testQueryChineseAndSpaceAndEmpty() throws UnsupportedEncodingExcepti "cse://1.1.1.1:1234/abc?a=1&b=&country=" + URLEncoder.encode("中 国", StandardCharsets.UTF_8.name()); URIEndpointObject ep = new URIEndpointObject(strUri); - Map> querys = Deencapsulation.getField(ep, "querys"); - Assert.assertEquals(3, querys.size()); + Map> queries = Deencapsulation.getField(ep, "queries"); + Assertions.assertEquals(3, queries.size()); - Assert.assertEquals(1, ep.getQuery("a").size()); - Assert.assertEquals("1", ep.getFirst("a")); + Assertions.assertEquals(1, ep.getQuery("a").size()); + Assertions.assertEquals("1", ep.getFirst("a")); - Assert.assertEquals(1, ep.getQuery("b").size()); - Assert.assertEquals("", ep.getFirst("b")); + Assertions.assertEquals(1, ep.getQuery("b").size()); + Assertions.assertEquals("", ep.getFirst("b")); - Assert.assertEquals(1, ep.getQuery("country").size()); - Assert.assertEquals("中 国", ep.getFirst("country")); + Assertions.assertEquals(1, ep.getQuery("country").size()); + Assertions.assertEquals("中 国", ep.getFirst("country")); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestAbstractPart.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestAbstractPart.java index 3b4f82858e9..ae84a460e98 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestAbstractPart.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestAbstractPart.java @@ -19,57 +19,49 @@ import java.io.IOException; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestAbstractPart { AbstractPart part = new AbstractPart(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private void initExpectedException() { - expectedException.expect(Error.class); - expectedException.expectMessage(Matchers.is("not supported method")); + private void checkError(Error error) { + Assertions.assertEquals("not supported method", error.getMessage()); } @Test public void getInputStream() throws IOException { - initExpectedException(); - - part.getInputStream(); + Error error = Assertions.assertThrows(Error.class, () -> part.getInputStream()); + checkError(error); } @Test public void getContentType() throws IOException { - Assert.assertEquals(MediaType.APPLICATION_OCTET_STREAM, part.getContentType()); + Assertions.assertEquals(MediaType.APPLICATION_OCTET_STREAM, part.getContentType()); String contentType = "abc"; part.contentType(contentType); - Assert.assertEquals(contentType, part.getContentType()); + Assertions.assertEquals(contentType, part.getContentType()); } @Test public void getName() throws IOException { - Assert.assertNull(part.getName()); + Assertions.assertNull(part.getName()); String name = "abc"; part.name = name; - Assert.assertEquals(name, part.getName()); + Assertions.assertEquals(name, part.getName()); } @Test public void getSubmittedFileName() throws IOException { - Assert.assertNull(part.getSubmittedFileName()); + Assertions.assertNull(part.getSubmittedFileName()); String submittedFileName = "abc"; part.setSubmittedFileName(submittedFileName); - Assert.assertEquals(submittedFileName, part.getSubmittedFileName()); + Assertions.assertEquals(submittedFileName, part.getSubmittedFileName()); } @Test @@ -77,62 +69,56 @@ public void setSubmittedFileName_contentTypeNotNull() { part.contentType(MediaType.TEXT_PLAIN); part.setSubmittedFileName("a.zip"); - Assert.assertEquals(MediaType.TEXT_PLAIN, part.getContentType()); + Assertions.assertEquals(MediaType.TEXT_PLAIN, part.getContentType()); } @Test public void setSubmittedFileName_setNull() { part.setSubmittedFileName(null); - Assert.assertEquals(MediaType.APPLICATION_OCTET_STREAM, part.getContentType()); + Assertions.assertEquals(MediaType.APPLICATION_OCTET_STREAM, part.getContentType()); } @Test public void setSubmittedFileName_setNormal() { part.setSubmittedFileName("a.zip"); - Assert.assertEquals("application/zip", part.getContentType()); + Assertions.assertEquals("application/zip", part.getContentType()); } @Test public void getSize() { - initExpectedException(); - - part.getSize(); + Error error = Assertions.assertThrows(Error.class, () -> part.getSize()); + checkError(error); } @Test public void write() throws IOException { - initExpectedException(); - - part.write("file"); + Error error = Assertions.assertThrows(Error.class, () -> part.write("file")); + checkError(error); } @Test public void delete() throws IOException { - initExpectedException(); - - part.delete(); + Error error = Assertions.assertThrows(Error.class, () -> part.delete()); + checkError(error); } @Test public void getHeader() { - initExpectedException(); - - part.getHeader("header"); + Error error = Assertions.assertThrows(Error.class, () -> part.getHeader("header")); + checkError(error); } @Test public void getHeaders() { - initExpectedException(); - - part.getHeaders("header"); + Error error = Assertions.assertThrows(Error.class, () -> part.getHeaders("header")); + checkError(error); } @Test public void getHeaderNames() { - initExpectedException(); - - part.getHeaderNames(); + Error error = Assertions.assertThrows(Error.class, () -> part.getHeaderNames()); + checkError(error); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestFilePart.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestFilePart.java index d06eda89150..b129bc2ec42 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestFilePart.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestFilePart.java @@ -20,13 +20,14 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class TestFilePart { static File file = new File("testFilePart.txt"); @@ -37,32 +38,32 @@ public class TestFilePart { FilePart part = new FilePart(name, file.getAbsolutePath()); - @BeforeClass + @BeforeAll public static void setup() throws IOException { file.delete(); - FileUtils.write(file, content); + FileUtils.write(file, content, StandardCharsets.UTF_8); } - @AfterClass + @AfterAll public static void teardown() { file.delete(); } @Test public void getName() { - Assert.assertEquals(name, part.getName()); + Assertions.assertEquals(name, part.getName()); } @Test public void getInputStream() throws IOException { try (InputStream is = part.getInputStream()) { - Assert.assertEquals(content, IOUtils.toString(is)); + Assertions.assertEquals(content, IOUtils.toString(is, StandardCharsets.UTF_8)); } } @Test public void getSize() { - Assert.assertEquals(content.length(), part.getSize()); + Assertions.assertEquals(content.length(), part.getSize()); } @Test @@ -70,22 +71,22 @@ public void write() throws IOException { File destFile = new File("testFilePartCopy.txt"); part.write(destFile.getPath()); - Assert.assertEquals(content, FileUtils.readFileToString(destFile)); + Assertions.assertEquals(content, FileUtils.readFileToString(destFile, StandardCharsets.UTF_8)); FilePart destPart = new FilePart(null, destFile); destPart.delete(); - Assert.assertFalse(destFile.exists()); + Assertions.assertFalse(destFile.exists()); } @Test public void deleteAfterFinished() { - Assert.assertFalse(part.isDeleteAfterFinished()); + Assertions.assertFalse(part.isDeleteAfterFinished()); - Assert.assertTrue(part.setDeleteAfterFinished(true).isDeleteAfterFinished()); + Assertions.assertTrue(part.setDeleteAfterFinished(true).isDeleteAfterFinished()); } @Test public void getAbsolutePath() { - Assert.assertEquals(file.getAbsolutePath(), part.getAbsolutePath()); + Assertions.assertEquals(file.getAbsolutePath(), part.getAbsolutePath()); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestInputStreamPart.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestInputStreamPart.java index f7e9a970ec7..6af3016ecd3 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestInputStreamPart.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestInputStreamPart.java @@ -22,8 +22,8 @@ import java.io.InputStream; import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestInputStreamPart { String name = "paramName"; @@ -36,14 +36,14 @@ public class TestInputStreamPart { @Test public void getName() { - Assert.assertEquals(name, part.getName()); + Assertions.assertEquals(name, part.getName()); } @Test public void test() throws IOException { try (InputStream is = part.getInputStream()) { byte[] content = IOUtils.toByteArray(is); - Assert.assertArrayEquals(bytes, content); + Assertions.assertArrayEquals(bytes, content); } } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestResourcePart.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestResourcePart.java index 2608bba11a1..e0d398e697c 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestResourcePart.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/part/TestResourcePart.java @@ -21,8 +21,8 @@ import java.io.InputStream; import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; @@ -37,14 +37,14 @@ public class TestResourcePart { @Test public void getName() { - Assert.assertEquals(name, part.getName()); + Assertions.assertEquals(name, part.getName()); } @Test public void getInputStream() throws IOException { try (InputStream is = part.getInputStream()) { byte[] content = IOUtils.toByteArray(is); - Assert.assertArrayEquals(bytes, content); + Assertions.assertArrayEquals(bytes, content); } } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/spring/TestPaasNamespaceHandler.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/spring/TestPaasNamespaceHandler.java index 93729f031df..41d5c03640a 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/spring/TestPaasNamespaceHandler.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/spring/TestPaasNamespaceHandler.java @@ -17,21 +17,21 @@ package org.apache.servicecomb.foundation.common.spring; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TestPaasNamespaceHandler { PaasNamespaceHandler paasNamespaceHandler = null; - @Before + @BeforeEach public void setUp() throws Exception { paasNamespaceHandler = new PaasNamespaceHandler(); } - @After + @AfterEach public void tearDown() throws Exception { paasNamespaceHandler = null; } @@ -44,6 +44,6 @@ public void testInit() { } catch (Exception e) { status = true; } - Assert.assertFalse(status); + Assertions.assertFalse(status); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/AsyncUtilsTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/AsyncUtilsTest.java new file mode 100644 index 00000000000..7ec1a215034 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/AsyncUtilsTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.junit.jupiter.api.Test; + +class AsyncUtilsTest { + @Test + void should_convert_success_async_to_sync() { + CompletableFuture future = CompletableFuture.completedFuture("value"); + + assertThat(AsyncUtils.toSync(future)).isEqualTo("value"); + } + + @Test + void should_convert_fail_async_to_sync() { + RuntimeExceptionWithoutStackTrace throwable = new RuntimeExceptionWithoutStackTrace(); + CompletableFuture future = AsyncUtils.completeExceptionally(throwable); + + Throwable catchThrowable = catchThrowable(() -> AsyncUtils.toSync(future)); + assertThat(catchThrowable).isSameAs(throwable); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/JsonUtilsTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/JsonUtilsTest.java new file mode 100644 index 00000000000..60c5d9c43a0 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/JsonUtilsTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class JsonUtilsTest { + + @Test + void testWriteUnicodeValueAsString() throws JsonProcessingException { + String unicodeStr = "测试"; + Map inMap = new HashMap<>(); + inMap.put("key", unicodeStr); + + Assertions.assertFalse(StringUtils.isAsciiPrintable(JsonUtils.writeValueAsString(inMap))); + String jsonStr = JsonUtils.writeUnicodeValueAsString(inMap); + Assertions.assertTrue(StringUtils.isAsciiPrintable(jsonStr)); + + Map outMap = JsonUtils.OBJ_MAPPER.readValue(jsonStr, new TypeReference>() { + }); + Assertions.assertEquals(unicodeStr, outMap.get("key")); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/Log4jUtilsTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/Log4jUtilsTest.java deleted file mode 100644 index dba8e00a8ac..00000000000 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/Log4jUtilsTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.utils; - -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import javax.xml.ws.Holder; - -import org.apache.log4j.PropertyConfigurator; -import org.apache.servicecomb.foundation.common.config.impl.PropertiesLoader; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.core.io.Resource; - -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class Log4jUtilsTest { - - @Before - public void before() { - Deencapsulation.setField(Log4jUtils.class, "inited", false); - } - - @Test - public void init() { - Holder propertiesLoaded = new Holder<>(false); - Holder logConfigured = new Holder<>(false); - Holder mergedFileWritten = new Holder<>(false); - final Properties logProperties = new Properties(); - logProperties.setProperty("paas.logs.file", "cse.log"); - final ArrayList logResList = new ArrayList<>(); - new MockUp() { - @Mock - Properties load() { - propertiesLoaded.value = true; - return logProperties; - } - - @Mock - List getFoundResList() { - return logResList; - } - }; - new MockUp() { - @Mock - void configure(Properties properties) { - logConfigured.value = true; - Assert.assertSame(properties, logProperties); - } - }; - new MockUp() { - @Mock - void outputFile(List resList, Properties properties) { - mergedFileWritten.value = true; - Assert.assertSame(logResList, resList); - Assert.assertSame(logProperties, properties); - } - }; - - Assert.assertFalse(Deencapsulation.getField(Log4jUtils.class, "inited")); - try { - Log4jUtils.init(); - } catch (Exception e) { - fail(e.getMessage()); - } - Assert.assertTrue(Deencapsulation.getField(Log4jUtils.class, "inited")); - Assert.assertTrue(propertiesLoaded.value); - Assert.assertTrue(logConfigured.value); - Assert.assertTrue(mergedFileWritten.value); - } - - @Test - public void initOnMergedFileOutputDisabled() { - Holder propertiesLoaded = new Holder<>(false); - Holder logConfigured = new Holder<>(false); - Holder mergedFileWritten = new Holder<>(false); - final Properties logProperties = new Properties(); - logProperties.setProperty("log4j.logger.outputConfig.enabled", "false"); - final ArrayList logResList = new ArrayList<>(); - new MockUp() { - @Mock - Properties load() { - propertiesLoaded.value = true; - return logProperties; - } - }; - new MockUp() { - @Mock - void configure(Properties properties) { - logConfigured.value = true; - Assert.assertSame(properties, logProperties); - } - }; - new MockUp() { - @Mock - void outputFile(List resList, Properties properties) { - mergedFileWritten.value = true; - Assert.assertSame(logResList, resList); - Assert.assertSame(logProperties, properties); - } - }; - - Assert.assertFalse(Deencapsulation.getField(Log4jUtils.class, "inited")); - try { - Log4jUtils.init(); - } catch (Exception e) { - fail(e.getMessage()); - } - Assert.assertTrue(Deencapsulation.getField(Log4jUtils.class, "inited")); - Assert.assertTrue(propertiesLoaded.value); - Assert.assertTrue(logConfigured.value); - Assert.assertFalse(mergedFileWritten.value); - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/ResourceUtilTest.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/ResourceUtilTest.java new file mode 100644 index 00000000000..9982eca9252 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/ResourceUtilTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ResourceUtilTest { + + @Test + public void loadResources_in_disk() throws IOException, URISyntaxException { + List uris = ResourceUtil.findResourcesBySuffix("META-INF/spring", ".xml"); + Assertions.assertEquals(1, uris.size()); + URI uri = uris.get(0); + Assertions.assertTrue(uri.toString().startsWith("file:"), "unexpected uri: " + uri); + Assertions.assertTrue(uri.toString().endsWith("META-INF/spring/config.bean.xml"), "unexpected uri: " + uri); + } + + @Test + public void loadResources_exact_file_in_disk() throws IOException, URISyntaxException { + List uris = ResourceUtil.findResources("META-INF/spring/config.bean.xml"); + Assertions.assertEquals(1, uris.size()); + URI uri = uris.get(0); + Assertions.assertTrue(uri.toString().startsWith("file:"), "unexpected uri: " + uri); + Assertions.assertTrue(uri.toString().endsWith("META-INF/spring/config.bean.xml"), "unexpected uri: " + uri); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java deleted file mode 100644 index c9a28c18567..00000000000 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestBeanUtils.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.common.utils; - -import org.aspectj.lang.annotation.Aspect; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestBeanUtils { - static interface Intf { - - } - - static class Impl implements Intf { - - } - - @Aspect - static class MyAspect { - } - - @BeforeClass - public static void setup() { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - } - - @AfterClass - public static void tearDown() { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - } - - @Test - public void test() { - Intf target = new Impl(); - AspectJProxyFactory factory = new AspectJProxyFactory(target); - MyAspect aspect = new MyAspect(); - factory.addAspect(aspect); - Intf proxy = factory.getProxy(); - - Assert.assertEquals(Impl.class, BeanUtils.getImplClassFromBean(proxy)); - Assert.assertEquals(Impl.class, BeanUtils.getImplClassFromBean(new Impl())); - } - - @Test - public void prepareServiceCombScanPackage_noExist_noMain() { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - new Expectations(JvmUtils.class) { - { - JvmUtils.findMainClass(); - result = null; - } - }; - - BeanUtils.prepareServiceCombScanPackage(); - - Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE)); - } - - @Test - public void prepareServiceCombScanPackage_noExist_scbMain() { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - new Expectations(JvmUtils.class) { - { - JvmUtils.findMainClass(); - result = TestBeanUtils.class; - } - }; - - BeanUtils.prepareServiceCombScanPackage(); - - Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE)); - } - - @Test - public void prepareServiceCombScanPackage_noExist_otherMain() { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - new Expectations(JvmUtils.class) { - { - JvmUtils.findMainClass(); - result = String.class; - } - }; - - BeanUtils.prepareServiceCombScanPackage(); - - Assert.assertEquals("org.apache.servicecomb,java.lang", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE)); - } - - @Test - public void prepareServiceCombScanPackage_exist() { - System.setProperty(BeanUtils.SCB_SCAN_PACKAGE, "a.b,,c.d"); - new Expectations(JvmUtils.class) { - { - JvmUtils.findMainClass(); - result = null; - } - }; - - BeanUtils.prepareServiceCombScanPackage(); - - Assert.assertEquals("a.b,c.d,org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE)); - } - - @Test - public void init(@Mocked ClassPathXmlApplicationContext context) { - System.clearProperty(BeanUtils.SCB_SCAN_PACKAGE); - new Expectations(JvmUtils.class) { - { - JvmUtils.findMainClass(); - result = TestBeanUtils.class; - } - }; - BeanUtils.init(); - - Assert.assertEquals("org.apache.servicecomb", System.getProperty(BeanUtils.SCB_SCAN_PACKAGE)); - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestExceptionUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestExceptionUtils.java index 1d075444b17..a9746b078e6 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestExceptionUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestExceptionUtils.java @@ -19,16 +19,16 @@ import java.io.IOException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestExceptionUtils { @Test public void testExceptionUtils() { Exception e = new Exception("Hello"); - Assert.assertEquals("cause:Exception,message:Hello", ExceptionUtils.getExceptionMessageWithoutTrace(e)); + Assertions.assertEquals("cause:Exception,message:Hello", ExceptionUtils.getExceptionMessageWithoutTrace(e)); Exception e2 = new Exception("FAIL", new IOException("IO")); - Assert.assertEquals("cause:Exception,message:FAIL;cause:IOException,message:IO", + Assertions.assertEquals("cause:Exception,message:FAIL;cause:IOException,message:IO", ExceptionUtils.getExceptionMessageWithoutTrace(e2)); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFileNameTooLong.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFileNameTooLong.java new file mode 100644 index 00000000000..0ccf049ffba --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFileNameTooLong.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.io.File; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestFileNameTooLong { + private static final Logger LOGGER = LoggerFactory.getLogger(TestFileNameTooLong.class); + + // ensure the maximum file path do not exceed. now set to 200(some old windows max 260) + // smaller is better, can refactor in future + // NOTICE: compiled classes or other generated files like surefire reports may exceed this size + private static final int MAN_FILE_SIZE = 200; + + @Test + public void assertFileNotTooLong() { + File folder = new File(System.getProperty("user.dir")); + LOGGER.error(folder.getAbsolutePath()); // $ROOT\foundations\foundation-common + File root = new File(folder.getParentFile().getParent()); + LOGGER.error(root.getAbsolutePath()); // $ROOT\foundations\foundation-common + Assertions.assertTrue(root.exists()); + Assertions.assertTrue(root.isDirectory()); + + List names = new LinkedList<>(); + findLongFileName(root, names, root.getAbsolutePath().length()); + Collections.sort(names); + names.forEach(LOGGER::error); + if (!names.isEmpty()) { + // for debug + Assertions.assertEquals("", names.toString()); + } + Assertions.assertTrue(names.isEmpty()); + } + + private static void findLongFileName(File folder, List holder, int baseLength) { + if (folder.isFile()) { + if (folder.getAbsolutePath().length() >= MAN_FILE_SIZE + baseLength) { + holder.add(folder.getAbsolutePath()); + } + } else if (folder.isDirectory() && !"target".equals(folder.getName())) { + File[] children = folder.listFiles(); + for (File child : children) { + findLongFileName(child, holder, baseLength); + } + } else { + return; + } + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFortifyUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFortifyUtils.java index 03b568b4086..5ca8147e146 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFortifyUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestFortifyUtils.java @@ -17,26 +17,23 @@ package org.apache.servicecomb.foundation.common.utils; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - import java.io.IOException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestFortifyUtils { @Test public void testFortifyUtils() throws IOException { - Assert.assertEquals("", FortifyUtils.getErrorMsg(null)); - Assert.assertEquals("", FortifyUtils.getErrorStack(null)); + Assertions.assertEquals("", FortifyUtils.getErrorMsg(null)); + Assertions.assertEquals("", FortifyUtils.getErrorStack(null)); } @Test public void testFilePerm() { - Assert.assertEquals(10, (FilePerm.getDefaultAclPerm().size())); - Assert.assertEquals(3, (FilePerm.getDefaultPosixPerm().size())); - Assert.assertEquals(4, (FilePerm.getPosixPerm(400).size())); + Assertions.assertEquals(10, (FilePerm.getDefaultAclPerm().size())); + Assertions.assertEquals(3, (FilePerm.getDefaultPosixPerm().size())); + Assertions.assertEquals(4, (FilePerm.getPosixPerm(400).size())); } @Test @@ -46,7 +43,7 @@ public void testGetErrorMsg() { FortifyUtils.getErrorMsg(e); - assertNull(FortifyUtils.getErrorMsg(e)); + Assertions.assertNull(FortifyUtils.getErrorMsg(e)); } @Test @@ -54,10 +51,10 @@ public void testGetSecurityXmlDocumentFactory() { try { FortifyUtils.getSecurityXmlDocumentFactory(); - assertNotNull(FortifyUtils.getSecurityXmlDocumentFactory()); + Assertions.assertNotNull(FortifyUtils.getSecurityXmlDocumentFactory()); } catch (Exception e) { /* Do not Worry */ - Assert.assertTrue(false); + Assertions.fail(); } } @@ -66,7 +63,7 @@ public void testGetErrorStack() { Throwable e = new Throwable(); FortifyUtils.getErrorStack(e); - Assert.assertNotEquals(true, FortifyUtils.getErrorStack(e)); + Assertions.assertNotEquals(true, FortifyUtils.getErrorStack(e)); } @Test @@ -74,6 +71,5 @@ public void testGetErrorInfo() { Throwable e = new Throwable(); FortifyUtils.getErrorInfo(e, true); - Assert.assertNotEquals(true, FortifyUtils.getErrorInfo(e, true)); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestGenericsUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestGenericsUtils.java new file mode 100644 index 00000000000..06de9612dd2 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestGenericsUtils.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; + +public class TestGenericsUtils { + @Test + public void testIsGenerics() { + Assertions.assertTrue(GenericsUtils.isGenericResponseType(List.class)); + Assertions.assertTrue(GenericsUtils.isGenericResponseType(Map.class)); + Assertions.assertTrue(GenericsUtils.isGenericResponseType(Person.class)); + + Assertions.assertFalse(GenericsUtils.isGenericResponseType(Man.class)); + Assertions.assertFalse(GenericsUtils.isGenericResponseType(String.class)); + Assertions.assertFalse(GenericsUtils.isGenericResponseType(GenericsUtils.class)); + + Assertions.assertFalse(GenericsUtils.isGenericResponseType(new ParameterizedTypeReference>() { + }.getType())); + } +} + +class Person { + private T value; + + public T getValue() { + return value; + } +} + +class Man extends Person { + +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestIOUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestIOUtils.java new file mode 100644 index 00000000000..42c7abe5d4a --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestIOUtils.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestIOUtils { + + @Test + public void testAnonymousPath() { + Assertions.assertEquals(":/:/r/2/y/b/y/0/s/microservice.yaml", + IOUtils.anonymousPath("jar:file:/D:/User/.m2/repository/servicecomb" + + "/transport-highway/2.3.0/classes/microservice.yaml")); + + Assertions.assertEquals(":/:/r/microservice.yaml", IOUtils.anonymousPath("file:/D:/User/microservice.yaml")); + + Assertions.assertEquals(":\\:\\r\\microservice.yaml", IOUtils.anonymousPath("file:\\D:\\User\\microservice.yaml")); + + Assertions.assertEquals("r\\t\\a.txt", IOUtils.anonymousPath("user\\test\\a.txt")); + + Assertions.assertEquals(":\\:\\a.txt", IOUtils.anonymousPath("file:\\D:\\a.txt")); + + Assertions.assertEquals(":\\a.txt", IOUtils.anonymousPath("D:\\a.txt")); + + Assertions.assertEquals("a.txt", IOUtils.anonymousPath("a.txt")); + } + +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java index 97a616dd7e5..10054efe4e8 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java @@ -16,122 +16,191 @@ */ package org.apache.servicecomb.foundation.common.utils; +import mockit.Mock; +import mockit.MockUp; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnJre; +import org.junit.jupiter.api.condition.JRE; + import java.io.ByteArrayInputStream; -import java.io.File; import java.io.InputStream; import java.net.URL; -import java.util.jar.JarFile; - -import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({JvmUtils.class}) -public class TestJvmUtils { - static String orgCmd = System.getProperty(JvmUtils.SUN_JAVA_COMMAND); - @Before - public void setup() { - System.clearProperty(JvmUtils.SUN_JAVA_COMMAND); - } - - @AfterClass - public static void tearDown() { - if (orgCmd == null) { - System.clearProperty(JvmUtils.SUN_JAVA_COMMAND); - return; - } - System.setProperty(JvmUtils.SUN_JAVA_COMMAND, orgCmd); - } +public class TestJvmUtils { @Test + @Disabled public void findMainClass_notExist() { - Assert.assertNull(JvmUtils.findMainClass()); + System.clearProperty(JvmUtils.SUN_JAVA_COMMAND); + Assertions.assertNull(JvmUtils.findMainClass()); } @Test + @Disabled public void findMainClass_existButEmpty() { System.setProperty(JvmUtils.SUN_JAVA_COMMAND, ""); - Assert.assertNull(JvmUtils.findMainClass()); + Assertions.assertNull(JvmUtils.findMainClass()); } @Test + @Disabled public void findMainClass_invalid() { LogCollector logCollector = new LogCollector(); System.setProperty(JvmUtils.SUN_JAVA_COMMAND, "invalidCls"); - Assert.assertNull(JvmUtils.findMainClass()); - Assert.assertEquals("\"invalidCls\" is not a valid class.", logCollector.getEvents().get(0).getMessage()); - logCollector.teardown(); + Assertions.assertNull(JvmUtils.findMainClass()); + Assertions.assertEquals("\"invalidCls\" is not a valid class.", logCollector.getEvents().get(0).getMessage()); + logCollector.tearDown(); } @Test + @Disabled public void findMainClass_class_normal() { System.setProperty(JvmUtils.SUN_JAVA_COMMAND, TestJvmUtils.class.getName() + " arg"); - Assert.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass()); + Assertions.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass()); } @Test + @Disabled public void findMainClass_jar_normal() throws Exception { - String content = String.format("Manifest-Version: 1.0\nMain-Class: %s\n", TestJvmUtils.class.getName()); - InputStream inputStream = new ByteArrayInputStream(content.getBytes()); - - URL url = PowerMockito.mock(URL.class); - String command = "a.jar"; - String manifestUri = "jar:file:" + new File(command).getAbsolutePath() + "!/" + JarFile.MANIFEST_NAME; - PowerMockito.whenNew(URL.class).withParameterTypes(String.class) - .withArguments(manifestUri).thenReturn(url); - PowerMockito.when(url.openStream()).thenReturn(inputStream); + String content = String.format("Manifest-Version: 1.0\nMain-Class: %s\n", TestJvmUtils.class.getName()); + InputStream inputStream = new ByteArrayInputStream(content.getBytes()); + new MockUp() { + @Mock + InputStream openStream() throws Exception { + return inputStream; + } + }; System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg"); - Assert.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass()); + Assertions.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass()); } @Test + @Disabled public void findMainClass_jar_null() throws Exception { String content = "Manifest-Version: 1.0\n"; InputStream inputStream = new ByteArrayInputStream(content.getBytes()); - URL url = PowerMockito.mock(URL.class); - String command = "a.jar"; - String manifestUri = "jar:file:/" + new File(command).getAbsolutePath() + "!/" + JarFile.MANIFEST_NAME; - PowerMockito.whenNew(URL.class).withParameterTypes(String.class) - .withArguments(manifestUri).thenReturn(url); - PowerMockito.when(url.openStream()).thenReturn(inputStream); + new MockUp() { + @Mock + InputStream openStream() throws Exception { + return inputStream; + } + }; System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg"); - Assert.assertNull(JvmUtils.findMainClass()); + Assertions.assertNull(JvmUtils.findMainClass()); } @Test + @Disabled + @EnabledOnJre(JRE.JAVA_17) public void findMainClass_jar_readFailed() throws Exception { - URL url = PowerMockito.mock(URL.class); - String command = "a.jar"; - String manifestUri = "jar:file:/" + new File(command).getAbsolutePath() + "!/" + JarFile.MANIFEST_NAME; - PowerMockito.whenNew(URL.class).withParameterTypes(String.class) - .withArguments(manifestUri).thenReturn(url); - PowerMockito.when(url.openStream()).thenThrow(new Error()); + new MockUp() { + @Mock + InputStream openStream() throws Exception { + throw new RuntimeExceptionWithoutStackTrace(); + } + }; System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg"); - Assert.assertNull(JvmUtils.findMainClass()); + Assertions.assertNull(JvmUtils.findMainClass()); } + + + @Test + @Disabled + public void findMainClassByStackTrace_normal() throws Exception{ + StackTraceElement[] stackTraceElements = { + new StackTraceElement("declaring.class.fileName", "methodName", "fileName", 100), + new StackTraceElement("java.lang.String", "main", "fileName", 120) + }; + new MockUp() { + @Mock + public StackTraceElement[] getStackTrace() { + return stackTraceElements; + } + }; + + Assertions.assertEquals(String.class, JvmUtils.findMainClassByStackTrace()); + } + + @Test + @Disabled + public void findMainClassByStackTrace_invalidClass() throws Exception{ + StackTraceElement[] stackTraceElements = { + new StackTraceElement("declaring.class.fileName", "methodName", "fileName", 100), + new StackTraceElement("InvalidClass", "main", "fileName", 120) + }; + new MockUp() { + @Mock + public StackTraceElement[] getStackTrace() { + return stackTraceElements; + } + }; + + Assertions.assertNull(JvmUtils.findMainClassByStackTrace()); + } + + + @Test + @Disabled + public void findMainClassByStackTrace_withoutMainMethod() throws Exception{ + StackTraceElement[] stackTraceElements = { + new StackTraceElement("declaring.class.fileName", "methodName", "fileName", 100), + new StackTraceElement("InvalidClass", "methodName", "fileName", 120) + }; + new MockUp() { + @Mock + public StackTraceElement[] getStackTrace() { + return stackTraceElements; + } + }; + + Assertions.assertNull(JvmUtils.findMainClassByStackTrace()); + } + + @Test + @Disabled + public void findMainClassByStackTrace_emptyStackTrace() throws Exception{ + new MockUp() { + @Mock + public StackTraceElement[] getStackTrace() { + return new StackTraceElement[]{}; + } + }; + + Assertions.assertNull(JvmUtils.findMainClassByStackTrace()); + } + + @Test + @Disabled + public void findMainClassByStackTrace_nullStackTrace() throws Exception{ + new MockUp() { + @Mock + public StackTraceElement[] getStackTrace() { + return null; + } + }; + + Assertions.assertNull(JvmUtils.findMainClassByStackTrace()); + } + } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaMetafactoryUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaMetafactoryUtils.java index 9b6b301a183..39647ba3dcf 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaMetafactoryUtils.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaMetafactoryUtils.java @@ -16,6 +16,11 @@ */ package org.apache.servicecomb.foundation.common.utils; +import static org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils.createObjectGetter; +import static org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils.createObjectSetter; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; @@ -25,14 +30,26 @@ import java.util.function.Supplier; import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnJre; +import org.junit.jupiter.api.condition.JRE; + +@EnabledOnJre(JRE.JAVA_8) public class TestLambdaMetafactoryUtils { public static class Model { - private int f1; + public int f1; + + private int f2; public int getF1() { return f1; @@ -42,6 +59,11 @@ public void setF1(int f1) { this.f1 = f1; } + public Model fluentSetF1(int f1) { + this.f1 = f1; + return this; + } + public List echo(List value) { return value; } @@ -61,31 +83,88 @@ public void createLambda_withInstance() throws Throwable { setter.accept(1); int f1 = (int) getter.get(); - Assert.assertEquals(1, f1); - Assert.assertThat((List) echo.apply(Arrays.asList(2)), Matchers.contains(2)); + Assertions.assertEquals(1, f1); + MatcherAssert.assertThat((List) echo.apply(Arrays.asList(2)), Matchers.contains(2)); } @SuppressWarnings("unchecked") @Test public void createGetterSetterByMethod() throws Throwable { - Getter getter = LambdaMetafactoryUtils.createGetter(Model.class.getMethod("getF1")); - Setter setter = LambdaMetafactoryUtils.createSetter(Model.class.getMethod("setF1", int.class)); + IntGetter getter = LambdaMetafactoryUtils.createGetter(Model.class.getMethod("getF1")); + IntSetter setter = LambdaMetafactoryUtils.createSetter(Model.class.getMethod("setF1", int.class)); + IntSetter fluentSetter = LambdaMetafactoryUtils + .createSetter(Model.class.getMethod("fluentSetF1", int.class)); BiFunction echo = LambdaMetafactoryUtils .createLambda(Model.class.getMethod("echo", List.class), BiFunction.class); setter.set(model, 1); - int f1 = (int) getter.get(model); - Assert.assertEquals(1, f1); - Assert.assertThat((List) echo.apply(model, Arrays.asList(2)), Matchers.contains(2)); + int f1 = getter.get(model); + Assertions.assertEquals(1, f1); + MatcherAssert.assertThat((List) echo.apply(model, Arrays.asList(2)), Matchers.contains(2)); + + fluentSetter.set(model, 2); + int ff1 = getter.get(model); + Assertions.assertEquals(2, ff1); } @Test - public void createGetterSetterByField() throws Throwable { - Field f1 = Model.class.getDeclaredField("f1"); - Getter getter = LambdaMetafactoryUtils.createGetter(f1); - Setter setter = LambdaMetafactoryUtils.createSetter(f1); + public void should_failed_when_createGetterSetterByField_and_field_is_not_public() throws Throwable { + Field field = Model.class.getDeclaredField("f2"); + assertThat(catchThrowable(() -> LambdaMetafactoryUtils.createGetter(field))) + .isInstanceOf(IllegalStateException.class) + .hasMessage( + "Can not access field, a public field or accessor is required.Declaring class is org.apache.servicecomb.foundation.common.utils.TestLambdaMetafactoryUtils$Model, field is f2"); + assertThat(catchThrowable(() -> LambdaMetafactoryUtils.createSetter(field))) + .isInstanceOf(IllegalStateException.class) + .hasMessage( + "Can not access field, a public field or accessor is required.Declaring class is org.apache.servicecomb.foundation.common.utils.TestLambdaMetafactoryUtils$Model, field is f2"); + } - setter.set(model, 1); - Assert.assertEquals(1, (int) getter.get(model)); + public static class Base { + private T base; + + public T getBase() { + return base; + } + + public Base setBase(T base) { + this.base = base; + return this; + } + } + + public static class Child extends Base { + private int child; + + public int getChild() { + return child; + } + + public Child setChild(int child) { + this.child = child; + return this; + } + } + + @Test + public void should_support_primitive_type() { + Child child = new Child(); + + ObjectMapper mapper = JsonUtils.OBJ_MAPPER; + BeanDescription beanDescription = mapper.getSerializationConfig().introspect(mapper.constructType(Child.class)); + List properties = beanDescription.findProperties(); + assertThat(properties).hasSize(2); + + for (int idx = 0; idx < properties.size(); idx++) { + BeanPropertyDefinition property = properties.get(idx); + + Setter setter = createObjectSetter(property.getSetter().getAnnotated()); + setter.set(child, idx); + + Getter getter = createObjectGetter(property.getGetter().getAnnotated()); + Object value = getter.get(child); + + assertThat(value).isEqualTo(idx); + } } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaPerformance.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaPerformance.java index 5ee8d7856f5..ab92c86216b 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaPerformance.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestLambdaPerformance.java @@ -24,12 +24,13 @@ import org.apache.servicecomb.foundation.common.utils.TestLambdaMetafactoryUtils.Model; import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; public class TestLambdaPerformance { static Model model = new Model(); // 20 field/msg, 10_0000tps - static int count = 20 * 10_0000; + static int count = 20 * 100_0000; static int sum = 0; @@ -37,13 +38,14 @@ public class TestLambdaPerformance { static MethodHandle mh_f1_getter; - static Getter lambda_f1_method_getter; + static IntGetter lambda_f1_method_getter; static Field f1_field; - static Getter lambda_f1_field_getter; + static Getter lambda_f1_field_getter; static { + model.setF1(123456); try { f1_field = Model.class.getDeclaredField("f1"); f1_field.setAccessible(true); @@ -75,11 +77,20 @@ public static long reflectfieldF1() throws IllegalAccessException { return System.nanoTime() - start; } + public static long reflectIntFieldF1() throws IllegalAccessException { + long start = System.nanoTime(); + sum = 0; + for (int idx = 0; idx < count; idx++) { + sum += f1_field.getInt(model); + } + return System.nanoTime() - start; + } + public static long lambdaMethodGetter() throws Throwable { long start = System.nanoTime(); sum = 0; for (int idx = 0; idx < count; idx++) { - sum += (int) lambda_f1_method_getter.get(model); + sum += lambda_f1_method_getter.get(model); } return System.nanoTime() - start; } @@ -88,7 +99,7 @@ public static long lambdaFieldGetter() throws Throwable { long start = System.nanoTime(); sum = 0; for (int idx = 0; idx < count; idx++) { - sum += (int) lambda_f1_field_getter.get(model); + sum += lambda_f1_field_getter.get(model); } return System.nanoTime() - start; } @@ -121,22 +132,27 @@ public static long reflectGetter() throws InvocationTargetException, IllegalAcce } public static void main(String[] args) throws Throwable { - directGetter(); lambdaMethodGetter(); - reflectGetter(); + directGetter(); mhGetterInvoke(); + reflectGetter(); mhGetterExact(); reflectfieldF1(); + reflectIntFieldF1(); + + System.out.println("mhGetterInvoke : " + mhGetterInvoke()); + System.out.println("mhGetterExact : " + mhGetterExact()); + System.out.println("reflectGetter : " + reflectGetter()); + + System.out.println(""); - System.out.println("directGetter : " + directGetter()); - System.out.println("lambdaMethodGetter: " + lambdaMethodGetter()); - System.out.println("mhGetterInvoke : " + mhGetterInvoke()); - System.out.println("mhGetterExact : " + mhGetterExact()); - System.out.println("reflectGetter : " + reflectGetter()); + System.out.println("reflectfieldF1 : " + reflectfieldF1()); + System.out.println("lambdaFieldGetter : " + lambdaFieldGetter()); System.out.println(""); - System.out.println("reflectfieldF1 : " + reflectfieldF1()); - System.out.println("lambdaFieldGetter : " + lambdaFieldGetter()); + System.out.println("lambdaMethodGetter : " + lambdaMethodGetter()); + System.out.println("directGetter : " + directGetter()); + System.out.println("reflectIntFieldF1 : " + reflectIntFieldF1()); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestMimeTypesUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestMimeTypesUtils.java new file mode 100644 index 00000000000..55d88f6ef96 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestMimeTypesUtils.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestMimeTypesUtils { + @Test + public void testSortedAcceptableMimeTypes1() { + String accept = "text/html"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(1, types.size()); + Assertions.assertEquals("text/html", types.get(0)); + } + + @Test + public void testSortedAcceptableMimeTypes2() { + String accept = "text/html, application/json"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(2, types.size()); + Assertions.assertEquals("text/html", types.get(0)); + Assertions.assertEquals("application/json", types.get(1)); + } + + @Test + public void testSortedAcceptableMimeTypes3() { + String accept = "text/html,application/json"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(2, types.size()); + Assertions.assertEquals("text/html", types.get(0)); + Assertions.assertEquals("application/json", types.get(1)); + } + + @Test + public void testSortedAcceptableMimeTypes4() { + String accept = "text/html; q=0.8,application/json; q=0.9"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(2, types.size()); + Assertions.assertEquals("application/json", types.get(0)); + Assertions.assertEquals("text/html", types.get(1)); + } + + @Test + public void testSortedAcceptableMimeTypes5() { + String accept = "text/html;q=0.8,application/json;q=0.9"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(2, types.size()); + Assertions.assertEquals("application/json", types.get(0)); + Assertions.assertEquals("text/html", types.get(1)); + } + + @Test + public void testSortedAcceptableMimeTypes6() { + String accept = "text/html; q=0.8,application/json; q=0.9, text/plain"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(3, types.size()); + Assertions.assertEquals("text/plain", types.get(0)); + Assertions.assertEquals("application/json", types.get(1)); + Assertions.assertEquals("text/html", types.get(2)); + } + + @Test + public void testSortedAcceptableMimeTypes7() { + String accept = "text/html;q=0.8,application/json;q=0.9,text/plain"; + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); + Assertions.assertEquals(3, types.size()); + Assertions.assertEquals("text/plain", types.get(0)); + Assertions.assertEquals("application/json", types.get(1)); + Assertions.assertEquals("text/html", types.get(2)); + } + + @Test + public void getSortedAcceptableMimeTypesNull() { + List types = MimeTypesUtils.getSortedAcceptableMimeTypes(null); + Assertions.assertSame(Collections.emptyList(), types); + } +} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRSAUtil.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRSAUtil.java index 2d43ff9d729..6bd9b386e36 100644 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRSAUtil.java +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRSAUtil.java @@ -21,22 +21,37 @@ import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestRSAUtil { + @BeforeAll + public static void setUpClass() { + Environment environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keyGeneratorAlgorithm", "RSA")) + .thenReturn("RSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.signAlgorithm", "SHA256withRSA")) + .thenReturn("SHA256withRSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keySize", int.class, 2048)) + .thenReturn(2048); + } @Test public void testSignVerify() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException { - RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair(); + KeyPairEntry keyPairEntry = KeyPairUtils.generateALGKeyPair(); - Assert.assertNotNull(rsaKeyPairEntry.getPublicKeyEncoded()); - Assert.assertNotNull(rsaKeyPairEntry.getPrivateKey()); - Assert.assertNotNull(rsaKeyPairEntry.getPublicKey()); + Assertions.assertNotNull(keyPairEntry.getPublicKeyEncoded()); + Assertions.assertNotNull(keyPairEntry.getPrivateKey()); + Assertions.assertNotNull(keyPairEntry.getPublicKey()); String testContent = "instance-id@201711201930@randomstr"; - String signstr = RSAUtils.sign(testContent, rsaKeyPairEntry.getPrivateKey()); - Assert.assertTrue(RSAUtils.verify(rsaKeyPairEntry.getPublicKeyEncoded(), signstr, testContent)); + String signstr = KeyPairUtils.sign(testContent, keyPairEntry.getPrivateKey()); + Assertions.assertTrue(KeyPairUtils.verify(keyPairEntry.getPublicKeyEncoded(), signstr, testContent)); } @Test @@ -48,6 +63,6 @@ public void testSignVerify2() "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ"; String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB"; - Assert.assertTrue(RSAUtils.verify(pubKey, sign, content)); + Assertions.assertTrue(KeyPairUtils.verify(pubKey, sign, content)); } } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRollingFileAppenderExt.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRollingFileAppenderExt.java deleted file mode 100644 index e7fe419b2fa..00000000000 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestRollingFileAppenderExt.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.utils; - -import java.io.File; - -import org.apache.log4j.Layout; -import org.apache.log4j.spi.LoggingEvent; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; - -public class TestRollingFileAppenderExt { - @Test - public void testRollingFileAppenderExt(@Injectable LoggingEvent event, - @Injectable Layout layout) throws Exception { - new Expectations() { - { - layout.format(event); - result = "test"; - } - }; - File cur = new File(System.getProperty("user.dir")); - File temp = new File(cur, "temptestfile.log"); - if (temp.exists()) { - temp.delete(); - } - RollingFileAppenderExt ext = new RollingFileAppenderExt(); - ext.setLayout(layout); - ext.setLogPermission("rw-------"); - ext.setFile(temp.getAbsolutePath()); - ext.setFile(temp.getAbsolutePath(), false, false, 300000); - Assert.assertEquals(ext.getLogPermission(), "rw-------"); - Assert.assertTrue(temp.exists()); - - temp.delete(); - ext.subAppend(event); - Assert.assertTrue(temp.exists()); - - ext.close(); - temp.delete(); - Assert.assertFalse(temp.exists()); - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java deleted file mode 100644 index 6b26ff9e882..00000000000 --- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.common.utils; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.core.Ordered; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -/** - * Test SPIServiceUtils - * - * - */ -public class TestSPIServiceUtils { - @Test - public void testGetTargetServiceNull() { - SPIServiceDef0 service = SPIServiceUtils.getTargetService(SPIServiceDef0.class); - Assert.assertNull(service); - } - - @Test - public void testGetTargetServiceNotNull() { - SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class); - Assert.assertTrue(SPIServiceDef.class.isInstance(service)); - - Assert.assertSame(service, SPIServiceUtils.getTargetService(SPIServiceDef.class)); - } - - @Test - public void testGetTargetService_special_null() { - Assert.assertNull(SPIServiceUtils.getTargetService(SPIServiceDef0.class, SPIServiceDef0Impl.class)); - } - - @Test - public void testGetTargetService_special_notNull() { - SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class, SPIServiceDefImpl.class); - Assert.assertTrue(SPIServiceDefImpl.class.isInstance(service)); - } - - @Test - public void testSort(@Mocked Ordered o1, @Mocked Ordered o2) { - Map map = new LinkedHashMap<>(); - map.put("a", o1); - map.put("b", o2); - - ServiceLoader serviceLoader = ServiceLoader.load(Ordered.class); - Deencapsulation.setField(serviceLoader, "providers", map); - new Expectations(ServiceLoader.class) { - { - o1.getOrder(); - result = -1; - o2.getOrder(); - result = Integer.MAX_VALUE; - ServiceLoader.load(Ordered.class); - result = serviceLoader; - } - }; - - Assert.assertThat(SPIServiceUtils.getSortedService(Ordered.class), Matchers.contains(o1, o2)); - Assert.assertThat(SPIServiceUtils.getAllService(Ordered.class), Matchers.contains(o1, o2)); - Assert.assertThat(SPIServiceUtils.getPriorityHighestService(Ordered.class), Matchers.is(o1)); - - Map, List> cache = Deencapsulation.getField(SPIServiceUtils.class, "cache"); - cache.clear(); - } - - @Test - public void getPriorityHighestService_null() { - Assert.assertNull(SPIServiceUtils.getPriorityHighestService(SPIServiceDef0.class)); - } - - interface PriorityIntf { - String getName(); - - int getOrder(); - } - - public class PriorityImpl implements PriorityIntf { - private final String name; - - private final int order; - - public PriorityImpl(String name, int order) { - this.name = name; - this.order = order; - } - - @Override - public String getName() { - return name; - } - - @Override - public int getOrder() { - return order; - } - - @Override - public String toString() { - return "PriorityImpl{" + - "name='" + name + '\'' + - ", order=" + order + - '}'; - } - } - - @Test - public void getPriorityHighestServices() { - Map instances = new LinkedHashMap<>(); - instances.putIfAbsent("1", new PriorityImpl("n1", 0)); - instances.putIfAbsent("2", new PriorityImpl("n1", -1)); - instances.putIfAbsent("3", new PriorityImpl("n1", 1)); - instances.putIfAbsent("4", new PriorityImpl("n2", 0)); - instances.putIfAbsent("5", new PriorityImpl("n2", -1)); - instances.putIfAbsent("6", new PriorityImpl("n2", 1)); - - ServiceLoader serviceLoader = ServiceLoader.load(PriorityIntf.class); - Deencapsulation.setField(serviceLoader, "providers", instances); - new Expectations(ServiceLoader.class) { - { - ServiceLoader.load(PriorityIntf.class); - result = serviceLoader; - } - }; - - Assert.assertThat(SPIServiceUtils.getPriorityHighestServices(inst -> inst.getName(), PriorityIntf.class), - Matchers.containsInAnyOrder(instances.get("2"), instances.get("5"))); - - Map, List> cache = Deencapsulation.getField(SPIServiceUtils.class, "cache"); - cache.clear(); - } -} diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestTypesUtil.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestTypesUtil.java new file mode 100644 index 00000000000..487ad288585 --- /dev/null +++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestTypesUtil.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.common.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestTypesUtil { + @Test + public void testTypesUtil() { + Assertions.assertEquals(double.class, TypesUtil.wrapperTypeToPrimitive(Double.class)); + Assertions.assertEquals(Float.class, TypesUtil.primitiveTypeToWrapper(float.class)); + Assertions + .assertEquals(TypesUtil.PRIMITIVE_CHAR, TypesUtil.wrapperJavaTypeToPrimitive(TypesUtil.PRIMITIVE_WRAPPER_CHAR)); + Assertions + .assertEquals(TypesUtil.PRIMITIVE_WRAPPER_BYTE, TypesUtil.primitiveJavaTypeToWrapper(TypesUtil.PRIMITIVE_BYTE)); + } +} diff --git a/foundations/foundation-common/src/test/resources/META-INF/spring/config.bean.xml b/foundations/foundation-common/src/test/resources/META-INF/spring/config.bean.xml index 2a0775ca9a9..dde401dec31 100644 --- a/foundations/foundation-common/src/test/resources/META-INF/spring/config.bean.xml +++ b/foundations/foundation-common/src/test/resources/META-INF/spring/config.bean.xml @@ -20,11 +20,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - - - - ${1.2} diff --git a/foundations/foundation-common/src/test/resources/config/config.test.1.inc.xml b/foundations/foundation-common/src/test/resources/config/config.test.1.inc.xml deleted file mode 100644 index af12a8bfdef..00000000000 --- a/foundations/foundation-common/src/test/resources/config/config.test.1.inc.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - classpath*:config/test.ext.properties - - - - classpath*:config/test.ext.xml - - diff --git a/foundations/foundation-common/src/test/resources/config/config.test.inc.xml b/foundations/foundation-common/src/test/resources/config/config.test.inc.xml deleted file mode 100644 index 441994aa2d8..00000000000 --- a/foundations/foundation-common/src/test/resources/config/config.test.inc.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - classpath*:config/test.properties - - - - classpath*:config/test.xml - - diff --git a/foundations/foundation-common/src/test/resources/config/log4j.common.test.properties b/foundations/foundation-common/src/test/resources/config/log4j.common.test.properties deleted file mode 100644 index 0f636e4bacf..00000000000 --- a/foundations/foundation-common/src/test/resources/config/log4j.common.test.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Override the log setting -paas.logs.dir=./target/logs -paas.logs.file=cse.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/foundations/foundation-common/src/test/resources/config/test.1.properties b/foundations/foundation-common/src/test/resources/config/test.1.properties deleted file mode 100644 index 02ca40987ff..00000000000 --- a/foundations/foundation-common/src/test/resources/config/test.1.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -1.1=1 diff --git a/foundations/foundation-common/src/test/resources/config/test.2.properties b/foundations/foundation-common/src/test/resources/config/test.2.properties deleted file mode 100644 index 4b479742b7b..00000000000 --- a/foundations/foundation-common/src/test/resources/config/test.2.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -1.2=2 diff --git a/foundations/foundation-common/src/test/resources/config/test.properties b/foundations/foundation-common/src/test/resources/config/test.properties deleted file mode 100644 index 88992190bfa..00000000000 --- a/foundations/foundation-common/src/test/resources/config/test.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -1=0 -1.1=0 -1.2=0 diff --git a/foundations/foundation-common/src/test/resources/config/test.xml b/foundations/foundation-common/src/test/resources/config/test.xml deleted file mode 100644 index 916224f3ef2..00000000000 --- a/foundations/foundation-common/src/test/resources/config/test.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - test value - diff --git a/foundations/foundation-common/src/test/resources/log4j.properties b/foundations/foundation-common/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/foundations/foundation-common/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/foundations/foundation-common/src/test/resources/log4j2.xml b/foundations/foundation-common/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/foundations/foundation-common/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/foundations/foundation-config/pom.xml b/foundations/foundation-config/pom.xml index d6ca6bbf52a..12c4a54c5be 100644 --- a/foundations/foundation-config/pom.xml +++ b/foundations/foundation-config/pom.xml @@ -21,7 +21,7 @@ foundations org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -40,30 +40,31 @@ spring-beans - com.netflix.archaius - archaius-core - - - commons-configuration - commons-configuration + org.springframework.boot + spring-boot-autoconfigure + org.yaml snakeyaml + + jakarta.annotation + jakarta.annotation-api + org.slf4j slf4j-api - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test @@ -73,6 +74,12 @@ org.apache.httpcomponents httpclient + + + commons-logging + commons-logging + + io.netty @@ -118,5 +125,10 @@ com.google.guava guava + + org.jmockit + jmockit + test + diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java new file mode 100644 index 00000000000..046b326b8b2 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/BootStrapProperties.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.env.Environment; + + +/** + * This class holds configurations that need to be configured + * through property files or environment variables. + * + * These properties are core model for java chassis, e.g. + *
+ *   servicecomb:
+ *     service:
+ *       application:
+ *       name:
+ *       version:
+ *       environment:
+ *       properties:
+ * 
+ * + */ +public class BootStrapProperties { + // start of : service definition keys + // service definition keys of old version + public static final String OLD_CONFIG_SERVICE_APPLICATION = "APPLICATION_ID"; + + public static final String OLD_CONFIG_SERVICE_NAME = "service_description.name"; + + public static final String OLD_CONFIG_SERVICE_VERSION = "service_description.version"; + + public static final String OLD_CONFIG_SERVICE_ROLE = "service_description.role"; + + public static final String OLD_CONFIG_SERVICE_ALIAS = "service_description.alias"; + + public static final String OLD_CONFIG_SERVICE_DESCRIPTION = "service_description.description"; + + public static final String OLD_CONFIG_SERVICE_ENVIRONMENT = "service_description.environment"; + + public static final String OLD_CONFIG_SERVICE_EXTENDED_CLASS = "service_description.propertyExtendedClass"; + + public static final String OLD_CONFIG_SERVICE_PROPERTIES = "service_description.properties"; + + // service instance definition keys of old version + public static final String OLD_CONFIG_SERVICE_INSTANCE_PROPERTIES = "instance_description.properties"; + + public static final String OLD_CONFIG_SERVICE_INSTANCE_EXTENDED_CLASS = "instance_description.propertyExtendedClass"; + + public static final String OLD_CONFIG_SERVICE_INSTANCE_INITIAL_STATUS = "instance_description.initialStatus"; + + // service definition keys of new version + public static final String CONFIG_SERVICE_APPLICATION = "servicecomb.service.application"; + + public static final String CONFIG_SERVICE_NAME = "servicecomb.service.name"; + + public static final String CONFIG_SERVICE_VERSION = "servicecomb.service.version"; + + public static final String CONFIG_SERVICE_ROLE = "servicecomb.service.role"; + + public static final String CONFIG_SERVICE_ALIAS = "servicecomb.service.alias"; + + public static final String CONFIG_SERVICE_DESCRIPTION = "servicecomb.service.description"; + + public static final String CONFIG_SERVICE_ENVIRONMENT = "servicecomb.service.environment"; + + public static final String CONFIG_SERVICE_EXTENDED_CLASS = "servicecomb.service.propertyExtendedClass"; + + public static final String CONFIG_SERVICE_PROPERTIES = "servicecomb.service.properties"; + + // service instance definition keys of new version + public static final String CONFIG_SERVICE_INSTANCE_PROPERTIES = "servicecomb.instance.properties"; + + public static final String CONFIG_SERVICE_INSTANCE_EXTENDED_CLASS = "servicecomb.instance.propertyExtendedClass"; + + public static final String CONFIG_SERVICE_INSTANCE_INITIAL_STATUS = "servicecomb.instance.initialStatus"; + + // configuration default values + public static final String DEFAULT_APPLICATION = "default"; + + public static final String DEFAULT_MICROSERVICE_NAME = "defaultMicroservice"; + + public static final String DEFAULT_MICROSERVICE_VERSION = "1.0.0.0"; + + public static final String DEFAULT_MICROSERVICE_ROLE = "FRONT"; + + public static final String DEFAULT_MICROSERVICE_ENVIRONMENT = ""; + + public static final String DEFAULT_MICROSERVICE_INSTANCE_INITIAL_STATUS = "UP"; + + public static String readApplication(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_APPLICATION, + OLD_CONFIG_SERVICE_APPLICATION, DEFAULT_APPLICATION); + } + + public static String readServiceName(Environment environment) { + String result = readStringValue(environment, CONFIG_SERVICE_NAME, OLD_CONFIG_SERVICE_NAME, + DEFAULT_MICROSERVICE_NAME); + checkMicroserviceName(result); + return result; + } + + public static String readServiceVersion(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_VERSION, OLD_CONFIG_SERVICE_VERSION, + DEFAULT_MICROSERVICE_VERSION); + } + + public static String readServiceRole(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_ROLE, OLD_CONFIG_SERVICE_ROLE, DEFAULT_MICROSERVICE_ROLE); + } + + public static String readServiceAlias(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_ALIAS, OLD_CONFIG_SERVICE_ALIAS, null); + } + + public static String readServiceDescription(Environment environment) { + String[] descriptionArray = environment.getProperty(CONFIG_SERVICE_DESCRIPTION, String[].class); + if (null == descriptionArray || descriptionArray.length < 1) { + descriptionArray = environment.getProperty(OLD_CONFIG_SERVICE_DESCRIPTION, String[].class); + } + + if (null == descriptionArray || descriptionArray.length < 1) { + return null; + } + + StringBuilder rawDescriptionBuilder = new StringBuilder(); + for (String desc : descriptionArray) { + rawDescriptionBuilder.append(desc).append(","); + } + + return rawDescriptionBuilder.substring(0, rawDescriptionBuilder.length() - 1); + } + + public static String readServiceEnvironment(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_ENVIRONMENT, OLD_CONFIG_SERVICE_ENVIRONMENT, + DEFAULT_MICROSERVICE_ENVIRONMENT); + } + + public static String readServiceExtendedClass(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_EXTENDED_CLASS, OLD_CONFIG_SERVICE_EXTENDED_CLASS, + null); + } + + public static Map readServiceProperties(Environment environment) { + return readProperties(environment, CONFIG_SERVICE_PROPERTIES, OLD_CONFIG_SERVICE_PROPERTIES); + } + + public static Map readServiceInstanceProperties(Environment environment) { + return readProperties(environment, CONFIG_SERVICE_INSTANCE_PROPERTIES, OLD_CONFIG_SERVICE_INSTANCE_PROPERTIES); + } + + public static String readServiceInstanceExtendedClass(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_INSTANCE_EXTENDED_CLASS, + OLD_CONFIG_SERVICE_INSTANCE_EXTENDED_CLASS, + null); + } + + public static String readServiceInstanceInitialStatus(Environment environment) { + return readStringValue(environment, CONFIG_SERVICE_INSTANCE_INITIAL_STATUS, + OLD_CONFIG_SERVICE_INSTANCE_INITIAL_STATUS, + DEFAULT_MICROSERVICE_INSTANCE_INITIAL_STATUS); + } + + private static String readStringValue(Environment environment, String newKey, String oldKey, + String defaultValue) { + String result = environment.getProperty(newKey); + if (result == null) { + return environment.getProperty(oldKey, defaultValue); + } + return result; + } + + private static Map readProperties(Environment environment, String newKey, String oldKey) { + String prefix = newKey; + Set keys = ConfigUtil.propertiesWithPrefix(environment, prefix); + if (keys.isEmpty()) { + prefix = oldKey; + keys = ConfigUtil.propertiesWithPrefix(environment, oldKey); + } + Map result = new HashMap<>(keys.size()); + for (String key : keys) { + result.put(key.substring(prefix.length() + 1), environment.getProperty(key)); + } + return result; + } + + private static void checkMicroserviceName(String name) { + // the configuration we used + // when resolve placeholder failed + // the result will remains ${var} + if (StringUtils.isEmpty(name) || name.contains("${")) { + throw new IllegalArgumentException(String.format( + "MicroserviceName '%s' is invalid. you must configure '%s' or set the placeholder value.", + name, + CONFIG_SERVICE_NAME)); + } + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigEnvironmentPostProcessor.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigEnvironmentPostProcessor.java new file mode 100644 index 00000000000..8462da9057d --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigEnvironmentPostProcessor.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.servicecomb.config.file.MicroserviceConfigLoader; +import org.apache.servicecomb.foundation.bootstrap.BootStrapService; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; + +/** + * Initialize configuration. + */ +public class ConfigEnvironmentPostProcessor implements EnvironmentPostProcessor { + public static final String MICROSERVICE_PROPERTY_SOURCE_NAME = "microservice.yaml"; + + public static final String MAPPING_PROPERTY_SOURCE_NAME = "mapping.yaml"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + LegacyPropertyFactory.setEnvironment(environment); + addMicroserviceDefinitions(environment); + startupBootStrapService(environment); + addDynamicConfigurationToSpring(environment); + } + + public static void addMicroserviceDefinitions(Environment environment) { + addMicroserviceYAMLToSpring(environment); + addMappingToSpring(environment); + } + + private void startupBootStrapService(Environment environment) { + for (BootStrapService bootStrapService : SPIServiceUtils.getSortedService(BootStrapService.class)) { + bootStrapService.startup(environment); + } + } + + /** + * make springboot have a change to add microservice.yaml source earlier
+ * to affect {@link Conditional} + * @param environment environment + */ + private static void addMicroserviceYAMLToSpring(Environment environment) { + if (!(environment instanceof ConfigurableEnvironment)) { + return; + } + + MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources(); + if (propertySources.contains(MICROSERVICE_PROPERTY_SOURCE_NAME)) { + return; + } + + propertySources.addLast(new EnumerablePropertySource(MICROSERVICE_PROPERTY_SOURCE_NAME) { + private final Map values = new HashMap<>(); + + private final String[] propertyNames; + + { + MicroserviceConfigLoader loader = new MicroserviceConfigLoader(); + loader.loadAndSort(); + + loader.getConfigModels() + .forEach(configModel -> values.putAll(YAMLUtil.retrieveItems("", configModel.getConfig()))); + + propertyNames = values.keySet().toArray(new String[0]); + } + + @Override + public String[] getPropertyNames() { + return propertyNames; + } + + @SuppressWarnings("unchecked") + @Override + public Object getProperty(String name) { + Object value = this.values.get(name); + + // spring will not resolve nested placeholder of list, so try to fix the problem + if (value instanceof List) { + value = ((List) value).stream() + .filter(item -> item instanceof String) + .map(item -> environment.resolvePlaceholders((String) item)) + .collect(Collectors.toList()); + } + return value; + } + }); + } + + private static void addMappingToSpring(Environment environment) { + if (!(environment instanceof ConfigurableEnvironment)) { + return; + } + + MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources(); + if (propertySources.contains(MAPPING_PROPERTY_SOURCE_NAME)) { + return; + } + + Map mappings = ConfigMapping.getConvertedMap(environment); + propertySources.addFirst(new MapPropertySource(MAPPING_PROPERTY_SOURCE_NAME, mappings)); + } + + private void addDynamicConfigurationToSpring(Environment environment) { + if (!(environment instanceof ConfigurableEnvironment)) { + return; + } + + for (DynamicPropertiesSource dynamicPropertiesSource : + SPIServiceUtils.getOrLoadSortedService(DynamicPropertiesSource.class)) { + ((ConfigurableEnvironment) environment).getPropertySources() + .addFirst(dynamicPropertiesSource.create(environment)); + } + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigMapping.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigMapping.java index 2c381bb2117..d80caaa51a9 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigMapping.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigMapping.java @@ -27,34 +27,45 @@ import java.util.List; import java.util.Map; -import org.apache.commons.configuration.Configuration; +import org.apache.servicecomb.config.file.AbstractConfigLoader; import org.apache.servicecomb.foundation.common.utils.JvmUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; /** * Created by on 2017/1/5. */ public final class ConfigMapping { - private static Map configMap = null; + private static final Map configMap; private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMapping.class); static { ClassLoader loader = JvmUtils.findClassLoader(); - List urlList = new ArrayList<>(); - configMap = new HashMap(); + List> mappingList = new ArrayList<>(); + configMap = new HashMap<>(); Enumeration urls; try { urls = loader.getResources("mapping.yaml"); while (urls.hasMoreElements()) { - urlList.add(urls.nextElement()); - } - for (URL url : urlList) { - try (InputStream in = url.openStream()) { - configMap.putAll(YAMLUtil.yaml2Properties(in)); + try (InputStream in = urls.nextElement().openStream()) { + mappingList.add(YAMLUtil.yaml2Properties(in)); } } + + mappingList.sort((a, b) -> { + int orderA = a.get(AbstractConfigLoader.ORDER_KEY) == null ? 0 : (int) a.get(AbstractConfigLoader.ORDER_KEY); + int orderB = b.get(AbstractConfigLoader.ORDER_KEY) == null ? 0 : (int) b.get(AbstractConfigLoader.ORDER_KEY); + return orderA - orderB; + }); + + mappingList.forEach(item -> { + item.remove(AbstractConfigLoader.ORDER_KEY); + configMap.putAll(item); + }); } catch (IOException e) { LOGGER.error("get config mapping file error!", e); } @@ -63,8 +74,10 @@ public final class ConfigMapping { private ConfigMapping() { } - public static String map(String key) { - return (String) configMap.get(key); + @VisibleForTesting + @SuppressWarnings("unchecked") + static T map(String key) { + return (T) configMap.get(key); } public static Map getMapping() { @@ -77,46 +90,30 @@ public static Map getConvertedMap(Map oldMap) { } Map retMap = new LinkedHashMap<>(); retMap.putAll(oldMap); - for (Map.Entry entry : configMap.entrySet()) { - String key = entry.getKey(); - Object configValue = oldMap.get(key); - if (configValue != null) { - if (entry.getValue() instanceof List) { - @SuppressWarnings("unchecked") - List newKeys = (List) entry.getValue(); - for (String newKey : newKeys) { - retMap.put(newKey, configValue); - } - } else { - String newKey = (String) entry.getValue(); - retMap.put(newKey, configValue); - } - } - } + configMap.entrySet().forEach(entry -> putConfigsToRetMap(retMap, entry, oldMap.get(entry.getKey()))); return retMap; } - public static Map getConvertedMap(Configuration config) { + public static Map getConvertedMap(Environment environment) { if (configMap == null) { return new LinkedHashMap<>(); } Map retMap = new LinkedHashMap<>(); - for (Map.Entry entry : configMap.entrySet()) { - String key = entry.getKey(); - Object configValue = config.getProperty(key); - if (configValue != null) { - if (entry.getValue() instanceof List) { - @SuppressWarnings("unchecked") - List newKeys = (List) entry.getValue(); - for (String newKey : newKeys) { - retMap.put(newKey, configValue); - } - } else { - String newKey = (String) entry.getValue(); - retMap.put(newKey, configValue); - } + configMap.entrySet().forEach(entry -> putConfigsToRetMap(retMap, entry, environment.getProperty(entry.getKey()))); + return retMap; + } + + private static void putConfigsToRetMap(Map retMap, Map.Entry entry, + Object configValue) { + if (configValue != null) { + if (entry.getValue() instanceof List) { + @SuppressWarnings("unchecked") + List newKeys = (List) entry.getValue(); + newKeys.forEach(newKey -> retMap.put(newKey, configValue)); + return; } + String newKey = (String) entry.getValue(); + retMap.put(newKey, configValue); } - return retMap; } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java index 4c1b65fd773..a09b2eaac36 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java @@ -17,304 +17,59 @@ package org.apache.servicecomb.config; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_CSE_PREFIX; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_KEY_SPLITER; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_SERVICECOMB_PREFIX; - +import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.EnvironmentConfiguration; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.servicecomb.config.archaius.scheduler.NeverStartPollingScheduler; -import org.apache.servicecomb.config.archaius.sources.ConfigModel; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigurationSource; -import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConcurrentMapConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicConfiguration; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicWatchedConfiguration; -import com.netflix.config.WatchedUpdateListener; -import com.netflix.config.WatchedUpdateResult; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; public final class ConfigUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigUtil.class); - - private static final String MICROSERVICE_CONFIG_LOADER_KEY = "cse-microservice-config-loader"; - - private static Map localConfig = new HashMap<>(); - - /** - *

The configurations not read by ServiceComb.

- *

- * For example, this map can store the configurations read by SpringBoot from application.properties, - * If users write the configurations of ServiceComb into application.yml instead of microservice.yaml, - * this can help {@link ConfigUtil} load config correctly. - *

- */ - private static final Map> EXTRA_CONFIG_MAP = new LinkedHashMap<>(); - private ConfigUtil() { } - public static void setConfigs(Map config) { - localConfig = config; - } - - public static void addConfig(String key, Object value) { - localConfig.put(key, value); - } - - public static Object getProperty(String key) { - Object config = DynamicPropertyFactory.getBackingConfigurationSource(); - return getProperty(config, key); - } - - public static Object getProperty(Object config, String key) { - if (null != config && Configuration.class.isInstance(config)) { - Configuration configuration = (Configuration) config; - return configuration.getProperty(key); - } - return null; - } - - private static void setMicroserviceConfigLoader(Configuration config, MicroserviceConfigLoader loader) { - config.setProperty(MICROSERVICE_CONFIG_LOADER_KEY, loader); - } - - public static MicroserviceConfigLoader getMicroserviceConfigLoader() { - return (MicroserviceConfigLoader) getProperty(MICROSERVICE_CONFIG_LOADER_KEY); - } - - public static MicroserviceConfigLoader getMicroserviceConfigLoader(Configuration config) { - return (MicroserviceConfigLoader) getProperty(config, MICROSERVICE_CONFIG_LOADER_KEY); - } - - public static ConcurrentCompositeConfiguration createLocalConfig() { - MicroserviceConfigLoader loader = new MicroserviceConfigLoader(); - loader.loadAndSort(); - if (localConfig.size() > 0) { - ConfigModel model = new ConfigModel(); - model.setConfig(localConfig); - loader.getConfigModels().add(model); - } - - LOGGER.info("create local config:"); - for (ConfigModel configModel : loader.getConfigModels()) { - LOGGER.info(" {}.", configModel.getUrl()); - } - - ConcurrentCompositeConfiguration config = ConfigUtil.createLocalConfig(loader.getConfigModels()); - ConfigUtil.setMicroserviceConfigLoader(config, loader); - return config; - } - - public static ConcurrentCompositeConfiguration createLocalConfig(List configModelList) { - ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration(); - - duplicateCseConfigToServicecomb(config, - new ConcurrentMapConfiguration(new SystemConfiguration()), - "configFromSystem"); - duplicateCseConfigToServicecomb(config, - convertEnvVariable(new ConcurrentMapConfiguration(new EnvironmentConfiguration())), - "configFromEnvironment"); - // If there is extra configurations, add it into config. - EXTRA_CONFIG_MAP.entrySet() - .stream() - .filter(mapEntry -> !mapEntry.getValue().isEmpty()) - .forEachOrdered(configMapEntry -> duplicateCseConfigToServicecomb(config, - new ConcurrentMapConfiguration(configMapEntry.getValue()), - configMapEntry.getKey())); - // we have already copy the cse config to the serviceComb config when we load the config from local yaml files - // hence, we do not need duplicate copy it. - config.addConfiguration( new DynamicConfiguration( - new MicroserviceConfigurationSource(configModelList), new NeverStartPollingScheduler()), - "configFromYamlFile"); - duplicateCseConfigToServicecombAtFront(config, - new ConcurrentMapConfiguration(ConfigMapping.getConvertedMap(config)), - "configFromMapping"); - return config; - } - - public static AbstractConfiguration convertEnvVariable(AbstractConfiguration source) { - Iterator keys = source.getKeys(); - while (keys.hasNext()) { - String key = keys.next(); - String[] separatedKey = key.split(CONFIG_KEY_SPLITER); - if (separatedKey.length == 1) { - continue; - } - String newKey = String.join(".", separatedKey); - source.addProperty(newKey, source.getProperty(key)); - } - return source; - } - - //inject a copy of servicecomb.xxx for cse.xxx - private static void duplicateCseConfigToServicecomb(AbstractConfiguration source) { - Iterator keys = source.getKeys(); - while (keys.hasNext()) { - String key = keys.next(); - if (!key.startsWith(CONFIG_CSE_PREFIX)) { - continue; - } - - String servicecombKey = CONFIG_SERVICECOMB_PREFIX + key.substring(key.indexOf(".") + 1); - if (!source.containsKey(servicecombKey)) { - source.addProperty(servicecombKey, source.getProperty(key)); - } else { - LOGGER - .warn( - "Key {} with an ambiguous item {} exists, it's recommended to use only one of them.", - key, servicecombKey); - } - } - } - - private static void duplicateCseConfigToServicecomb(ConcurrentCompositeConfiguration compositeConfiguration, - AbstractConfiguration source, - String sourceName) { - duplicateCseConfigToServicecomb(source); - - compositeConfiguration.addConfiguration(source, sourceName); - } - - private static void duplicateCseConfigToServicecombAtFront(ConcurrentCompositeConfiguration compositeConfiguration, - AbstractConfiguration source, - String sourceName) { - duplicateCseConfigToServicecomb(source); - - compositeConfiguration.addConfigurationAtFront(source, sourceName); - } - - private static ConfigCenterConfigurationSource createConfigCenterConfigurationSource( - Configuration localConfiguration) { - ConfigCenterConfigurationSource configCenterConfigurationSource = - SPIServiceUtils.getTargetService(ConfigCenterConfigurationSource.class); - if (null == configCenterConfigurationSource) { - LOGGER.info( - "config center SPI service can not find, skip to load configuration from config center"); - return null; + public static List parseArrayValue(String value) { + if (value == null) { + return new ArrayList<>(0); } - - if (!configCenterConfigurationSource.isValidSource(localConfiguration)) { - LOGGER.warn("Config Source serverUri is not correctly configured."); - return null; - } - return configCenterConfigurationSource; - } - - private static void createDynamicWatchedConfiguration( - ConcurrentCompositeConfiguration localConfiguration, - ConfigCenterConfigurationSource configCenterConfigurationSource) { - ConcurrentMapConfiguration injectConfig = new ConcurrentMapConfiguration(); - localConfiguration.addConfigurationAtFront(injectConfig, "extraInjectConfig"); - configCenterConfigurationSource.addUpdateListener(new ServiceCombPropertyUpdateListener(injectConfig)); - - DynamicWatchedConfiguration configFromConfigCenter = - new DynamicWatchedConfiguration(configCenterConfigurationSource); - duplicateCseConfigToServicecomb(configFromConfigCenter); - localConfiguration.addConfigurationAtFront(configFromConfigCenter, "configCenterConfig"); - } - - public static AbstractConfiguration createDynamicConfig() { - ConcurrentCompositeConfiguration compositeConfig = ConfigUtil.createLocalConfig(); - ConfigCenterConfigurationSource configCenterConfigurationSource = - createConfigCenterConfigurationSource(compositeConfig); - if (configCenterConfigurationSource != null) { - createDynamicWatchedConfiguration(compositeConfig, configCenterConfigurationSource); + String[] tokens = value.split(","); + List result = new ArrayList<>(tokens.length); + for (String t : tokens) { + result.add(t.trim()); } - return compositeConfig; + return result; } - public static void installDynamicConfig() { - if (ConfigurationManager.isConfigurationInstalled()) { - LOGGER.warn("Configuration installed by others, will ignore this configuration."); - return; - } - - ConcurrentCompositeConfiguration compositeConfig = ConfigUtil.createLocalConfig(); - ConfigCenterConfigurationSource configCenterConfigurationSource = - createConfigCenterConfigurationSource(compositeConfig); - if (configCenterConfigurationSource != null) { - createDynamicWatchedConfiguration(compositeConfig, configCenterConfigurationSource); - } - - ConfigurationManager.install(compositeConfig); - - if (configCenterConfigurationSource != null) { - configCenterConfigurationSource.init(compositeConfig); - } - } - - public static void destroyConfigCenterConfigurationSource() { - SPIServiceUtils.getAllService(ConfigCenterConfigurationSource.class).forEach(source -> { - try { - source.destroy(); - } catch (Throwable e) { - LOGGER.error("Failed to destroy {}", source.getClass().getName()); - } - }); - } - - public static void addExtraConfig(String extraConfigName, Map extraConfig) { - EXTRA_CONFIG_MAP.put(extraConfigName, extraConfig); - } - - public static void clearExtraConfig() { - EXTRA_CONFIG_MAP.clear(); - } - - private static class ServiceCombPropertyUpdateListener implements WatchedUpdateListener { - - private final ConcurrentMapConfiguration injectConfig; - - ServiceCombPropertyUpdateListener(ConcurrentMapConfiguration injectConfig) { - this.injectConfig = injectConfig; - } - - @Override - public void updateConfiguration(WatchedUpdateResult watchedUpdateResult) { - Map adds = watchedUpdateResult.getAdded(); - if (adds != null) { - for (String add : adds.keySet()) { - if (add.startsWith(CONFIG_CSE_PREFIX)) { - String key = CONFIG_SERVICECOMB_PREFIX + add.substring(add.indexOf(".") + 1); - injectConfig.addProperty(key, adds.get(add)); - } - } - } - - Map deletes = watchedUpdateResult.getDeleted(); - if (deletes != null) { - for (String delete : deletes.keySet()) { - if (delete.startsWith(CONFIG_CSE_PREFIX)) { - injectConfig.clearProperty(CONFIG_SERVICECOMB_PREFIX + delete.substring(delete.indexOf(".") + 1)); + public static Set propertiesWithPrefix(Environment environment, String prefix) { + Set result = new HashSet<>(); + for (PropertySource propertySource : ((ConfigurableEnvironment) environment).getPropertySources()) { + if (propertySource instanceof EnumerablePropertySource) { + for (String key : ((EnumerablePropertySource) propertySource).getPropertyNames()) { + if (key.startsWith(prefix)) { + result.add(key); } } } + } + return result; + } - Map changes = watchedUpdateResult.getChanged(); - if (changes != null) { - for (String change : changes.keySet()) { - if (change.startsWith(CONFIG_CSE_PREFIX)) { - String key = CONFIG_SERVICECOMB_PREFIX + change.substring(change.indexOf(".") + 1); - injectConfig.setProperty(key, changes.get(change)); + public static Map stringPropertiesWithPrefix(Environment environment, String prefix) { + Map result = new HashMap<>(); + for (PropertySource propertySource : ((ConfigurableEnvironment) environment).getPropertySources()) { + if (propertySource instanceof EnumerablePropertySource) { + for (String key : ((EnumerablePropertySource) propertySource).getPropertyNames()) { + if (key.startsWith(prefix)) { + result.put(key, environment.getProperty(key)); } } } } + return result; } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationChangedEvent.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationChangedEvent.java new file mode 100644 index 00000000000..2c0532a6543 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationChangedEvent.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * This event is fired when configuration changed. And the change is already applied to Environment. + * + * Listeners can use Environment to get the latest value. + */ +public class ConfigurationChangedEvent { + private final Map added; + + private final Map deleted; + + private final Map updated; + + private Set changed; + + private ConfigurationChangedEvent(Map added, Map updated, + Map deleted) { + this.added = added; + this.deleted = deleted; + this.updated = updated; + this.changed = new HashSet<>(); + this.changed.addAll(added.keySet()); + this.changed.addAll(updated.keySet()); + this.changed.addAll(deleted.keySet()); + } + + public static ConfigurationChangedEvent createIncremental(Map latest, Map last) { + Map itemsCreated = new HashMap<>(); + Map itemsDeleted = new HashMap<>(); + Map itemsModified = new HashMap<>(); + + for (Map.Entry entry : latest.entrySet()) { + String itemKey = entry.getKey(); + if (!last.containsKey(itemKey)) { + itemsCreated.put(itemKey, entry.getValue()); + } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) { + itemsModified.put(itemKey, entry.getValue()); + } + } + for (String itemKey : last.keySet()) { + if (!latest.containsKey(itemKey)) { + itemsDeleted.put(itemKey, null); + } + } + ConfigurationChangedEvent event = ConfigurationChangedEvent + .createIncremental(itemsCreated, itemsModified, itemsDeleted); + return event; + } + + public static ConfigurationChangedEvent createIncremental(Map added, Map updated, + Map deleted) { + return new ConfigurationChangedEvent(added, updated, deleted); + } + + public static ConfigurationChangedEvent createIncremental(Map updated) { + return new ConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>()); + } + + public final Map getAdded() { + return added; + } + + + public final Map getUpdated() { + return updated; + } + + + public final Map getDeleted() { + return deleted; + } + + public final Set getChanged() { + return changed; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java deleted file mode 100644 index 0288d93e6d4..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.configuration.AbstractConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.Ordered; -import org.springframework.core.env.CompositePropertySource; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.EnumerablePropertySource; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; -import org.springframework.util.StringUtils; - -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; - -public class ConfigurationSpringInitializer extends PropertyPlaceholderConfigurer implements EnvironmentAware { - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationSpringInitializer.class); - - public static final String EXTRA_CONFIG_SOURCE_PREFIX = "extraConfig-"; - - public ConfigurationSpringInitializer() { - setOrder(Ordered.LOWEST_PRECEDENCE / 2); - setIgnoreUnresolvablePlaceholders(true); - } - - /** - * Get configurations from Spring, merge them into the configurations of ServiceComb. - * @param environment From which to get the extra config. - */ - @Override - public void setEnvironment(Environment environment) { - String environmentName = generateNameForEnvironment(environment); - LOGGER.info("Environment received, will get configurations from [{}].", environmentName); - - Map extraConfig = getAllProperties(environment); - - ConfigUtil.addExtraConfig(EXTRA_CONFIG_SOURCE_PREFIX + environmentName, extraConfig); - - ConfigUtil.installDynamicConfig(); - } - - @Override - protected Properties mergeProperties() throws IOException { - Properties properties = super.mergeProperties(); - - AbstractConfiguration config = ConfigurationManager.getConfigInstance(); - Iterator iter = config.getKeys(); - while (iter.hasNext()) { - String key = iter.next(); - Object value = config.getProperty(key); - properties.put(key, value); - } - return properties; - } - - @Override - protected String resolvePlaceholder(String placeholder, Properties props) { - String propertyValue = super.resolvePlaceholder(placeholder, props); - if (propertyValue == null) { - return DynamicPropertyFactory.getInstance().getStringProperty(placeholder, null).get(); - } - return propertyValue; - } - - /** - * Try to get a name for identifying the environment. - * @param environment the target that the name is generated for. - * @return The generated name for the environment. - */ - private String generateNameForEnvironment(Environment environment) { - String environmentName = environment.getProperty("spring.config.name"); - if (!StringUtils.isEmpty(environmentName)) { - return environmentName; - } - - environmentName = environment.getProperty("spring.application.name"); - if (!StringUtils.isEmpty(environmentName)) { - return environmentName; - } - - return environment.getClass().getName() + "@" + environment.hashCode(); - } - - /** - * Traversal all {@link PropertySource} of {@link ConfigurableEnvironment}, and try to get all properties. - */ - private Map getAllProperties(Environment environment) { - Map configFromSpringBoot = new HashMap<>(); - - if (!(environment instanceof ConfigurableEnvironment)) { - return configFromSpringBoot; - } - - ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; - for (PropertySource propertySource : configurableEnvironment.getPropertySources()) { - getProperties(configurableEnvironment, propertySource, configFromSpringBoot); - } - return configFromSpringBoot; - } - - /** - * Get property names from {@link EnumerablePropertySource}, and get property value from {@link ConfigurableEnvironment#getProperty(String)} - */ - private void getProperties(ConfigurableEnvironment environment, PropertySource propertySource, - Map configFromSpringBoot) { - if (propertySource instanceof CompositePropertySource) { - // recursively get EnumerablePropertySource - CompositePropertySource compositePropertySource = (CompositePropertySource) propertySource; - compositePropertySource.getPropertySources().forEach(ps -> getProperties(environment, ps, configFromSpringBoot)); - return; - } - if (propertySource instanceof EnumerablePropertySource) { - EnumerablePropertySource enumerablePropertySource = (EnumerablePropertySource) propertySource; - for (String propertyName : enumerablePropertySource.getPropertyNames()) { - configFromSpringBoot.put(propertyName, environment.getProperty(propertyName)); - } - return; - } - - LOGGER.debug("a none EnumerablePropertySource is ignored, propertySourceName = [{}]", propertySource.getName()); - } -} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DataCenterProperties.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DataCenterProperties.java new file mode 100644 index 00000000000..df61c22f547 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DataCenterProperties.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config; + +public class DataCenterProperties { + public static final String PREFIX = "servicecomb.datacenter"; + + private String name; + + private String region; + + private String availableZone; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAvailableZone() { + return availableZone; + } + + public void setAvailableZone(String availableZone) { + this.availableZone = availableZone; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicProperties.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicProperties.java index 47e060af733..58f84dd97b0 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicProperties.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicProperties.java @@ -23,10 +23,6 @@ import java.util.function.LongConsumer; public interface DynamicProperties { - - DynamicProperties DEFAULT_PROPERTY_OBSERVATION = new DynamicProperties() { - }; - default String getStringProperty(String propertyName, Consumer consumer, String defaultValue) { return defaultValue; } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesImpl.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesImpl.java index 027d70c4112..323e84d80aa 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesImpl.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesImpl.java @@ -17,109 +17,163 @@ package org.apache.servicecomb.config; -import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; import java.util.function.LongConsumer; -import org.apache.commons.configuration.AbstractConfiguration; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.springframework.core.env.Environment; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicBooleanProperty; -import com.netflix.config.DynamicDoubleProperty; -import com.netflix.config.DynamicFloatProperty; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicLongProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; +import com.google.common.eventbus.Subscribe; -class DynamicPropertiesImpl implements DynamicProperties { +public class DynamicPropertiesImpl implements DynamicProperties { + private static class Holder { + C callback; - DynamicPropertiesImpl() { + D defaultValue; + + Holder(C callback, D defaultValue) { + this.callback = callback; + this.defaultValue = defaultValue; + } } - DynamicPropertiesImpl(AbstractConfiguration... configurations) { - ConcurrentCompositeConfiguration configuration = new ConcurrentCompositeConfiguration(); - Arrays.stream(configurations).forEach(configuration::addConfiguration); + private final Map, String>>> stringCallbacks = new ConcurrentHashMap<>(); + + private final Map>> intCallbacks = new ConcurrentHashMap<>(); + + private final Map>> longCallbacks = new ConcurrentHashMap<>(); + + private final Map>> floatCallbacks = new ConcurrentHashMap<>(); - ConfigurationManager.install(configuration); + private final Map>> doubleCallbacks = new ConcurrentHashMap<>(); + + private final Map, Boolean>>> booleanCallbacks = new ConcurrentHashMap<>(); + + private final Environment environment; + + public DynamicPropertiesImpl(Environment environment) { + this.environment = environment; + EventManager.register(this); + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (Entry entry : event.getAdded().entrySet()) { + updateValue(entry); + } + + for (Entry entry : event.getUpdated().entrySet()) { + updateValue(entry); + } + + for (Entry entry : event.getDeleted().entrySet()) { + updateValue(entry); + } + } + + private void updateValue(Entry entry) { + if (stringCallbacks.containsKey(entry.getKey())) { + for (Holder, String> callbacks : stringCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), callbacks.defaultValue)); + } + } + if (intCallbacks.containsKey(entry.getKey())) { + for (Holder callbacks : intCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), Integer.class, callbacks.defaultValue)); + } + } + if (longCallbacks.containsKey(entry.getKey())) { + for (Holder callbacks : longCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), Long.class, callbacks.defaultValue)); + } + } + if (floatCallbacks.containsKey(entry.getKey())) { + for (Holder callbacks : floatCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), Float.class, callbacks.defaultValue)); + } + } + if (doubleCallbacks.containsKey(entry.getKey())) { + for (Holder callbacks : doubleCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), Double.class, callbacks.defaultValue)); + } + } + if (booleanCallbacks.containsKey(entry.getKey())) { + for (Holder, Boolean> callbacks : booleanCallbacks.get(entry.getKey())) { + callbacks.callback.accept(environment.getProperty(entry.getKey(), Boolean.class, callbacks.defaultValue)); + } + } } @Override public String getStringProperty(String propertyName, Consumer consumer, String defaultValue) { - DynamicStringProperty prop = propertyFactoryInstance().getStringProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + stringCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, defaultValue); } @Override public String getStringProperty(String propertyName, String defaultValue) { - return propertyFactoryInstance().getStringProperty(propertyName, defaultValue).get(); + return environment.getProperty(propertyName, defaultValue); } @Override public int getIntProperty(String propertyName, IntConsumer consumer, int defaultValue) { - DynamicIntProperty prop = propertyFactoryInstance().getIntProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + intCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, int.class, defaultValue); } @Override public int getIntProperty(String propertyName, int defaultValue) { - return propertyFactoryInstance().getIntProperty(propertyName, defaultValue).get(); + return environment.getProperty(propertyName, int.class, defaultValue); } @Override public long getLongProperty(String propertyName, LongConsumer consumer, long defaultValue) { - DynamicLongProperty prop = propertyFactoryInstance().getLongProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + longCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, long.class, defaultValue); } @Override public long getLongProperty(String propertyName, long defaultValue) { - return propertyFactoryInstance().getLongProperty(propertyName, defaultValue).get(); + return environment.getProperty(propertyName, long.class, defaultValue); } @Override public float getFloatProperty(String propertyName, DoubleConsumer consumer, float defaultValue) { - DynamicFloatProperty prop = propertyFactoryInstance().getFloatProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + floatCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, float.class, defaultValue); } @Override public float getFloatProperty(String propertyName, float defaultValue) { - return propertyFactoryInstance().getFloatProperty(propertyName, defaultValue).get(); + return environment.getProperty(propertyName, float.class, defaultValue); } @Override public double getDoubleProperty(String propertyName, DoubleConsumer consumer, double defaultValue) { - DynamicDoubleProperty prop = propertyFactoryInstance().getDoubleProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + doubleCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, double.class, defaultValue); } @Override public double getDoubleProperty(String propertyName, double defaultValue) { - return propertyFactoryInstance().getDoubleProperty(propertyName, defaultValue).get(); + return environment.getProperty(propertyName, double.class, defaultValue); } @Override public boolean getBooleanProperty(String propertyName, Consumer consumer, boolean defaultValue) { - DynamicBooleanProperty prop = propertyFactoryInstance().getBooleanProperty(propertyName, defaultValue); - prop.addCallback(() -> consumer.accept(prop.get())); - return prop.get(); + booleanCallbacks.computeIfAbsent(propertyName, key -> new HashSet<>()).add(new Holder<>(consumer, defaultValue)); + return environment.getProperty(propertyName, boolean.class, defaultValue); } @Override public boolean getBooleanProperty(String propertyName, boolean defaultValue) { - return propertyFactoryInstance().getBooleanProperty(propertyName, defaultValue).get(); - } - - private DynamicPropertyFactory propertyFactoryInstance() { - return DynamicPropertyFactory.getInstance(); + return environment.getProperty(propertyName, boolean.class, defaultValue); } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesSource.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesSource.java new file mode 100644 index 00000000000..8634bff29f3 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/DynamicPropertiesSource.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config; + +import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; + +/** + * SPI to add new DynamicPropertiesSource. + */ +public interface DynamicPropertiesSource extends Ordered { + PropertySource create(Environment environment); +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/FoundationConfigConfiguration.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/FoundationConfigConfiguration.java new file mode 100644 index 00000000000..1f74e897dd6 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/FoundationConfigConfiguration.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config; + +import org.apache.servicecomb.config.inject.InjectBeanPostProcessor; +import org.apache.servicecomb.config.priority.ConfigObjectFactory; +import org.apache.servicecomb.config.priority.PriorityPropertyFactory; +import org.apache.servicecomb.config.priority.PriorityPropertyManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.env.Environment; + +@Configuration +@SuppressWarnings("unused") +public class FoundationConfigConfiguration { + @Bean + public static InjectBeanPostProcessor scbInjectBeanPostProcessor( + @Autowired @Lazy PriorityPropertyManager priorityPropertyManager) { + return new InjectBeanPostProcessor(priorityPropertyManager); + } + + @Bean + public PriorityPropertyManager scbPriorityPropertyManager(ConfigObjectFactory configObjectFactory) { + return new PriorityPropertyManager(configObjectFactory); + } + + @Bean + public PriorityPropertyFactory scbPriorityPropertyFactory(Environment environment) { + return new PriorityPropertyFactory(environment); + } + + @Bean + public DynamicPropertiesImpl scbDynamicProperties(Environment environment) { + return new DynamicPropertiesImpl(environment); + } + + @Bean + public ConfigObjectFactory scbConfigObjectFactory(PriorityPropertyFactory propertyFactory) { + return new ConfigObjectFactory(propertyFactory); + } + + @Bean + @ConfigurationProperties(prefix = DataCenterProperties.PREFIX) + public DataCenterProperties scbDataCenterProperties() { + return new DataCenterProperties(); + } + + @Bean + public InMemoryDynamicPropertiesSource scbInMemoryDynamicPropertiesSource() { + return new InMemoryDynamicPropertiesSource(); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/InMemoryDynamicPropertiesSource.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/InMemoryDynamicPropertiesSource.java new file mode 100644 index 00000000000..f6139af0a24 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/InMemoryDynamicPropertiesSource.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +/** + * This DynamicPropertiesSource is created for easier system tests. + */ +public class InMemoryDynamicPropertiesSource implements DynamicPropertiesSource { + public static final String SOURCE_NAME = "in-memory"; + + private static final Map DYNAMIC = new HashMap<>(); + + @Override + public PropertySource create(Environment environment) { + return new MapPropertySource(SOURCE_NAME, DYNAMIC); + } + + @Override + public int getOrder() { + return -100; + } + + public static void update(String key, Object value) { + DYNAMIC.put(key, value); + + HashMap updated = new HashMap<>(); + updated.put(key, value); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + } + + public static void reset() { + DYNAMIC.clear(); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/LastPropertyPlaceholderConfigurer.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/LastPropertyPlaceholderConfigurer.java deleted file mode 100644 index 374334e45bf..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/LastPropertyPlaceholderConfigurer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; -import org.springframework.core.Ordered; -import org.springframework.stereotype.Component; - -// do not implements PriorityOrdered, must be Ordered -// because this bean must run after PropertyPlaceholderConfigurer -// this class's purpose: when asked to resolve placeholder, then throw exception directly -@Component -public class LastPropertyPlaceholderConfigurer implements BeanFactoryPostProcessor, Ordered { - @Override - public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - new PropertyPlaceholderConfigurer().postProcessBeanFactory(beanFactory); - } -} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java index abcf1fa749a..2dc116a304b 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/YAMLUtil.java @@ -17,22 +17,25 @@ package org.apache.servicecomb.config; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_CSE_PREFIX; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_SERVICECOMB_PREFIX; - import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.constructor.SafeConstructor; -/** - * Created by on 2017/1/5. - */ public final class YAMLUtil { private YAMLUtil() { } + private static Yaml safeParser() { + // Yaml instance is not thread safe, create a new instance for each parser + return new Yaml(new SafeConstructor(new LoaderOptions())); + } + /** * load a input {@link InputStream} to be a map {@link Map}, you have to close the inputStream by yourself, such as:
*

try (InputStream in = url.openStream()) {
@@ -45,27 +48,67 @@ private YAMLUtil() { @SuppressWarnings("unchecked") public static Map yaml2Properties(InputStream input) { Map configurations = new LinkedHashMap<>(); - Yaml yaml = new Yaml(); - yaml.loadAll(input).forEach(data -> configurations.putAll(retrieveItems("", (Map) data))); + safeParser().loadAll(input).forEach(data -> { + if (data instanceof Map && isValidMap((Map) data)) { + configurations.putAll(retrieveItems("", (Map) data)); + } else { + throw new IllegalArgumentException("input cannot be convert to map"); + } + }); return configurations; } @SuppressWarnings("unchecked") - public static Map retrieveItems(String prefix, Map propertieMap) { + private static boolean isValidMap(Map data) { + for (Map.Entry entry : data.entrySet()) { + Object key = entry.getKey(); + Object value = entry.getValue(); + if (key instanceof String) { + if (value instanceof Map) { + return isValidMap((Map) value); + } + continue; + } + return false; + } + return true; + } + + /** + * load a input {@link String} to be a map {@link Map} + * @param input the String to be loaded + * @return a config map + */ + @SuppressWarnings("unchecked") + public static Map yaml2Properties(String input) { + Map configurations = new LinkedHashMap<>(); + safeParser().loadAll(input).forEach(data -> { + if (data instanceof Map && isValidMap((Map) data)) { + configurations.putAll(retrieveItems("", (Map) data)); + } else { + throw new IllegalArgumentException("input cannot be convert to map"); + } + }); + return configurations; + } + + public static T parserObject(String yamlContent, Class clazz) { + Yaml parser = new Yaml(new Constructor(new TypeDescription(clazz, clazz), new LoaderOptions())); + return parser.loadAs(yamlContent, clazz); + } + + @SuppressWarnings("unchecked") + public static Map retrieveItems(String prefix, Map propertiesMap) { Map result = new LinkedHashMap<>(); if (!prefix.isEmpty()) { prefix += "."; } - for (Map.Entry entry : propertieMap.entrySet()) { + for (Map.Entry entry : propertiesMap.entrySet()) { if (entry.getValue() instanceof Map) { result.putAll(retrieveItems(prefix + entry.getKey(), (Map) entry.getValue())); } else { String key = prefix + entry.getKey(); - if (key.startsWith(CONFIG_CSE_PREFIX)) { - String servicecombKey = CONFIG_SERVICECOMB_PREFIX + key.substring(key.indexOf(".") + 1); - result.put(servicecombKey, entry.getValue()); - } result.put(key, entry.getValue()); } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/scheduler/NeverStartPollingScheduler.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/scheduler/NeverStartPollingScheduler.java deleted file mode 100644 index fb52d066385..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/scheduler/NeverStartPollingScheduler.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.scheduler; - -import com.netflix.config.AbstractPollingScheduler; - -/** - * Created by on 2017/3/29. - */ -public class NeverStartPollingScheduler extends AbstractPollingScheduler { - @Override - protected void schedule(Runnable runnable) { - return; - } - - @Override - public void stop() { - return; - } -} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigSourceMaker.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigSourceMaker.java deleted file mode 100644 index f822e30d985..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigSourceMaker.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -public class ConfigSourceMaker { - - public static MicroserviceConfigurationSource yamlConfigSource() { - MicroserviceConfigLoader loader = new MicroserviceConfigLoader(); - loader.loadAndSort(); - - return new MicroserviceConfigurationSource(loader.getConfigModels()); - } -} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigurationSource.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigurationSource.java deleted file mode 100644 index e39c987a710..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigurationSource.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.config.YAMLUtil; - -import com.netflix.config.PollResult; -import com.netflix.config.PolledConfigurationSource; - -public class MicroserviceConfigurationSource implements PolledConfigurationSource { - private final List configModels; - - public MicroserviceConfigurationSource(List configModels) { - this.configModels = configModels; - } - - public List getConfigModels() { - return configModels; - } - - public PollResult poll(boolean b, Object o) throws Exception { - Map configurations = new LinkedHashMap<>(); - - for (ConfigModel configModel : configModels) { - configurations.putAll(YAMLUtil.retrieveItems("", configModel.getConfig())); - } - - return PollResult.createFull(configurations); - } -} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/AbstractConfigLoader.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/AbstractConfigLoader.java similarity index 95% rename from foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/AbstractConfigLoader.java rename to foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/AbstractConfigLoader.java index fad59592a21..085afc8c7e5 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/AbstractConfigLoader.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/AbstractConfigLoader.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.config.archaius.sources; +package org.apache.servicecomb.config.file; import java.io.IOException; import java.net.URL; @@ -33,7 +33,7 @@ public abstract class AbstractConfigLoader { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractConfigLoader.class); - private static final String ORDER_KEY = "servicecomb-config-order"; + public static final String ORDER_KEY = "servicecomb-config-order"; protected final List configModels = new ArrayList<>(); @@ -56,7 +56,7 @@ protected void loadFromClassPath(String resourceName) throws IOException { public ConfigModel load(URL url) throws IOException { Map config = loadData(url); // load a empty or all commented yaml, will get a null map - // this is not a error + // this is not an error if (config == null) { config = new LinkedHashMap<>(); } @@ -98,7 +98,7 @@ protected List findURLFromClassPath(String resourceName) throws IOException return urlList; } - private class ConfigModelWrapper { + private static class ConfigModelWrapper { ConfigModel model; int addOrder; diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigModel.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/ConfigModel.java similarity index 85% rename from foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigModel.java rename to foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/ConfigModel.java index e9c263db178..41732f9ab71 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/ConfigModel.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/ConfigModel.java @@ -15,12 +15,15 @@ * limitations under the License. */ -package org.apache.servicecomb.config.archaius.sources; +package org.apache.servicecomb.config.file; import java.net.URL; import java.util.Map; +import org.apache.servicecomb.foundation.common.utils.IOUtils; + public class ConfigModel { + private URL url; private int order; @@ -50,4 +53,10 @@ public Map getConfig() { public void setConfig(Map config) { this.config = config; } + + @Override + public String toString() { + return url == null ? "" : IOUtils.anonymousPath(url.toString()); + } + } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigLoader.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/MicroserviceConfigLoader.java similarity index 93% rename from foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigLoader.java rename to foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/MicroserviceConfigLoader.java index f0229782739..f33f9cc237f 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/MicroserviceConfigLoader.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/MicroserviceConfigLoader.java @@ -15,15 +15,16 @@ * limitations under the License. */ -package org.apache.servicecomb.config.archaius.sources; +package org.apache.servicecomb.config.file; import java.io.IOException; import java.net.URL; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; + public class MicroserviceConfigLoader extends YAMLConfigLoader { private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceConfigLoader.class); @@ -52,8 +53,9 @@ public MicroserviceConfigLoader() { } public void loadAndSort() { + String configFileFromClasspath = null; try { - String configFileFromClasspath = + configFileFromClasspath = System.getProperty(DEFAULT_FILE_NAME) == null ? DEFAULT_CONFIG_FILE_NAME : System.getProperty(DEFAULT_FILE_NAME); super.load(configFileFromClasspath); @@ -68,8 +70,8 @@ public void loadAndSort() { } sort(); - } catch (IOException e) { - throw new ServiceCombException("Failed to load microservice config", e); + } catch (Exception e) { + throw new ServiceCombException("Failed to load microservice configFile " + configFileFromClasspath, e); } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/YAMLConfigLoader.java similarity index 84% rename from foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java rename to foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/YAMLConfigLoader.java index f0fb4536e0b..ac69e8d4df0 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/archaius/sources/YAMLConfigLoader.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/file/YAMLConfigLoader.java @@ -15,23 +15,20 @@ * limitations under the License. */ -package org.apache.servicecomb.config.archaius.sources; +package org.apache.servicecomb.config.file; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Map; -import org.yaml.snakeyaml.Yaml; +import org.apache.servicecomb.config.YAMLUtil; public class YAMLConfigLoader extends AbstractConfigLoader { - @SuppressWarnings("unchecked") @Override protected Map loadData(URL url) throws IOException { - Yaml yaml = new Yaml(); - try (InputStream inputStream = url.openStream()) { - return yaml.loadAs(inputStream, Map.class); + return YAMLUtil.yaml2Properties(inputStream); } } } diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java new file mode 100644 index 00000000000..fbdeff42554 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectBeanPostProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.inject; + +import java.util.Collections; + +import org.apache.servicecomb.config.priority.PriorityPropertyManager; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +public class InjectBeanPostProcessor implements BeanPostProcessor { + private final PriorityPropertyManager priorityPropertyManager; + + public InjectBeanPostProcessor(PriorityPropertyManager priorityPropertyManager) { + this.priorityPropertyManager = priorityPropertyManager; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Class beanCls = BeanUtils.getImplClassFromBean(bean); + InjectProperties injectProperties = beanCls.getAnnotation(InjectProperties.class); + if (injectProperties == null) { + return bean; + } + + priorityPropertyManager.createConfigObject(bean, Collections.emptyMap()); + + return bean; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperties.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperties.java new file mode 100644 index 00000000000..1bee2882473 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.inject; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(RUNTIME) +@Target(TYPE) +@Inherited +public @interface InjectProperties { + /** + * The name prefix of the properties that are valid to bind to this object. + * @return the name prefix of the properties to bind + */ + String prefix() default ""; +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperty.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperty.java new file mode 100644 index 00000000000..3c19e6f7e1d --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/InjectProperty.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.inject; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(RUNTIME) +@Target(FIELD) +public @interface InjectProperty { + /** + * override prefix of {@link InjectProperties} + * @return prefix of keys + */ + String prefix() default ""; + + /** + *

+   * The name of the property
+   * 1.support priority
+   *   high,middle,low
+   * 2.support placeholder
+   *   name is root.${placeholder-1}.name
+   *   placeholder-1 is k1
+   *   then final name is root.k1.name
+   * 3.placeholder can be a list
+   *   name is root.${placeholder-1}.name
+   *   placeholder-1 is a list, value is k1-1/k1-2
+   *   then final name is root.k1-1.name/root.k1-2.name
+   * 
+ * @return the name of the property + */ + String[] keys() default {}; + + String defaultValue() default ""; +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/PlaceholderResolver.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/PlaceholderResolver.java new file mode 100644 index 00000000000..b05ab11a73c --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/inject/PlaceholderResolver.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.inject; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; + +/** + *
+ * not care for performance
+ *
+ * behavior of multiple list if defined:
+ *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#multi_list()
+ * behavior of nested and multiple list variable is undefined
+ *   org.apache.servicecomb.config.inject.TestPlaceholderResolver#mixed()
+ * 
+ */ +public class PlaceholderResolver { + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("(?\\\\)?\\$\\{(?[^{}]+)\\}"); + + static class SplitPart { + boolean var; + + String fullName; + + Object value; + + public SplitPart(boolean var, String fullName) { + this.var = var; + this.fullName = fullName; + } + + @Override + public String toString() { + return "SplitPart{" + + "var=" + var + + ", fullName='" + fullName + '\'' + + ", value=" + value + + '}'; + } + } + + static class Row { + List parts = new ArrayList<>(); + + int cartesianProductCount = 1; + + int varCount = 0; + } + + public String replaceFirst(String str) { + return replace(str, Collections.emptyMap()).get(0); + } + + public String replaceFirst(String str, Map parameters) { + return replace(str, parameters).get(0); + } + + public List replace(String str, Map parameters) { + List finalRows = replaceToRows(str, parameters); + + List replaced = new ArrayList<>(); + for (Row row : finalRows) { + resolve(row, replaced); + } + + replaced.replaceAll(s -> s.replace("\\$", "$")); + return replaced; + } + + private List replaceToRows(String str, Map parameters) { + List finalRows = new ArrayList<>(); + List remainRows = new ArrayList<>(); + replaceToRows(str, parameters, remainRows, finalRows); + + for (String row : remainRows) { + List nestedRows = replaceToRows(row, parameters); + finalRows.addAll(nestedRows); + } + return finalRows; + } + + private void replaceToRows(String str, Map parameters, List remainRows, + List finalRows) { + Row row = parseToRow(str, parameters); + if (row.varCount == 0 && row.cartesianProductCount == 1) { + finalRows.add(row); + return; + } + + resolve(row, remainRows); + } + + private Row parseToRow(String str, Map parameters) { + Matcher matcher = PLACEHOLDER_PATTERN.matcher(str); + Row row = new Row(); + + int last = 0; + while (matcher.find()) { + row.parts.add(new SplitPart(false, str.substring(last, matcher.start()))); + last = matcher.end(); + + if (matcher.group("escape") != null) { + row.parts.add(new SplitPart(false, matcher.group().substring(1))); + continue; + } + + String name = matcher.group("name"); + Object value = findValue(parameters, name); + if (value instanceof Collection) { + row.cartesianProductCount *= ((Collection) value).size(); + } + if (value != null) { + row.varCount++; + } + + SplitPart splitPart = new SplitPart(value != null, matcher.group()); + splitPart.value = value; + row.parts.add(splitPart); + } + row.parts.add(new SplitPart(false, str.substring(last))); + + return row; + } + + // resolve placeholder and execute cartesian product + @SuppressWarnings("unchecked") + private void resolve(Row row, List resolvedRows) { + List stringBuilders = new ArrayList<>(); + for (int idx = 0; idx < row.cartesianProductCount; idx++) { + stringBuilders.add(new StringBuilder()); + } + + int collectionRepeatCount = 1; + for (SplitPart part : row.parts) { + if (!part.var) { + for (int idx = 0; idx < row.cartesianProductCount; idx++) { + StringBuilder sb = stringBuilders.get(idx); + + if (part.fullName.startsWith("$")) { + sb.append("\\" + part.fullName); + continue; + } + + sb.append(part.fullName); + } + continue; + } + + if (part.value instanceof Collection) { + int size = ((Collection) part.value).size(); + int rowRepeatCount = row.cartesianProductCount / size / collectionRepeatCount; + + int valueIdx = 0; + for (int collectionRepeatIdx = 0; collectionRepeatIdx < collectionRepeatCount; collectionRepeatIdx++) { + for (String value : (Collection) part.value) { + for (int repeatIdx = 0; repeatIdx < rowRepeatCount; repeatIdx++) { + StringBuilder sb = stringBuilders.get(valueIdx); + valueIdx++; + sb.append(value); + } + } + } + + collectionRepeatCount *= size; + continue; + } + + // normal var + for (int idx = 0; idx < row.cartesianProductCount; idx++) { + StringBuilder sb = stringBuilders.get(idx); + sb.append(part.value); + } + } + + for (StringBuilder sb : stringBuilders) { + resolvedRows.add(sb.toString()); + } + } + + private Object findValue(Map parameters, String key) { + Object value = parameters.get(key); + if (value == null) { + value = LegacyPropertyFactory.getStringProperty(key); + } + return value; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/Parser.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/Parser.java new file mode 100644 index 00000000000..216253a67f1 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/Parser.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.parser; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; + +public interface Parser { + String CONTENT_TYPE_YAML = "yaml"; + String CONTENT_TYPE_PROPERTIES = "properties"; + String CONTENT_TYPE_RAW = "raw"; + + YamlParser yamlParser = new YamlParser(); + PropertiesParser propertiesParser = new PropertiesParser(); + RawParser rawParser = new RawParser(); + + Map parse(String content, String prefix, boolean addPrefix); + + static Parser findParser(String contentType) { + switch (contentType) { + case CONTENT_TYPE_YAML: + return yamlParser; + case CONTENT_TYPE_PROPERTIES: + return propertiesParser; + case CONTENT_TYPE_RAW: + return rawParser; + default: + throw new IllegalArgumentException("not supported contentType=" + contentType); + } + } + + @SuppressWarnings("unchecked") + static Map propertiesToMap(Properties properties, String prefix, boolean addPrefix) { + Map result = new HashMap<>(); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + String value = properties.getProperty(key); + + if (addPrefix && !StringUtils.isEmpty(prefix)) { + key = prefix + "." + key; + } + + if (value == null) { + result.put(key, null); + } else { + result.put(key, value.trim()); + } + } + return result; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/PropertiesParser.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/PropertiesParser.java new file mode 100644 index 00000000000..84bfae13d3a --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/PropertiesParser.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.parser; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PropertiesParser implements Parser { + private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesParser.class); + + @Override + public Map parse(String content, String prefix, boolean addPrefix) { + Properties properties = new Properties(); + try { + properties.load(new StringReader(content)); + } catch (IOException e) { + LOGGER.error("parse properties content failed, message={}", e.getMessage()); + } + return Parser.propertiesToMap(properties, prefix, addPrefix); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/RawParser.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/RawParser.java new file mode 100644 index 00000000000..b22d52d42fb --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/RawParser.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.parser; + +import java.util.HashMap; +import java.util.Map; + +public class RawParser implements Parser { + @Override + public Map parse(String content, String prefix, boolean addPrefix) { + Map result = new HashMap<>(); + result.put(prefix, content); + return result; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/YamlParser.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/YamlParser.java new file mode 100644 index 00000000000..fd572eaab55 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/parser/YamlParser.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.parser; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Properties; + +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.io.ByteArrayResource; + +public class YamlParser implements Parser { + @Override + public Map parse(String content, String prefix, boolean addPrefix) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8))); + Properties properties = yamlFactory.getObject(); + return Parser.propertiesToMap(properties, prefix, addPrefix); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObject.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObject.java new file mode 100644 index 00000000000..19e75c1ed34 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObject.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import java.util.List; + +public class ConfigObject { + private final T instance; + + private final List properties; + + public ConfigObject(T instance, List properties) { + this.instance = instance; + this.properties = properties; + } + + public T getInstance() { + return instance; + } + + public List getProperties() { + return properties; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectFactory.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectFactory.java new file mode 100644 index 00000000000..ff18b827e39 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectFactory.java @@ -0,0 +1,237 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.inject.InjectProperties; +import org.apache.servicecomb.config.inject.InjectProperty; +import org.apache.servicecomb.config.inject.PlaceholderResolver; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.type.TypeFactory; + +/** + * must create by PriorityPropertyManager
+ * or register to PriorityPropertyManager manually
+ *
+ * ${} or ${not-exist-key} is valid key in archaius
+ * so this wrapper mechanism will not throw exception even can not find value by placeholder + */ +public class ConfigObjectFactory { + private final PriorityPropertyFactory propertyFactory; + + private final Map, JavaType> classCache = new ConcurrentHashMapEx<>(); + + private final Map javaTypeCache = new ConcurrentHashMapEx<>(); + + private final Map> beanDescriptionCache = new ConcurrentHashMapEx<>(); + + public ConfigObjectFactory(PriorityPropertyFactory propertyFactory) { + this.propertyFactory = propertyFactory; + } + + public PriorityPropertyFactory getPropertyFactory() { + return propertyFactory; + } + + public ConfigObject create(Class cls, Map parameters) { + try { + return create(cls.getDeclaredConstructor().newInstance(), parameters); + } catch (Throwable e) { + throw new IllegalStateException("create config object failed, class=" + cls.getName(), e); + } + } + + public ConfigObject create(T instance, Map parameters) { + String prefix = initPrefix(instance.getClass()); + List properties = createProperties(instance, prefix, parameters); + + return new ConfigObject<>(instance, properties); + } + + private String initPrefix(Class cls) { + InjectProperties injectProperties = cls.getAnnotation(InjectProperties.class); + if (injectProperties == null) { + return ""; + } + + String prefix = injectProperties.prefix(); + if (prefix.isEmpty()) { + return ""; + } + return prefix + "."; + } + + public List createProperties(Object instance, String prefix, Map parameters) { + List properties = new ArrayList<>(); + JavaType javaType = classCache.computeIfAbsent(instance.getClass(), TypeFactory.defaultInstance()::constructType); + BeanDescription beanDescription = javaTypeCache.computeIfAbsent(javaType, + JsonUtils.OBJ_MAPPER.getSerializationConfig()::introspect); + for (BeanPropertyDefinition propertyDefinition : beanDescription.findProperties()) { + if (propertyDefinition.getField() == null) { + continue; + } + + if (propertyDefinition.getSetter() == null && !propertyDefinition.getField().isPublic()) { + continue; + } + + PriorityProperty priorityProperty = createPriorityProperty(propertyDefinition.getField().getAnnotated(), + prefix, parameters); + if (priorityProperty == null) { + continue; + } + Setter setter = beanDescriptionCache.computeIfAbsent(propertyDefinition, + LambdaMetafactoryUtils::createObjectSetter); + setter.set(instance, priorityProperty.getValue()); + properties.add(new ConfigObjectProperty(setter, priorityProperty)); + } + return properties; + } + + private PriorityProperty createPriorityProperty(Field field, String prefix, Map parameters) { + String[] keys = collectPropertyKeys(field, prefix, parameters); + + Class fieldCls = field.getType(); + switch (fieldCls.getName()) { + case "int": + return createIntProperty(field, keys, 0); + case "java.lang.Integer": + return createIntProperty(field, keys, null); + case "long": + return createLongProperty(field, keys, 0L); + case "java.lang.Long": + return createLongProperty(field, keys, null); + case "java.lang.String": + return createStringProperty(field, keys); + case "float": + return createFloatProperty(field, keys, 0f); + case "java.lang.Float": + return createFloatProperty(field, keys, null); + case "double": + return createDoubleProperty(field, keys, 0.0); + case "java.lang.Double": + return createDoubleProperty(field, keys, null); + case "boolean": + return createBooleanProperty(field, keys, false); + case "java.lang.Boolean": + return createBooleanProperty(field, keys, null); + default: + return null; + } + } + + private PriorityProperty createStringProperty(Field field, String[] keys) { + String defaultValue = null; + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = injectProperty.defaultValue(); + } + } + + return propertyFactory.getOrCreate(String.class, null, defaultValue, keys); + } + + private PriorityProperty createDoubleProperty(Field field, String[] keys, Double defaultValue) { + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = Double.parseDouble(injectProperty.defaultValue()); + } + } + + return propertyFactory.getOrCreate(Double.class, null, defaultValue, keys); + } + + private PriorityProperty createFloatProperty(Field field, String[] keys, Float defaultValue) { + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = Float.parseFloat(injectProperty.defaultValue()); + } + } + + return propertyFactory.getOrCreate(Float.class, null, defaultValue, keys); + } + + private PriorityProperty createBooleanProperty(Field field, String[] keys, Boolean defaultValue) { + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = Boolean.parseBoolean(injectProperty.defaultValue()); + } + } + + return propertyFactory.getOrCreate(Boolean.class, null, defaultValue, keys); + } + + private PriorityProperty createLongProperty(Field field, String[] keys, Long defaultValue) { + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = Long.parseLong(injectProperty.defaultValue()); + } + } + + return propertyFactory.getOrCreate(Long.class, null, defaultValue, keys); + } + + private PriorityProperty createIntProperty(Field field, String[] keys, Integer defaultValue) { + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.defaultValue().isEmpty()) { + defaultValue = Integer.parseInt(injectProperty.defaultValue()); + } + } + + return propertyFactory.getOrCreate(Integer.class, null, defaultValue, keys); + } + + private String[] collectPropertyKeys(Field field, String prefix, Map parameters) { + String propertyPrefix = prefix; + String[] keys = new String[] {field.getName()}; + + InjectProperty injectProperty = field.getAnnotation(InjectProperty.class); + if (injectProperty != null) { + if (!injectProperty.prefix().isEmpty()) { + propertyPrefix = injectProperty.prefix() + "."; + } + if (injectProperty.keys().length != 0) { + keys = injectProperty.keys(); + } + } + + List finalKeys = new ArrayList<>(); + for (String key : keys) { + List resolvedKeys = new PlaceholderResolver().replace(propertyPrefix + key, parameters); + finalKeys.addAll(resolvedKeys); + } + + return finalKeys.toArray(new String[0]); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectProperty.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectProperty.java new file mode 100644 index 00000000000..be17eee8644 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/ConfigObjectProperty.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import org.apache.servicecomb.foundation.common.utils.bean.Setter; + +/** + * do not reference config object instance, otherwise gc for weak hash map will failed + */ +public class ConfigObjectProperty { + private final Setter setter; + + private final PriorityProperty property; + + public ConfigObjectProperty(Setter setter, PriorityProperty property) { + this.setter = setter; + this.property = property; + } + + public void updateValueWhenChanged(Object instance, String changedKey) { + if (property.isChangedKey(changedKey)) { + property.updateValue(); + setter.set(instance, property.getValue()); + } + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/DynamicProperty.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/DynamicProperty.java new file mode 100644 index 00000000000..48588b6ec04 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/DynamicProperty.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import org.springframework.core.env.Environment; + +public class DynamicProperty { + private final Environment environment; + + private final String propName; + + public DynamicProperty(Environment environment, String propName) { + this.environment = environment; + this.propName = propName; + } + + public Integer getInteger() { + return environment.getProperty(propName, Integer.class); + } + + public Long getLong() { + return environment.getProperty(propName, Long.class); + } + + public String getString() { + return environment.getProperty(propName); + } + + public Boolean getBoolean() { + return environment.getProperty(propName, Boolean.class); + } + + public Double getDouble() { + return environment.getProperty(propName, Double.class); + } + + public Float getFloat() { + return environment.getProperty(propName, Float.class); + } + + public String getName() { + return propName; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityProperty.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityProperty.java new file mode 100644 index 00000000000..c1c30896159 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityProperty.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +/** + * must create by PriorityPropertyManager
+ * or register to PriorityPropertyManager manually + * @param + */ +public final class PriorityProperty { + private static final Logger LOGGER = LoggerFactory.getLogger(PriorityProperty.class); + + private final PriorityPropertyType propertyType; + + private final String joinedPriorityKeys; + + private final Function internalValueReader; + + private final DynamicProperty[] properties; + + private T finalValue; + + public PriorityProperty(Environment environment, PriorityPropertyType propertyType) { + this.propertyType = propertyType; + this.joinedPriorityKeys = Arrays.toString(propertyType.getPriorityKeys()); + this.internalValueReader = collectReader(propertyType.getType()); + this.properties = createProperties(environment, propertyType.getPriorityKeys()); + initValue(); + } + + private DynamicProperty[] createProperties(Environment environment, String[] priorityKeys) { + DynamicProperty[] properties = new DynamicProperty[priorityKeys.length]; + for (int idx = 0; idx < priorityKeys.length; idx++) { + String key = priorityKeys[idx].trim(); + properties[idx] = new DynamicProperty(environment, key); + } + return properties; + } + + private Function collectReader(Type type) { + if (type == int.class || type == Integer.class) { + return this::readInt; + } + + if (type == long.class || type == Long.class) { + return this::readLong; + } + + if (type == String.class) { + return this::readString; + } + + if (type == boolean.class || type == Boolean.class) { + return this::readBoolean; + } + + if (type == double.class || type == Double.class) { + return this::readDouble; + } + + if (type == float.class || type == Float.class) { + return this::readFloat; + } + + throw new IllegalStateException("not support, type=" + type.getTypeName()); + } + + @SuppressWarnings("unchecked") + private T readInt(DynamicProperty property) { + return (T) property.getInteger(); + } + + @SuppressWarnings("unchecked") + private T readLong(DynamicProperty property) { + return (T) property.getLong(); + } + + @SuppressWarnings("unchecked") + private T readString(DynamicProperty property) { + return (T) property.getString(); + } + + @SuppressWarnings("unchecked") + private T readBoolean(DynamicProperty property) { + return (T) property.getBoolean(); + } + + @SuppressWarnings("unchecked") + private T readDouble(DynamicProperty property) { + return (T) property.getDouble(); + } + + @SuppressWarnings("unchecked") + private T readFloat(DynamicProperty property) { + return (T) property.getFloat(); + } + + public String[] getPriorityKeys() { + return propertyType.getPriorityKeys(); + } + + public T getDefaultValue() { + return propertyType.getDefaultValue(); + } + + public DynamicProperty[] getProperties() { + return properties; + } + + void initValue() { + String effectiveKey = doUpdateFinalValue(); + LOGGER.debug("config inited, \"{}\" set to {}, effective key is \"{}\".", + joinedPriorityKeys, finalValue, effectiveKey); + } + + synchronized boolean updateValue() { + T lastValue = finalValue; + String effectiveKey = doUpdateFinalValue(); + if (effectiveKey != null) { + LOGGER.debug("config changed, \"{}\" changed from {} to {}, effective key is \"{}\".", + joinedPriorityKeys, lastValue, finalValue, effectiveKey); + return true; + } + + return false; + } + + /** + * + * @return if value changed, return effectiveKey, otherwise null + */ + private String doUpdateFinalValue() { + T lastValue = finalValue; + + String effectiveKey = "default value"; + T value = propertyType.getDefaultValue(); + for (DynamicProperty property : properties) { + T propValue = internalValueReader.apply(property); + if (propValue == null || propValue.equals(propertyType.getInvalidValue())) { + continue; + } + + effectiveKey = property.getName(); + value = propValue; + break; + } + + if (Objects.equals(lastValue, value)) { + return null; + } + + finalValue = value; + return effectiveKey; + } + + public T getValue() { + return finalValue; + } + + public boolean isChangedKey(String changedKey) { + if (changedKey == null) { + // property source changed or clear, and so on + return true; + } + + for (DynamicProperty property : properties) { + if (changedKey.equals(property.getName())) { + return true; + } + } + + return false; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyFactory.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyFactory.java new file mode 100644 index 00000000000..abd43f8d404 --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import java.lang.reflect.Type; +import java.util.Map; +import java.util.stream.Stream; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +public class PriorityPropertyFactory { + private final Map, PriorityProperty> properties = new ConcurrentHashMapEx<>(); + + private final Environment environment; + + public PriorityPropertyFactory(Environment environment) { + this.environment = environment; + } + + @VisibleForTesting + public Stream> getProperties() { + return properties.values().stream(); + } + + @SuppressWarnings("unchecked") + public PriorityProperty getOrCreate(Type type, T invalidValue, T defaultValue, String... priorityKeys) { + PriorityPropertyType propertyType = new PriorityPropertyType<>(type, invalidValue, defaultValue, priorityKeys); + return (PriorityProperty) properties.computeIfAbsent(propertyType, + key -> new PriorityProperty<>(environment, key)); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyManager.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyManager.java new file mode 100644 index 00000000000..8ed1e7dea2e --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyManager.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import static java.util.Collections.synchronizedMap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.WeakHashMap; + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.foundation.common.event.EventManager; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.Subscribe; + +public class PriorityPropertyManager { + private final ConfigObjectFactory configObjectFactory; + + // key is config object instance + // value is properties of the config object instance + private final Map> configObjectMap = synchronizedMap(new WeakHashMap<>()); + + public PriorityPropertyManager(ConfigObjectFactory configObjectFactory) { + this.configObjectFactory = configObjectFactory; + EventManager.register(this); + } + + public PriorityPropertyFactory getPropertyFactory() { + return configObjectFactory.getPropertyFactory(); + } + + public void close() { + + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + // just loop all properties, it's very fast, no need to do any optimize + for (Entry> entry : configObjectMap.entrySet()) { + Object instance = entry.getKey(); + entry.getValue().forEach( + configObjectProperty -> { + for (String updatedKey : event.getChanged()) { + configObjectProperty.updateValueWhenChanged(instance, updatedKey); + } + }); + } + } + + @VisibleForTesting + public Map> getConfigObjectMap() { + return configObjectMap; + } + + public T createConfigObject(Class cls, Object... kvs) { + Map parameters = new HashMap<>(); + for (int idx = 0; idx < kvs.length; idx += 2) { + parameters.put(kvs[idx].toString(), kvs[idx + 1]); + } + + return createConfigObject(cls, parameters); + } + + public T createConfigObject(Class cls, Map parameters) { + ConfigObject configObject = configObjectFactory.create(cls, parameters); + return saveConfigObject(configObject); + } + + public T createConfigObject(T instance, Map parameters) { + ConfigObject configObject = configObjectFactory.create(instance, parameters); + return saveConfigObject(configObject); + } + + private T saveConfigObject(ConfigObject configObject) { + configObjectMap.put(configObject.getInstance(), configObject.getProperties()); + return configObject.getInstance(); + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyType.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyType.java new file mode 100644 index 00000000000..843bbd83aaa --- /dev/null +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/priority/PriorityPropertyType.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Objects; + +public class PriorityPropertyType { + private final Type type; + + // when got invalid value will try next level + // null always be a invalid value + private final T invalidValue; + + // when got invalid value by lowest level, will use defaultValue + private final T defaultValue; + + // priorityKeys[0] has the highest priority + private final String[] priorityKeys; + + public PriorityPropertyType(Type type, T invalidValue, T defaultValue, String... priorityKeys) { + this.type = type; + this.invalidValue = invalidValue; + this.defaultValue = defaultValue; + this.priorityKeys = priorityKeys; + } + + public Type getType() { + return type; + } + + public T getInvalidValue() { + return invalidValue; + } + + public T getDefaultValue() { + return defaultValue; + } + + public String[] getPriorityKeys() { + return priorityKeys; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PriorityPropertyType that = (PriorityPropertyType) o; + return type.equals(that.type) && Objects.equals(invalidValue, that.invalidValue) && Objects + .equals(defaultValue, that.defaultValue) && Arrays.equals(priorityKeys, that.priorityKeys); + } + + @Override + public int hashCode() { + int result = Objects.hash(type, invalidValue, defaultValue); + result = 31 * result + Arrays.hashCode(priorityKeys); + return result; + } +} diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/spi/ConfigCenterConfigurationSource.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/spi/ConfigCenterConfigurationSource.java deleted file mode 100644 index cc651d9ddd0..00000000000 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/spi/ConfigCenterConfigurationSource.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.spi; - -import org.apache.commons.configuration.Configuration; - -import com.netflix.config.WatchedConfigurationSource; - -public interface ConfigCenterConfigurationSource extends WatchedConfigurationSource { - boolean isValidSource(Configuration localConfiguration); - - void init(Configuration localConfiguration); - - default void destroy() { - - } -} diff --git a/foundations/foundation-config/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource b/foundations/foundation-config/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource new file mode 100644 index 00000000000..1f148e651eb --- /dev/null +++ b/foundations/foundation-config/src/main/resources/META-INF/services/org.apache.servicecomb.config.DynamicPropertiesSource @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.config.InMemoryDynamicPropertiesSource diff --git a/foundations/foundation-config/src/main/resources/META-INF/spring.factories b/foundations/foundation-config/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000000..1654b618370 --- /dev/null +++ b/foundations/foundation-config/src/main/resources/META-INF/spring.factories @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.springframework.boot.env.EnvironmentPostProcessor=\ + org.apache.servicecomb.config.ConfigEnvironmentPostProcessor diff --git a/foundations/foundation-config/src/main/resources/META-INF/spring/cse.bean.xml b/foundations/foundation-config/src/main/resources/META-INF/spring/cse.bean.xml deleted file mode 100644 index 952cfc03782..00000000000 --- a/foundations/foundation-config/src/main/resources/META-INF/spring/cse.bean.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - diff --git a/foundations/foundation-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/foundations/foundation-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..5d39e597fdc --- /dev/null +++ b/foundations/foundation-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.config.FoundationConfigConfiguration diff --git a/foundations/foundation-config/src/main/resources/mapping.yaml b/foundations/foundation-config/src/main/resources/mapping.yaml index 8bccf589448..83cd60bbc75 100644 --- a/foundations/foundation-config/src/main/resources/mapping.yaml +++ b/foundations/foundation-config/src/main/resources/mapping.yaml @@ -14,5 +14,9 @@ ## See the License for the specific language governing permissions and ## limitations under the License. ## --------------------------------------------------------------------------- +servicecomb-config-order: -100 SERVICECOMB_ENV: service_description.environment + +servicecomb.loadbalance.stats.timerIntervalInMilis: + - servicecomb.loadbalance.stats.timerIntervalInMillis diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/BootStrapPropertiesTest.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/BootStrapPropertiesTest.java new file mode 100644 index 00000000000..38a8a4a8b5d --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/BootStrapPropertiesTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config; + +import static org.apache.servicecomb.foundation.test.scaffolding.AssertUtils.assertPrettyJson; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Map.Entry; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; + +public class BootStrapPropertiesTest { + private Map readInstanceProperties(String yaml) { + Map properties = YAMLUtil.yaml2Properties(yaml); + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + MapPropertySource propertySource = new MapPropertySource("yaml", properties); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + + for (Entry entry : properties.entrySet()) { + Mockito.when(environment.getProperty(entry.getKey())).thenReturn(entry.getValue().toString()); + } + + return BootStrapProperties.readServiceInstanceProperties(environment); + } + + @Test + void should_be_empty_when_old_and_new_key_not_exists() { + Map properties = readInstanceProperties("k: v"); + + assertThat(properties).isEmpty(); + } + + @Test + void should_read_boolean_to_string() { + Map properties = readInstanceProperties(""" + servicecomb: + instance: + properties: + k: true"""); + + assertPrettyJson(properties).isEqualTo(""" + { + "k" : "true" + }"""); + } + + @Test + void should_read_number_to_string() { + Map properties = readInstanceProperties(""" + servicecomb: + instance: + properties: + k: 1"""); + + assertPrettyJson(properties).isEqualTo(""" + { + "k" : "1" + }"""); + } + + @Test + void should_read_by_old_prefix_when_new_prefix_not_exists() { + Map properties = readInstanceProperties(""" + instance_description: + properties: + k: v + k1: v1"""); + + assertPrettyJson(properties).isEqualTo(""" + { + "k1" : "v1", + "k" : "v" + }"""); + } + + @Test + void should_ignore_old_prefix_when_new_prefix_exists() { + Map properties = readInstanceProperties(""" + instance_description: + properties: + k: v + k1: v1 + servicecomb: + instance: + properties: + k: new"""); + + assertPrettyJson(properties).isEqualTo(""" + { + "k" : "new" + }"""); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/DynamicPropertiesTest.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/DynamicPropertiesTest.java index 9090a64ae8f..3f72af9b2cb 100644 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/DynamicPropertiesTest.java +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/DynamicPropertiesTest.java @@ -23,22 +23,20 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.number.IsCloseTo.closeTo; +import java.util.HashMap; import java.util.Objects; +import org.apache.servicecomb.foundation.common.event.EventManager; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import com.netflix.config.ConcurrentMapConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; import com.seanyinx.github.unit.scaffolding.Poller; import com.seanyinx.github.unit.scaffolding.Randomness; -import mockit.Deencapsulation; - public class DynamicPropertiesTest { - private static final String stringPropertyName = uniquify("stringPropertyName"); private static final String intPropertyName = uniquify("intPropertyName"); @@ -57,7 +55,7 @@ public class DynamicPropertiesTest { private static final long longOldValue = Randomness.nextLong(); - private static final double floatOldValue = Randomness.nextDouble(); + private static final float floatOldValue = Double.valueOf(Randomness.nextDouble()).floatValue(); private static final double doubleOldValue = Randomness.nextDouble(); @@ -65,9 +63,9 @@ public class DynamicPropertiesTest { private static final double ERROR = 0.0000001; - private static DynamicProperties dynamicProperties; + private static Environment environment; - private static ConcurrentMapConfiguration configuration; + private static DynamicProperties dynamicProperties; private final Poller poller = new Poller(2000, 100); @@ -86,26 +84,24 @@ public class DynamicPropertiesTest { @BeforeClass public static void setUpClass() throws Exception { - tearDown(); - configuration = new ConcurrentMapConfiguration(); + environment = Mockito.mock(Environment.class); writeInitialConfig(); - dynamicProperties = new DynamicPropertiesImpl(configuration); + dynamicProperties = new DynamicPropertiesImpl(environment); } @AfterClass public static void tearDown() throws Exception { - Deencapsulation.setField(ConfigurationManager.class, "instance", null); - Deencapsulation.setField(ConfigurationManager.class, "customConfigurationInstalled", false); - Deencapsulation.setField(DynamicPropertyFactory.class, "config", null); + } private static void writeInitialConfig() throws Exception { - configuration.setProperty(stringPropertyName, stringOldValue); - configuration.setProperty(intPropertyName, String.valueOf(intOldValue)); - configuration.setProperty(longPropertyName, String.valueOf(longOldValue)); - configuration.setProperty(floatPropertyName, String.valueOf(floatOldValue)); - configuration.setProperty(doublePropertyName, String.valueOf(doubleOldValue)); - configuration.setProperty(booleanPropertyName, String.valueOf(booleanOldValue)); + Mockito.when(environment.getProperty(stringPropertyName, (String) null)).thenReturn(stringOldValue); + Mockito.when(environment.getProperty(intPropertyName, int.class, 0)).thenReturn(intOldValue); + Mockito.when(environment.getProperty(longPropertyName, long.class, 0L)).thenReturn(longOldValue); + Mockito.when(environment.getProperty(floatPropertyName, float.class, 0F)).thenReturn(floatOldValue); + Mockito.when(environment.getProperty(doublePropertyName, double.class, 0D)).thenReturn(doubleOldValue); + Mockito.when(environment.getProperty(booleanPropertyName, boolean.class, false)) + .thenReturn(booleanOldValue); } @Test @@ -118,7 +114,10 @@ public void observesSpecifiedStringProperty() throws Exception { String newValue = uniquify("newValue"); - configuration.setProperty(stringPropertyName, newValue); + Mockito.when(environment.getProperty(stringPropertyName, (String) null)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(stringPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); poller.assertEventually(() -> Objects.equals(stringPropertyValue, newValue)); } @@ -133,24 +132,37 @@ public void observesSpecifiedIntProperty() throws Exception { int newValue = Randomness.nextInt(); - configuration.setProperty(intPropertyName, String.valueOf(newValue)); + Mockito.when(environment.getProperty(intPropertyName, Integer.class, 0)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(intPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); poller.assertEventually(() -> intPropertyValue == newValue); } @Test public void observesSpecifiedLongProperty() throws Exception { + Mockito.when(environment.getProperty(longPropertyName, long.class, 3L)).thenReturn(longOldValue); + long property = dynamicProperties.getLongProperty(longPropertyName, 0); assertThat(property, is(longOldValue)); - property = dynamicProperties.getLongProperty(longPropertyName, value -> longPropertyValue = value, 0); + property = dynamicProperties.getLongProperty(longPropertyName, value -> longPropertyValue = value, 3L); assertThat(property, is(longOldValue)); long newValue = Randomness.nextLong(); - configuration.setProperty(longPropertyName, String.valueOf(newValue)); + Mockito.when(environment.getProperty(longPropertyName, Long.class, 3L)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(longPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); - poller.assertEventually(() -> longPropertyValue == newValue); + Mockito.when(environment.getProperty(longPropertyName, Long.class, 3L)).thenReturn(3L); + HashMap deleted = new HashMap<>(); + deleted.put(longPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(new HashMap<>(), new HashMap<>(), deleted)); + + poller.assertEventually(() -> longPropertyValue == 3L); } @Test @@ -158,12 +170,15 @@ public void observesSpecifiedFloatProperty() throws Exception { double property = dynamicProperties.getFloatProperty(floatPropertyName, 0); assertThat(property, closeTo(floatOldValue, ERROR)); - property = dynamicProperties.getFloatProperty(floatPropertyName, value -> floatPropertyValue = value, 0); + property = dynamicProperties.getFloatProperty(floatPropertyName, value -> floatPropertyValue = value, 0f); assertThat(property, closeTo(floatOldValue, ERROR)); - double newValue = Randomness.nextDouble(); + float newValue = Double.valueOf(Randomness.nextDouble()).floatValue(); - configuration.setProperty(floatPropertyName, String.valueOf(newValue)); + Mockito.when(environment.getProperty(floatPropertyName, Float.class, 0f)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(floatPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); poller.assertEventually(() -> Math.abs(floatPropertyValue - newValue) < ERROR); } @@ -173,12 +188,15 @@ public void observesSpecifiedDoubleProperty() throws Exception { double property = dynamicProperties.getDoubleProperty(doublePropertyName, 0); assertThat(property, closeTo(doubleOldValue, ERROR)); - property = dynamicProperties.getDoubleProperty(doublePropertyName, value -> doublePropertyValue = value, 0); + property = dynamicProperties.getDoubleProperty(doublePropertyName, value -> doublePropertyValue = value, 0d); assertThat(property, closeTo(doubleOldValue, ERROR)); double newValue = Randomness.nextDouble(); - configuration.setProperty(doublePropertyName, String.valueOf(newValue)); + Mockito.when(environment.getProperty(doublePropertyName, Double.class, 0d)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(doublePropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); poller.assertEventually(() -> Math.abs(doublePropertyValue - newValue) < ERROR); } @@ -196,7 +214,10 @@ public void observesSpecifiedBooleanProperty() throws Exception { boolean newValue = !booleanOldValue; - configuration.setProperty(booleanPropertyName, String.valueOf(newValue)); + Mockito.when(environment.getProperty(booleanPropertyName, Boolean.class, booleanOldValue)).thenReturn(newValue); + HashMap updated = new HashMap<>(); + updated.put(booleanPropertyName, newValue); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); poller.assertEventually(() -> booleanPropertyValue == newValue); } diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/MapBasedConfigurationSource.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/MapBasedConfigurationSource.java deleted file mode 100644 index 5f08c8a8905..00000000000 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/MapBasedConfigurationSource.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; - -import com.netflix.config.WatchedUpdateListener; -import com.netflix.config.WatchedUpdateResult; - -public class MapBasedConfigurationSource implements ConfigCenterConfigurationSource { - - private static final Map properties = new ConcurrentHashMap<>(); - - private static final Set listeners = new HashSet<>(); - - static { - properties.put("servicecomb.abc.key", "xyz"); - } - - @Override - public boolean isValidSource(Configuration localConfiguration) { - if (localConfiguration.getProperty("cse.config.client.serverUri") == null) { - return false; - } - return true; - } - - @Override - public void init(Configuration localConfiguration) { - - } - - @Override - public void addUpdateListener(WatchedUpdateListener listener) { - listeners.add(listener); - } - - @Override - public void removeUpdateListener(WatchedUpdateListener listener) { - listeners.remove(listener); - } - - @Override - public Map getCurrentData() throws Exception { - return properties; - } - - void addProperty(String property, Object value) { - properties.put(property, value); - - Map adds = new HashMap<>(); - adds.put(property, value); - - listeners.forEach( - listener -> listener.updateConfiguration(WatchedUpdateResult.createIncremental(adds, null, null))); - } - - void setProperty(String property, Object value) { - properties.replace(property, value); - - Map changeds = new HashMap<>(); - changeds.put(property, value); - - listeners.forEach(listener -> listener - .updateConfiguration(WatchedUpdateResult.createIncremental(null, changeds, null))); - } - - void deleteProperty(String property) { - properties.remove(property); - - Map deletes = new HashMap<>(); - deletes.put(property, null); - - listeners.forEach( - listener -> listener.updateConfiguration(WatchedUpdateResult.createIncremental(null, null, deletes))); - } - - public Map getProperties() { - return properties; - } -} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigMapping.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigMapping.java index 834beab1d7f..1da5a2f5938 100644 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigMapping.java +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigMapping.java @@ -17,23 +17,22 @@ package org.apache.servicecomb.config; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - +import java.util.List; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -/** - * Created by on 2017/1/5. - */ public class TestConfigMapping { @Test public void testMapping() { - String value = ConfigMapping.map("SERVICECOMB_ENV"); + List value = ConfigMapping.map("SERVICECOMB_ENV"); + Assertions.assertEquals(2, value.size()); + Assertions.assertEquals("service_description.environment", value.get(0)); + Assertions.assertEquals("service_description.environment.old", value.get(1)); + Map m = ConfigMapping.getMapping(); - assertEquals("service_description.environment", value); - assertNotNull(m); + Assertions.assertNotNull(m); } @Test @@ -41,7 +40,7 @@ public void testConvertedMap() { String value = ConfigMapping.map("CSE_ENV_MAPPING"); Map m = ConfigMapping.getMapping(); Map m1 = ConfigMapping.getConvertedMap(m); - assertEquals("servicecomb.testmapping.key", value); - assertNotNull(m1); + Assertions.assertEquals("servicecomb.testmapping.key", value); + Assertions.assertNotNull(m1); } } diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java deleted file mode 100644 index f6e14480b5f..00000000000 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config; - -import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertThat; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.servicecomb.config.archaius.sources.ConfigModel; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.DynamicConfiguration; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicWatchedConfiguration; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; - -public class TestConfigUtil { - - private static final String systemPropertyName = "servicecomb.cse.servicecomb.system.setting"; - - private static final String systemExpected = uniquify("ran"); - - private static final String environmentPropertyName = "servicecomb.cse.servicecomb.environment.setting"; - - private static final String environmentExpected = uniquify("ran"); - - private final MapBasedConfigurationSource configurationSource = new MapBasedConfigurationSource(); - - @BeforeClass - public static void beforeTest() { - ArchaiusUtils.resetConfig(); - - System.setProperty(systemPropertyName, systemExpected); - try { - setEnv(environmentPropertyName, environmentExpected); - setEnv("MY_SERVICES_ENDPOINT", "https://myhost:8888"); - } catch (Exception e) { - throw new IllegalStateException(e); - } - - ConfigUtil.installDynamicConfig(); - } - - @AfterClass - public static void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testAddConfig() { - Map config = new HashMap<>(); - config.put("service_description.name", "service_name_test"); - ConfigUtil.setConfigs(config); - ConfigUtil.addConfig("service_description.version", "1.0.2"); - ConfigUtil.addConfig("cse.test.enabled", true); - ConfigUtil.addConfig("cse.test.num", 10); - AbstractConfiguration configuration = ConfigUtil.createDynamicConfig(); - Assert.assertEquals(configuration.getString("service_description.name"), "service_name_test"); - Assert.assertTrue(configuration.getBoolean("cse.test.enabled")); - Assert.assertEquals(configuration.getInt("cse.test.num"), 10); - } - - @Test - public void testCreateDynamicConfigNoConfigCenterSPI() { - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getTargetService(ConfigCenterConfigurationSource.class); - result = null; - } - }; - - AbstractConfiguration dynamicConfig = ConfigUtil.createDynamicConfig(); - MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(dynamicConfig); - List list = loader.getConfigModels(); - Assert.assertEquals(loader, ConfigUtil.getMicroserviceConfigLoader(dynamicConfig)); - Assert.assertEquals(1, list.size()); - Assert.assertNotEquals(DynamicWatchedConfiguration.class, - ((ConcurrentCompositeConfiguration) dynamicConfig).getConfiguration(0).getClass()); - } - - @Test - public void testCreateDynamicConfigHasConfigCenter() { - AbstractConfiguration dynamicConfig = ConfigUtil.createDynamicConfig(); - Assert.assertEquals(DynamicWatchedConfiguration.class, - ((ConcurrentCompositeConfiguration) dynamicConfig).getConfiguration(0).getClass()); - } - - @Test - public void testGetPropertyInvalidConfig() { - Assert.assertNull(ConfigUtil.getProperty(null, "any")); - Assert.assertNull(ConfigUtil.getProperty(new Object(), "any")); - } - - @Test - public void propertiesFromFileIsDuplicatedToCse() { - String expected = "value"; - - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("cse.cse.servicecomb.file", null) - .get(), - equalTo(null)); - - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.file", null) - .get(), - equalTo(expected)); - } - - @Test - public void propertiesFromSystemIsDuplicatedToCse() { - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty(systemPropertyName, null) - .get(), - equalTo(systemExpected)); - - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.system.setting", null) - .get(), - equalTo(systemExpected)); - } - - @Test - public void propertiesFromEnvironmentIsDuplicatedToCse() { - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty(environmentPropertyName, null) - .get(), - equalTo(environmentExpected)); - - assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.environment.setting", null) - .get(), - equalTo(environmentExpected)); - } - - @Test - public void duplicateServiceCombConfigToCseListValue() { - List list = Arrays.asList("a", "b"); - - AbstractConfiguration config = new DynamicConfiguration(); - config.addProperty("cse.list", list); - Deencapsulation.invoke(ConfigUtil.class, "duplicateCseConfigToServicecomb", config); - - Object result = config.getProperty("servicecomb.list"); - assertThat(result, instanceOf(List.class)); - assertThat(result, equalTo(list)); - } - - @Test - public void propertiesAddFromDynamicConfigSourceIsDuplicated() { - String expected = uniquify("ran"); - String someProperty = "cse.cse.servicecomb.add"; - String injectProperty = "servicecomb.cse.servicecomb.add"; - - configurationSource.addProperty(someProperty, expected); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - String changed = uniquify("changed"); - configurationSource.addProperty(someProperty, changed); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(changed)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(changed)); - - expected = uniquify("ran"); - someProperty = "cse.servicecomb.cse.add"; - injectProperty = "servicecomb.servicecomb.cse.add"; - - configurationSource.addProperty(someProperty, expected); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - changed = uniquify("changed"); - configurationSource.addProperty(someProperty, changed); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(changed)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(changed)); - } - - @Test - public void propertiesChangeFromDynamicConfigSourceIsDuplicated() { - String expected = uniquify("ran"); - String someProperty = "cse.cse.servicecomb.change"; - String injectProperty = "servicecomb.cse.servicecomb.change"; - configurationSource.addProperty(someProperty, expected); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - String changed = uniquify("changed"); - configurationSource.setProperty(someProperty, changed); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(changed)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(changed)); - - expected = uniquify("ran"); - someProperty = "cse.servicecomb.cse.change"; - injectProperty = "servicecomb.servicecomb.cse.change"; - configurationSource.addProperty(someProperty, expected); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - changed = uniquify("changed"); - configurationSource.setProperty(someProperty, changed); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(changed)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(changed)); - } - - @Test - public void propertiesDeleteFromDynamicConfigSourceIsDuplicated() { - String expected = uniquify("ran"); - String someProperty = "cse.cse.servicecomb.delete"; - String injectProperty = "servicecomb.cse.servicecomb.delete"; - configurationSource.addProperty(someProperty, expected); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - configurationSource.deleteProperty(someProperty); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(null)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(null)); - - expected = uniquify("ran"); - someProperty = "cse.servicecomb.cse.delete"; - injectProperty = "servicecomb.servicecomb.cse.delete"; - configurationSource.addProperty(someProperty, expected); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(expected)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(expected)); - - configurationSource.deleteProperty(someProperty); - - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(someProperty, null).get(), - equalTo(null)); - assertThat(DynamicPropertyFactory.getInstance().getStringProperty(injectProperty, null).get(), - equalTo(null)); - } - - @Test - public void testConvertEnvVariable() { - String someProperty = "cse_service_registry_address"; - AbstractConfiguration config = new DynamicConfiguration(); - config.addProperty(someProperty, "testing"); - AbstractConfiguration result = ConfigUtil.convertEnvVariable(config); - assertThat(result.getString("cse.service.registry.address"), equalTo("testing")); - assertThat(result.getString("cse_service_registry_address"), equalTo("testing")); - } - - @Test - public void testCreateLocalConfigWithExtraConfig() { - Map extraConfig = new ConcurrentHashMapEx<>(1); - String extraConfigKey = "extraConfigKey"; - String extraConfigValue = "value"; - String overriddenConfigKey = "servicecomb.cse.servicecomb.file"; - extraConfig.put(extraConfigKey, extraConfigValue); - final String propertyHigherPriority = "higher_priority"; - String mapedKey1 = "servicecomb.service.mapping.address"; - String mapedKey2 = "servicecomb.service1.mapping.address"; - extraConfig.put(overriddenConfigKey, propertyHigherPriority); - - ConfigUtil.addExtraConfig("testExtraConfig", extraConfig); - - ConcurrentCompositeConfiguration localConfiguration = ConfigUtil.createLocalConfig(); - - Assert.assertEquals(extraConfigValue, localConfiguration.getProperty(extraConfigKey)); - Assert.assertEquals(propertyHigherPriority, localConfiguration.getString(overriddenConfigKey)); - // Test mapping key/value from self mappfing.xml - Assert.assertEquals("https://myhost:8888", localConfiguration.getString(mapedKey1)); - Assert.assertEquals("https://myhost:8888", localConfiguration.getString(mapedKey2)); - } - - @SuppressWarnings("unchecked") - private static void setEnv(String key, String value) throws IllegalAccessException, NoSuchFieldException { - Class[] classes = Collections.class.getDeclaredClasses(); - Map env = System.getenv(); - for (Class cl : classes) { - if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { - Field field = cl.getDeclaredField("m"); - field.setAccessible(true); - Object obj = field.get(env); - Map map = (Map) obj; - map.put(key, value); - } - } - } - - @Test - public void destroyConfigCenterConfigurationSource() { - AtomicInteger count = new AtomicInteger(); - ConfigCenterConfigurationSource source = new MockUp() { - @Mock - void destroy() { - count.incrementAndGet(); - } - }.getMockInstance(); - - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getAllService(ConfigCenterConfigurationSource.class); - result = Arrays.asList(source, source); - } - }; - - ConfigUtil.destroyConfigCenterConfigurationSource(); - - Assert.assertEquals(2, count.get()); - } -} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java deleted file mode 100644 index 3dc9b71ada5..00000000000 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyString; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.mockito.stubbing.Answer; -import org.springframework.core.Ordered; -import org.springframework.core.env.CompositePropertySource; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; -import org.springframework.jndi.JndiPropertySource; - -import com.netflix.config.ConfigurationManager; - -import mockit.Deencapsulation; - -public class TestConfigurationSpringInitializer { - @Before - public void beforeTest() { - ConfigUtil.clearExtraConfig(); - ArchaiusUtils.resetConfig(); - } - - @After - public void afterTest() { - ConfigUtil.clearExtraConfig(); - ArchaiusUtils.resetConfig(); - } - - @Test - public void testAll() { - ConfigurationSpringInitializer configurationSpringInitializer = new ConfigurationSpringInitializer(); - ConfigUtil.installDynamicConfig(); - - Assert.assertEquals(Ordered.LOWEST_PRECEDENCE / 2, configurationSpringInitializer.getOrder()); - Assert.assertEquals(true, - Deencapsulation.getField(configurationSpringInitializer, "ignoreUnresolvablePlaceholders")); - - Object o = ConfigUtil.getProperty("zq"); - @SuppressWarnings("unchecked") - List> listO = (List>) o; - Assert.assertEquals(3, listO.size()); - Assert.assertNull(ConfigUtil.getProperty("notExist")); - - MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(); - Assert.assertNotNull(loader); - - Configuration instance = ConfigurationManager.getConfigInstance(); - ConfigUtil.installDynamicConfig(); - // must not reinstall - Assert.assertEquals(instance, ConfigurationManager.getConfigInstance()); - } - - @Test - public void testSetEnvironment() { - ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); - MutablePropertySources propertySources = new MutablePropertySources(); - Map propertyMap = new HashMap<>(); - final String map0Key0 = "map0-Key0"; - final String map1Key0 = "map1-Key0"; - final String map2Key0 = "map2-Key0"; - final String map3Key0 = "map3-Key0"; - propertyMap.put(map0Key0, "map0-Value0"); - propertyMap.put(map1Key0, "map1-Value0"); - propertyMap.put(map2Key0, "map2-Value0"); - propertyMap.put(map3Key0, "map3-Value0"); - - /* - propertySources - |- compositePropertySource0 - | |- mapPropertySource0 - | | |- map0-Key0 = map0-Value0 - | |- compositePropertySource1 - | |- mapPropertySource1 - | | |- map1-Key0 = map1-Value0 - | |- mapPropertySource2 - | |- map2-Key0 = map2-Value0 - | |- JndiPropertySource(mocked) - |- mapPropertySource3 - |- map3-Key0 = map3-Value0 - */ - CompositePropertySource compositePropertySource0 = new CompositePropertySource("compositePropertySource0"); - propertySources.addFirst(compositePropertySource0); - - HashMap map0 = new HashMap<>(); - map0.put(map0Key0, propertyMap.get(map0Key0)); - MapPropertySource mapPropertySource0 = new MapPropertySource("mapPropertySource0", map0); - compositePropertySource0.addFirstPropertySource(mapPropertySource0); - - CompositePropertySource compositePropertySource1 = new CompositePropertySource("compositePropertySource1"); - compositePropertySource0.addPropertySource(compositePropertySource1); - HashMap map1 = new HashMap<>(); - map1.put(map1Key0, propertyMap.get(map1Key0)); - MapPropertySource mapPropertySource1 = new MapPropertySource("mapPropertySource1", map1); - compositePropertySource1.addPropertySource(mapPropertySource1); - HashMap map2 = new HashMap<>(); - map2.put(map2Key0, propertyMap.get(map2Key0)); - MapPropertySource mapPropertySource2 = new MapPropertySource("mapPropertySource2", map2); - compositePropertySource1.addPropertySource(mapPropertySource2); - compositePropertySource1.addPropertySource(Mockito.mock(JndiPropertySource.class)); - - HashMap map3 = new HashMap<>(); - map3.put(map3Key0, propertyMap.get(map3Key0)); - MapPropertySource mapPropertySource3 = new MapPropertySource("mapPropertySource3", map3); - compositePropertySource0.addPropertySource(mapPropertySource3); - - Mockito.when(environment.getPropertySources()).thenReturn(propertySources); - Mockito.doAnswer((Answer) invocation -> { - Object[] args = invocation.getArguments(); - String propertyName = (String) args[0]; - - if ("spring.config.name".equals(propertyName) || "spring.application.name".equals(propertyName)) { - return null; - } - - String value = propertyMap.get(propertyName); - if (null == value) { - fail("get unexpected property name: " + propertyName); - } - return value; - }).when(environment).getProperty(anyString()); - - new ConfigurationSpringInitializer().setEnvironment(environment); - - Map> extraLocalConfig = getExtraConfigMapFromConfigUtil(); - assertFalse(extraLocalConfig.isEmpty()); - Map extraProperties = extraLocalConfig - .get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + environment.getClass().getName() + "@" - + environment.hashCode()); - assertNotNull(extraLocalConfig); - for (Entry entry : propertyMap.entrySet()) { - assertEquals(entry.getValue(), extraProperties.get(entry.getKey())); - } - } - - @Test - public void testSetEnvironmentOnEnvironmentName() { - // get environment name from spring.config.name - ConfigurableEnvironment environment0 = Mockito.mock(ConfigurableEnvironment.class); - MutablePropertySources propertySources0 = new MutablePropertySources(); - Mockito.when(environment0.getPropertySources()).thenReturn(propertySources0); - Map map0 = new HashMap<>(1); - map0.put("spring.config.name", "application"); - propertySources0.addFirst(new MapPropertySource("mapPropertySource0", map0)); - Mockito.when(environment0.getProperty("spring.config.name")).thenReturn("application"); - - // get environment name from spring.application.name - ConfigurableEnvironment environment1 = Mockito.mock(ConfigurableEnvironment.class); - MutablePropertySources propertySources1 = new MutablePropertySources(); - Mockito.when(environment1.getPropertySources()).thenReturn(propertySources1); - Map map1 = new HashMap<>(1); - map1.put("spring.application.name", "bootstrap"); - propertySources1.addFirst(new MapPropertySource("mapPropertySource1", map1)); - Mockito.when(environment1.getProperty("spring.application.name")).thenReturn("bootstrap"); - - // get environment name from className+hashcode - ConfigurableEnvironment environment2 = Mockito.mock(ConfigurableEnvironment.class); - MutablePropertySources propertySources2 = new MutablePropertySources(); - Mockito.when(environment2.getPropertySources()).thenReturn(propertySources2); - Map map2 = new HashMap<>(1); - map2.put("key2", "value2"); - propertySources2.addFirst(new MapPropertySource("mapPropertySource2", map2)); - Mockito.when(environment2.getProperty("key2")).thenReturn("value2"); - - ConfigurationSpringInitializer configurationSpringInitializer = new ConfigurationSpringInitializer(); - configurationSpringInitializer.setEnvironment(environment0); - configurationSpringInitializer.setEnvironment(environment1); - configurationSpringInitializer.setEnvironment(environment2); - - Map> extraConfig = getExtraConfigMapFromConfigUtil(); - assertEquals(3, extraConfig.size()); - - Map extraProperties = extraConfig - .get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + "application"); - assertEquals(1, extraProperties.size()); - assertEquals("application", extraProperties.get("spring.config.name")); - - extraProperties = extraConfig.get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + "bootstrap"); - assertEquals(1, extraProperties.size()); - assertEquals("bootstrap", extraProperties.get("spring.application.name")); - - extraProperties = extraConfig.get( - ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + environment2.getClass().getName() + "@" - + environment2.hashCode()); - assertEquals(1, extraProperties.size()); - assertEquals("value2", extraProperties.get("key2")); - } - - private Map> getExtraConfigMapFromConfigUtil() { - return Deencapsulation - .getField(ConfigUtil.class, "EXTRA_CONFIG_MAP"); - } -} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestLastPropertyPlaceholderConfigurer.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestLastPropertyPlaceholderConfigurer.java deleted file mode 100644 index d3d8491db9e..00000000000 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestLastPropertyPlaceholderConfigurer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config; - -import java.io.IOException; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.stereotype.Component; -import org.springframework.util.StringValueResolver; - -public class TestLastPropertyPlaceholderConfigurer { - @Component - static class Bean extends PropertyPlaceholderConfigurer implements EmbeddedValueResolverAware { - StringValueResolver resolver; - - public Bean() { - setIgnoreUnresolvablePlaceholders(true); - } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } - - @Override - protected Properties mergeProperties() throws IOException { - Properties properties = super.mergeProperties(); - properties.put("a", "aValue"); - return properties; - } - } - - @Test - public void test() { - AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(this.getClass().getPackage().getName()); - Bean bean = context.getBean(Bean.class); - - Assert.assertEquals("aValue", bean.resolver.resolveStringValue("${a}")); - try { - bean.resolver.resolveStringValue("${b}"); - Assert.fail("must throw exception"); - } catch (IllegalArgumentException e) { - Assert.assertEquals("Could not resolve placeholder 'b' in value \"${b}\"", e.getMessage()); - } - - context.close(); - } -} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java new file mode 100644 index 00000000000..4abafe8765e --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestYAMLUtil.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config; + +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestYAMLUtil { + public static class Person { + String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class UnsafePerson { + String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Test + public void testSafeParser() { + Person person = YAMLUtil.parserObject("name: hello", Person.class); + Assertions.assertEquals("hello", person.getName()); + } + + @Test + public void testYamlConfig() { + RuntimeException runtimeException = Assertions.assertThrows(RuntimeException.class, () -> YAMLUtil.yaml2Properties("servicecomb.service.registry.enabled: {{true}}")); + Assertions.assertEquals("input cannot be convert to map", runtimeException.getMessage()); + } + + @Test + @SuppressWarnings("unchecked") + public void testListValue() { + Map result = YAMLUtil.yaml2Properties("hello: a,b"); + Assertions.assertEquals(result.size(), 1); + String listValue = (String) result.get("hello"); + Assertions.assertEquals(listValue, "a,b"); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestYAMLConfigurationSource.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestYAMLConfigurationSource.java deleted file mode 100644 index dee754dcd3f..00000000000 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestYAMLConfigurationSource.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.config.archaius.sources; - -import static org.apache.servicecomb.config.archaius.sources.ConfigSourceMaker.yamlConfigSource; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.net.URL; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.servicecomb.config.archaius.scheduler.NeverStartPollingScheduler; -import org.junit.Assert; -import org.junit.Test; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConcurrentMapConfiguration; -import com.netflix.config.DynamicConfiguration; -import com.netflix.config.PollResult; - -/** - * Created by on 2017/1/5. - */ -public class TestYAMLConfigurationSource { - - @Test - public void testPullFromClassPath() throws Exception { - MicroserviceConfigurationSource configSource = yamlConfigSource(); - PollResult result = configSource.poll(true, null); - Map configMap = result.getComplete(); - assertNotNull(configMap); - assertEquals(25, configMap.size()); - assertNotNull(configMap.get("trace.handler.sampler.percent")); - assertEquals(0.5, configMap.get("trace.handler.sampler.percent")); - } - - @Test - public void testPullFroGivenURL() throws Exception { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - URL test1URL = loader.getResource("test1.yaml"); - URL test2URL = loader.getResource("test2.yaml"); - System.setProperty("servicecomb.configurationSource.additionalUrls", test1URL.toString() + "," + test2URL.toString()); - MicroserviceConfigurationSource configSource = yamlConfigSource(); - PollResult result = configSource.poll(true, null); - Map configMap = result.getComplete(); - - assertEquals(3, configSource.getConfigModels().size()); - assertNotNull(configMap); - assertEquals(36, configMap.size()); - assertNotNull(configMap.get("trace.handler.sampler.percent")); - assertEquals(0.5, configMap.get("trace.handler.sampler.percent")); - - System.getProperties().remove("servicecomb.configurationSource.additionalUrls"); - } - - @Test - public void testFullOperation() { - // configuration from system properties - ConcurrentMapConfiguration configFromSystemProperties = - new ConcurrentMapConfiguration(new SystemConfiguration()); - // configuration from yaml file - DynamicConfiguration configFromYamlFile = - new DynamicConfiguration(yamlConfigSource(), new NeverStartPollingScheduler()); - // create a hierarchy of configuration that makes - // 1) dynamic configuration source override system properties - ConcurrentCompositeConfiguration finalConfig = new ConcurrentCompositeConfiguration(); - finalConfig.addConfiguration(configFromYamlFile, "yamlConfig"); - finalConfig.addConfiguration(configFromSystemProperties, "systemEnvConfig"); - Assert.assertEquals(0.5, finalConfig.getDouble("trace.handler.sampler.percent"), 0.5); - - Object o = finalConfig.getProperty("zq"); - @SuppressWarnings("unchecked") - List> listO = (List>) o; - Assert.assertEquals(3, listO.size()); - } -} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestMicroserviceConfigLoader.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/file/TestMicroserviceConfigLoader.java similarity index 84% rename from foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestMicroserviceConfigLoader.java rename to foundations/foundation-config/src/test/java/org/apache/servicecomb/config/file/TestMicroserviceConfigLoader.java index cadfc2244c8..0084976d004 100644 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/archaius/sources/TestMicroserviceConfigLoader.java +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/file/TestMicroserviceConfigLoader.java @@ -15,9 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.config.archaius.sources; - -import static org.junit.Assert.assertEquals; +package org.apache.servicecomb.config.file; import java.io.FileNotFoundException; import java.io.IOException; @@ -27,8 +25,8 @@ import java.util.List; import java.util.stream.Collectors; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestMicroserviceConfigLoader { @@ -49,7 +47,7 @@ public void configsSortedByInsertionOrder() throws MalformedURLException { loader.sort(); - assertEquals(urls("jar:c", "jar:b", "jar:a"), urlsOf(loader.getConfigModels())); + Assertions.assertEquals(urls("jar:c", "jar:b", "jar:a"), urlsOf(loader.getConfigModels())); } @Test @@ -60,7 +58,7 @@ public void configsSortedBySpecifiedOrder() throws MalformedURLException { loader.sort(); - assertEquals(urls("jar:c", "jar:b", "jar:a"), urlsOf(loader.getConfigModels())); + Assertions.assertEquals(urls("jar:c", "jar:b", "jar:a"), urlsOf(loader.getConfigModels())); } @Test @@ -71,7 +69,7 @@ public void jarsAlwaysHaveHigherPriorityThanFiles() throws MalformedURLException loader.sort(); - assertEquals(urls("jar:j1", "file:f2", "file:f1"), urlsOf(loader.getConfigModels())); + Assertions.assertEquals(urls("jar:j1", "file:f2", "file:f1"), urlsOf(loader.getConfigModels())); } private String urlsOf(List configModels) { @@ -89,7 +87,7 @@ private String urls(String... urls) { @Test public void testLoadEmptyYaml() throws IOException { loader.load("empty.yaml"); - Assert.assertTrue(loader.getConfigModels().get(0).getConfig().isEmpty()); + Assertions.assertTrue(loader.getConfigModels().get(0).getConfig().isEmpty()); } @Test @@ -97,9 +95,9 @@ public void testLoadNotExistYaml() throws IOException { URL url = URI.create("file:/notExist.yaml").toURL(); try { loader.load(url); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (FileNotFoundException e) { - Assert.assertTrue(true); + Assertions.assertTrue(true); } } } diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestConfigObjectFactory.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestConfigObjectFactory.java new file mode 100644 index 00000000000..9e5915b0c20 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestConfigObjectFactory.java @@ -0,0 +1,532 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.inject; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.priority.TestPriorityPropertyBase; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestConfigObjectFactory extends TestPriorityPropertyBase { + public static class ConfigNoAnnotation { + public String strValue; + + private String strValue1; + + public int intValue; + + private int intValue1; + + public Integer intValueObj; + + private Integer intValueObj1; + + public long longValue; + + private long longValue1; + + public Long longValueObj; + + private Long longValueObj1; + + public float floatValue; + + private float floatValue1; + + public Float floatValueObj; + + private Float floatValueObj1; + + public double doubleValue; + + private double doubleValue1; + + public Double doubleValueObj; + + private Double doubleValueObj1; + + public boolean booleanValue; + + private boolean booleanValue1; + + public Boolean booleanValueObj; + + private Boolean booleanValueObj1; + + public String getStrValue1() { + return strValue1; + } + + public void setStrValue1(String strValue1) { + this.strValue1 = strValue1; + } + + public int getIntValue1() { + return intValue1; + } + + public void setIntValue1(int intValue1) { + this.intValue1 = intValue1; + } + + public Integer getIntValueObj1() { + return intValueObj1; + } + + public void setIntValueObj1(Integer intValueObj1) { + this.intValueObj1 = intValueObj1; + } + + public long getLongValue1() { + return longValue1; + } + + public void setLongValue1(long longValue1) { + this.longValue1 = longValue1; + } + + public Long getLongValueObj1() { + return longValueObj1; + } + + public void setLongValueObj1(Long longValueObj1) { + this.longValueObj1 = longValueObj1; + } + + public float getFloatValue1() { + return floatValue1; + } + + public void setFloatValue1(float floatValue1) { + this.floatValue1 = floatValue1; + } + + public Float getFloatValueObj1() { + return floatValueObj1; + } + + public void setFloatValueObj1(Float floatValueObj1) { + this.floatValueObj1 = floatValueObj1; + } + + public double getDoubleValue1() { + return doubleValue1; + } + + public void setDoubleValue1(double doubleValue1) { + this.doubleValue1 = doubleValue1; + } + + public Double getDoubleValueObj1() { + return doubleValueObj1; + } + + public void setDoubleValueObj1(Double doubleValueObj1) { + this.doubleValueObj1 = doubleValueObj1; + } + + public boolean isBooleanValue1() { + return booleanValue1; + } + + public void setBooleanValue1(boolean booleanValue1) { + this.booleanValue1 = booleanValue1; + } + + public Boolean getBooleanValueObj1() { + return booleanValueObj1; + } + + public void setBooleanValueObj1(Boolean booleanValueObj1) { + this.booleanValueObj1 = booleanValueObj1; + } + } + + @Test + public void noAnnotation_defaultValue() { + ConfigNoAnnotation config = priorityPropertyManager.createConfigObject(ConfigNoAnnotation.class); + + Assertions.assertNull(config.strValue); + Assertions.assertNull(config.getStrValue1()); + + Assertions.assertEquals(0, config.intValue); + Assertions.assertEquals(0, config.getIntValue1()); + Assertions.assertNull(config.intValueObj); + Assertions.assertNull(config.getIntValueObj1()); + + Assertions.assertEquals(0, config.longValue); + Assertions.assertEquals(0, config.getLongValue1()); + Assertions.assertNull(config.longValueObj); + Assertions.assertNull(config.getLongValueObj1()); + + Assertions.assertEquals(0, config.floatValue, 0); + Assertions.assertEquals(0, config.getFloatValue1(), 0); + Assertions.assertNull(config.floatValueObj); + Assertions.assertNull(config.getFloatValueObj1()); + + Assertions.assertEquals(0, config.doubleValue, 0); + Assertions.assertEquals(0, config.getDoubleValue1(), 0); + Assertions.assertNull(config.doubleValueObj); + Assertions.assertNull(config.getDoubleValueObj1()); + + Assertions.assertFalse(config.booleanValue); + Assertions.assertFalse(config.isBooleanValue1()); + Assertions.assertNull(config.booleanValueObj); + Assertions.assertNull(config.getBooleanValueObj1()); + } + + @Test + public void noAnnotation_initValue() { + Mockito.when(environment.getProperty("strValue")).thenReturn("strValue"); + Mockito.when(environment.getProperty("strValue1")).thenReturn("strValue1"); + + Mockito.when(environment.getProperty("intValue", Integer.class)).thenReturn(1); + Mockito.when(environment.getProperty("intValue1", Integer.class)).thenReturn(2); + Mockito.when(environment.getProperty("intValueObj", Integer.class)).thenReturn(3); + Mockito.when(environment.getProperty("intValueObj1", Integer.class)).thenReturn(4); + + Mockito.when(environment.getProperty("longValue", Long.class)).thenReturn(5L); + Mockito.when(environment.getProperty("longValue1", Long.class)).thenReturn(6L); + Mockito.when(environment.getProperty("longValueObj", Long.class)).thenReturn(7L); + Mockito.when(environment.getProperty("longValueObj1", Long.class)).thenReturn(8L); + + Mockito.when(environment.getProperty("floatValue", Float.class)).thenReturn(9.0F); + Mockito.when(environment.getProperty("floatValue1", Float.class)).thenReturn(10.0F); + Mockito.when(environment.getProperty("floatValueObj", Float.class)).thenReturn(11.0F); + Mockito.when(environment.getProperty("floatValueObj1", Float.class)).thenReturn(12.0F); + + Mockito.when(environment.getProperty("doubleValue", Double.class)).thenReturn(13.0D); + Mockito.when(environment.getProperty("doubleValue1", Double.class)).thenReturn(14.0D); + Mockito.when(environment.getProperty("doubleValueObj", Double.class)).thenReturn(15.0D); + Mockito.when(environment.getProperty("doubleValueObj1", Double.class)).thenReturn(16.0D); + + Mockito.when(environment.getProperty("booleanValue", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValue1", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValueObj", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValueObj1", Boolean.class)).thenReturn(true); + + ConfigNoAnnotation config = priorityPropertyManager.createConfigObject(ConfigNoAnnotation.class); + + Assertions.assertEquals("strValue", config.strValue); + Assertions.assertEquals("strValue1", config.getStrValue1()); + + Assertions.assertEquals(1, config.intValue); + Assertions.assertEquals(2, config.getIntValue1()); + Assertions.assertEquals(3, (int) config.intValueObj); + Assertions.assertEquals(4, (int) config.getIntValueObj1()); + + Assertions.assertEquals(5, config.longValue); + Assertions.assertEquals(6, config.getLongValue1()); + Assertions.assertEquals(7, (long) config.longValueObj); + Assertions.assertEquals(8, (long) config.getLongValueObj1()); + + Assertions.assertEquals(9, config.floatValue, 0); + Assertions.assertEquals(10, config.getFloatValue1(), 0); + Assertions.assertEquals(11, config.floatValueObj, 0); + Assertions.assertEquals(12, config.getFloatValueObj1(), 0); + + Assertions.assertEquals(13, config.doubleValue, 0); + Assertions.assertEquals(14, config.getDoubleValue1(), 0); + Assertions.assertEquals(15, config.doubleValueObj, 0); + Assertions.assertEquals(16, config.getDoubleValueObj1(), 0); + + Assertions.assertTrue(config.booleanValue); + Assertions.assertTrue(config.isBooleanValue1()); + Assertions.assertTrue(config.booleanValueObj); + Assertions.assertTrue(config.getBooleanValueObj1()); + } + + @Test + public void noAnnotation_updateValue() { + ConfigNoAnnotation config = priorityPropertyManager.createConfigObject(ConfigNoAnnotation.class); + + Mockito.when(environment.getProperty("strValue")).thenReturn("strValue"); + Mockito.when(environment.getProperty("strValue1")).thenReturn("strValue1"); + + Mockito.when(environment.getProperty("intValue", Integer.class)).thenReturn(1); + Mockito.when(environment.getProperty("intValue1", Integer.class)).thenReturn(2); + Mockito.when(environment.getProperty("intValueObj", Integer.class)).thenReturn(3); + Mockito.when(environment.getProperty("intValueObj1", Integer.class)).thenReturn(4); + + Mockito.when(environment.getProperty("longValue", Long.class)).thenReturn(5L); + Mockito.when(environment.getProperty("longValue1", Long.class)).thenReturn(6L); + Mockito.when(environment.getProperty("longValueObj", Long.class)).thenReturn(7L); + Mockito.when(environment.getProperty("longValueObj1", Long.class)).thenReturn(8L); + + Mockito.when(environment.getProperty("floatValue", Float.class)).thenReturn(9.0F); + Mockito.when(environment.getProperty("floatValue1", Float.class)).thenReturn(10.0F); + Mockito.when(environment.getProperty("floatValueObj", Float.class)).thenReturn(11.0F); + Mockito.when(environment.getProperty("floatValueObj1", Float.class)).thenReturn(12.0F); + + Mockito.when(environment.getProperty("doubleValue", Double.class)).thenReturn(13.0D); + Mockito.when(environment.getProperty("doubleValue1", Double.class)).thenReturn(14.0D); + Mockito.when(environment.getProperty("doubleValueObj", Double.class)).thenReturn(15.0D); + Mockito.when(environment.getProperty("doubleValueObj1", Double.class)).thenReturn(16.0D); + + Mockito.when(environment.getProperty("booleanValue", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValue1", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValueObj", Boolean.class)).thenReturn(true); + Mockito.when(environment.getProperty("booleanValueObj1", Boolean.class)).thenReturn(true); + + HashMap updated = new HashMap<>(); + updated.put("strValue", "strValue"); + updated.put("strValue1", "strValue1"); + + updated.put("intValue", 0); + updated.put("intValue1", 1); + updated.put("intValueObj", 2); + updated.put("intValueObj1", 3); + + updated.put("longValue", 5L); + updated.put("longValue1", 6L); + updated.put("longValueObj", 7L); + updated.put("longValueObj1", 8L); + + updated.put("floatValue", 9.0F); + updated.put("floatValue1", 10.0F); + updated.put("floatValueObj", 11.0F); + updated.put("floatValueObj1", 12.0F); + + updated.put("doubleValue", 13.0D); + updated.put("doubleValue1", 14.0D); + updated.put("doubleValueObj", 15.0D); + updated.put("doubleValueObj1", 16.0D); + + updated.put("booleanValue", true); + updated.put("booleanValue1", true); + updated.put("booleanValueObj", true); + updated.put("booleanValueObj1", true); + + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + Assertions.assertEquals("strValue", config.strValue); + Assertions.assertEquals("strValue1", config.getStrValue1()); + + Assertions.assertEquals(1, config.intValue); + Assertions.assertEquals(2, config.getIntValue1()); + Assertions.assertEquals(3, (int) config.intValueObj); + Assertions.assertEquals(4, (int) config.getIntValueObj1()); + + Assertions.assertEquals(5, config.longValue); + Assertions.assertEquals(6, config.getLongValue1()); + Assertions.assertEquals(7, (long) config.longValueObj); + Assertions.assertEquals(8, (long) config.getLongValueObj1()); + + Assertions.assertEquals(9, config.floatValue, 0); + Assertions.assertEquals(10, config.getFloatValue1(), 0); + Assertions.assertEquals(11, config.floatValueObj, 0); + Assertions.assertEquals(12, config.getFloatValueObj1(), 0); + + Assertions.assertEquals(13, config.doubleValue, 0); + Assertions.assertEquals(14, config.getDoubleValue1(), 0); + Assertions.assertEquals(15, config.doubleValueObj, 0); + Assertions.assertEquals(16, config.getDoubleValueObj1(), 0); + + Assertions.assertTrue(config.booleanValue); + Assertions.assertTrue(config.isBooleanValue1()); + Assertions.assertTrue(config.booleanValueObj); + Assertions.assertTrue(config.getBooleanValueObj1()); + } + + @InjectProperties(prefix = "root") + public static class ConfigWithAnnotation { + @InjectProperty(prefix = "override", keys = {"high", "low"}) + public String strValue; + + @InjectProperty(keys = "${key}.value") + public int intValue; + + @InjectProperty(keys = "${low-list}.a.${high-list}.b") + public long longValue; + + @InjectProperty(keys = "${full-list}") + public float floatValue; + + @InjectProperty(defaultValue = "abc") + public String strDef; + + @InjectProperty(defaultValue = "1") + public int intDef; + + @InjectProperty(defaultValue = "2") + public long longDef; + + @InjectProperty(defaultValue = "3") + public float floatDef; + + @InjectProperty(defaultValue = "4") + public double doubleDef; + + @InjectProperty(defaultValue = "true") + public boolean booleanDef; + } + + @Test + public void annotationDefault() { + ConfigWithAnnotation config = priorityPropertyManager.createConfigObject(ConfigWithAnnotation.class); + + Assertions.assertEquals("abc", config.strDef); + Assertions.assertEquals(1, config.intDef); + Assertions.assertEquals(2, config.longDef); + Assertions.assertEquals(3, config.floatDef, 0); + Assertions.assertEquals(4, config.doubleDef, 0); + Assertions.assertTrue(config.booleanDef); + } + + @Test + public void placeholder_multi_list() { + ConfigWithAnnotation config = priorityPropertyManager.createConfigObject(ConfigWithAnnotation.class, + "low-list", Arrays.asList("low-1", "low-2"), + "high-list", Arrays.asList("high-1", "high-2")); + // low-1.a.high-1.b + // low-1.a.high-2.b + // low-2.a.high-1.b + // low-2.a.high-2.b + + Assertions.assertEquals(0, config.longValue); + + Mockito.when(environment.getProperty("root.low-2.a.high-2.b", Long.class)).thenReturn(Long.MAX_VALUE); + HashMap updated = new HashMap<>(); + updated.put("root.low-2.a.high-2.b", Long.MAX_VALUE); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals(Long.MAX_VALUE, config.longValue); + + Mockito.when(environment.getProperty("root.low-2.a.high-1.b", Long.class)).thenReturn(Long.MAX_VALUE - 1); + updated = new HashMap<>(); + updated.put("root.low-2.a.high-1.b", Long.MAX_VALUE - 1); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + Assertions.assertEquals(Long.MAX_VALUE - 1, config.longValue); + + Mockito.when(environment.getProperty("root.low-1.a.high-2.b", Long.class)).thenReturn(Long.MAX_VALUE - 2); + updated = new HashMap<>(); + updated.put("root.low-1.a.high-2.b", Long.MAX_VALUE - 2); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals(Long.MAX_VALUE - 2, config.longValue); + + Mockito.when(environment.getProperty("root.low-1.a.high-1.b", Long.class)).thenReturn(Long.MAX_VALUE - 3); + updated = new HashMap<>(); + updated.put("root.low-1.a.high-1.b", Long.MAX_VALUE - 3); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals(Long.MAX_VALUE - 3, config.longValue); + } + + @Test + public void placeholder_full_list() { + ConfigWithAnnotation config = priorityPropertyManager.createConfigObject(ConfigWithAnnotation.class, + "full-list", Arrays.asList("l1-1", "l1-2")); + + Assertions.assertEquals(0, config.floatValue, 0); + + Mockito.when(environment.getProperty("root.l1-2", Float.class)).thenReturn(1F); + HashMap updated = new HashMap<>(); + updated.put("root.l1-2", 1F); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + Assertions.assertEquals(1F, config.floatValue, 0); + + Mockito.when(environment.getProperty("root.l1-1", Float.class)).thenReturn(2F); + updated = new HashMap<>(); + updated.put("root.l1-1", 2F); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + Assertions.assertEquals(2F, config.floatValue, 0); + } + + @Test + public void placeholder_normal() { + ConfigWithAnnotation config = priorityPropertyManager.createConfigObject(ConfigWithAnnotation.class, "key", "k"); + + Assertions.assertEquals(0, config.intValue); + + Mockito.when(environment.getProperty("root.k.value", Integer.class)).thenReturn(1); + Map updated = new HashMap<>(); + updated.put("root.k.value", 1); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals(1, config.intValue); + } + + @Test + public void overridePrefix() { + ConfigWithAnnotation config = priorityPropertyManager.createConfigObject(ConfigWithAnnotation.class); + + Mockito.when(environment.getProperty("override.high")).thenReturn("high"); + HashMap updated = new HashMap<>(); + updated.put("override.high", "high"); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals("high", config.strValue); + + Mockito.when(environment.getProperty("override.high")).thenReturn(null); + updated = new HashMap<>(); + updated.put("override.high", null); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertNull(config.strValue); + + Mockito.when(environment.getProperty("override.low")).thenReturn("low"); + updated = new HashMap<>(); + updated.put("override.low", "low"); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertEquals("low", config.strValue); + + Mockito.when(environment.getProperty("override.low")).thenReturn(null); + updated = new HashMap<>(); + updated.put("override.low", null); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + Assertions.assertNull(config.strValue); + } + + @InjectProperties(prefix = "root") + public static class ConfigWithPojo { + + @InjectProperties(prefix = "root.model") + public static class Model { + @InjectProperty(defaultValue = "h") + public String name; + } + + @InjectProperty(defaultValue = "4") + public int index; + + public Model model; + } + + @Test + public void configWithPojoWork() { + ConfigWithPojo config = priorityPropertyManager.createConfigObject(ConfigWithPojo.class); + ConfigWithPojo.Model model = priorityPropertyManager.createConfigObject(ConfigWithPojo.Model.class); + config.model = model; + + Assertions.assertEquals(4, config.index); + Assertions.assertEquals("h", config.model.name); + + Mockito.when(environment.getProperty("root.index", Integer.class)).thenReturn(5); + Mockito.when(environment.getProperty("root.model.name")).thenReturn("w"); + Map updated = new HashMap<>(); + updated.put("root.index", 5); + updated.put("root.model.name", "w"); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + Assertions.assertEquals(5, config.index); + Assertions.assertEquals("w", config.model.name); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestPlaceholderResolver.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestPlaceholderResolver.java new file mode 100644 index 00000000000..d6407785f65 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/inject/TestPlaceholderResolver.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.inject; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestPlaceholderResolver { + static Map parameters = new HashMap<>(); + + static PlaceholderResolver resolver = new PlaceholderResolver(); + + @BeforeAll + public static void setupClass() { + parameters.put("key", "value"); + parameters.put("varOfVar", Arrays.asList("${key}")); + + parameters.put("priority", "low"); + + parameters.put("low-list", Arrays.asList("low-1", "low-2")); + parameters.put("middle-list", Arrays.asList("middle-1", "middle-2")); + parameters.put("high-list", Arrays.asList("high-1", "high-2")); + } + + protected Environment environment; + + @BeforeEach + public void setup() { + environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + } + + @Test + public void unknown() { + MatcherAssert.assertThat(resolver.replace("prefix${xxx}suffix", parameters), + Matchers.contains("prefix${xxx}suffix")); + } + + @Test + public void empty() { + MatcherAssert.assertThat(resolver.replace("prefix${}suffix", parameters), + Matchers.contains("prefix${}suffix")); + } + + @Test + public void notComplete() { + MatcherAssert.assertThat(resolver.replace("prefix${suffix", parameters), + Matchers.contains("prefix${suffix")); + } + + @Test + public void normal() { + MatcherAssert.assertThat(resolver.replace("prefix.${key}.suffix", parameters), + Matchers.contains("prefix.value.suffix")); + } + + @Test + public void disable() { + MatcherAssert.assertThat(resolver.replace("prefix.\\${key}.suffix", parameters), + Matchers.contains("prefix.${key}.suffix")); + } + + @Test + public void varOfVar() { + MatcherAssert.assertThat(resolver.replace("prefix.${varOfVar}.suffix", parameters), + Matchers.contains("prefix.value.suffix")); + } + + @Test + public void list() { + MatcherAssert.assertThat(resolver.replace("prefix.${low-list}.suffix", parameters), + Matchers.contains("prefix.low-1.suffix", "prefix.low-2.suffix")); + } + + @Test + public void multi_list() { + MatcherAssert.assertThat(resolver.replace("prefix.${low-list}.${middle-list}.${high-list}.suffix", parameters), + Matchers.contains( + "prefix.low-1.middle-1.high-1.suffix", + "prefix.low-1.middle-1.high-2.suffix", + "prefix.low-1.middle-2.high-1.suffix", + "prefix.low-1.middle-2.high-2.suffix", + "prefix.low-2.middle-1.high-1.suffix", + "prefix.low-2.middle-1.high-2.suffix", + "prefix.low-2.middle-2.high-1.suffix", + "prefix.low-2.middle-2.high-2.suffix")); + } + + @Test + public void nested() { + MatcherAssert.assertThat(resolver.replace("prefix.${${priority}-list}.suffix", parameters), + Matchers.contains("prefix.low-1.suffix", "prefix.low-2.suffix")); + } + + @Test + public void mixed() { + MatcherAssert.assertThat( + resolver.replace("prefix.${${priority}-list}.${key}.${high-list}.suffix ${xxx}", parameters), + Matchers.contains( + "prefix.low-1.value.high-1.suffix ${xxx}", + "prefix.low-2.value.high-1.suffix ${xxx}", + "prefix.low-1.value.high-2.suffix ${xxx}", + "prefix.low-2.value.high-2.suffix ${xxx}")); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/parser/TestParser.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/parser/TestParser.java new file mode 100644 index 00000000000..69409347116 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/parser/TestParser.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.parser; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import org.junit.Test; + +public class TestParser { + @Test + public void testRawParser() { + Parser parser = Parser.findParser(Parser.CONTENT_TYPE_RAW); + assertThat(parser.parse("world", "hello", true)).containsKey("hello").containsValue("world"); + assertThat(parser.parse("world", "hello", false)).containsKey("hello").containsValue("world"); + } + + @Test + public void testPropertiesParser() { + Parser parser = Parser.findParser(Parser.CONTENT_TYPE_PROPERTIES); + assertThat(parser.parse("l1-1=3.0\n" + + "l1-2=2.0", "hello", true)).containsKeys("hello.l1-1", "hello.l1-2") + .containsValues("2.0", "3.0"); + assertThat(parser.parse("l1-1=3.0\n" + + "l1-2=2.0", "hello", false)).containsKeys("l1-1", "l1-2") + .containsValues("2.0", "3.0"); + } + + @Test + public void testYamlParser() { + Parser parser = Parser.findParser(Parser.CONTENT_TYPE_YAML); + assertThat(parser.parse("l1-1: 3.0\n" + + "l1-2: 2.0", "hello", true)).containsKeys("hello.l1-1", "hello.l1-2") + .containsValues("2.0", "3.0"); + assertThat(parser.parse("l1-1: 3.0\n" + + "l1-2: 2.0", "false", false)).containsKeys("l1-1", "l1-2") + .containsValues("2.0", "3.0"); + } + + @Test + public void testInvalidParser() { + Throwable exception = catchThrowable(() -> Parser.findParser("unknown")); + assertThat(exception).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityProperty.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityProperty.java new file mode 100644 index 00000000000..85b3185d251 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityProperty.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestPriorityProperty extends TestPriorityPropertyBase { + String high = "ms.schema.op"; + + String middle = "ms.schema"; + + String low = "ms"; + + String[] keys = {high, middle, low}; + + @Test + public void testLong() { + PriorityProperty config = propertyFactory.getOrCreate(Long.class, -1L, -2L, keys); + Assertions.assertEquals(-2L, (long) config.getValue()); + + updateLong(low, 1L, config); + Assertions.assertEquals(1L, (long) config.getValue()); + + updateLong(middle, 2L, config); + Assertions.assertEquals(2L, (long) config.getValue()); + + updateLong(high, 3L, config); + Assertions.assertEquals(3L, (long) config.getValue()); + + updateLong(middle, null, config); + Assertions.assertEquals(3L, (long) config.getValue()); + + updateLong(middle, 2L, config); + updateLong(high, null, config); + Assertions.assertEquals(2L, (long) config.getValue()); + + updateLong(middle, null, config); + Assertions.assertEquals(1L, (long) config.getValue()); + + updateLong(low, null, config); + Assertions.assertEquals(-2L, (long) config.getValue()); + } + + @Test + public void testInt() { + PriorityProperty config = propertyFactory.getOrCreate(Integer.class, -1, -2, keys); + Assertions.assertEquals(-2L, (int) config.getValue()); + + updateInt(low, 1, config); + Assertions.assertEquals(1, (int) config.getValue()); + + updateInt(middle, 2, config); + Assertions.assertEquals(2, (int) config.getValue()); + + updateInt(high, 3, config); + Assertions.assertEquals(3, (int) config.getValue()); + + updateInt(middle, null, config); + Assertions.assertEquals(3, (int) config.getValue()); + updateInt(middle, 2, config); + + updateInt(high, null, config); + Assertions.assertEquals(2, (int) config.getValue()); + + updateInt(middle, null, config); + Assertions.assertEquals(1, (int) config.getValue()); + + updateInt(low, null, config); + Assertions.assertEquals(-2, (int) config.getValue()); + } + + private void updateFloat(String key, Float value, PriorityProperty config) { + Mockito.when(environment.getProperty(key, Float.class)).thenReturn(value); + config.updateValue(); + } + + private void updateStr(String key, String value, PriorityProperty config) { + Mockito.when(environment.getProperty(key)).thenReturn(value); + config.updateValue(); + } + + private void updateInt(String key, Integer value, PriorityProperty config) { + Mockito.when(environment.getProperty(key, Integer.class)).thenReturn(value); + config.updateValue(); + } + + private void updateLong(String key, Long value, PriorityProperty config) { + Mockito.when(environment.getProperty(key, Long.class)).thenReturn(value); + config.updateValue(); + } + + private void updateBoolean(String key, Boolean value, PriorityProperty config) { + Mockito.when(environment.getProperty(key, Boolean.class)).thenReturn(value); + config.updateValue(); + } + + private void updateDouble(String key, Double value, PriorityProperty config) { + Mockito.when(environment.getProperty(key, Double.class)).thenReturn(value); + config.updateValue(); + } + + @Test + public void testString() { + PriorityProperty config = propertyFactory.getOrCreate(String.class, null, "def", keys); + Assertions.assertEquals("def", config.getValue()); + + updateStr(low, "1", config); + Assertions.assertEquals("1", config.getValue()); + + updateStr(middle, "2", config); + Assertions.assertEquals("2", config.getValue()); + + updateStr(high, "3", config); + Assertions.assertEquals("3", config.getValue()); + + updateStr(middle, null, config); + Assertions.assertEquals("3", config.getValue()); + + updateStr(middle, "2", config); + updateStr(high, null, config); + Assertions.assertEquals("2", config.getValue()); + + updateStr(middle, null, config); + Assertions.assertEquals("1", config.getValue()); + + updateStr(low, null, config); + Assertions.assertEquals("def", config.getValue()); + } + + @Test + public void testBoolean() { + PriorityProperty config = propertyFactory.getOrCreate(Boolean.class, null, false, keys); + Assertions.assertFalse(config.getValue()); + + updateBoolean(low, true, config); + Assertions.assertTrue(config.getValue()); + + updateBoolean(middle, false, config); + Assertions.assertFalse(config.getValue()); + + updateBoolean(high, true, config); + Assertions.assertTrue(config.getValue()); + + updateBoolean(middle, false, config); + Assertions.assertTrue(config.getValue()); + + updateBoolean(middle, false, config); + updateBoolean(high, null, config); + Assertions.assertFalse(config.getValue()); + + updateBoolean(middle, null, config); + Assertions.assertTrue(config.getValue()); + + updateBoolean(low, null, config); + Assertions.assertFalse(config.getValue()); + } + + @Test + public void testDouble() { + PriorityProperty config = propertyFactory.getOrCreate(Double.class, null, -2.0, keys); + Assertions.assertEquals(-2, config.getValue(), 0); + + updateDouble(low, 1D, config); + Assertions.assertEquals(1, config.getValue(), 0); + + updateDouble(middle, 2D, config); + Assertions.assertEquals(2, config.getValue(), 0); + + updateDouble(high, 3D, config); + Assertions.assertEquals(3, config.getValue(), 0); + + updateDouble(middle, null, config); + Assertions.assertEquals(3, config.getValue(), 0); + + updateDouble(middle, 2D, config); + updateDouble(high, null, config); + Assertions.assertEquals(2, config.getValue(), 0); + + updateDouble(middle, null, config); + Assertions.assertEquals(1, config.getValue(), 0); + + updateDouble(low, null, config); + Assertions.assertEquals(-2, config.getValue(), 0); + } + + @Test + public void testFloat() { + PriorityProperty config = propertyFactory.getOrCreate(Float.class, null, -2.0f, keys); + Assertions.assertEquals(-2, config.getValue(), 0); + + updateFloat(low, 1F, config); + Assertions.assertEquals(1, config.getValue(), 0); + + updateFloat(middle, 2F, config); + Assertions.assertEquals(2, config.getValue(), 0); + + updateFloat(high, 3F, config); + Assertions.assertEquals(3, config.getValue(), 0); + + updateFloat(middle, null, config); + Assertions.assertEquals(3, config.getValue(), 0); + + updateFloat(middle, 2F, config); + updateFloat(high, null, config); + Assertions.assertEquals(2, config.getValue(), 0); + + updateFloat(middle, null, config); + Assertions.assertEquals(1, config.getValue(), 0); + + updateFloat(low, null, config); + Assertions.assertEquals(-2, config.getValue(), 0); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyBase.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyBase.java new file mode 100644 index 00000000000..375a755ec03 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyBase.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.config.priority; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestPriorityPropertyBase { + protected PriorityPropertyManager priorityPropertyManager; + + protected PriorityPropertyFactory propertyFactory; + + protected Environment environment; + + @BeforeEach + public void setup() { + environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + + propertyFactory = new PriorityPropertyFactory(environment); + priorityPropertyManager = new PriorityPropertyManager(new ConfigObjectFactory(propertyFactory)); + } + + @AfterEach + public void teardown() { + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyFactory.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyFactory.java new file mode 100644 index 00000000000..1e33e3af684 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class TestPriorityPropertyFactory extends TestPriorityPropertyBase { + @Test + void should_not_create_multiple_instances_for_same_parameter() { + PriorityProperty p1 = propertyFactory.getOrCreate(int.class, null, 0, "high", "low"); + PriorityProperty p2 = propertyFactory.getOrCreate(int.class, null, 0, "high", "low"); + + assertThat(p1).isSameAs(p2); + assertThat(propertyFactory.getProperties().count()).isEqualTo(1); + } + + @Test + void should_create_different_instances_for_different_parameter() { + PriorityProperty p1 = propertyFactory.getOrCreate(int.class, null, 0, "high", "low"); + PriorityProperty p2 = propertyFactory.getOrCreate(long.class, null, 0L, "high", "low"); + + assertThat(p1).isNotSameAs(p2); + assertThat(propertyFactory.getProperties().count()).isEqualTo(2); + } +} diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyManager.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyManager.java new file mode 100644 index 00000000000..291d8614562 --- /dev/null +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/priority/TestPriorityPropertyManager.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.config.priority; + +import org.apache.servicecomb.config.inject.InjectProperties; +import org.apache.servicecomb.config.inject.InjectProperty; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestPriorityPropertyManager extends TestPriorityPropertyBase { + String high = "ms.schema.op"; + + String middle = "ms.schema"; + + String low = "ms"; + + String[] keys = {high, middle, low}; + + @InjectProperties(prefix = "root") + public static class ConfigWithAnnotation { + @InjectProperty(prefix = "override", keys = {"high", "low"}, defaultValue = "abc") + public String strValue; + } + + private void waitKeyForGC(PriorityPropertyManager priorityPropertyManager) { + long maxTime = 10000; + long currentTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - currentTime < maxTime) { + if (priorityPropertyManager.getConfigObjectMap().isEmpty()) { + break; + } + System.runFinalization(); + System.gc(); + try { + Thread.yield(); + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + @Test + public void testConfigurationsAreGCCollected() { + long timeBegin = System.currentTimeMillis(); + + for (int i = 0; i < 100; i++) { + for (int j = 0; j < 100; j++) { + ConfigWithAnnotation configConfigObject = priorityPropertyManager.createConfigObject( + ConfigWithAnnotation.class); + Assertions.assertEquals("abc", configConfigObject.strValue); + PriorityProperty configPriorityProperty = propertyFactory.getOrCreate(Long.class, -1L, -2L, keys); + Assertions.assertEquals(-2L, (long) configPriorityProperty.getValue()); + } + } + + waitKeyForGC(priorityPropertyManager); + + Assertions.assertTrue(priorityPropertyManager.getConfigObjectMap().isEmpty()); + System.out.println("Token : " + (System.currentTimeMillis() - timeBegin)); + } +} diff --git a/foundations/foundation-config/src/test/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource b/foundations/foundation-config/src/test/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource deleted file mode 100644 index 54abbb2cacf..00000000000 --- a/foundations/foundation-config/src/test/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.config.MapBasedConfigurationSource \ No newline at end of file diff --git a/foundations/foundation-config/src/test/resources/log4j.properties b/foundations/foundation-config/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/foundations/foundation-config/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/foundations/foundation-config/src/test/resources/mapping.yaml b/foundations/foundation-config/src/test/resources/mapping.yaml index 0603585ccc2..66d6b0d08e1 100644 --- a/foundations/foundation-config/src/test/resources/mapping.yaml +++ b/foundations/foundation-config/src/test/resources/mapping.yaml @@ -14,8 +14,12 @@ ## See the License for the specific language governing permissions and ## limitations under the License. ## --------------------------------------------------------------------------- +servicecomb-config-order: 0 CSE_ENV_MAPPING: servicecomb.testmapping.key MY_SERVICES_ENDPOINT: - servicecomb.service.mapping.address - servicecomb.service1.mapping.address +SERVICECOMB_ENV: + - service_description.environment + - service_description.environment.old diff --git a/foundations/foundation-config/src/test/resources/microservice.yaml b/foundations/foundation-config/src/test/resources/microservice.yaml index a7b123716db..43a9078fba0 100644 --- a/foundations/foundation-config/src/test/resources/microservice.yaml +++ b/foundations/foundation-config/src/test/resources/microservice.yaml @@ -60,8 +60,10 @@ cse: service_description: name: testDemo - -servicecomb: - cse: - servicecomb: - file: value # this is a config for TestConfigUtil.testCreateLocalConfigWithExtraConfig() +holder: b,c,d +test: + commonSeparatedString: a,b,c + commonSeparatedStringHolder: ${holder} + stringArray: + - m + - n diff --git a/foundations/foundation-config/src/test/resources/test1.yaml b/foundations/foundation-config/src/test/resources/test1.yaml index 708d0e82f8b..e171487901f 100644 --- a/foundations/foundation-config/src/test/resources/test1.yaml +++ b/foundations/foundation-config/src/test/resources/test1.yaml @@ -38,11 +38,11 @@ shutDownHandler: enabled: true timeLimit: 30000 -hsa: +has: manager: url: 127.0.0.1 - serializer: - default: protostuff + serializer: + default: protostuff provider: service: name: ${spring.application.name} @@ -52,7 +52,7 @@ hsa: rpc: serviceLevel: interface dsf: -# ip: "10.57.65.225" +# ip: "10.57.65.225" port: 7450 eureka: diff --git a/foundations/foundation-metrics/pom.xml b/foundations/foundation-metrics/pom.xml index 843f3b04465..d893011c4d4 100644 --- a/foundations/foundation-metrics/pom.xml +++ b/foundations/foundation-metrics/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb foundations - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT foundation-metrics Java Chassis::Foundations::Metrics @@ -32,16 +32,22 @@ foundation-common - com.netflix.archaius - archaius-core + io.micrometer + micrometer-core - com.netflix.spectator - spectator-reg-servo + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test - org.slf4j - slf4j-log4j12 + org.jmockit + jmockit test diff --git a/foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java b/foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java deleted file mode 100644 index cccc7107f43..00000000000 --- a/foundations/foundation-metrics/src/main/java/com/netflix/spectator/api/SpectatorUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.spectator.api; - -public final class SpectatorUtils { - private SpectatorUtils() { - } - - public static Id createDefaultId(String name) { - return new DefaultId(name); - } - - public static void removeExpiredMeters(Registry registry) { - if (registry instanceof AbstractRegistry) { - ((AbstractRegistry) registry).removeExpiredMeters(); - } - } - - public static void registerMeter(Registry registry, Meter meter) { - if (!(registry instanceof AbstractRegistry)) { - throw new IllegalStateException("registry must be a AbstractRegistry, class=" + registry.getClass().getName()); - } - ((AbstractRegistry) registry).getOrCreate(meter.id(), Meter.class, null, _id -> meter); - } -} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java index d2647f082ad..86529a36e41 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java @@ -16,37 +16,58 @@ */ package org.apache.servicecomb.foundation.metrics; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import com.google.common.eventbus.EventBus; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.micrometer.core.instrument.MeterRegistry; + public class MetricsBootstrap { - private GlobalRegistry globalRegistry; + private static final Logger LOGGER = LoggerFactory.getLogger(MetricsBootstrap.class); - private EventBus eventBus; + private final MetricsBootstrapConfig config; - private MetricsBootstrapConfig config = new MetricsBootstrapConfig(); + private MeterRegistry meterRegistry; + + private EventBus eventBus; private ScheduledExecutorService executorService; - public void start(GlobalRegistry globalRegistry, EventBus eventBus) { - this.globalRegistry = globalRegistry; + private List metricsInitializers; + + @Autowired + public MetricsBootstrap(MetricsBootstrapConfig config) { + this.config = config; + } + + @Autowired + public void setMetricsInitializers(List metricsInitializers) { + this.metricsInitializers = metricsInitializers; + } + + @Autowired + public void setMeterRegistry(MeterRegistry meterRegistry) { + this.meterRegistry = meterRegistry; + } + + public void start(EventBus eventBus) { this.eventBus = eventBus; this.executorService = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder() - .setNameFormat("spectator-poller-%d") + .setNameFormat("metrics-poller-%d") .build()); - loadMetricsInitializers(); + metricsInitializers.forEach(initializer -> initializer.init(this.meterRegistry, eventBus, config)); startPoll(); } @@ -55,26 +76,28 @@ public void shutdown() { executorService.shutdown(); } - List initializers = new ArrayList<>(SPIServiceUtils.getSortedService(MetricsInitializer.class)); - Collections.reverse(initializers); - initializers.forEach(initializer -> initializer.destroy()); - } - - protected void loadMetricsInitializers() { - SPIServiceUtils.getSortedService(MetricsInitializer.class) - .forEach(initializer -> initializer.init(globalRegistry, eventBus, config)); + Collections.reverse(metricsInitializers); + metricsInitializers.forEach(MetricsInitializer::destroy); } protected void startPoll() { executorService.scheduleAtFixedRate(this::pollMeters, - 0, + config.getMsPollInterval(), config.getMsPollInterval(), TimeUnit.MILLISECONDS); } public synchronized void pollMeters() { - long secondInterval = TimeUnit.MILLISECONDS.toSeconds(config.getMsPollInterval()); - PolledEvent polledEvent = globalRegistry.poll(secondInterval); - eventBus.post(polledEvent); + metricsInitializers.forEach(initializer -> { + if (initializer instanceof PeriodMeter) { + ((PeriodMeter) initializer).poll(System.currentTimeMillis(), config.getMsPollInterval()); + } + }); + try { + PolledEvent polledEvent = new PolledEvent(meterRegistry.getMeters()); + eventBus.post(polledEvent); + } catch (Throwable e) { + LOGGER.error("poll meters error. ", e); + } } } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrapConfig.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrapConfig.java index 09322ca3462..53ab9a6d6ff 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrapConfig.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrapConfig.java @@ -16,24 +16,52 @@ */ package org.apache.servicecomb.foundation.metrics; -import com.netflix.config.DynamicPropertyFactory; +import org.springframework.core.env.Environment; public class MetricsBootstrapConfig { public static final String METRICS_WINDOW_TIME = "servicecomb.metrics.window_time"; - public static final int DEFAULT_METRICS_WINDOW_TIME = 60000; + public static final String CONFIG_LATENCY_DISTRIBUTION = "servicecomb.metrics.invocation.latencyDistribution"; + + public static final String CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN = + "servicecomb.metrics.publisher.defaultLog.invocation.latencyDistribution.minScopeLength"; + + public static final int DEFAULT_METRICS_WINDOW_TIME = 300_000; private long msPollInterval; - public MetricsBootstrapConfig() { + private String latencyDistribution; + + private int minScopeLength; + + private Environment environment; + + public MetricsBootstrapConfig(Environment environment) { + this.environment = environment; msPollInterval = - DynamicPropertyFactory.getInstance().getIntProperty(METRICS_WINDOW_TIME, DEFAULT_METRICS_WINDOW_TIME).get(); + environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME); if (msPollInterval < 1000) { msPollInterval = 1000; } + + latencyDistribution = environment.getProperty(CONFIG_LATENCY_DISTRIBUTION, String.class); + minScopeLength = environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7); + } + + public Environment getEnvironment() { + return environment; } public long getMsPollInterval() { return msPollInterval; } + + public String getLatencyDistribution() { + return latencyDistribution; + } + + public int getMinScopeLength() { + return minScopeLength; + } } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsInitializer.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsInitializer.java index 88201dcb2cc..3cb0b8f95f0 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsInitializer.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsInitializer.java @@ -16,19 +16,16 @@ */ package org.apache.servicecomb.foundation.metrics; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; - import com.google.common.eventbus.EventBus; +import io.micrometer.core.instrument.MeterRegistry; + public interface MetricsInitializer { default int getOrder() { return 0; } - /** - * if create new registry, must add to globalRegistry - */ - void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config); + void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config); default void destroy() { diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PolledEvent.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PolledEvent.java index 6b7c3018c68..0814f96149f 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PolledEvent.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PolledEvent.java @@ -18,17 +18,14 @@ import java.util.List; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; +import io.micrometer.core.instrument.Meter; + public class PolledEvent { private List meters; - private List measurements; - - public PolledEvent(List meters, List measurements) { + public PolledEvent(List meters) { this.meters = meters; - this.measurements = measurements; } public List getMeters() { @@ -38,12 +35,4 @@ public List getMeters() { public void setMeters(List meters) { this.meters = meters; } - - public List getMeasurements() { - return measurements; - } - - public void setMeasurements(List measurements) { - this.measurements = measurements; - } } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/health/HealthCheckResult.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/health/HealthCheckResult.java index fc147fbd643..930288aa5f3 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/health/HealthCheckResult.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/health/HealthCheckResult.java @@ -22,7 +22,6 @@ public class HealthCheckResult { private String information; - //unsupport object or generic type,so string.. private String extraData; private long timestamp; diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java deleted file mode 100644 index d9e2f46d583..00000000000 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/AbstractPeriodMeter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.meter; - -import java.util.Collections; -import java.util.List; - -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; - -public abstract class AbstractPeriodMeter implements PeriodMeter { - protected Id id; - - protected List allMeasurements = Collections.emptyList(); - - public Id id() { - return id; - } - - @Override - public Iterable measure() { - return allMeasurements; - } - - public boolean hasExpired() { - return false; - } -} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyDistributionConfig.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyDistributionConfig.java new file mode 100644 index 00000000000..d464697024f --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyDistributionConfig.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.metrics.meter; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LatencyDistributionConfig { + public static final Long MAX_LATENCY = 60 * 60 * 1000L; + + private static final Logger LOGGER = LoggerFactory.getLogger(LatencyDistributionConfig.class); + + private final List scopeConfigs = new ArrayList<>(); + + /** + * + * @param config scope definition, time unit is milliseconds, eg:0,1,10 + */ + public LatencyDistributionConfig(String config) { + if (StringUtils.isEmpty(config)) { + return; + } + config = config.trim() + "," + MAX_LATENCY; + String[] array = config.split("\\s*,+\\s*"); + try { + for (int idx = 0; idx < array.length - 1; idx++) { + long msMin = Long.parseLong(array[idx]); + long msMax = Long.parseLong(array[idx + 1]); + if (msMin >= msMax) { + String msg = String.format("invalid latency scope, min=%s, max=%s.", array[idx], array[idx + 1]); + throw new IllegalStateException(msg); + } + + LatencyScopeConfig latencyScopeConfig = new LatencyScopeConfig(msMin, msMax); + scopeConfigs.add(latencyScopeConfig); + } + } catch (Throwable e) { + LOGGER.error("Failed to parse latencyDistributionConfig, value={}", config, e); + throw e; + } + } + + public List getScopeConfigs() { + return scopeConfigs; + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyScopeConfig.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyScopeConfig.java new file mode 100644 index 00000000000..0beeb7cfee9 --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/LatencyScopeConfig.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.metrics.meter; + +public class LatencyScopeConfig { + // [min, max) + // even max equals Long.MAX_VALUE, still not include it + // because it will never happened in real cases + private final long msMin; + + private final long msMax; + + public LatencyScopeConfig(long msMin, long msMax) { + this.msMin = msMin; + this.msMax = msMax; + } + + public long getMsMin() { + return msMin; + } + + public long getMsMax() { + return msMax; + } + + @Override + public String toString() { + return "LatencyScopeConfig[" + msMin + ", " + msMax + ')'; + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java index f91d781e17a..a846d08179d 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/PeriodMeter.java @@ -16,13 +16,6 @@ */ package org.apache.servicecomb.foundation.metrics.meter; -import java.util.List; - -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; - -public interface PeriodMeter extends Meter { - void calcMeasurements(long msNow, long secondInterval); - - void calcMeasurements(List measurements, long msNow, long secondInterval); +public interface PeriodMeter { + void poll(long msNow, long secondInterval); } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java deleted file mode 100644 index 09803a4718d..00000000000 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/SimpleTimer.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.meter; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.LongAdder; - -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Statistic; -import com.netflix.spectator.impl.AtomicDouble; - -/** - * ServoTimer is too slow - * this is a faster timer - */ -public class SimpleTimer extends AbstractPeriodMeter { - private static final double CNV_SECONDS = 1.0 / TimeUnit.SECONDS.toNanos(1L); - - private final Id idCount; - - private final Id idTotalTime; - - private final Id idMax; - - private final LongAdder count = new LongAdder(); - - private final LongAdder totalTime = new LongAdder(); - - private final AtomicDouble max = new AtomicDouble(); - - private long lastCount = 0; - - private long lastTotalTime = 0; - - public SimpleTimer(Id id) { - this.id = id; - this.idCount = id.withTag(Statistic.count); - this.idTotalTime = id.withTag(Statistic.totalTime); - this.idMax = id.withTag(Statistic.max); - } - - public void record(long nanoAmount) { - if (nanoAmount >= 0) { - totalTime.add(nanoAmount); - count.increment(); - max.max(nanoAmount); - } - } - - private Measurement newMeasurement(Id id, long msNow, Number n) { - return new Measurement(id, msNow, n.doubleValue()); - } - - @Override - public void calcMeasurements(long msNow, long secondInterval) { - List measurements = new ArrayList<>(3); - calcMeasurements(measurements, msNow, secondInterval); - allMeasurements = measurements; - } - - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - long currentCount = count.longValue(); - long currentTotalTime = totalTime.longValue(); - - measurements.add(newMeasurement(idCount, msNow, (double) (currentCount - lastCount) / secondInterval)); - measurements - .add(newMeasurement(idTotalTime, msNow, (currentTotalTime - lastTotalTime) / secondInterval * CNV_SECONDS)); - measurements.add(newMeasurement(idMax, msNow, max.get() * CNV_SECONDS)); - - lastCount = currentCount; - lastTotalTime = currentTotalTime; - // maybe lost some max value, but not so important? - max.set(0); - } -} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/DefaultTagFinder.java similarity index 88% rename from foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java rename to foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/DefaultTagFinder.java index dc731a84637..f29227c6a72 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/DefaultTagFinder.java @@ -14,12 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.metrics.publish.spectator; +package org.apache.servicecomb.foundation.metrics.publish; -import com.netflix.spectator.api.Tag; + +import io.micrometer.core.instrument.Tag; public class DefaultTagFinder implements TagFinder { - private String tagKey; + private final String tagKey; private boolean skipOnNull; @@ -45,7 +46,7 @@ public String getTagKey() { @Override public Tag find(Iterable tags) { for (Tag tag : tags) { - if (tag.key().equals(tagKey)) { + if (tag.getKey().equals(tagKey)) { return tag; } } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementGroupConfig.java similarity index 89% rename from foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java rename to foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementGroupConfig.java index 48075fc8a4a..cec6db25eb4 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementGroupConfig.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.metrics.publish.spectator; +package org.apache.servicecomb.foundation.metrics.publish; import java.util.Arrays; import java.util.HashMap; @@ -24,7 +24,7 @@ public class MeasurementGroupConfig { // key is measurement id name - private Map> groups = new HashMap<>(); + private final Map> groups = new HashMap<>(); public MeasurementGroupConfig() { } @@ -38,7 +38,7 @@ public void addGroup(String idName, Object... tagNameOrFinders) { Arrays .asList(tagNameOrFinders) .stream() - .map(r -> TagFinder.build(r)) + .map(TagFinder::build) .collect(Collectors.toList())); } diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementNode.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementNode.java new file mode 100644 index 00000000000..8ff19a15345 --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementNode.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.metrics.publish; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter.Id; + +public class MeasurementNode implements Comparable { + private final String name; + + private final Id id; + + private final List measurements = new ArrayList<>(); + + private Map children; + + public MeasurementNode(String name, Id id, Map children) { + this.name = name; + this.id = id; + this.children = children; + } + + public String getName() { + return this.name; + } + + public Id getId() { + return id; + } + + public Map getChildren() { + return children; + } + + public MeasurementNode findChild(String childName) { + if (children == null) { + return null; + } + return children.get(childName); + } + + public MeasurementNode findChild(String... childNames) { + MeasurementNode node = this; + for (String childName : childNames) { + if (node == null) { + return null; + } + + node = node.findChild(childName); + } + return node; + } + + public MeasurementNode addChild(String childName, Id id, Measurement measurement) { + if (children == null) { + children = new LinkedHashMap<>(); + } + + MeasurementNode node = children.computeIfAbsent(childName, name -> new MeasurementNode(name, id, null)); + + if (measurement != null) { + node.addMeasurement(measurement); + } + + return node; + } + + public List getMeasurements() { + return measurements; + } + + public void addMeasurement(Measurement measurement) { + measurements.add(measurement); + } + + public double summary() { + double result = 0; + for (Measurement measurement : measurements) { + result += measurement.getValue(); + } + + return result; + } + + @Override + public int compareTo(MeasurementNode o) { + return this.name.compareTo(o.name); + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementTree.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementTree.java new file mode 100644 index 00000000000..a03c4739ef7 --- /dev/null +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/MeasurementTree.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.metrics.publish; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.distribution.CountAtBucket; +import io.micrometer.core.instrument.distribution.HistogramSnapshot; + +// like select * from meters group by ...... +// but output a tree not a table +public class MeasurementTree extends MeasurementNode { + public MeasurementTree() { + super(null, null, null); + } + + // groupConfig: + // key: id name + // value: id tag keys + // only id name exists in groupConfig will accept, others will be ignored + public void from(Iterator meters, MeasurementGroupConfig groupConfig) { + meters.forEachRemaining(meter -> { + // This code snip is not very good design. But DistributionSummary is quite special. + if (meter instanceof DistributionSummary distributionSummary) { + HistogramSnapshot snapshot = distributionSummary.takeSnapshot(); + CountAtBucket[] countAtBuckets = snapshot.histogramCounts(); + List distributions = new ArrayList<>(countAtBuckets.length); + for (CountAtBucket countAtBucket : countAtBuckets) { + final double value = countAtBucket.count(); + distributions.add(new Measurement(() -> value, + Statistic.COUNT)); + } + + from(meter.getId(), distributions, groupConfig); + return; + } + + Iterable measurements = meter.measure(); + from(meter.getId(), measurements, groupConfig); + }); + } + + public void from(Id id, Iterable measurements, MeasurementGroupConfig groupConfig) { + for (Measurement measurement : measurements) { + MeasurementNode node = addChild(id.getName(), id, measurement); + + List tagFinders = groupConfig.findTagFinders(id.getName()); + if (tagFinders == null) { + continue; + } + + for (TagFinder tagFinder : tagFinders) { + Tag tag = tagFinder.find(id.getTags()); + if (tag == null) { + if (tagFinder.skipOnNull()) { + break; + } + throw new IllegalStateException( + String.format("tag key \"%s\" not exist in %s", + tagFinder.getTagKey(), + id)); + } + + node = node.addChild(tag.getValue(), id, measurement); + } + + node.addChild(measurement.getStatistic().name(), id, measurement); + } + } +} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/TagFinder.java similarity index 92% rename from foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java rename to foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/TagFinder.java index 0762afb8de4..e1f3c8b402c 100644 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java +++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/TagFinder.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.metrics.publish.spectator; +package org.apache.servicecomb.foundation.metrics.publish; -import com.netflix.spectator.api.Tag; +import io.micrometer.core.instrument.Tag; public interface TagFinder { static TagFinder build(Object obj) { diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java deleted file mode 100644 index 0518ebe1935..00000000000 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.publish.spectator; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.netflix.spectator.api.Measurement; - -public class MeasurementNode { - private String name; - - private List measurements = new ArrayList<>(); - - private Map children; - - public MeasurementNode(String name, Map children) { - this.name = name; - this.children = children; - } - - public String getName() { - return name; - } - - public Map getChildren() { - return children; - } - - public MeasurementNode findChild(String childName) { - if (children == null) { - return null; - } - return children.get(childName); - } - - public MeasurementNode findChild(String... childNames) { - MeasurementNode node = this; - for (String childName : childNames) { - if (node == null) { - return null; - } - - node = node.findChild(childName); - } - return node; - } - - public MeasurementNode addChild(String childName, Measurement measurement) { - if (children == null) { - children = new HashMap<>(); - } - - MeasurementNode node = children.computeIfAbsent(childName, name -> { - return new MeasurementNode(name, null); - }); - node.addMeasurement(measurement); - - return node; - } - - public List getMeasurements() { - return measurements; - } - - public void addMeasurement(Measurement measurement) { - measurements.add(measurement); - } - - public double summary() { - double result = 0; - for (Measurement measurement : measurements) { - result += measurement.value(); - } - - return result; - } -} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java deleted file mode 100644 index 79101fa166e..00000000000 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.publish.spectator; - -import java.util.Iterator; -import java.util.List; - -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Tag; - -// like select * from meters group by ...... -// but output a tree not a table -public class MeasurementTree extends MeasurementNode { - public MeasurementTree() { - super(null, null); - } - - // groupConfig: - // key: id name - // value: id tag keys - // only id name exists in groupConfig will accept, others will be ignored - public void from(Iterator meters, MeasurementGroupConfig groupConfig) { - meters.forEachRemaining(meter -> { - Iterable measurements = meter.measure(); - from(measurements, groupConfig); - }); - } - - public void from(Iterable measurements, MeasurementGroupConfig groupConfig) { - for (Measurement measurement : measurements) { - Id id = measurement.id(); - MeasurementNode node = addChild(id.name(), measurement); - - List tagFinders = groupConfig.findTagFinders(id.name()); - if (tagFinders == null) { - continue; - } - - for (TagFinder tagFinder : tagFinders) { - Tag tag = tagFinder.find(id.tags()); - if (tag == null) { - if (tagFinder.skipOnNull()) { - break; - } - throw new IllegalStateException( - String.format("tag key \"%s\" not exist in %s", - tagFinder.getTagKey(), - measurement)); - } - - node = node.addChild(tag.value(), measurement); - } - } - } -} diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java deleted file mode 100644 index 9af39d02d1b..00000000000 --- a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/registry/GlobalRegistry.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.registry; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.servicecomb.foundation.metrics.PolledEvent; -import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; - -import com.netflix.spectator.api.Clock; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.SpectatorUtils; - -public class GlobalRegistry { - private Clock clock; - - private List registries = new CopyOnWriteArrayList<>(); - - private Registry defaultRegistry; - - public GlobalRegistry() { - this(Clock.SYSTEM); - } - - public GlobalRegistry(Clock clock) { - this.clock = clock; - } - - public Clock getClock() { - return clock; - } - - public List getRegistries() { - return registries; - } - - public Registry getDefaultRegistry() { - return defaultRegistry; - } - - public synchronized void add(Registry registry) { - if (registries.isEmpty()) { - defaultRegistry = registry; - } - registries.add(registry); - } - - public synchronized void remove(Registry registry) { - registries.remove(registry); - if (registry != defaultRegistry) { - return; - } - - if (registries.isEmpty()) { - defaultRegistry = null; - return; - } - - defaultRegistry = registries.get(0); - } - - public synchronized void removeAll() { - registries.clear(); - defaultRegistry = null; - } - - @SuppressWarnings("unchecked") - public T find(Class cls) { - for (Registry registry : registries) { - if (cls.isAssignableFrom(registry.getClass())) { - return (T) registry; - } - } - return null; - } - - public PolledEvent poll(long secondInterval) { - long msNow = clock.wallTime(); - List meters = new ArrayList<>(); - List measurements = new ArrayList<>(); - for (Registry registry : registries) { - SpectatorUtils.removeExpiredMeters(registry); - - for (Meter meter : registry) { - if (meter instanceof PeriodMeter) { - ((PeriodMeter) meter).calcMeasurements(msNow, secondInterval); - } - - meters.add(meter); - meter.measure().forEach(measurements::add); - } - } - - return new PolledEvent(meters, measurements); - } -} diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java index 748774578a9..231b0099ed4 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java @@ -16,92 +16,69 @@ */ package org.apache.servicecomb.foundation.metrics; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; public class TestMetricsBootstrap { - MetricsBootstrap bootstrap = new MetricsBootstrap(); - - GlobalRegistry globalRegistry = new GlobalRegistry(); + MetricsBootstrap bootstrap; EventBus eventBus = new EventBus(); + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + + MetricsBootstrapConfig config = new MetricsBootstrapConfig(environment); + bootstrap = new MetricsBootstrap(config); + bootstrap.setMetricsInitializers(List.of()); + } + @Test public void loadMetricsInitializers() { List initList = new ArrayList<>(); MetricsInitializer metricsInitializer = new MetricsInitializer() { @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { initList.add(this); } }; - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(MetricsInitializer.class); - result = Arrays.asList(metricsInitializer, metricsInitializer); - } - }; - - bootstrap.start(globalRegistry, eventBus); - bootstrap.shutdown(); - Assert.assertThat(initList, Matchers.contains(metricsInitializer, metricsInitializer)); - } - - @Test - public void pollMeters(@Mocked Registry registry, @Mocked Meter meter, @Mocked Measurement measurement, - @Mocked ScheduledExecutorService executor) { - List meters = Arrays.asList(meter); - globalRegistry.add(registry); - new Expectations(Executors.class) { - { - Executors.newScheduledThreadPool(1, (ThreadFactory) any); - result = executor; - registry.iterator(); - result = meters.iterator(); - meter.measure(); - result = Arrays.asList(measurement); - } - }; - bootstrap.start(globalRegistry, eventBus); - - PolledEvent result = new PolledEvent(null, null); - eventBus.register(new Object() { - @Subscribe - public void onEvent(PolledEvent event) { - result.setMeters(event.getMeters()); - result.setMeasurements(event.getMeasurements()); - } - }); + bootstrap.setMetricsInitializers(Arrays.asList(metricsInitializer, metricsInitializer)); - bootstrap.pollMeters(); + bootstrap.start(eventBus); bootstrap.shutdown(); - Assert.assertEquals(meters, result.getMeters()); - Assert.assertThat(result.getMeasurements(), Matchers.contains(measurement)); + + MatcherAssert.assertThat(initList, Matchers.contains(metricsInitializer, metricsInitializer)); } @Test - public void shutdown(@Mocked ScheduledExecutorService scheduledExecutorService) { + public void shutdown() { + ScheduledExecutorService scheduledExecutorService = Mockito.mock(ScheduledExecutorService.class); List destroyList = new ArrayList<>(); MetricsInitializer initializer1 = new MetricsInitializer() { @Override @@ -110,7 +87,7 @@ public int getOrder() { } @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { } @Override @@ -126,7 +103,7 @@ public int getOrder() { } @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { } @Override @@ -134,23 +111,17 @@ public void destroy() { destroyList.add(this); } }; - - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(MetricsInitializer.class); - result = Arrays.asList(initializer1, initializer2); - } - }; + bootstrap.setMetricsInitializers(Arrays.asList(initializer1, initializer2)); Deencapsulation.setField(bootstrap, "executorService", scheduledExecutorService); bootstrap.shutdown(); - Assert.assertThat(destroyList, Matchers.contains(initializer2, initializer1)); + MatcherAssert.assertThat(destroyList, Matchers.contains(initializer2, initializer1)); } @Test public void shutdown_notStart() { - Assert.assertNull(Deencapsulation.getField(bootstrap, "executorService")); + Assertions.assertNull(Deencapsulation.getField(bootstrap, "executorService")); // should not throw exception bootstrap.shutdown(); diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/health/TestHealthCheckerManager.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/health/TestHealthCheckerManager.java index d353660bbc5..fad079aaed5 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/health/TestHealthCheckerManager.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/health/TestHealthCheckerManager.java @@ -19,13 +19,13 @@ import java.util.Map; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TestHealthCheckerManager { - private HealthChecker good = new HealthChecker() { + private final HealthChecker good = new HealthChecker() { @Override public String getName() { return "testBad"; @@ -37,7 +37,7 @@ public HealthCheckResult check() { } }; - private HealthChecker bad = new HealthChecker() { + private final HealthChecker bad = new HealthChecker() { @Override public String getName() { return "testGood"; @@ -49,7 +49,7 @@ public HealthCheckResult check() { } }; - @Before + @BeforeEach public void reset() { HealthCheckerManager.getInstance().unregister(good.getName()); HealthCheckerManager.getInstance().unregister(bad.getName()); @@ -58,14 +58,14 @@ public void reset() { @Test public void checkResultCount_None() { Map results = HealthCheckerManager.getInstance().check(); - Assert.assertEquals(0, results.size()); + Assertions.assertEquals(0, results.size()); } @Test public void checkResultCount_One() { HealthCheckerManager.getInstance().register(good); Map results = HealthCheckerManager.getInstance().check(); - Assert.assertEquals(1, results.size()); + Assertions.assertEquals(1, results.size()); } @Test @@ -73,7 +73,7 @@ public void checkResultCount_Both() { HealthCheckerManager.getInstance().register(good); HealthCheckerManager.getInstance().register(bad); Map results = HealthCheckerManager.getInstance().check(); - Assert.assertEquals(2, results.size()); + Assertions.assertEquals(2, results.size()); } @Test @@ -81,9 +81,9 @@ public void checkGoodResult() { HealthCheckerManager.getInstance().register(good); HealthCheckerManager.getInstance().register(bad); HealthCheckResult result = HealthCheckerManager.getInstance().check().get("testGood"); - Assert.assertEquals(true, result.isHealthy()); - Assert.assertEquals("good", result.getInformation()); - Assert.assertEquals("good component", result.getExtraData()); + Assertions.assertTrue(result.isHealthy()); + Assertions.assertEquals("good", result.getInformation()); + Assertions.assertEquals("good component", result.getExtraData()); } @Test @@ -91,8 +91,8 @@ public void checkBadResult() { HealthCheckerManager.getInstance().register(good); HealthCheckerManager.getInstance().register(bad); HealthCheckResult result = HealthCheckerManager.getInstance().check().get("testBad"); - Assert.assertEquals(false, result.isHealthy()); - Assert.assertEquals("bad", result.getInformation()); - Assert.assertEquals("bad component", result.getExtraData()); + Assertions.assertFalse(result.isHealthy()); + Assertions.assertEquals("bad", result.getInformation()); + Assertions.assertEquals("bad component", result.getExtraData()); } } diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestLatencyDistributionConfig.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestLatencyDistributionConfig.java new file mode 100644 index 00000000000..5144896e015 --- /dev/null +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestLatencyDistributionConfig.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.metrics.meter; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestLatencyDistributionConfig { + + @Test + public void testValidProperty() { + String validProperty1 = "0,1,2,10"; + String validProperty2 = "0,1, 2 , 10 "; + String validProperty3 = "0,1,2,10,"; + + LatencyDistributionConfig config1 = new LatencyDistributionConfig(validProperty1); + LatencyDistributionConfig config2 = new LatencyDistributionConfig(validProperty2); + LatencyDistributionConfig config3 = new LatencyDistributionConfig(validProperty3); + + Assertions.assertEquals(4, config1.getScopeConfigs().size()); + Assertions.assertEquals(4, config2.getScopeConfigs().size()); + Assertions.assertEquals(4, config3.getScopeConfigs().size()); + } + + @Test + public void testInValidProperty1() { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + LatencyDistributionConfig latencyDistributionConfig = new LatencyDistributionConfig("2,1,10"); + Assertions.assertEquals(0, latencyDistributionConfig.getScopeConfigs().size()); + }); + Assertions.assertEquals("invalid latency scope, min=2, max=1.", exception.getMessage()); + } + + @Test + public void testInValidProperty2() { + NumberFormatException exception = Assertions.assertThrows(NumberFormatException.class, () -> { + LatencyDistributionConfig latencyDistributionConfig = new LatencyDistributionConfig("a,1,10"); + Assertions.assertEquals(0, latencyDistributionConfig.getScopeConfigs().size()); + }); + Assertions.assertEquals("For input string: \"a\"", exception.getMessage()); + } +} diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java deleted file mode 100644 index 1d344973ea7..00000000000 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/meter/TestSimpleTimer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.metrics.meter; - -import org.junit.Assert; -import org.junit.Test; - -import com.netflix.spectator.api.SpectatorUtils; - -public class TestSimpleTimer { - SimpleTimer timer = new SimpleTimer(SpectatorUtils.createDefaultId("name")); - - @Test - public void measure() { - timer.record(2); - timer.record(4); - - Assert.assertFalse(timer.measure().iterator().hasNext()); - - timer.calcMeasurements(1, 2); - Assert.assertEquals( - "[Measurement(name:statistic=count,1,1.0), Measurement(name:statistic=totalTime,1,3.0000000000000004E-9), Measurement(name:statistic=max,1,4.0E-9)]", - timer.measure().toString()); - Assert.assertFalse(timer.hasExpired()); - Assert.assertEquals("name", timer.id().name()); - } -} diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestDefaultTagFinder.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestDefaultTagFinder.java index 84a288a014c..46220069b97 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestDefaultTagFinder.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestDefaultTagFinder.java @@ -19,33 +19,34 @@ import java.util.Arrays; import java.util.List; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.metrics.publish.DefaultTagFinder; +import org.apache.servicecomb.foundation.metrics.publish.TagFinder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import com.netflix.spectator.api.BasicTag; -import com.netflix.spectator.api.Tag; +import io.micrometer.core.instrument.Tag; public class TestDefaultTagFinder { TagFinder finder = new DefaultTagFinder("key"); @Test public void getTagKey() { - Assert.assertEquals("key", finder.getTagKey()); + Assertions.assertEquals("key", finder.getTagKey()); } @Test public void readSucc() { - Tag tag = new BasicTag("key", "value"); - List tags = Arrays.asList(new BasicTag("t1", "t1v"), + Tag tag = Tag.of("key", "value"); + List tags = Arrays.asList(Tag.of("t1", "t1v"), tag); - Assert.assertSame(tag, finder.find(tags)); + Assertions.assertSame(tag, finder.find(tags)); } @Test public void readFail() { - List tags = Arrays.asList(new BasicTag("t1", "t1v")); + List tags = Arrays.asList(Tag.of("t1", "t1v")); - Assert.assertNull(finder.find(tags)); + Assertions.assertNull(finder.find(tags)); } } diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java index 51b6a56ab0f..60d77b4c75a 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java @@ -19,11 +19,14 @@ import java.util.List; import java.util.Map; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.TagFinder; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; import mockit.Deencapsulation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestMeasurementGroupConfig { MeasurementGroupConfig config = new MeasurementGroupConfig(); @@ -32,7 +35,7 @@ public class TestMeasurementGroupConfig { @Test public void defaultConstruct() { - Assert.assertTrue(groups.isEmpty()); + Assertions.assertTrue(groups.isEmpty()); } @Test @@ -40,10 +43,9 @@ public void constructAddGroup() { config = new MeasurementGroupConfig("id", "tag1"); groups = Deencapsulation.getField(config, "groups"); - Assert.assertThat(groups.keySet(), Matchers.contains("id")); - Assert.assertThat(groups.get("id").stream().map(e -> { - return e.getTagKey(); - }).toArray(), Matchers.arrayContaining("tag1")); + MatcherAssert.assertThat(groups.keySet(), Matchers.contains("id")); + MatcherAssert.assertThat(groups.get("id").stream().map(TagFinder::getTagKey).toArray(), + Matchers.arrayContaining("tag1")); } @Test @@ -51,13 +53,9 @@ public void addGroup() { config.addGroup("id1", "tag1.1", "tag1.2"); config.addGroup("id2", "tag2.1", "tag2.2"); - Assert.assertThat(groups.keySet(), Matchers.contains("id2", "id1")); - Assert.assertThat(groups.get("id1").stream().map(e -> { - return e.getTagKey(); - }).toArray(), Matchers.arrayContaining("tag1.1", "tag1.2")); - Assert.assertThat(groups.get("id2").stream().map(e -> { - return e.getTagKey(); - }).toArray(), Matchers.arrayContaining("tag2.1", "tag2.2")); + MatcherAssert.assertThat(groups.keySet(), Matchers.containsInAnyOrder("id2", "id1")); + MatcherAssert.assertThat(groups.get("id1").stream().map(TagFinder::getTagKey).toArray(), Matchers.arrayContaining("tag1.1", "tag1.2")); + MatcherAssert.assertThat(groups.get("id2").stream().map(TagFinder::getTagKey).toArray(), Matchers.arrayContaining("tag2.1", "tag2.2")); } @Test @@ -65,8 +63,7 @@ public void findTagReaders() { config.addGroup("id1", "tag1.1", "tag1.2"); config.addGroup("id2", "tag2.1", "tag2.2"); - Assert.assertThat(config.findTagFinders("id2").stream().map(e -> { - return e.getTagKey(); - }).toArray(), Matchers.arrayContaining("tag2.1", "tag2.2")); + MatcherAssert.assertThat(config.findTagFinders("id2").stream().map(TagFinder::getTagKey).toArray(), + Matchers.arrayContaining("tag2.1", "tag2.2")); } } diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java index 585fd9aeceb..be7681ae5cd 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java @@ -19,79 +19,85 @@ import java.util.HashMap; import java.util.Map; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; -import com.netflix.spectator.api.Measurement; - +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Meter.Type; +import io.micrometer.core.instrument.Tags; import mockit.Expectations; import mockit.Mocked; public class TestMeasurementNode { - MeasurementNode node = new MeasurementNode("name", null); + Id id = new Id("name", Tags.empty(), null, null, Type.OTHER); + + MeasurementNode node = new MeasurementNode("name", id, null); @Test public void getName() { - Assert.assertEquals("name", node.getName()); + Assertions.assertEquals("name", node.getName()); } @Test public void getChildren() { Map children = new HashMap<>(); - node = new MeasurementNode("name", children); + node = new MeasurementNode("name", id, children); - Assert.assertSame(children, node.getChildren()); + Assertions.assertSame(children, node.getChildren()); } @Test public void findChild_noChildren() { - Assert.assertNull(node.findChild("child")); + Assertions.assertNull(node.findChild("child")); } @Test public void findChild_multiLevel_noMiddleChildren(@Mocked Measurement measurement) { - MeasurementNode c1 = node.addChild("c1", measurement); - c1.addChild("c2", measurement); + MeasurementNode c1 = node.addChild("c1", id, measurement); + c1.addChild("c2", id, measurement); - Assert.assertNull(node.findChild("c1_notExist", "c2")); + Assertions.assertNull(node.findChild("c1_notExist", "c2")); } @Test public void findChild_multiLevel_ok(@Mocked Measurement measurement) { - MeasurementNode c1 = node.addChild("c1", measurement); - MeasurementNode c2 = c1.addChild("c2", measurement); + MeasurementNode c1 = node.addChild("c1", id, measurement); + MeasurementNode c2 = c1.addChild("c2", id, measurement); - Assert.assertSame(c2, node.findChild("c1", "c2")); + Assertions.assertSame(c2, node.findChild("c1", "c2")); } @Test public void addChild(@Mocked Measurement measurement) { - MeasurementNode c1 = node.addChild("c1", measurement); - MeasurementNode c2 = node.addChild("c2", measurement); + MeasurementNode c1 = node.addChild("c1", id, measurement); + MeasurementNode c2 = node.addChild("c2", id, measurement); - Assert.assertSame(c1, node.findChild("c1")); - Assert.assertSame(c2, node.findChild("c2")); + Assertions.assertSame(c1, node.findChild("c1")); + Assertions.assertSame(c2, node.findChild("c2")); } @Test public void getMeasurements(@Mocked Measurement measurement) { node.addMeasurement(measurement); - Assert.assertThat(node.getMeasurements(), Matchers.contains(measurement)); + MatcherAssert.assertThat(node.getMeasurements(), Matchers.contains(measurement)); } @Test public void summary(@Mocked Measurement measurement) { new Expectations() { { - measurement.value(); + measurement.getValue(); result = 10; } }; node.addMeasurement(measurement); node.addMeasurement(measurement); - Assert.assertEquals(20, node.summary(), 0); + Assertions.assertEquals(20, node.summary(), 0); } } diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java index 21936960300..d21354be5b2 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java @@ -18,31 +18,26 @@ import java.util.concurrent.TimeUnit; -import org.hamcrest.Matchers; -import org.junit.Assert; +import org.apache.servicecomb.foundation.metrics.publish.DefaultTagFinder; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.Statistic; -import com.netflix.spectator.api.Timer; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; public class TestMeasurementTree { MeasurementTree tree = new MeasurementTree(); - ManualClock clock = new ManualClock(); - - Registry registry = new DefaultRegistry(clock); + MeterRegistry registry = new SimpleMeterRegistry(); Timer timer; - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Before public void setup() { timer = registry.timer("id", @@ -59,37 +54,40 @@ public void setup() { @Test public void from() { - timer.record(10, TimeUnit.NANOSECONDS); - timer.record(2, TimeUnit.NANOSECONDS); + timer.record(10, TimeUnit.SECONDS); + timer.record(2, TimeUnit.SECONDS); - MeasurementGroupConfig config = new MeasurementGroupConfig("id", "g1", "g2", Statistic.count.key()); - tree.from(registry.iterator(), config); + MeasurementGroupConfig config = new MeasurementGroupConfig("id", "g1", "g2"); + tree.from(registry.getMeters().iterator(), config); - Assert.assertEquals(2, tree.getChildren().size()); + Assertions.assertEquals(2, tree.getChildren().size()); MeasurementNode node = tree.findChild("id", "g1v", "g2v"); - Assert.assertEquals(2d, node.findChild(Statistic.count.value()).getMeasurements().get(0).value(), 0); - Assert.assertEquals(12d, node.findChild(Statistic.totalTime.value()).getMeasurements().get(0).value(), 0); - Assert.assertEquals(0d, tree.findChild("id_notCare").summary(), 0); + Assertions.assertEquals(2d, + node.findChild(Statistic.COUNT.name()).getMeasurements().get(0).getValue(), 0); + Assertions.assertEquals(12d, + node.findChild(Statistic.TOTAL_TIME.name()).getMeasurements().get(0).getValue(), 0); + Assertions.assertEquals(0d, tree.findChild("id_notCare").summary(), 0); } @Test public void from_withSkipOnNull() { try { MeasurementGroupConfig config = new MeasurementGroupConfig("id", new DefaultTagFinder("notExist", true)); - tree.from(registry.iterator(), config); + tree.from(registry.getMeters().iterator(), config); } catch (Exception e) { - Assert.fail("should not throw exception"); + Assertions.fail("should not throw exception"); } } @Test public void from_failed() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("tag key \"notExist\" not exist in Measurement(id:g1=g1v:g2=g2v:statistic=count:t3=t3v:t4=t4v,0,0.0)")); - - MeasurementGroupConfig config = new MeasurementGroupConfig("id", "notExist"); - tree.from(registry.iterator(), config); + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + MeasurementGroupConfig config = new MeasurementGroupConfig("id", "notExist"); + tree.from(registry.getMeters().iterator(), config); + }); + Assertions.assertEquals( + "tag key \"notExist\" not exist in MeterId{name='id', tags=[tag(g1=g1v),tag(g2=g2v),tag(t3=t3v),tag(t4=t4v)]}", + exception.getMessage()); } } diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java index 1f5551b04a8..2a0d960637a 100644 --- a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java +++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java @@ -16,48 +16,39 @@ */ package org.apache.servicecomb.foundation.metrics.publish.spectator; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.apache.servicecomb.foundation.metrics.publish.DefaultTagFinder; +import org.apache.servicecomb.foundation.metrics.publish.TagFinder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestTagFinder { - @Rule - public ExpectedException expectedException = ExpectedException.none(); @Test public void buildFromString() { String name = "key"; TagFinder finder = TagFinder.build(name); - Assert.assertEquals(name, finder.getTagKey()); - Assert.assertEquals(DefaultTagFinder.class, finder.getClass()); + Assertions.assertEquals(name, finder.getTagKey()); + Assertions.assertEquals(DefaultTagFinder.class, finder.getClass()); } @Test public void buildFromTagFinder() { TagFinder finder = new DefaultTagFinder("key"); - Assert.assertSame(finder, TagFinder.build(finder)); + Assertions.assertSame(finder, TagFinder.build(finder)); DefaultTagFinder tagFinder = new DefaultTagFinder("key", true); - Assert.assertSame(tagFinder, TagFinder.build(tagFinder)); + Assertions.assertSame(tagFinder, TagFinder.build(tagFinder)); } @Test public void buildFromInvalidType() { - expectedException.expect(IllegalArgumentException.class); - expectedException - .expectMessage(Matchers.is("only support String or TagFinder, but got " + Integer.class.getName())); - - TagFinder.build(1); + IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> TagFinder.build(1)); + Assertions.assertEquals("only support String or TagFinder, but got " + Integer.class.getName(), exception.getMessage()); } @Test public void buildFromNull() { - expectedException.expect(IllegalArgumentException.class); - expectedException - .expectMessage(Matchers.is("only support String or TagFinder, but got null")); - - TagFinder.build(null); + IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> TagFinder.build(null)); + Assertions.assertEquals("only support String or TagFinder, but got null", exception.getMessage()); } } diff --git a/foundations/foundation-metrics/src/test/resources/log4j.properties b/foundations/foundation-metrics/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/foundations/foundation-metrics/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/foundations/foundation-protobuf/README.md b/foundations/foundation-protobuf/README.md index fdb04eca12a..c225e89dc87 100644 --- a/foundations/foundation-protobuf/README.md +++ b/foundations/foundation-protobuf/README.md @@ -1,34 +1,45 @@ # Overview -There are many existing protobuf codecs, but not suit for us, so we create new one: -- official, must generate code - - 40+ lines proto file, generate 5000+ java code - - bind business model to protobuf, but our business can switch different codecs dynamically - - strong type, there is no business jar in edge service, no strong types -- protostuff - - strong type - - map codec is not compatible to protobuf -- jackson - - not support map/any type - - performance is not so good - +There are many existing protobuf codecs, but all of them are not suit for us. +ServiceComb data model is just POJO, not bind to any codec mechanism, so we had to create new one: + +| | ServiceComb | protobuf | protostuff | jackson | +| -------------------------------------------------------- | :-----------: | :------: | :------------: | :-----: | +| generate code | no need
just POJO | must
100+ lines IDL, generate 10000+ java code | no need
POJO with Annotation(eg:@Tag) | no need | +| support null element in repeated field | no | no | not compatible | no | +| support "oneOf" | no | yes | no | no | +| support "packed" | yes | yes | no | no | +| support "map" | yes | yes | not compatible | no | +| support "any" | yes | yes | not compatible | no | +| support "any" not defined in IDL | yes
extend based on "any" mechanism | no | not compatible | no | +| support field: `List>` | yes | no | not compatible | no | +| support field: `List>` | yes | no | not compatible | no | +| support field: `Map>` | yes | no | not compatible | no | +| support field: `Map>` | yes | no | not compatible | no | +| support field: array | yes | no | not compatible | no | +| support generic POJO type, eg:`CustomGeneric` | yes | no | no | no | +| serialize/deserialize based on IDL | yes | no | no | yes | +| serialize not repeated number field ignore default value | yes | yes | no | no | +| serialize from map model | yes | no | no | no | +| deserialize to map model | yes | no | no | no | + # Usage -## Create factory - one factory instance globally is enough +## Create factory + one factory instance globally is enough ```java ProtoMapperFactory factory = new ProtoMapperFactory(); ``` ## Load proto definition - create mapper instance for each proto definition -- load from classpath + create mapper instance for each proto definition +- load from classpath ```java ProtoMapper protoMapper = factory.createFromName("protobuf.proto"); ``` -- load from proto content +- load from proto content ```java ProtoMapper protoMapper = factory.createFromContent(protoContent); ``` ## Serialize -serializer is reusable and thread safe +serializer is reusable and thread safe Assuming you have a proto definition ```proto message User { @@ -39,11 +50,10 @@ and a POJO class ```java public class User { private String name; - // getter and setter + // getter and setter } ``` -```java -RootSerializer serializer = protoMapper.findRootSerializer("User"); +RootSerializer serializer = protoMapper.createRootSerializer("User", User.class); User user = new User(); user.setName("userName"); @@ -52,50 +62,21 @@ byte[] pojoBytes= serializer.serialize(user); Map map = new HashMap<>(); map.put("name", "userName"); byte[] mapBytes = serializer.serialize(map); +```java + // pojoBytes equals mapBytes ``` ## Deserialize -deserializer is reusable and thread safe +deserializer is reusable and thread safe ```java -RootDeserializer pojoDeserializer = protoMapper.createRootDeserializer(User.class, "User"); -RootDeserializer mapDeserializer = protoMapper.createRootDeserializer(Map.class, "User"); +RootDeserializer pojoDeserializer = protoMapper.createRootDeserializer("User", User.class); +RootDeserializer> mapDeserializer = protoMapper.createRootDeserializer("User", Map.class); User user = pojoDeserializer.deserialize(bytes); Map map = mapDeserializer.deserialize(bytes); ``` -# Features -- compare to official protobuf: - - extend "any" type, for standard not support cases, use "json" schema to codec it. -- compare to protoStuff runtime: - - for a proto message type, not only support strong type(Pojo), but alse support weak type(Map) - - support "any" type - - support generic pojo type, eg:CustomGeneric<User> - - **NOT** support List>/List> any more, because protobuf specification not support it, and the parser can not parse the proto file -- compare to jackson protobuf: - - can parse protobuf 3 proto file - - support protobuf 3: map/any -- compare to all: - - just pojo, no need any code generation and annotation - - one model can serialize to different version proto file to support different version server - - support text data come from http,can serrialize from different data type - - number fields (int32/int64 and so on) - - number - - String - - String[] - - string fields - - string - - string[] - - bool fields - - boolean - - string - - string[] - - enum fields - - enum - - number - - string - - string[] # Performance ``` 1.protobuf @@ -106,50 +87,67 @@ Map map = mapDeserializer.deserialize(bytes); 2.protoStuff some scenes, there is no field but have getter or setter, so we can not use unsafe to access field so we disable protoStuff unsafe feature + + for repeated fields, protoStuff have better performance, but not compatible to protobuf + 3.jackson - not support map, so skip map in map/mixed test + not support map/any/recursive, ignore related fields 4.serialize result size ScbStrong/ScbWeak/Protobuf have the same and smaller size, because skip all default/null value - + Empty: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :250 250 235 156 437 -ser len :36 0 0 0 56 -deser time(ms):125 15 0 257 483 -deser-ser len :36 0 0 0 56 + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 519 515 240 288 1242 +serialize len : 36 0 0 0 56 +deserialize time(ms): 161 69 10 516 486 +deserialize->serialize len: 36 0 0 0 56 +serialize+deserialize(ms) : 680 584 250 804 1728 Scalars: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :235 264 218 156 413 -ser len :53 21 21 21 73 -deser time(ms):156 63 94 225 469 -deser-ser len :53 21 21 21 73 + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 557 529 328 262 1357 +serialize len : 56 24 24 24 76 +deserialize time(ms): 181 141 115 527 504 +deserialize->serialize len: 56 24 24 24 76 +serialize+deserialize(ms) : 738 670 443 789 1861 + +Pojo: + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 571 574 276 309 1304 +serialize len : 46 10 10 10 66 +deserialize time(ms): 230 69 112 668 537 +deserialize->serialize len: 46 10 10 10 66 +serialize+deserialize(ms) : 801 643 388 977 1841 SimpleList: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :266 250 220 172 440 -ser len :68 32 32 32 88 -deser time(ms):234 94 109 265 499 -deser-ser len :68 32 32 32 88 + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 590 609 296 637 1320 +serialize len : 68 32 32 32 88 +deserialize time(ms): 233 105 122 2226 541 +deserialize->serialize len: 68 32 32 32 88 +serialize+deserialize(ms) : 823 714 418 2863 1861 PojoList: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :297 343 235 187 543 -ser len :56 20 20 20 76 -deser time(ms):211 126 168 298 610 -deser-ser len :56 20 20 20 76 + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 609 632 319 2777 1407 +serialize len : 56 20 20 20 76 +deserialize time(ms): 244 134 173 2287 679 +deserialize->serialize len: 56 20 20 20 76 +serialize+deserialize(ms) : 853 766 492 5064 2086 Map: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :404 512 424 533 403 -ser len :92 54 54 54 56 -deser time(ms):500 343 406 750 359 -deser-ser len :92 54 54 54 56 + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 746 772 491 1079 1298 +serialize len : 92 54 54 54 56 +deserialize time(ms): 522 427 468 1031 422 +deserialize->serialize len: 92 54 54 54 56 +serialize+deserialize(ms) : 1268 1199 959 2110 1720 Mixed: - Protostuff ScbStrong ScbWeak Protobuf Jackson -ser time(ms) :579 704 547 579 625 -ser len :161 127 127 127 125 -deser time(ms):736 623 766 1015 798 -deser-ser len :161 127 127 127 125 -``` \ No newline at end of file + Protostuff ScbStrong ScbWeak Protobuf Jackson +serialize time(ms) : 1686 1999 2034 2112 2537 +serialize len : 479 505 505 505 489 +deserialize time(ms): 1969 2154 2923 2984 3316 +deserialize->serialize len: 479 505 505 505 489 +serialize+deserialize(ms) : 3655 4153 4957 5096 5853 +``` diff --git a/foundations/foundation-protobuf/pom.xml b/foundations/foundation-protobuf/pom.xml index 8ed2d9c8526..cb8662c7bfb 100644 --- a/foundations/foundation-protobuf/pom.xml +++ b/foundations/foundation-protobuf/pom.xml @@ -21,11 +21,12 @@ foundations org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 foundation-protobuf + Java Chassis::Foundations::Protobuf @@ -49,10 +50,11 @@ jsr305 - + com.google.protobuf protobuf-java + test @@ -66,4 +68,35 @@ - \ No newline at end of file + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protoc3-maven-plugin.version}:exe:${os.detected.classifier} + true + grpc-java + io.grpc:protoc-gen-grpc-java:${protoc-gen-grpc-java-plugin.version}:exe:${os.detected.classifier} + src/test/resources + + **/jacksonRoot.proto + **/method.proto + **/model.proto + + + + + generate-test-sources + + test-compile + + + + + + + + diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/ByteArrayInputEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/ByteArrayInputEx.java new file mode 100644 index 00000000000..f496a709426 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/ByteArrayInputEx.java @@ -0,0 +1,594 @@ +//======================================================================== +//Copyright 2007-2010 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import static io.protostuff.WireFormat.TAG_TYPE_BITS; +import static io.protostuff.WireFormat.WIRETYPE_END_GROUP; +import static io.protostuff.WireFormat.WIRETYPE_FIXED32; +import static io.protostuff.WireFormat.WIRETYPE_FIXED64; +import static io.protostuff.WireFormat.WIRETYPE_LENGTH_DELIMITED; +import static io.protostuff.WireFormat.WIRETYPE_START_GROUP; +import static io.protostuff.WireFormat.WIRETYPE_VARINT; +import static io.protostuff.WireFormat.getTagFieldNumber; +import static io.protostuff.WireFormat.getTagWireType; +import static io.protostuff.WireFormat.makeTag; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.fasterxml.jackson.databind.util.ArrayBuilders; + +import io.protostuff.StringSerializer.STRING; + +/** + * Forked and modified from protostuff + * + * Reads and decodes protocol buffer message fields from an internal byte array buffer. This object is re-usable via + * doing a reset on the byte array position and length. This is used internally by {@link IOUtil} where it catches + * {@link ArrayIndexOutOfBoundsException} when a message is truncated. + * + * @author David Yu + * @created Jun 22, 2010 + */ +public final class ByteArrayInputEx implements InputEx { + private final byte[] buffer; + + private int offset, limit, lastTag = 0; + + private int packedLimit = 0; + + private ArrayBuilders arrayBuilders; + + public ByteArrayInputEx(byte[] buffer) { + this(buffer, 0, buffer.length); + } + + public ByteArrayInputEx(byte[] buffer, int offset, int len) { + this.buffer = buffer; + this.offset = offset; + this.limit = offset + len; + } + + /** + * Return true if currently reading packed field + */ + public boolean isCurrentFieldPacked() { + return packedLimit != 0 && packedLimit != offset; + } + + /** + * Attempt to read a field tag, returning zero if we have reached EOF. Protocol message parsers use this to read + * tags, since a protocol message may legally end wherever a tag occurs, and zero is not a valid tag number. + */ + public int readTag() throws IOException { + if (offset == limit) { + lastTag = 0; + return 0; + } + + final int tag = readRawVarint32(); + if (tag >>> TAG_TYPE_BITS == 0) { + // If we actually read zero, that's not a valid tag. + throw ProtobufException.invalidTag(); + } + lastTag = tag; + return tag; + } + + /** + * Verifies that the last call to readTag() returned the given tag value. This is used to verify that a nested group + * ended with the correct end tag. + * + * @throws ProtobufException + * {@code value} does not match the last tag. + */ + public void checkLastTagWas(final int value) throws ProtobufException { + if (lastTag != value) { + throw ProtobufException.invalidEndTag(); + } + } + + /** + * Reads and discards a single field, given its tag value. + * + * @return {@code false} if the tag is an endgroup tag, in which case nothing is skipped. Otherwise, returns + * {@code true}. + */ + public boolean skipField(final int tag) throws IOException { + switch (getTagWireType(tag)) { + case WIRETYPE_VARINT: + readInt32(); + return true; + case WIRETYPE_FIXED64: + readRawLittleEndian64(); + return true; + case WIRETYPE_LENGTH_DELIMITED: + final int size = readRawVarint32(); + if (size < 0) { + throw ProtobufException.negativeSize(); + } + offset += size; + return true; + case WIRETYPE_START_GROUP: + skipMessage(); + checkLastTagWas(makeTag(getTagFieldNumber(tag), WIRETYPE_END_GROUP)); + return true; + case WIRETYPE_END_GROUP: + return false; + case WIRETYPE_FIXED32: + readRawLittleEndian32(); + return true; + default: + throw ProtobufException.invalidWireType(); + } + } + + /** + * Reads and discards an entire message. This will read either until EOF or until an endgroup tag, whichever comes + * first. + */ + public void skipMessage() throws IOException { + while (true) { + final int tag = readTag(); + if (tag == 0 || !skipField(tag)) { + return; + } + } + } + + @Override + public void handleUnknownField(int fieldNumber) throws IOException { + skipField(lastTag); + } + + @Override + public int readFieldNumber() throws IOException { + if (offset == limit) { + lastTag = 0; + return 0; + } + + // are we reading packed field? + if (isCurrentFieldPacked()) { + if (packedLimit < offset) { + throw ProtobufException.misreportedSize(); + } + + // Return field number while reading packed field + return lastTag >>> TAG_TYPE_BITS; + } + + packedLimit = 0; + final int tag = readRawVarint32(); + final int fieldNumber = tag >>> TAG_TYPE_BITS; + if (fieldNumber == 0) { + // If we actually read zero, that's not a valid tag. + throw ProtobufException.invalidTag(); + } + + lastTag = tag; + return fieldNumber; + } + + /** + * Check if this field have been packed into a length-delimited field. If so, update internal state to reflect that + * packed fields are being read. + * + */ + private void checkIfPackedField() throws IOException { + // Do we have the start of a packed field? + if (packedLimit == 0 && getTagWireType(lastTag) == WIRETYPE_LENGTH_DELIMITED) { + final int length = readRawVarint32(); + if (length < 0) { + throw ProtobufException.negativeSize(); + } + + if (offset + length > limit) { + throw ProtobufException.misreportedSize(); + } + + this.packedLimit = this.offset + length; + } + } + + /** + * Read a {@code double} field value from the internal buffer. + */ + @Override + public double readDouble() { + return Double.longBitsToDouble(readRawLittleEndian64()); + } + + /** + * Read a {@code float} field value from the internal buffer. + */ + @Override + public float readFloat() { + return Float.intBitsToFloat(readRawLittleEndian32()); + } + + /** + * Read a {@code uint64} field value from the internal buffer. + */ + @Override + public long readUInt64() throws IOException { + return readRawVarint64(); + } + + /** + * Read an {@code int64} field value from the internal buffer. + */ + @Override + public long readInt64() throws IOException { + return readRawVarint64(); + } + + /** + * Read an {@code int32} field value from the internal buffer. + */ + @Override + public int readInt32() throws IOException { + return readRawVarint32(); + } + + /** + * Read a {@code fixed64} field value from the internal buffer. + */ + @Override + public long readFixed64() { + return readRawLittleEndian64(); + } + + /** + * Read a {@code fixed32} field value from the internal buffer. + */ + @Override + public int readFixed32() { + return readRawLittleEndian32(); + } + + /** + * Read a {@code bool} field value from the internal buffer. + */ + @Override + public boolean readBool() { + return buffer[offset++] != 0; + } + + /** + * Read a {@code uint32} field value from the internal buffer. + */ + @Override + public int readUInt32() throws IOException { + return readRawVarint32(); + } + + /** + * Read an enum field value from the internal buffer. Caller is responsible for converting the numeric value to an + * actual enum. + */ + @Override + public int readEnum() throws IOException { + return readRawVarint32(); + } + + /** + * Read an {@code sfixed32} field value from the internal buffer. + */ + @Override + public int readSFixed32() { + return readRawLittleEndian32(); + } + + /** + * Read an {@code sfixed64} field value from the internal buffer. + */ + @Override + public long readSFixed64() { + return readRawLittleEndian64(); + } + + /** + * Read an {@code sint32} field value from the internal buffer. + */ + @Override + public int readSInt32() throws IOException { + final int n = readRawVarint32(); + return (n >>> 1) ^ -(n & 1); + } + + /** + * Read an {@code sint64} field value from the internal buffer. + */ + @Override + public long readSInt64() throws IOException { + final long n = readRawVarint64(); + return (n >>> 1) ^ -(n & 1); + } + + @Override + public String readString() throws IOException { + final int length = readRawVarint32(); + if (length < 0) { + throw ProtobufException.negativeSize(); + } + + if (offset + length > limit) { + throw ProtobufException.misreportedSize(); + } + + final int offset = this.offset; + + this.offset += length; + + return STRING.deser(buffer, offset, length); + } + + @Override + public ByteString readBytes() throws IOException { + return ByteString.wrap(readByteArray()); + } + + @Override + public byte[] readByteArray() throws IOException { + final int length = readRawVarint32(); + if (length < 0) { + throw ProtobufException.negativeSize(); + } + + if (offset + length > limit) { + throw ProtobufException.misreportedSize(); + } + + final byte[] copy = new byte[length]; + System.arraycopy(buffer, offset, copy, 0, length); + + offset += length; + + return copy; + } + + @Override + public T mergeObject(T value, final SchemaReader schema) throws IOException { + final int length = readRawVarint32(); + if (length < 0) { + throw ProtobufException.negativeSize(); + } + + // save old limit + final int oldLimit = this.limit; + + this.limit = offset + length; + + if (value == null) { + value = schema.newMessage(); + } + schema.mergeFrom(this, value); + checkLastTagWas(0); + + // restore old limit + this.limit = oldLimit; + + return value; + } + + /** + * Reads a var int 32 from the internal byte buffer. + */ + public int readRawVarint32() throws IOException { + byte tmp = buffer[offset++]; + if (tmp >= 0) { + return tmp; + } + int result = tmp & 0x7f; + if ((tmp = buffer[offset++]) >= 0) { + result |= tmp << 7; + } else { + result |= (tmp & 0x7f) << 7; + if ((tmp = buffer[offset++]) >= 0) { + result |= tmp << 14; + } else { + result |= (tmp & 0x7f) << 14; + if ((tmp = buffer[offset++]) >= 0) { + result |= tmp << 21; + } else { + result |= (tmp & 0x7f) << 21; + result |= (tmp = buffer[offset++]) << 28; + if (tmp < 0) { + // Discard upper 32 bits. + for (int i = 0; i < 5; i++) { + if (buffer[offset++] >= 0) { + return result; + } + } + throw ProtobufException.malformedVarint(); + } + } + } + } + return result; + } + + /** + * Reads a var int 64 from the internal byte buffer. + */ + public long readRawVarint64() throws IOException { + final byte[] buffer = this.buffer; + int offset = this.offset; + + int shift = 0; + long result = 0; + while (shift < 64) { + final byte b = buffer[offset++]; + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + this.offset = offset; + return result; + } + shift += 7; + } + throw ProtobufException.malformedVarint(); + } + + /** + * Read a 32-bit little-endian integer from the internal buffer. + */ + public int readRawLittleEndian32() { + final byte[] buffer = this.buffer; + int offset = this.offset; + + final byte b1 = buffer[offset++]; + final byte b2 = buffer[offset++]; + final byte b3 = buffer[offset++]; + final byte b4 = buffer[offset++]; + + this.offset = offset; + + return (((int) b1 & 0xff)) | + (((int) b2 & 0xff) << 8) | + (((int) b3 & 0xff) << 16) | + (((int) b4 & 0xff) << 24); + } + + /** + * Read a 64-bit little-endian integer from the internal byte buffer. + */ + public long readRawLittleEndian64() { + final byte[] buffer = this.buffer; + int offset = this.offset; + + final byte b1 = buffer[offset++]; + final byte b2 = buffer[offset++]; + final byte b3 = buffer[offset++]; + final byte b4 = buffer[offset++]; + final byte b5 = buffer[offset++]; + final byte b6 = buffer[offset++]; + final byte b7 = buffer[offset++]; + final byte b8 = buffer[offset++]; + + this.offset = offset; + + return (((long) b1 & 0xff)) | + (((long) b2 & 0xff) << 8) | + (((long) b3 & 0xff) << 16) | + (((long) b4 & 0xff) << 24) | + (((long) b5 & 0xff) << 32) | + (((long) b6 & 0xff) << 40) | + (((long) b7 & 0xff) << 48) | + (((long) b8 & 0xff) << 56); + } + + /** + * Reads a byte array/ByteBuffer value. + */ + @Override + public ByteBuffer readByteBuffer() throws IOException { + return ByteBuffer.wrap(readByteArray()); + } + + @Override + public ArrayBuilders getArrayBuilders() { + if (arrayBuilders == null) { + arrayBuilders = new ArrayBuilders(); + } + return arrayBuilders; + } + + @Override + public int readPackedInt32() throws IOException { + checkIfPackedField(); + return readRawVarint32(); + } + + @Override + public int readPackedUInt32() throws IOException { + checkIfPackedField(); + return readRawVarint32(); + } + + @Override + public int readPackedSInt32() throws IOException { + checkIfPackedField(); + final int n = readRawVarint32(); + return (n >>> 1) ^ -(n & 1); + } + + @Override + public int readPackedFixed32() throws IOException { + checkIfPackedField(); + return readRawLittleEndian32(); + } + + @Override + public int readPackedSFixed32() throws IOException { + checkIfPackedField(); + return readRawLittleEndian32(); + } + + @Override + public long readPackedInt64() throws IOException { + checkIfPackedField(); + return readRawVarint64(); + } + + @Override + public long readPackedUInt64() throws IOException { + checkIfPackedField(); + return readRawVarint64(); + } + + @Override + public long readPackedSInt64() throws IOException { + checkIfPackedField(); + final long n = readRawVarint64(); + return (n >>> 1) ^ -(n & 1); + } + + @Override + public long readPackedFixed64() throws IOException { + checkIfPackedField(); + return readRawLittleEndian64(); + } + + @Override + public long readPackedSFixed64() throws IOException { + checkIfPackedField(); + return readRawLittleEndian64(); + } + + @Override + public float readPackedFloat() throws IOException { + checkIfPackedField(); + return Float.intBitsToFloat(readRawLittleEndian32()); + } + + @Override + public double readPackedDouble() throws IOException { + checkIfPackedField(); + return Double.longBitsToDouble(readRawLittleEndian64()); + } + + @Override + public boolean readPackedBool() throws IOException { + checkIfPackedField(); + return buffer[offset++] != 0; + } + + @Override + public int readPackedEnum() throws IOException { + checkIfPackedField(); + return readRawVarint32(); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/InputEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/InputEx.java new file mode 100644 index 00000000000..c2dbe1b30d3 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/InputEx.java @@ -0,0 +1,164 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.fasterxml.jackson.databind.util.ArrayBuilders; + +/** + * Forked and modified from protostuff
+ * + * An Input lets an application read primitive data types and objects from a source of data. + * + * @author David Yu + * @created Nov 9, 2009 + */ +public interface InputEx { + + /** + * The underlying implementation should handle the unknown field. + */ + void handleUnknownField(int fieldNumber) throws IOException; + + /** + * Reads field number. + */ + int readFieldNumber() throws IOException; + + /** + * Reads a variable int field value. + */ + int readInt32() throws IOException; + + /** + * Reads an unsigned int field value. + */ + int readUInt32() throws IOException; + + /** + * Reads a signed int field value. + */ + int readSInt32() throws IOException; + + /** + * Reads a fixed int(4 bytes) field value. + */ + int readFixed32() throws IOException; + + /** + * Reads a signed+fixed int(4 bytes) field value. + */ + int readSFixed32() throws IOException; + + /** + * Reads a variable long field value. + */ + long readInt64() throws IOException; + + /** + * Reads an unsigned long field value. + */ + long readUInt64() throws IOException; + + /** + * Reads a signed long field value. + */ + long readSInt64() throws IOException; + + /** + * Reads a fixed long(8 bytes) field value. + */ + long readFixed64() throws IOException; + + /** + * Reads a signed+fixed long(8 bytes) field value. + */ + long readSFixed64() throws IOException; + + /** + * Reads a float field value. + */ + float readFloat() throws IOException; + + /** + * Reads a double field value. + */ + double readDouble() throws IOException; + + /** + * Reads a boolean field value. + */ + boolean readBool() throws IOException; + + /** + * Reads an enum(its number) field value. + */ + int readEnum() throws IOException; + + /** + * Reads a {@link String} field value. + */ + String readString() throws IOException; + + /** + * Reads a {@link ByteString} field value. + */ + ByteString readBytes() throws IOException; + + /** + * Reads a byte array field value. + */ + byte[] readByteArray() throws IOException; + + ByteBuffer readByteBuffer() throws IOException; + + /** + * Merges an object(with schema) field value. The provided {@link Schema schema} handles the deserialization for the + * object. + */ + T mergeObject(T value, SchemaReader schema) throws IOException; + + ArrayBuilders getArrayBuilders(); + + int readPackedInt32() throws IOException; + + int readPackedUInt32() throws IOException; + + int readPackedSInt32() throws IOException; + + int readPackedFixed32() throws IOException; + + int readPackedSFixed32() throws IOException; + + long readPackedInt64() throws IOException; + + long readPackedUInt64() throws IOException; + + long readPackedSInt64() throws IOException; + + long readPackedFixed64() throws IOException; + + long readPackedSFixed64() throws IOException; + + float readPackedFloat() throws IOException; + + double readPackedDouble() throws IOException; + + boolean readPackedBool() throws IOException; + + int readPackedEnum() throws IOException; +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/OutputEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/OutputEx.java new file mode 100644 index 00000000000..aefd1bfcc7d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/OutputEx.java @@ -0,0 +1,210 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import static io.protostuff.ProtobufOutputEx.encodeZigZag64; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + *
+ * Forked and modified from protostuff
+ * difference for scalar types:
+ *                   OutputEx         OutputEx
+ * writeXXX          all scenes     repeated not packed, write with tag, not ignore default value
+ * writePackedXXX    ---            repeated packed, write without tag, not ignore default value
+ * writeScalarXXX    ---            not repeated field, not write default value
+ * 
+ * + * An OutputEx lets an application write primitive data types and objects to a sink of data. + * + * @author David Yu + * @created Nov 9, 2009 + */ +public interface OutputEx { + + /** + * Writes a variable int field. + */ + void writeInt32(int tag, int tagSize, int value) throws IOException; + + /** + * Writes an unsigned int field. + */ + void writeUInt32(int tag, int tagSize, int value) throws IOException; + + /** + * Writes a signed int field. + */ + void writeSInt32(int tag, int tagSize, int value) throws IOException; + + /** + * Writes a fixed int(4 bytes) field. + */ + void writeFixed32(int tag, int tagSize, int value) throws IOException; + + /** + * Writes a signed+fixed int(4 bytes) field. + */ + void writeSFixed32(int tag, int tagSize, int value) throws IOException; + + /** + * Writes a variable long field. + */ + void writeInt64(int tag, int tagSize, long value) throws IOException; + + /** + * Writes an unsigned long field. + */ + void writeUInt64(int tag, int tagSize, long value) throws IOException; + + /** + * Writes a signed long field. + */ + void writeSInt64(int tag, int tagSize, long value) throws IOException; + + /** + * Writes a fixed long(8 bytes) field. + */ + void writeFixed64(int tag, int tagSize, long value) throws IOException; + + /** + * Writes a signed+fixed long(8 bytes) field. + */ + void writeSFixed64(int tag, int tagSize, long value) throws IOException; + + /** + * Writes a float field. + */ + void writeFloat(int tag, int tagSize, float value) throws IOException; + + /** + * Writes a double field. + */ + void writeDouble(int tag, int tagSize, double value) throws IOException; + + /** + * Writes a boolean field. + */ + void writeBool(int tag, int tagSize, boolean value) throws IOException; + + /** + * Writes a enum(its number) field. + */ + void writeEnum(int tag, int tagSize, int value) throws IOException; + + /** + * Writes a String field. + */ + void writeString(int tag, int tagSize, String value) throws IOException; + + /** + * Writes a ByteString(wraps byte array) field. + */ + void writeBytes(int tag, int tagSize, ByteString value) throws IOException; + + /** + * Writes a byte array field. + */ + void writeByteArray(int tag, int tagSize, byte[] value) throws IOException; + + /** + * Writes a binary or a pre-encoded utf8 string. + */ + void writeByteRange(boolean utf8String, int tag, int tagSize, byte[] value, int offset, int length) + throws IOException; + + /** + * Writes an object(using its schema) field. + */ + void writeObject(int tag, int tagSize, T value, SchemaWriter schemaWriter) throws IOException; + + void writeBytes(int tag, int tagSize, ByteBuffer value) throws IOException; + + byte[] toByteArray(); + + void writePackedInt32(int value) throws IOException; + + void writeScalarInt32(int tag, int tagSize, int value) throws IOException; + + default void writePackedInt64(long value) throws IOException { + writePackedUInt64(value); + } + + void writeScalarInt64(int tag, int tagSize, long value) throws IOException; + + void writePackedUInt32(int value) throws IOException; + + void writeScalarUInt32(int tag, int tagSize, int value) throws IOException; + + void writePackedUInt64(long value) throws IOException; + + void writeScalarUInt64(int tag, int tagSize, long value) throws IOException; + + void writePackedSInt32(int value) throws IOException; + + void writeScalarSInt32(int tag, int tagSize, int value) throws IOException; + + default void writePackedSInt64(long value) throws IOException { + writePackedUInt64(encodeZigZag64(value)); + } + + void writeScalarSInt64(int tag, int tagSize, long value) throws IOException; + + void writePackedFixed32(int value) throws IOException; + + void writeScalarFixed32(int tag, int tagSize, int value) throws IOException; + + void writePackedFixed64(long value) throws IOException; + + void writeScalarFixed64(int tag, int tagSize, long value) throws IOException; + + default void writePackedSFixed32(int value) throws IOException { + writePackedFixed32(value); + } + + void writeScalarSFixed32(int tag, int tagSize, int value) throws IOException; + + default void writePackedSFixed64(long value) throws IOException { + writePackedFixed64(value); + } + + void writeScalarSFixed64(int tag, int tagSize, long value) throws IOException; + + default void writePackedFloat(float value) throws IOException { + writePackedFixed32(Float.floatToRawIntBits(value)); + } + + void writeScalarFloat(int tag, int tagSize, float value) throws IOException; + + default void writePackedDouble(double value) throws IOException { + writePackedFixed64(Double.doubleToRawLongBits(value)); + } + + void writeScalarDouble(int tag, int tagSize, double value) throws IOException; + + void writePackedBool(boolean value) throws IOException; + + void writeScalarBool(int tag, int tagSize, boolean value) throws IOException; + + default void writePackedEnum(int value) throws IOException { + writePackedInt32(value); + } + + void writeScalarEnum(int tag, int tagSize, int value) throws IOException; + + void writeScalarString(int tag, int tagSize, String value) throws IOException; +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/ProtobufOutputEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/ProtobufOutputEx.java new file mode 100644 index 00000000000..8c47ab44271 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/ProtobufOutputEx.java @@ -0,0 +1,854 @@ +//======================================================================== +//Copyright 2007-2010 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import static io.protostuff.StringSerializer.writeUTF8VarDelimited; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +/** + * Forked and modified from protostuff
+ * + * Protobuf serialization where the messages must be fully buffered on memory before it can be written to the socket ( + * {@link OutputStream}). + * + * @author David Yu + * @created May 18, 2010 + */ +public final class ProtobufOutputEx extends WriteSession implements OutputEx { + public static final int LITTLE_ENDIAN_32_SIZE = 4, LITTLE_ENDIAN_64_SIZE = 8; + + public ProtobufOutputEx() { + super(LinkedBuffer.allocate()); + } + + public ProtobufOutputEx(LinkedBuffer buffer) { + super(buffer); + } + + public ProtobufOutputEx(LinkedBuffer buffer, int nextBufferSize) { + super(buffer, nextBufferSize); + } + + /** + * Resets this output for re-use. + */ + @Override + public ProtobufOutputEx clear() { + super.clear(); + return this; + } + + @Override + public void writeInt32(int tag, int tagSize, int value) { + if (value < 0) { + tail = writeTagAndRawVarInt64(tag, tagSize, value, this, tail); + return; + } + + tail = writeTagAndRawVarInt32(tag, tagSize, value, this, tail); + } + + @Override + public void writeUInt32(int tag, int tagSize, int value) { + tail = writeTagAndRawVarInt32(tag, tagSize, value, this, tail); + } + + @Override + public void writeSInt32(int tag, int tagSize, int value) { + tail = writeTagAndRawVarInt32(tag, tagSize, encodeZigZag32(value), this, tail); + } + + @Override + public void writeFixed32(int tag, int tagSize, int value) { + tail = writeTagAndRawLittleEndian32(tag, tagSize, value, this, tail); + } + + @Override + public void writeSFixed32(int tag, int tagSize, int value) { + tail = writeTagAndRawLittleEndian32(tag, tagSize, value, this, tail); + } + + @Override + public void writeInt64(int tag, int tagSize, long value) { + tail = writeTagAndRawVarInt64(tag, tagSize, value, this, tail); + } + + @Override + public void writeUInt64(int tag, int tagSize, long value) { + tail = writeTagAndRawVarInt64(tag, tagSize, value, this, tail); + } + + @Override + public void writeSInt64(int tag, int tagSize, long value) { + tail = writeTagAndRawVarInt64(tag, tagSize, encodeZigZag64(value), this, tail); + } + + @Override + public void writeFixed64(int tag, int tagSize, long value) { + tail = writeTagAndRawLittleEndian64(tag, tagSize, value, this, tail); + } + + @Override + public void writeSFixed64(int tag, int tagSize, long value) { + tail = writeTagAndRawLittleEndian64(tag, tagSize, value, this, tail); + } + + @Override + public void writeFloat(int tag, int tagSize, float value) { + tail = writeTagAndRawLittleEndian32(tag, tagSize, Float.floatToRawIntBits(value), this, tail); + } + + @Override + public void writeDouble(int tag, int tagSize, double value) { + tail = writeTagAndRawLittleEndian64(tag, tagSize, Double.doubleToRawLongBits(value), this, tail); + } + + @Override + public void writeBool(int tag, int tagSize, boolean value) { + tail = writeTagAndRawVarInt32(tag, tagSize, value ? 1 : 0, this, tail); + } + + @Override + public void writeEnum(int tag, int tagSize, int number) { + writeInt32(tag, tagSize, number); + } + + @Override + public void writeString(int tag, int tagSize, String value) { + tail = writeUTF8VarDelimited( + value, + this, + writeRawVarInt32(tag, this, tail)); + } + + @Override + public void writeBytes(int tag, int tagSize, ByteString value) { + writeByteArray(tag, tagSize, value.getBytes()); + } + + @Override + public void writeByteArray(int tag, int tagSize, byte[] bytes) { + tail = writeTagAndByteArray( + tag, tagSize, + bytes, 0, bytes.length, + this, + tail); + } + + @Override + public void writeByteRange(boolean utf8String, int tag, int tagSize, byte[] value, int offset, int length) { + tail = writeTagAndByteArray( + tag, tagSize, + value, offset, length, + this, + tail); + } + + @Override + public void writeObject(final int tag, int tagSize, final T value, final SchemaWriter schemaWriter) + throws IOException { + final LinkedBuffer lastBuffer; + + // write the tag + if (tagSize == 1 && tail.offset != tail.buffer.length) { + lastBuffer = tail; + size++; + lastBuffer.buffer[lastBuffer.offset++] = (byte) tag; + } else { + tail = lastBuffer = writeRawVarInt32(tag, this, tail); + } + + final int lastOffset = tail.offset, lastSize = size; + + if (lastOffset == lastBuffer.buffer.length) { + // not enough size for the 1-byte delimiter + final LinkedBuffer nextBuffer = new LinkedBuffer(nextBufferSize); + // new buffer for the content + tail = nextBuffer; + + schemaWriter.writeTo(this, value); + + final int msgSize = size - lastSize; + + final byte[] delimited = new byte[computeRawVarint32Size(msgSize)]; + writeRawVarInt32(msgSize, delimited, 0); + + size += delimited.length; + + // wrap the byte array (delimited) and insert between the two buffers + new LinkedBuffer(delimited, 0, delimited.length, lastBuffer).next = nextBuffer; + return; + } + + // we have enough space for the 1-byte delim + lastBuffer.offset++; + size++; + + schemaWriter.writeTo(this, value); + + final int msgSize = size - lastSize - 1; + + // optimize for small messages + if (msgSize < 128) { + // fits + lastBuffer.buffer[lastOffset] = (byte) msgSize; + return; + } + + // split into two buffers + + // the second buffer (contains the message contents) + final LinkedBuffer view = new LinkedBuffer(lastBuffer.buffer, + lastOffset + 1, lastBuffer.offset); + + if (lastBuffer == tail) { + tail = view; + } else { + view.next = lastBuffer.next; + } + + // the first buffer (contains the tag) + lastBuffer.offset = lastOffset; + + final byte[] delimited = new byte[computeRawVarint32Size(msgSize)]; + writeRawVarInt32(msgSize, delimited, 0); + + // add the difference + size += (delimited.length - 1); + + // wrap the byte array (delimited) and insert between the two buffers + new LinkedBuffer(delimited, 0, delimited.length, lastBuffer).next = view; + } + + /* + * Write the nested message encoded as group. + * + * void writeObjectEncodedAsGroup(final int fieldNumber, final T value, final SchemaEx schema, final boolean + * repeated) throws IOException { tail = writeRawVarInt32( makeTag(fieldNumber, WIRETYPE_START_GROUP), this, tail); + * + * schema.writeTo(this, value); + * + * tail = writeRawVarInt32( makeTag(fieldNumber, WIRETYPE_END_GROUP), this, tail); } + */ + + /* ----------------------------------------------------------------- */ + + /** + * Returns the buffer encoded with the variable int 32. + */ + public static LinkedBuffer writeRawVarInt32(int value, final WriteSession session, + LinkedBuffer lb) { + final int size = computeRawVarint32Size(value); + + if (lb.offset + size > lb.buffer.length) { + lb = new LinkedBuffer(session.nextBufferSize, lb); + } + + final byte[] buffer = lb.buffer; + int offset = lb.offset; + lb.offset += size; + session.size += size; + + if (size == 1) { + buffer[offset] = (byte) value; + } else { + for (int i = 0, last = size - 1; i < last; i++, value >>>= 7) { + buffer[offset++] = (byte) ((value & 0x7F) | 0x80); + } + + buffer[offset] = (byte) value; + } + + return lb; + } + + /** + * Returns the buffer encoded with the tag and byte array + */ + public static LinkedBuffer writeTagAndByteArray(int tag, int tagSize, final byte[] value, + int offset, int valueLen, + final WriteSession session, LinkedBuffer lb) { + if (valueLen == 0) { + // write only the tag and delimiter + return writeTagAndRawVarInt32(tag, tagSize, valueLen, session, lb); + } + + lb = writeTagAndRawVarInt32(tag, tagSize, valueLen, session, lb); + + session.size += valueLen; + + final int available = lb.buffer.length - lb.offset; + if (valueLen > available) { + if (available + session.nextBufferSize < valueLen) { + // too large ... so we wrap and insert (zero-copy) + if (available == 0) { + // buffer was actually full ... return a fresh buffer + return new LinkedBuffer(session.nextBufferSize, + new LinkedBuffer(value, offset, offset + valueLen, lb)); + } + + // continue with the existing byte array of the previous buffer + return new LinkedBuffer(lb, + new LinkedBuffer(value, offset, offset + valueLen, lb)); + } + + // copy what can fit + System.arraycopy(value, offset, lb.buffer, lb.offset, available); + + lb.offset += available; + + // grow + lb = new LinkedBuffer(session.nextBufferSize, lb); + + final int leftover = valueLen - available; + + // copy what's left + System.arraycopy(value, offset + available, lb.buffer, 0, leftover); + + lb.offset += leftover; + + return lb; + } + + // it fits + System.arraycopy(value, offset, lb.buffer, lb.offset, valueLen); + + lb.offset += valueLen; + + return lb; + } + + /** + * Returns the buffer encoded with the tag and var int 32 + */ + public static LinkedBuffer writeTagAndRawVarInt32(int tag, int tagSize, int value, + final WriteSession session, LinkedBuffer lb) { + final int size = computeRawVarint32Size(value); + final int totalSize = tagSize + size; + + if (lb.offset + totalSize > lb.buffer.length) { + lb = new LinkedBuffer(session.nextBufferSize, lb); + } + + final byte[] buffer = lb.buffer; + int offset = lb.offset; + lb.offset += totalSize; + session.size += totalSize; + + if (tagSize == 1) { + buffer[offset++] = (byte) tag; + } else { + for (int i = 0, last = tagSize - 1; i < last; i++, tag >>>= 7) { + buffer[offset++] = (byte) ((tag & 0x7F) | 0x80); + } + + buffer[offset++] = (byte) tag; + } + + if (size == 1) { + buffer[offset] = (byte) value; + } else { + for (int i = 0, last = size - 1; i < last; i++, value >>>= 7) { + buffer[offset++] = (byte) ((value & 0x7F) | 0x80); + } + + buffer[offset] = (byte) value; + } + + return lb; + } + + /** + * Returns the buffer encoded with the tag and var int 64 + */ + public static LinkedBuffer writeTagAndRawVarInt64(int tag, int tagSize, long value, + final WriteSession session, LinkedBuffer lb) { + final int size = computeRawVarint64Size(value); + final int totalSize = tagSize + size; + + if (lb.offset + totalSize > lb.buffer.length) { + lb = new LinkedBuffer(session.nextBufferSize, lb); + } + + final byte[] buffer = lb.buffer; + int offset = lb.offset; + lb.offset += totalSize; + session.size += totalSize; + + if (tagSize == 1) { + buffer[offset++] = (byte) tag; + } else { + for (int i = 0, last = tagSize - 1; i < last; i++, tag >>>= 7) { + buffer[offset++] = (byte) ((tag & 0x7F) | 0x80); + } + + buffer[offset++] = (byte) tag; + } + + if (size == 1) { + buffer[offset] = (byte) value; + } else { + for (int i = 0, last = size - 1; i < last; i++, value >>>= 7) { + buffer[offset++] = (byte) (((int) value & 0x7F) | 0x80); + } + + buffer[offset] = (byte) value; + } + + return lb; + } + + /** + * Returns the buffer encoded with the tag and little endian 32 + */ + public static LinkedBuffer writeTagAndRawLittleEndian32(int tag, int tagSize, int value, + final WriteSession session, LinkedBuffer lb) { + final int totalSize = tagSize + LITTLE_ENDIAN_32_SIZE; + + if (lb.offset + totalSize > lb.buffer.length) { + lb = new LinkedBuffer(session.nextBufferSize, lb); + } + + final byte[] buffer = lb.buffer; + int offset = lb.offset; + lb.offset += totalSize; + session.size += totalSize; + + if (tagSize == 1) { + buffer[offset++] = (byte) tag; + } else { + for (int i = 0, last = tagSize - 1; i < last; i++, tag >>>= 7) { + buffer[offset++] = (byte) ((tag & 0x7F) | 0x80); + } + + buffer[offset++] = (byte) tag; + } + + writeRawLittleEndian32(value, buffer, offset); + + return lb; + } + + /** + * Returns the buffer encoded with the tag and little endian 64 + */ + public static LinkedBuffer writeTagAndRawLittleEndian64(int tag, int tagSize, long value, + final WriteSession session, LinkedBuffer lb) { + final int totalSize = tagSize + LITTLE_ENDIAN_64_SIZE; + + if (lb.offset + totalSize > lb.buffer.length) { + lb = new LinkedBuffer(session.nextBufferSize, lb); + } + + final byte[] buffer = lb.buffer; + int offset = lb.offset; + lb.offset += totalSize; + session.size += totalSize; + + if (tagSize == 1) { + buffer[offset++] = (byte) tag; + } else { + for (int i = 0, last = tagSize - 1; i < last; i++, tag >>>= 7) { + buffer[offset++] = (byte) ((tag & 0x7F) | 0x80); + } + + buffer[offset++] = (byte) tag; + } + + writeRawLittleEndian64(value, buffer, offset); + + return lb; + } + + /** Encode and write a varint to the byte array */ + public static void writeRawVarInt32(int value, final byte[] buf, int offset) throws IOException { + while (true) { + if ((value & ~0x7F) == 0) { + buf[offset] = (byte) value; + return; + } else { + buf[offset++] = (byte) ((value & 0x7F) | 0x80); + value >>>= 7; + } + } + } + + /** + * Writes the encoded little endian 32 and returns the bytes written + */ + public static int writeRawLittleEndian32(int value, byte[] buffer, int offset) { + if (buffer.length - offset < LITTLE_ENDIAN_32_SIZE) { + throw new IllegalArgumentException("buffer capacity not enough."); + } + + buffer[offset++] = (byte) (value & 0xFF); + buffer[offset++] = (byte) (value >> 8 & 0xFF); + buffer[offset++] = (byte) (value >> 16 & 0xFF); + buffer[offset] = (byte) (value >> 24 & 0xFF); + + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Writes the encoded little endian 64 and returns the bytes written + */ + public static int writeRawLittleEndian64(long value, byte[] buffer, int offset) { + if (buffer.length - offset < LITTLE_ENDIAN_64_SIZE) { + throw new IllegalArgumentException("buffer capacity not enough."); + } + + buffer[offset++] = (byte) (value & 0xFF); + buffer[offset++] = (byte) (value >> 8 & 0xFF); + buffer[offset++] = (byte) (value >> 16 & 0xFF); + buffer[offset++] = (byte) (value >> 24 & 0xFF); + buffer[offset++] = (byte) (value >> 32 & 0xFF); + buffer[offset++] = (byte) (value >> 40 & 0xFF); + buffer[offset++] = (byte) (value >> 48 & 0xFF); + buffer[offset] = (byte) (value >> 56 & 0xFF); + + return LITTLE_ENDIAN_64_SIZE; + } + + /* METHODS FROM CodedOutput */ + + // Protocol Buffers - Google's data interchange format + // Copyright 2008 Google Inc. All rights reserved. + // http://code.google.com/p/protobuf/ + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are + // met: + // + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above + // copyright notice, this list of conditions and the following disclaimer + // in the documentation and/or other materials provided with the + // distribution. + // * Neither the name of Google Inc. nor the names of its + // contributors may be used to endorse or promote products derived from + // this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + /** + * Compute the number of bytes that would be needed to encode a varint. {@code value} is treated as unsigned, so it + * won't be sign-extended if negative. + */ + public static int computeRawVarint32Size(final int value) { + if ((value & (0xffffffff << 7)) == 0) { + return 1; + } + if ((value & (0xffffffff << 14)) == 0) { + return 2; + } + if ((value & (0xffffffff << 21)) == 0) { + return 3; + } + if ((value & (0xffffffff << 28)) == 0) { + return 4; + } + return 5; + } + + /** + * Compute the number of bytes that would be needed to encode a varint. + */ + public static int computeRawVarint64Size(final long value) { + if ((value & (0xffffffffffffffffL << 7)) == 0) { + return 1; + } + if ((value & (0xffffffffffffffffL << 14)) == 0) { + return 2; + } + if ((value & (0xffffffffffffffffL << 21)) == 0) { + return 3; + } + if ((value & (0xffffffffffffffffL << 28)) == 0) { + return 4; + } + if ((value & (0xffffffffffffffffL << 35)) == 0) { + return 5; + } + if ((value & (0xffffffffffffffffL << 42)) == 0) { + return 6; + } + if ((value & (0xffffffffffffffffL << 49)) == 0) { + return 7; + } + if ((value & (0xffffffffffffffffL << 56)) == 0) { + return 8; + } + if ((value & (0xffffffffffffffffL << 63)) == 0) { + return 9; + } + return 10; + } + + /** + * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into values that can be efficiently encoded + * with varint. (Otherwise, negative values must be sign-extended to 64 bits to be varint encoded, thus always + * taking 10 bytes on the wire.) + * + * @param n + * A signed 32-bit integer. + * @return An unsigned 32-bit integer, stored in a signed int because Java has no explicit unsigned support. + */ + public static int encodeZigZag32(final int n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); + } + + /** + * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into values that can be efficiently encoded + * with varint. (Otherwise, negative values must be sign-extended to 64 bits to be varint encoded, thus always + * taking 10 bytes on the wire.) + * + * @param n + * A signed 64-bit integer. + * @return An unsigned 64-bit integer, stored in a signed int because Java has no explicit unsigned support. + */ + public static long encodeZigZag64(final long n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); + } + + /** + * Writes a ByteBuffer field. + */ + @Override + public void writeBytes(int tag, int tagSize, ByteBuffer value) { + writeByteRange(false, tag, tagSize, value.array(), value.arrayOffset() + value.position(), value.remaining()); + } + + public void toOutputStream(OutputStream outputStream) throws IOException { + LinkedBuffer.writeTo(outputStream, head); + } + + @Override + public void writePackedInt32(int value) { + if (value >= 0) { + tail = writeRawVarInt32(value, this, tail); + return; + } + + writePackedUInt64(value); + } + + @Override + public void writeScalarInt32(int tag, int tagSize, int value) { + if (value != 0) { + writeInt32(tag, tagSize, value); + } + } + + @Override + public void writeScalarInt64(int tag, int tagSize, long value) { + if (value != 0) { + writeInt64(tag, tagSize, value); + } + } + + @Override + public void writePackedUInt32(int value) { + tail = writeRawVarInt32(value, this, tail); + } + + @Override + public void writeScalarUInt32(int tag, int tagSize, int value) { + if (value != 0) { + writeUInt32(tag, tagSize, value); + } + } + + @Override + public void writePackedUInt64(long value) { + final int size = computeRawVarint64Size(value); + + if (tail.offset + size > tail.buffer.length) { + tail = new LinkedBuffer(this.nextBufferSize, tail); + } + + final byte[] buffer = tail.buffer; + int offset = tail.offset; + tail.offset += size; + this.size += size; + + if (size == 1) { + buffer[offset] = (byte) value; + } else { + for (int i = 0, last = size - 1; i < last; i++, value >>>= 7) { + buffer[offset++] = (byte) (((int) value & 0x7F) | 0x80); + } + + buffer[offset] = (byte) value; + } + } + + @Override + public void writeScalarUInt64(int tag, int tagSize, long value) { + if (value != 0) { + writeUInt64(tag, tagSize, value); + } + } + + @Override + public void writePackedSInt32(int value) { + tail = writeRawVarInt32(encodeZigZag32(value), this, tail); + } + + @Override + public void writeScalarSInt32(int tag, int tagSize, int value) { + if (value != 0) { + writeSInt32(tag, tagSize, value); + } + } + + @Override + public void writeScalarSInt64(int tag, int tagSize, long value) { + if (value != 0) { + writeSInt64(tag, tagSize, value); + } + } + + @Override + public void writePackedFixed32(int value) { + final int size = LITTLE_ENDIAN_32_SIZE; + + if (tail.offset + size > tail.buffer.length) { + tail = new LinkedBuffer(this.nextBufferSize, tail); + } + + final byte[] buffer = tail.buffer; + int offset = tail.offset; + tail.offset += size; + this.size += size; + + buffer[offset++] = (byte) (value & 0xFF); + buffer[offset++] = (byte) (value >> 8 & 0xFF); + buffer[offset++] = (byte) (value >> 16 & 0xFF); + buffer[offset] = (byte) (value >> 24 & 0xFF); + } + + @Override + public void writeScalarFixed32(int tag, int tagSize, int value) { + if (value != 0) { + writeFixed32(tag, tagSize, value); + } + } + + @Override + public void writePackedFixed64(long value) { + final int size = LITTLE_ENDIAN_64_SIZE; + + if (tail.offset + size > tail.buffer.length) { + tail = new LinkedBuffer(this.nextBufferSize, tail); + } + + final byte[] buffer = tail.buffer; + int offset = tail.offset; + tail.offset += size; + this.size += size; + + buffer[offset++] = (byte) (value & 0xFF); + buffer[offset++] = (byte) (value >> 8 & 0xFF); + buffer[offset++] = (byte) (value >> 16 & 0xFF); + buffer[offset++] = (byte) (value >> 24 & 0xFF); + buffer[offset++] = (byte) (value >> 32 & 0xFF); + buffer[offset++] = (byte) (value >> 40 & 0xFF); + buffer[offset++] = (byte) (value >> 48 & 0xFF); + buffer[offset] = (byte) (value >> 56 & 0xFF); + } + + @Override + public void writeScalarFixed64(int tag, int tagSize, long value) { + if (value != 0) { + writeFixed64(tag, tagSize, value); + } + } + + @Override + public void writeScalarSFixed32(int tag, int tagSize, int value) { + if (value != 0) { + writeSFixed32(tag, tagSize, value); + } + } + + @Override + public void writeScalarSFixed64(int tag, int tagSize, long value) { + if (value != 0) { + writeSFixed64(tag, tagSize, value); + } + } + + @Override + public void writeScalarFloat(int tag, int tagSize, float value) { + if (value != 0) { + writeFloat(tag, tagSize, value); + } + } + + @Override + public void writeScalarDouble(int tag, int tagSize, double value) { + if (value != 0) { + writeDouble(tag, tagSize, value); + } + } + + @Override + public void writePackedBool(boolean value) { + final int size = 1; + + if (tail.offset + size > tail.buffer.length) { + tail = new LinkedBuffer(this.nextBufferSize, tail); + } + + final byte[] buffer = tail.buffer; + int offset = tail.offset; + tail.offset += size; + this.size += size; + + buffer[offset] = (byte) (value ? 1 : 0); + } + + @Override + public void writeScalarBool(int tag, int tagSize, boolean value) { + if (value) { + writeBool(tag, tagSize, value); + } + } + + @Override + public void writeScalarEnum(int tag, int tagSize, int value) { + writeScalarInt32(tag, tagSize, value); + } + + public void writeScalarString(int tag, int tagSize, String value) { + writeString(tag, tagSize, value); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaEx.java new file mode 100644 index 00000000000..15c22e7fd51 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaEx.java @@ -0,0 +1,40 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +/** + * Forked and modified from protostuff + * + * Handles the serialization and deserialization of a message/object tied to this. + *

+ * Basically, any object can be serialized via protobuf. As long as its schema is provided, it does not need to + * implement {@link Message}. This was designed with "unobtrusive" in mind. The goal was to be able to + * serialize/deserialize any existing object without having to touch its source. This will enable you to customize the + * serialization of objects from 3rd party libraries. + * + * @author David Yu + * @created Nov 9, 2009 + */ +public interface SchemaEx extends SchemaWriter, SchemaReader { + /** + * Returns the simple name of the message tied to this schema. Allows custom schemas to provide a custom name other + * than typeClass().getSimpleName(); + */ + default String messageName() { + throw new UnsupportedOperationException(); + } + + void init(); +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaReader.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaReader.java new file mode 100644 index 00000000000..c77db0c9730 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaReader.java @@ -0,0 +1,28 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import java.io.IOException; + +public interface SchemaReader { + /** + * Creates the message/object tied to this schema. + */ + default T newMessage() { + return null; + } + + void mergeFrom(InputEx input, T message) throws IOException; +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java new file mode 100644 index 00000000000..b7842bb01ae --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java @@ -0,0 +1,21 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff; + +import java.io.IOException; + +public interface SchemaWriter { + void writeTo(OutputEx output, T value) throws IOException; +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/package-info.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/package-info.java new file mode 100644 index 00000000000..fad90514b8d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/package-info.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + *

+ * classes in protostuff are "final" or not all suitable for ServiceComb
+ *   1.final
+ *     io.protostuff.ProtobufOutputEx
+ *     io.protostuff.ByteArrayInput
+ *   2.not suitable
+ *     1) io.protostuff.OutputEx
+ *        fieldNumber changed to tag, avoid makeTag every time
+ *        not support write packed value
+ *        not support ignore default scalar value
+ *     2) io.protostuff.SchemaEx
+ *        make it simpler
+ *     3) codec of map is not compatible to protobuf
+ * so we must copy and modified them
+ * 
+ */ + +package io.protostuff; diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java new file mode 100644 index 00000000000..b36a176dad4 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java @@ -0,0 +1,94 @@ +//======================================================================== +//Copyright 2007-2010 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff.runtime; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Forked and modified from protostuff + * + * Field mapping implemented on top of java array for lookup by number. + * + * This is the most efficient implementation for almost all cases. But + * it should not be used when field numbers are sparse and especially + * when max field number is big - as this mapping internally uses array + * of integers with size equal to max field number. In latter case + * {@code HashFieldMapEx} should be used. + * + * @see HashFieldMapEx + * + * @author Kostiantyn Shchepanovskyi + */ +public final class ArrayFieldMapEx implements FieldMapEx { + private final List> fields; + + private final FieldSchema[] fieldsByNumber; + + private final Map> fieldsByName; + + @SuppressWarnings("unchecked") + public ArrayFieldMapEx(Collection> fields, int lastFieldNumber) { + fieldsByName = new HashMap<>(); + fieldsByNumber = (FieldSchema[]) new FieldSchema[lastFieldNumber + 1]; + for (FieldSchema f : fields) { + FieldSchema last = this.fieldsByName.put(f.name, f); + if (last != null) { + throw new IllegalStateException(last + " and " + f + " cannot have the same name."); + } + if (fieldsByNumber[f.getFieldNumber()] != null) { + throw new IllegalStateException( + fieldsByNumber[f.getFieldNumber()] + " and " + f + " cannot have the same number."); + } + + fieldsByNumber[f.getFieldNumber()] = f; + } + + List> fieldList = new ArrayList<>(fields.size()); + for (FieldSchema field : fieldsByNumber) { + if (field != null) { + fieldList.add(field); + } + } + this.fields = Collections.unmodifiableList(fieldList); + } + + @Override + public FieldSchema getFieldByNumber(int n) { + return n < fieldsByNumber.length ? fieldsByNumber[n] : null; + } + + @Override + public FieldSchema getFieldByName(String fieldName) { + return fieldsByName.get(fieldName); + } + + /** + * Returns the message's total number of fields. + */ + @Override + public int getFieldCount() { + return fields.size(); + } + + @Override + public List> getFields() { + return fields; + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java new file mode 100644 index 00000000000..e0234493e27 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java @@ -0,0 +1,55 @@ +//======================================================================== +//Copyright 2007-2010 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff.runtime; + +import java.util.Collection; +import java.util.List; + +/** + * Forked and modified from protostuff + * + * Interface for map of fields - defines how to you get field by name or number (tag). + * + * @author Kostiantyn Shchepanovskyi + */ +public interface FieldMapEx { + int MIN_TAG_FOR_HASH_FIELD_MAP = 100; + + static boolean preferHashFieldMap(int fieldCount, int lastFieldNumber) { + return lastFieldNumber > MIN_TAG_FOR_HASH_FIELD_MAP && lastFieldNumber >= 2 * fieldCount; + } + + static FieldMapEx createFieldMap(Collection> fields) { + int lastFieldNumber = 0; + for (FieldSchema field : fields) { + if (field.getFieldNumber() > lastFieldNumber) { + lastFieldNumber = field.getFieldNumber(); + } + } + if (preferHashFieldMap(fields.size(), lastFieldNumber)) { + return new HashFieldMapEx<>(fields); + } + // array field map should be more efficient + return new ArrayFieldMapEx<>(fields, lastFieldNumber); + } + + FieldSchema getFieldByNumber(int n); + + FieldSchema getFieldByName(String fieldName); + + int getFieldCount(); + + List> getFields(); +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldSchema.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldSchema.java new file mode 100644 index 00000000000..e0ed7bb3b5f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldSchema.java @@ -0,0 +1,96 @@ +//======================================================================== +//Copyright 2007-2009 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff.runtime; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.ProtobufOutputEx; +import io.protostuff.WireFormat; +import io.protostuff.compiler.model.Field; + +/** + * Forked and modified from protostuff + * + * Represents a field of a message/pojo. + */ +public abstract class FieldSchema { + protected final Field protoField; + + protected final String name; + + protected final int fieldNumber; + + protected final int tag; + + protected final int tagSize; + + protected final boolean packed; + + protected final JavaType javaType; + + protected final boolean primitive; + + public FieldSchema(Field protoField, JavaType javaType) { + this.protoField = protoField; + this.name = protoField.getName(); + this.fieldNumber = protoField.getTag(); + this.packed = ProtoUtils.isPacked(protoField); + + int wireType = packed && protoField.isRepeated() ? WireFormat.WIRETYPE_LENGTH_DELIMITED + : FieldTypeUtils.convert(protoField.getType()).wireType; + this.tag = WireFormat.makeTag(fieldNumber, wireType); + this.tagSize = ProtobufOutputEx.computeRawVarint32Size(tag); + + this.javaType = javaType; + this.primitive = javaType.isPrimitive(); + } + + public int getFieldNumber() { + return fieldNumber; + } + + public Field getProtoField() { + return protoField; + } + + public int mergeFrom(InputEx input, T message) throws IOException { + throw new UnsupportedOperationException(); + } + + public boolean isPrimitive() { + return primitive; + } + + public void getAndWriteTo(OutputEx output, T message) throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * write from map + * + * @param output + * @param value field value, will not be null + * @throws IOException + */ + public void writeTo(OutputEx output, Object value) throws IOException { + throw new UnsupportedOperationException(); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldTypeUtils.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldTypeUtils.java new file mode 100644 index 00000000000..c9a141b7373 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldTypeUtils.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.protostuff.runtime; + +import io.protostuff.WireFormat.FieldType; +import io.protostuff.compiler.model.ScalarFieldType; + +public final class FieldTypeUtils { + public static FieldType convert(io.protostuff.compiler.model.FieldType fieldType) { + if (fieldType.isEnum()) { + return FieldType.ENUM; + } + + if (fieldType.isScalar()) { + switch ((ScalarFieldType) fieldType) { + case INT32: + return FieldType.INT32; + case INT64: + return FieldType.INT64; + case UINT32: + return FieldType.UINT32; + case UINT64: + return FieldType.UINT64; + case SINT32: + return FieldType.SINT32; + case SINT64: + return FieldType.SINT64; + case FIXED32: + return FieldType.FIXED32; + case FIXED64: + return FieldType.FIXED64; + case SFIXED32: + return FieldType.SFIXED32; + case SFIXED64: + return FieldType.SFIXED64; + case FLOAT: + return FieldType.FLOAT; + case DOUBLE: + return FieldType.DOUBLE; + case BOOL: + return FieldType.BOOL; + case STRING: + return FieldType.STRING; + case BYTES: + return FieldType.BYTES; + default: + throw new IllegalStateException("bug: miss process of " + fieldType); + } + } + + if (fieldType.isMessage()) { + return FieldType.MESSAGE; + } + + throw new IllegalStateException("bug: miss process of " + fieldType); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/HashFieldMapEx.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/HashFieldMapEx.java new file mode 100644 index 00000000000..d810233ed05 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/HashFieldMapEx.java @@ -0,0 +1,86 @@ +//======================================================================== +//Copyright 2007-2010 David Yu dyuproject@gmail.com +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package io.protostuff.runtime; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Forked and modified from protostuff + * + * Field mapping implemented on top of hash for field lookup by number. + * + * This is the less efficient than {@code ArrayFieldMapEx} for almost all cases. + * But in case when field numbers are sparse and especially when max field + * number is big - this mapping should be used. + * + * @see ArrayFieldMapEx + * + * @author Kostiantyn Shchepanovskyi + */ +public final class HashFieldMapEx implements FieldMapEx { + private final List> fields; + + private final Map> fieldsByNumber; + + private final Map> fieldsByName; + + public HashFieldMapEx(Collection> fields) { + fieldsByName = new HashMap<>(); + fieldsByNumber = new HashMap<>(); + for (FieldSchema f : fields) { + if (fieldsByName.containsKey(f.name)) { + FieldSchema prev = fieldsByName.get(f.name); + throw new IllegalStateException(prev + " and " + f + " cannot have the same name."); + } + if (fieldsByNumber.containsKey(f.fieldNumber)) { + FieldSchema prev = fieldsByNumber.get(f.fieldNumber); + throw new IllegalStateException(prev + " and " + f + " cannot have the same number."); + } + this.fieldsByNumber.put(f.fieldNumber, f); + this.fieldsByName.put(f.name, f); + } + + List> fieldList = new ArrayList<>(fields.size()); + fieldList.addAll(fields); + fieldList.sort(Comparator.comparingInt(FieldSchema::getFieldNumber)); + this.fields = Collections.unmodifiableList(fieldList); + } + + @Override + public FieldSchema getFieldByNumber(int n) { + return fieldsByNumber.get(n); + } + + @Override + public FieldSchema getFieldByName(String fieldName) { + return fieldsByName.get(fieldName); + } + + @Override + public int getFieldCount() { + return fields.size(); + } + + @Override + public List> getFields() { + return fields; + } +} diff --git a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/MessageSchema.java b/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/MessageSchema.java deleted file mode 100644 index 065b8e166aa..00000000000 --- a/foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/MessageSchema.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.protostuff.runtime; - -import static io.protostuff.runtime.RuntimeSchema.MIN_TAG_FOR_HASH_FIELD_MAP; - -import java.io.IOException; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.bean.Getter; -import org.apache.servicecomb.foundation.protobuf.ProtoMapper; -import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptor; -import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.PojoFieldSerializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; -import io.protostuff.compiler.model.Message; -import io.protostuff.runtime.RuntimeEnv.Instantiator; - -public class MessageSchema implements Schema, FieldMap { - private static final Logger LOGGER = LoggerFactory.getLogger(MessageSchema.class); - - private ProtoMapper protoMapper; - - private FieldMap fieldMap; - - private Class typeClass; - - private Instantiator instantiator; - - private Message message; - - // one class can bind to different proto message (almost different version) - // so save the information only in message, not global - private final Map> pojoFieldSerializers = new ConcurrentHashMapEx<>(); - - public void init(ProtoMapper protoMapper, Collection> fields, Message message) { - init(protoMapper, null, fields, null, message); - } - - public void init(ProtoMapper protoMapper, Class typeClass, Collection> fields, - Instantiator instantiator, - Message message) { - this.protoMapper = protoMapper; - this.fieldMap = createFieldMap(fields); - this.instantiator = instantiator; - this.typeClass = typeClass; - this.message = message; - } - - public Message getMessage() { - return message; - } - - private FieldMap createFieldMap(Collection> fields) { - int lastFieldNumber = 0; - for (Field field : fields) { - if (field.number > lastFieldNumber) { - lastFieldNumber = field.number; - } - } - if (preferHashFieldMap(fields, lastFieldNumber)) { - return new HashFieldMap<>(fields); - } - // array field map should be more efficient - return new ArrayFieldMap<>(fields, lastFieldNumber); - } - - private boolean preferHashFieldMap(Collection> fields, int lastFieldNumber) { - return lastFieldNumber > MIN_TAG_FOR_HASH_FIELD_MAP && lastFieldNumber >= 2 * fields.size(); - } - - @Override - public String getFieldName(int number) { - // only called on writes - final Field field = fieldMap.getFieldByNumber(number); - return field == null ? null : field.name; - } - - @Override - public int getFieldNumber(String name) { - final Field field = fieldMap.getFieldByName(name); - return field == null ? null : field.number; - } - - @Override - public boolean isInitialized(Object message) { - return true; - } - - @Override - public Object newMessage() { - return instantiator.newInstance(); - } - - @Override - public String messageName() { - return message.getName(); - } - - @Override - public String messageFullName() { - return message.getCanonicalName(); - } - - @Override - public Class typeClass() { - return typeClass; - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - Field field = null; - try { - for (int n = input.readFieldNumber(this); n != 0; n = input.readFieldNumber(this)) { - field = fieldMap.getFieldByNumber(n); - if (field == null) { - input.handleUnknownField(n, this); - } else { - field.mergeFrom(input, message); - } - } - } catch (IOException e) { - logError((FieldSchema) field, "deserialize", e); - throw e; - } catch (RuntimeException e) { - logError((FieldSchema) field, "deserialize", e); - throw e; - } - } - - protected void logError(FieldSchema fieldSchema, String action, Throwable e) { - if (fieldSchema == null) { - return; - } - - io.protostuff.compiler.model.Field protoField = fieldSchema.getProtoField(); - LOGGER.error("Failed to {}, field={}:{}, type={}", - action, - protoField.getType().getCanonicalName(), - protoField.getName(), - protoField.getTypeName(), - e.getMessage()); - } - - @SuppressWarnings("unchecked") - @Override - public void writeTo(Output output, Object message) throws IOException { - if (message == null) { - return; - } - - if (message instanceof Map) { - writeFromMap(output, (Map) message); - return; - } - - writeFromPojo(output, message); - } - - /** - *
-   * when use with generic
-   * each time serialize the value field, will run with the real type
-   * so there is no problem
-   *
-   * eg: CustomeGeneric<User> someMethod(CustomGeneric<People> input)
-   *   input: {
-   *     People value
-   *   }
-   *   output: {
-   *     User value
-   *   }
-   * 
- * @param output - * @param value - * @throws IOException - */ - protected void writeFromPojo(Output output, Object value) throws IOException { - List serializers = pojoFieldSerializers - .computeIfAbsent(value.getClass(), this::createFieldSerializers); - for (PojoFieldSerializer serializer : serializers) { - serializer.writeTo(output, value); - } - } - - protected List createFieldSerializers(Type type) { - BeanDescriptor beanDescriptor = protoMapper.getBeanDescriptorManager().getOrCreateBeanDescriptor(type); - List pojoFieldSerializers = new ArrayList<>(); - for (Field f : fieldMap.getFields()) { - PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get(f.name); - if (propertyDescriptor == null) { - continue; - } - - Getter getter = propertyDescriptor.getGetter(); - if (getter == null) { - continue; - } - - pojoFieldSerializers.add(new PojoFieldSerializer(getter, (FieldSchema) f)); - } - - return pojoFieldSerializers; - } - - protected void writeFromMap(Output output, Map map) throws IOException { - for (Entry entry : map.entrySet()) { - if (entry.getValue() == null) { - continue; - } - - Field field = fieldMap.getFieldByName(entry.getKey()); - if (field == null) { - // not defined in proto, ignore it. - continue; - } - - field.writeTo(output, entry.getValue()); - } - } - - @Override - public Field getFieldByNumber(int n) { - return fieldMap.getFieldByNumber(n); - } - - @Override - public Field getFieldByName(String fieldName) { - return fieldMap.getFieldByName(fieldName); - } - - @Override - public int getFieldCount() { - return fieldMap.getFieldCount(); - } - - @Override - public List> getFields() { - return fieldMap.getFields(); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapper.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapper.java index 0af2afb8882..7a5e6950019 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapper.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapper.java @@ -20,9 +20,7 @@ import java.util.Map; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.protobuf.internal.RootPropertyWrapDeserializer; import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptorManager; -import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.DeserializerSchemaManager; import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.SerializerSchemaManager; @@ -32,6 +30,8 @@ import io.protostuff.compiler.model.Message; import io.protostuff.compiler.model.Proto; +import io.protostuff.compiler.model.Service; +import io.protostuff.compiler.model.ServiceMethod; public class ProtoMapper { private final ObjectMapper jsonMapper; @@ -62,6 +62,14 @@ public Proto getProto() { return proto; } + public SerializerSchemaManager getSerializerSchemaManager() { + return serializerSchemaManager; + } + + public DeserializerSchemaManager getDeserializerSchemaManager() { + return deserializerSchemaManager; + } + public ObjectMapper getJsonMapper() { return jsonMapper; } @@ -88,36 +96,48 @@ public Message getMessageFromCanonicaName(String messageCanonicalName) { return null; } - public RootSerializer findRootSerializer(String shortMessageName) { - return serializerSchemaManager.findRootSerializer(shortMessageName); + public Message getRequestMessage(String operationId) { + Service service = proto.getServices().get(0); + ServiceMethod serviceMethod = service.getMethod(operationId); + if (serviceMethod == null) { + throw new IllegalArgumentException("operation not found, operation id=" + operationId); + } + return serviceMethod.getArgType(); } - public RootSerializer findRootSerializerByCanonical(String canonicalMessageName) { - return serializerSchemaManager.findRootSerializerByCanonical(canonicalMessageName); + public Message getResponseMessage(String operationId) { + Service service = proto.getServices().get(0); + ServiceMethod serviceMethod = service.getMethod(operationId); + return serviceMethod.getReturnType(); } - public RootDeserializer createRootDeserializer(Type type, String shortMessageName) { - return createRootDeserializer(TypeFactory.defaultInstance().constructType(type), shortMessageName); - } + public synchronized RootSerializer createRootSerializer(String shortMessageName, Type type) { + Message message = proto.getMessage(shortMessageName); + if (message == null) { + throw new IllegalStateException("can not find proto message to create serializer, name=" + shortMessageName); + } - public RootDeserializer createRootDeserializer(JavaType javaType, String shortMessageName) { - return deserializerSchemaManager.createRootDeserializer(javaType, shortMessageName); + return createRootSerializer(message, type); } - public RootDeserializer createRootDeserializer(JavaType javaType, Message message) { - return deserializerSchemaManager.createRootDeserializer(javaType, message); + public synchronized RootSerializer createRootSerializer(Message message, Type type) { + return serializerSchemaManager.createRootSerializer(message, type); } - public RootDeserializer createPropertyRootDeserializer(String shortWrapMessageName, Type propertyType) { - Message message = proto.getMessage(shortWrapMessageName); - if (!deserializerSchemaManager.isWrapProperty(message)) { - return createRootDeserializer(propertyType, shortWrapMessageName); + public synchronized RootDeserializer createRootDeserializer(String shortMessageName, Type type) { + Message message = proto.getMessage(shortMessageName); + if (message == null) { + throw new IllegalStateException("can not find proto message to create deserializer, name=" + shortMessageName); } - JavaType propertyWrapJavaType = TypeFactory.defaultInstance().constructParametricType( - PropertyWrapper.class, - TypeFactory.defaultInstance().constructType(propertyType)); - RootDeserializer rootDeserializer = createRootDeserializer(propertyWrapJavaType, message); - return new RootPropertyWrapDeserializer(rootDeserializer); + return createRootDeserializer(message, type); + } + + public synchronized RootDeserializer createRootDeserializer(Message message, Type type) { + return deserializerSchemaManager.createRootDeserializer(message, type); + } + + public synchronized RootDeserializer createRootDeserializer(Message message, Map types) { + return deserializerSchemaManager.createRootDeserializer(message, types); } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapperFactory.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapperFactory.java index 1e1caba71da..3081ffe4c5e 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapperFactory.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/ProtoMapperFactory.java @@ -28,20 +28,23 @@ public class ProtoMapperFactory { // 1.to support "any" type // 2.to find bean properties - private ObjectMapper jsonMapper = new ObjectMapper(); + private final ObjectMapper jsonMapper = new ObjectMapper(); - private BeanDescriptorManager beanDescriptorManager; + private final BeanDescriptorManager beanDescriptorManager; - private ProtoParser protoParser = new ProtoParser(); + private final ProtoParser protoParser = new ProtoParser(); public ProtoMapperFactory() { jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); jsonMapper.setSerializationInclusion(Include.NON_NULL); -// jsonMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, JsonTypeInfo.As.PROPERTY); beanDescriptorManager = new BeanDescriptorManager(jsonMapper.getSerializationConfig()); } + public ObjectMapper getJsonMapper() { + return jsonMapper; + } + public BeanDescriptorManager getBeanDescriptorManager() { return beanDescriptorManager; } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootDeserializer.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootDeserializer.java index 7b600bc486f..8afee6c729c 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootDeserializer.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootDeserializer.java @@ -18,43 +18,30 @@ import java.io.IOException; -import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptor; +import io.protostuff.ByteArrayInputEx; +import io.protostuff.InputEx; +import io.protostuff.SchemaEx; -import io.protostuff.ByteArrayInput; -import io.protostuff.Input; -import io.protostuff.runtime.MessageSchema; +public class RootDeserializer { + protected SchemaEx schema; -public class RootDeserializer { - private BeanDescriptor beanDescriptor; - - private MessageSchema schema; - - public RootDeserializer(BeanDescriptor beanDescriptor, MessageSchema schema) { - this.beanDescriptor = beanDescriptor; + public RootDeserializer(SchemaEx schema) { this.schema = schema; } - public BeanDescriptor getBeanDescriptor() { - return beanDescriptor; - } - - public void setBeanDescriptor(BeanDescriptor beanDescriptor) { - this.beanDescriptor = beanDescriptor; - } - - public MessageSchema getSchema() { + public SchemaEx getSchema() { return schema; } - public void setSchema(MessageSchema schema) { + public void setSchema(SchemaEx schema) { this.schema = schema; } @SuppressWarnings("unchecked") - public T deserialize(byte[] bytes) throws IOException { - Input input = new ByteArrayInput(bytes, false); - Object instance = beanDescriptor.create(); + public T deserialize(byte[] bytes) throws IOException { + InputEx input = new ByteArrayInputEx(bytes); + T instance = schema.newMessage(); schema.mergeFrom(input, instance); - return (T) instance; + return instance; } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootSerializer.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootSerializer.java index 7065caf33f4..f4fd245576a 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootSerializer.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/RootSerializer.java @@ -17,36 +17,31 @@ package org.apache.servicecomb.foundation.protobuf; import java.io.IOException; +import java.io.OutputStream; -import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.ProtoStreamOutput; - -import io.protostuff.runtime.MessageSchema; +import io.protostuff.ProtobufOutputEx; +import io.protostuff.SchemaEx; public class RootSerializer { - private MessageSchema schema; + private final SchemaEx schema; - public RootSerializer(MessageSchema schema) { + public RootSerializer(SchemaEx schema) { this.schema = schema; } - public MessageSchema getSchema() { - return schema; - } - - public void setSchema(MessageSchema schema) { - this.schema = schema; + public byte[] serialize(Object value) throws IOException { + ProtobufOutputEx output = new ProtobufOutputEx(); + if (value != null) { + schema.writeTo(output, value); + } + return output.toByteArray(); } - /** - * not same to standard ProtoStuff mechanism - * parameter "value" of writeTo is self value, not owner - * @param value - * @return - * @throws IOException - */ - public byte[] serialize(Object value) throws IOException { - ProtoStreamOutput output = new ProtoStreamOutput(); - schema.writeTo(output, value); - return output.toBytes(); + public void serialize(OutputStream outputStream, Object value) throws IOException { + ProtobufOutputEx output = new ProtobufOutputEx(); + if (value != null) { + schema.writeTo(output, value); + } + output.toOutputStream(outputStream); } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoConst.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoConst.java index 72f376490b3..117d82d1300 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoConst.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoConst.java @@ -16,6 +16,7 @@ */ package org.apache.servicecomb.foundation.protobuf.internal; +import java.util.ArrayList; import java.util.LinkedHashMap; import org.apache.servicecomb.foundation.protobuf.internal.parser.ProtoParser; @@ -30,25 +31,31 @@ public final class ProtoConst { private ProtoConst() { } - public static String ANNOTATION_WRAP_PROPERTY = "@WrapProperty"; + public static final String ANNOTATION_WRAP_ARGUMENTS = "@WrapArguments"; - public static String OP_HINT = " scb:"; + public static final String ANNOTATION_WRAP_PROPERTY = "@WrapProperty"; - public static String PACK_SCHEMA = "type.googleapis.com/"; + public static String ANNOTATION_RPC = "@Rpc"; - public static String JSON_SCHEMA = "json/"; + public static final String PACK_SCHEMA = "type.googleapis.com/"; - public static String JSON_ID_NAME = "@type"; + public static final String JSON_SCHEMA = "json/"; - public static JavaType MAP_TYPE = TypeFactory.defaultInstance().constructType(LinkedHashMap.class); + public static final String JSON_ID_NAME = "@type"; - public static Proto ANY_PROTO; + public static final JavaType MAP_TYPE = TypeFactory.defaultInstance().constructType(LinkedHashMap.class); - public static Message ANY; + public static final JavaType LIST_TYPE = TypeFactory.defaultInstance().constructType(ArrayList.class); - public static Proto EMPTY_PROTO; + public static final JavaType OBJECT_TYPE = TypeFactory.defaultInstance().constructType(Object.class); - public static Message EMPTY; + public static final Proto ANY_PROTO; + + public static final Message ANY; + + public static final Proto EMPTY_PROTO; + + public static final Message EMPTY; static { ProtoParser protoParser = new ProtoParser(); diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java new file mode 100644 index 00000000000..2d5c7e0c748 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/ProtoUtils.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.compiler.model.DynamicMessage; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.FieldContainer; +import io.protostuff.compiler.model.Message; +import io.protostuff.compiler.model.ScalarFieldType; +import io.protostuff.compiler.model.Type; + +public final class ProtoUtils { + private ProtoUtils() { + } + + public static boolean isEmptyMessage(Message protoField) { + return protoField.getCanonicalName().equals(ProtoConst.EMPTY.getCanonicalName()); + } + + public static boolean isAnyMessage(Message protoField) { + return protoField.getCanonicalName().equals(ProtoConst.ANY.getCanonicalName()); + } + + public static boolean isAnyField(Field protoField) { + return protoField.getType().getCanonicalName().equals(ProtoConst.ANY.getCanonicalName()); + } + + public static boolean isWrapArguments(FieldContainer fieldContainer) { + return fieldContainer.getCommentLines().contains(ProtoConst.ANNOTATION_WRAP_ARGUMENTS); + } + + public static boolean isWrapProperty(FieldContainer fieldContainer) { + return fieldContainer.getCommentLines().contains(ProtoConst.ANNOTATION_WRAP_PROPERTY); + } + + /** + * all supported type, default to packed + * @param protoField + * @return + */ + public static boolean isSupportPacked(Field protoField) { + if (protoField.getType().isEnum()) { + return true; + } + + if (protoField.getType().isScalar()) { + ScalarFieldType scalarFieldType = (ScalarFieldType) protoField.getType(); + return scalarFieldType != ScalarFieldType.STRING && scalarFieldType != ScalarFieldType.BYTES; + } + + return false; + } + + public static boolean isPacked(Field protoField) { + DynamicMessage.Value dynamicMessageValue = protoField.getOptions().get("packed"); + if (dynamicMessageValue != null) { + return dynamicMessageValue.getBoolean(); + } + + return isSupportPacked(protoField); + } + + public static void throwNotSupportWrite(Field protoField, Object value) throws IllegalStateException { + throwNotSupportWrite(protoField, value.getClass()); + } + + public static void throwNotSupportWrite(Field protoField, Class cls) throws IllegalStateException { + throw new IllegalStateException( + String.format("not support serialize from %s to proto %s, field=%s:%s", + cls.getName(), + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + public static void throwNotSupportMerge(Field protoField, JavaType javaType) throws IllegalStateException { + throw new IllegalStateException( + String.format("not support deserialize proto %s as %s, field=%s:%s", + protoField.getTypeName(), + javaType.toCanonical(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + public static void throwNotSupportNullElement(Field protoField) throws IllegalStateException { + throw new IllegalStateException( + String.format("not support serialize null element, field=%s:%s", + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/RootPropertyWrapDeserializer.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/RootPropertyWrapDeserializer.java deleted file mode 100644 index ab646993e35..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/RootPropertyWrapDeserializer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.RootDeserializer; -import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; - -public class RootPropertyWrapDeserializer extends RootDeserializer { - private final RootDeserializer rootDeserializer; - - public RootPropertyWrapDeserializer(RootDeserializer rootDeserializer) { - super(null, null); - this.rootDeserializer = rootDeserializer; - } - - @Override - public T deserialize(byte[] bytes) throws IOException { - PropertyWrapper propertyWrapper = rootDeserializer.deserialize(bytes); - return propertyWrapper.value; - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptor.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptor.java index 868d151cfc9..f6e15e03363 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptor.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptor.java @@ -20,8 +20,6 @@ import java.util.Map; import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; -import org.apache.servicecomb.foundation.common.utils.bean.Getter; -import org.apache.servicecomb.foundation.common.utils.bean.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,18 +33,12 @@ public class BeanDescriptor { private JavaType javaType; - private BeanFactory factory; - - private Map propertyDescriptors = new HashMap<>(); + private final Map propertyDescriptors = new HashMap<>(); public JavaType getJavaType() { return javaType; } - public BeanFactory getFactory() { - return factory; - } - public Map getPropertyDescriptors() { return propertyDescriptors; } @@ -54,14 +46,11 @@ public Map getPropertyDescriptors() { public void init(SerializationConfig serializationConfig, JavaType javaType) { this.javaType = javaType; - this.factory = BeanFactory.createFactory(javaType); - BeanDescription beanDescription = serializationConfig.introspect(javaType); for (BeanPropertyDefinition propertyDefinition : beanDescription.findProperties()) { PropertyDescriptor propertyDescriptor = new PropertyDescriptor(); propertyDescriptor.setName(propertyDefinition.getName()); propertyDescriptor.setJavaType(propertyDefinition.getPrimaryType()); - propertyDescriptor.setFactory(BeanFactory.createFactory(propertyDefinition.getPrimaryType())); try { propertyDescriptor.setGetter(initGetter(propertyDefinition)); @@ -81,19 +70,20 @@ public void init(SerializationConfig serializationConfig, JavaType javaType) { } } - protected Getter initGetter(BeanPropertyDefinition propertyDefinition) throws Throwable { + @SuppressWarnings("unchecked") + public static T initGetter(BeanPropertyDefinition propertyDefinition) { if (propertyDefinition.hasGetter()) { return LambdaMetafactoryUtils.createGetter(propertyDefinition.getGetter().getAnnotated()); } if (propertyDefinition.hasField() && propertyDefinition.getField().isPublic()) { - return LambdaMetafactoryUtils.createGetter(propertyDefinition.getField().getAnnotated()); + return (T) LambdaMetafactoryUtils.createGetter(propertyDefinition.getField().getAnnotated()); } return null; } - protected Setter initSetter(BeanPropertyDefinition propertyDefinition) throws Throwable { + protected Object initSetter(BeanPropertyDefinition propertyDefinition) { if (propertyDefinition.hasSetter()) { return LambdaMetafactoryUtils.createSetter(propertyDefinition.getSetter().getAnnotated()); } @@ -104,8 +94,4 @@ protected Setter initSetter(BeanPropertyDefinition propertyDefinition) throws Th return null; } - - public Object create() { - return factory.create(); - } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptorManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptorManager.java index 58945b00766..11a1aa221ec 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptorManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanDescriptorManager.java @@ -26,9 +26,9 @@ import com.fasterxml.jackson.databind.type.TypeFactory; public class BeanDescriptorManager { - private SerializationConfig serializationConfig; + private final SerializationConfig serializationConfig; - private Map beanDescriptors = new ConcurrentHashMapEx<>(); + private final Map beanDescriptors = new ConcurrentHashMapEx<>(); public BeanDescriptorManager(SerializationConfig serializationConfig) { this.serializationConfig = serializationConfig; diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanFactory.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanFactory.java deleted file mode 100644 index 24594ac2ea0..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/BeanFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.bean; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.fasterxml.jackson.databind.JavaType; - -import io.protostuff.compiler.model.Field; - -public interface BeanFactory { - static BeanFactory createFactory(Field field) { - // map also is repeated, so must determine first - if (field.isMap()) { - return BeanFactory::mapFactory; - } - - if (field.isRepeated()) { - return BeanFactory::listFactory; - } - - if (field.getType().isScalar()) { - // no need a factory - return null; - } - - return BeanFactory::mapFactory; - } - - static BeanFactory createFactory(JavaType javaType) { - if (javaType.isPrimitive()) { - // no need a factory - return null; - } - - if (List.class.isAssignableFrom(javaType.getRawClass())) { - return BeanFactory::listFactory; - } - - if (Set.class.isAssignableFrom(javaType.getRawClass())) { - return BeanFactory::setFactory; - } - - if (Map.class.isAssignableFrom(javaType.getRawClass())) { - return BeanFactory::mapFactory; - } - - return new ConstructorFactory(javaType); - } - - @SuppressWarnings("unchecked") - static T listFactory() { - return (T) new ArrayList<>(); - } - - @SuppressWarnings("unchecked") - static T setFactory() { - return (T) new LinkedHashSet<>(); - } - - @SuppressWarnings("unchecked") - static T mapFactory() { - return (T) new LinkedHashMap<>(); - } - - class ConstructorFactory implements BeanFactory { - private final JavaType javaType; - - public ConstructorFactory(JavaType javaType) { - this.javaType = javaType; - } - - @SuppressWarnings("unchecked") - @Override - public T create() { - try { - return (T) javaType.getRawClass().newInstance(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - } - - T create(); -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyDescriptor.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyDescriptor.java index 4fb6a8fd0cb..fa4cd6243b0 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyDescriptor.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyDescriptor.java @@ -16,9 +16,6 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.bean; -import org.apache.servicecomb.foundation.common.utils.bean.Getter; -import org.apache.servicecomb.foundation.common.utils.bean.Setter; - import com.fasterxml.jackson.databind.JavaType; public class PropertyDescriptor { @@ -26,12 +23,9 @@ public class PropertyDescriptor { private JavaType javaType; - private Getter getter; - - private Setter setter; + private Object getter; - // not available for primitive types - private BeanFactory factory; + private Object setter; public String getName() { return name; @@ -49,27 +43,21 @@ public void setJavaType(JavaType javaType) { this.javaType = javaType; } - public Getter getGetter() { - return getter; + @SuppressWarnings("unchecked") + public T getGetter() { + return (T) getter; } - public void setGetter(Getter getter) { + public void setGetter(Object getter) { this.getter = getter; } - public Setter getSetter() { - return setter; + @SuppressWarnings("unchecked") + public T getSetter() { + return (T) setter; } - public void setSetter(Setter setter) { + public void setSetter(Object setter) { this.setter = setter; } - - public BeanFactory getFactory() { - return factory; - } - - public void setFactory(BeanFactory factory) { - this.factory = factory; - } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyWrapper.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyWrapper.java index 17b8d41dd8b..3dc2634378a 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyWrapper.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/bean/PropertyWrapper.java @@ -17,5 +17,13 @@ package org.apache.servicecomb.foundation.protobuf.internal.bean; public class PropertyWrapper { - public T value; + private T value; + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ContentFileReader.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ContentFileReader.java index a501221dafa..89bf2b43282 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ContentFileReader.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ContentFileReader.java @@ -16,28 +16,28 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.parser; -import javax.annotation.Nullable; - import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import io.protostuff.compiler.parser.FileReader; public class ContentFileReader implements FileReader { - private FileReader importReader; + private final FileReader importReader; + + private final String content; - private boolean contentReaded; + private boolean contentRead; - public ContentFileReader(FileReader importReader) { + public ContentFileReader(FileReader importReader, String content) { this.importReader = importReader; + this.content = content; } - @Nullable @Override public CharStream read(String contentOrName) { - if (!contentReaded) { - contentReaded = true; - return CharStreams.fromString(contentOrName); + if (!contentRead) { + contentRead = true; + return CharStreams.fromString(this.content); } return importReader.read(contentOrName); diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ProtoParser.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ProtoParser.java index 423a5d7afdd..e25e9b3f0aa 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ProtoParser.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/parser/ProtoParser.java @@ -32,21 +32,43 @@ * can be reused */ public class ProtoParser { - private Injector injector = Guice.createInjector(new ParserModule()); + private static final String DEFAULT_PROTO_NAME = "default.proto"; - private FileReaderFactory fileReaderFactory = injector.getInstance(FileReaderFactory.class); + private final Injector injector = Guice.createInjector(new ParserModule()); - private FileReader defaultReader = fileReaderFactory.create(Collections.emptyList()); + private final FileReaderFactory fileReaderFactory = injector.getInstance(FileReaderFactory.class); - private FileDescriptorLoader loader = injector.getInstance(FileDescriptorLoader.class); + private final FileReader defaultReader = fileReaderFactory.create(Collections.emptyList()); + + private final FileDescriptorLoader loader = injector.getInstance(FileDescriptorLoader.class); public Proto parseFromContent(String content) { - ProtoContext context = loader.load(new ContentFileReader(defaultReader), content); - return context.getProto(); + // io.protostuff.compiler.parser.ClasspathFileReader will use ContextClassLoader load resource, but in some environment, + // ContextClassLoader is null, and we use class loader instead. + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + if (classLoader == null) { + Thread.currentThread().setContextClassLoader(ProtoParser.class.getClassLoader()); + } + ProtoContext context = loader.load(new ContentFileReader(defaultReader, content), DEFAULT_PROTO_NAME); + return context.getProto(); + } finally { + Thread.currentThread().setContextClassLoader(classLoader); + } } public Proto parse(String name) { - ProtoContext context = loader.load(defaultReader, name); - return context.getProto(); + // io.protostuff.compiler.parser.ClasspathFileReader will use ContextClassLoader load resource, but in some environment, + // ContextClassLoader is null, and we use class loader instead. + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + if (classLoader == null) { + Thread.currentThread().setContextClassLoader(ProtoParser.class.getClassLoader()); + } + ProtoContext context = loader.load(defaultReader, name); + return context.getProto(); + } finally { + Thread.currentThread().setContextClassLoader(classLoader); + } } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntrySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntrySchema.java deleted file mode 100644 index f4828e81028..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntrySchema.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.Map; - -import org.apache.servicecomb.foundation.protobuf.ProtoMapper; -import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; - -import io.protostuff.CustomSchema; -import io.protostuff.Input; -import io.protostuff.Output; - -public class AnyEntrySchema extends CustomSchema { - private final ProtoMapper protoMapper; - - public AnyEntrySchema(ProtoMapper protoMapper) { - super(null); - this.protoMapper = protoMapper; - } - - @Override - public boolean isInitialized(Object message) { - return true; - } - - @Override - public Object newMessage() { - return new AnyEntry(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - input.readFieldNumber(null); - String typeUrl = input.readString(); - - input.readFieldNumber(null); - byte[] bytes = input.readByteArray(); - - input.readFieldNumber(null); - - AnyEntry anyEntry = (AnyEntry) message; - anyEntry.setTypeUrl(typeUrl); - anyEntry.setValue(bytes); - } - - protected String getInputActualTypeName(Object input) { - if (!(input instanceof Map)) { - return input.getClass().getSimpleName(); - } - - // @JsonTypeInfo(use = Id.NAME) - Object actualTypeName = ((Map) input).get(ProtoConst.JSON_ID_NAME); - if (actualTypeName != null && actualTypeName instanceof String) { - return (String) actualTypeName; - } - - return null; - } - - /** - *
-   * if message is type of CustomGeneric<User>
-   * we can not get any information of "User" from message.getClass()
-   *
-   * when use with ServiceComb
-   * proto definition convert from swagger, the proto type will be "CustomGenericUser"
-   * is not match to "CustomGeneric"
-   * so message will be serialized with json schema
-   * 
- * @param output - * @param message - * @throws IOException - */ - @Override - public void writeTo(Output output, Object message) throws IOException { - String actualTypeName = getInputActualTypeName(message); - RootSerializer actualValueSerializer = protoMapper.findRootSerializer(actualTypeName); - if (actualValueSerializer != null) { - standardPack(output, message, actualValueSerializer); - return; - } - - // not standard, protobuf can not support or not define this type , just extend - jsonExtend(output, message); - } - - protected void standardPack(Output output, Object message, RootSerializer actualValueSerializer) throws IOException { - output.writeString(1, - ProtoConst.PACK_SCHEMA + actualValueSerializer.getSchema().getMessage().getCanonicalName(), - false); - - byte[] bytes = actualValueSerializer.serialize(message); - output.writeByteArray(2, bytes, false); - } - - protected void jsonExtend(Output output, Object input) throws IOException { - output.writeString(1, ProtoConst.JSON_SCHEMA + input.getClass().getName(), false); - - byte[] bytes = protoMapper.getJsonMapper().writeValueAsBytes(input); - output.writeByteArray(2, bytes, false); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnySchema.java deleted file mode 100644 index cae8c360077..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnySchema.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.protobuf.ProtoMapper; -import org.apache.servicecomb.foundation.protobuf.RootDeserializer; -import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; - -import com.fasterxml.jackson.databind.JavaType; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; -import io.protostuff.compiler.model.Message; - -public class AnySchema extends FieldSchema { - private final ProtoMapper protoMapper; - - private final AnyEntrySchema anyEntrySchema; - - // key is message canonical name - private final Map rootDeserializers = new ConcurrentHashMapEx<>(); - - public AnySchema(ProtoMapper protoMapper, Field protoField) { - super(protoField); - this.protoMapper = protoMapper; - this.anyEntrySchema = new AnyEntrySchema(protoMapper); - } - - @Override - public Object readFrom(Input input) throws IOException { - AnyEntry anyEntry = (AnyEntry) input.mergeObject(null, anyEntrySchema); - if (anyEntry.getTypeUrl().startsWith(ProtoConst.PACK_SCHEMA)) { - return standardUnpack(anyEntry.getTypeUrl(), anyEntry.getValue()); - } - - return jsonExtendMergeFrom(anyEntry.getTypeUrl(), anyEntry.getValue()); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - Object anyValue = readFrom(input); - setter.set(message, anyValue); - } - - @SuppressWarnings("unchecked") - protected Object standardUnpack(String typeUrl, byte[] bytes) throws IOException { - String msgCanonicalName = typeUrl.substring(ProtoConst.PACK_SCHEMA.length()); - RootDeserializer valueDeserializer = rootDeserializers - .computeIfAbsent(msgCanonicalName, this::createRootDeserializerFromCanonicaName); - Object value = valueDeserializer.deserialize(bytes); - if (value instanceof Map) { - ((Map) value).put(ProtoConst.JSON_ID_NAME, valueDeserializer.getSchema().messageName()); - } - return value; - } - - protected RootDeserializer createRootDeserializerFromCanonicaName(String msgCanonicalName) { - Message message = protoMapper.getMessageFromCanonicaName(msgCanonicalName); - if (message == null) { - throw new IllegalStateException( - "can not find proto message to create deserializer, name=" + msgCanonicalName); - } - - JavaType javaType = protoMapper.getAnyTypes().get(msgCanonicalName); - if (javaType == null) { - javaType = ProtoConst.MAP_TYPE; - } - return protoMapper.createRootDeserializer(javaType, message); - } - - protected Object jsonExtendMergeFrom(String typeUrl, byte[] bytes) throws IOException { - return protoMapper.getJsonMapper().readValue(bytes, Object.class); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - output.writeObject(number, value, anyEntrySchema, repeated); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/EnumMeta.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/EnumMeta.java new file mode 100644 index 00000000000..79a842a68c5 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/EnumMeta.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.compiler.model.EnumConstant; +import io.protostuff.compiler.model.Field; + +public class EnumMeta { + private final Map enumNameToValueMap = new HashMap<>(); + + // key is idl defined enum value + // value is Enum or null + private final Map> enumValues = new HashMap<>(); + + public EnumMeta(Field protoField, JavaType javaType) { + io.protostuff.compiler.model.Enum enumType = (io.protostuff.compiler.model.Enum) protoField.getType(); + for (EnumConstant enumConstant : enumType.getConstants()) { + enumNameToValueMap.put(enumConstant.getName(), enumConstant.getValue()); + enumValues.put(enumConstant.getValue(), null); + } + + if (!javaType.isEnumType()) { + return; + } + + try { + Method method = javaType.getRawClass().getMethod("values"); + method.setAccessible(true); + Object[] values = (Object[]) method.invoke(null); + for (Object value : values) { + Enum enumValue = (Enum) value; + enumValues.put(enumNameToValueMap.get(enumValue.name()), enumValue); + } + } catch (Throwable e) { + throw new IllegalStateException( + "Failed to collect enum values, class=" + javaType.getRawClass().getName(), e); + } + } + + public boolean containsValue(Integer value) { + return enumValues.containsKey(value); + } + + public Enum getEnumByValue(int enumValue) { + return enumValues.get(enumValue); + } + + public Integer getValueByName(String name) { + return enumNameToValueMap.get(name); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/FieldSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/FieldSchema.java deleted file mode 100644 index ad83bf0c985..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/FieldSchema.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.common.utils.bean.Getter; -import org.apache.servicecomb.foundation.common.utils.bean.Setter; -import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanFactory; -import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.ProtoStreamOutput; - -import com.google.common.annotations.VisibleForTesting; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Pipe; -import io.protostuff.compiler.model.Field; -import io.protostuff.compiler.model.Type; - -public abstract class FieldSchema extends io.protostuff.runtime.Field { - protected final Field protoField; - - protected Getter getter; - - protected Setter setter; - - protected BeanFactory factory; - - public FieldSchema(Field protoField) { - super(ProtoSchemaUtils.convert(protoField.getType()), - protoField.getTag(), - protoField.getName(), - protoField.isRepeated(), - null); - this.protoField = protoField; - } - - public Field getProtoField() { - return protoField; - } - - public Getter getGetter() { - return getter; - } - - public void setGetter(Getter getter) { - this.getter = getter; - } - - public Setter getSetter() { - return setter; - } - - public void setSetter(Setter setter) { - this.setter = setter; - } - - public void setFactory(BeanFactory factory) { - this.factory = factory; - } - - protected void throwNotSupportValue(Object value) throws IllegalStateException { - throw new IllegalStateException( - String.format("not support serialize from %s to proto %s, field=%s:%s", - value.getClass().getName(), - protoField.getTypeName(), - ((Type) protoField.getParent()).getCanonicalName(), - protoField.getName())); - } - - @SuppressWarnings("unchecked") - protected T getOrCreateFieldValue(Object message) { - Object value = getter.get(message); - if (value == null) { - value = this.factory.create(); - setter.set(message, value); - } - return (T) value; - } - - @Override - protected void transfer(Pipe pipe, Input input, Output output, boolean repeated) { - throw new UnsupportedOperationException(); - } - - public abstract Object readFrom(Input input) throws IOException; - - @VisibleForTesting - public byte[] writeTo(Object message) throws IOException { - ProtoStreamOutput output = new ProtoStreamOutput(); - writeTo(output, message); - return output.toBytes(); - } - - @Override - public abstract void writeTo(Output output, Object message) throws IOException; - - @Override - public abstract void mergeFrom(Input input, Object message) throws IOException; -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapEntrySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapEntrySchema.java deleted file mode 100644 index a969f25d65f..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapEntrySchema.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; - -import io.protostuff.CustomSchema; -import io.protostuff.Input; -import io.protostuff.Output; - -public class MapEntrySchema extends CustomSchema { - private final FieldSchema keySchema; - - private final FieldSchema valueSchema; - - public MapEntrySchema(FieldSchema keySchema, FieldSchema valueSchema) { - super(null); - this.keySchema = keySchema; - this.valueSchema = valueSchema; - } - - @Override - public boolean isInitialized(Object message) { - return true; - } - - @SuppressWarnings("unchecked") - @Override - public void mergeFrom(Input input, Object message) throws IOException { - input.readFieldNumber(null); - Object key = keySchema.readFrom(input); - - input.readFieldNumber(null); - Object value = valueSchema.readFrom(input); - - input.readFieldNumber(null); - - ((Map) message).put(key, value); - } - - @SuppressWarnings("unchecked") - @Override - public void writeTo(Output output, Object message) throws IOException { - keySchema.writeTo(output, ((Entry) message).getKey()); - valueSchema.writeTo(output, ((Entry) message).getValue()); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapSchema.java deleted file mode 100644 index bee0e4b2a13..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MapSchema.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class MapSchema extends FieldSchema { - private final MapEntrySchema entrySchema; - - public MapSchema(Field protoField, FieldSchema keySchema, FieldSchema valueSchema) { - super(protoField); - this.entrySchema = new MapEntrySchema(keySchema, valueSchema); - } - - @Override - public Object readFrom(Input input) { - throw new UnsupportedOperationException(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - Map map = getOrCreateFieldValue(message); - input.mergeObject(map, entrySchema); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - @SuppressWarnings("unchecked") - Map map = (Map) value; - for (Entry entry : map.entrySet()) { - if (entry.getKey() == null || entry.getValue() == null) { - continue; - } - - output.writeObject(number, entry, entrySchema, true); - } - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MessageAsFieldSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MessageAsFieldSchema.java index cb5df01bfbd..5f4fa999a37 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MessageAsFieldSchema.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/MessageAsFieldSchema.java @@ -18,33 +18,53 @@ import java.io.IOException; -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class MessageAsFieldSchema extends FieldSchema { + protected final SchemaEx schema; -public class MessageAsFieldSchema extends FieldSchema { - protected Schema schema; + protected final Getter getter; - public MessageAsFieldSchema(Field protoField, Schema schema) { - super(protoField); + protected final Setter setter; + + public MessageAsFieldSchema(Field protoField, PropertyDescriptor propertyDescriptor, SchemaEx schema) { + super(protoField, propertyDescriptor.getJavaType()); this.schema = schema; + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); } @Override - public void writeTo(Output output, Object value) throws IOException { - output.writeObject(number, value, schema, false); + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value == null) { + return; + } + + output.writeObject(tag, tagSize, value, schema); } @Override - public Object readFrom(Input input) throws IOException { - return input.mergeObject(null, schema); + public final void writeTo(OutputEx output, Object value) throws IOException { + output.writeObject(tag, tagSize, value, schema); } @Override - public void mergeFrom(Input input, Object message) throws IOException { - Object existing = getter.get(message); - Object fieldValue = input.mergeObject(existing, schema); - setter.set(message, fieldValue); + public final int mergeFrom(InputEx input, T message) throws IOException { + Object value = getter.get(message); + if (value == null) { + value = schema.newMessage(); + setter.set(message, value); + } + input.mergeObject(value, schema); + return input.readFieldNumber(); } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageAsFieldSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageAsFieldSchema.java deleted file mode 100644 index 0a1e7c043df..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageAsFieldSchema.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.List; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.Schema; -import io.protostuff.compiler.model.Field; -import io.protostuff.runtime.MessageSchema; - -/** - * - */ -public class PropertyWrapMessageAsFieldSchema extends MessageAsFieldSchema { - private PropertyWrapMessageSchema propertyWrapMessageSchema; - - private FieldSchema fieldSchema; - - public PropertyWrapMessageAsFieldSchema(Field protoField, Schema schema) { - super(protoField, schema); - - List> list = ((MessageSchema) schema).getFields(); - this.fieldSchema = (FieldSchema) list.get(0); - - propertyWrapMessageSchema = new PropertyWrapMessageSchema(); - propertyWrapMessageSchema.setFieldSchema(fieldSchema); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - output.writeObject(number, value, propertyWrapMessageSchema, false); - } - - @Override - public Object readFrom(Input input) throws IOException { - Object instance = schema.newMessage(); - input.mergeObject(instance, schema); - return fieldSchema.getter.get(instance); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - throw new UnsupportedOperationException(); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageSchema.java deleted file mode 100644 index b585d64d1a7..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapMessageSchema.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; - -import io.protostuff.Output; -import io.protostuff.runtime.MessageSchema; - -public class PropertyWrapMessageSchema extends MessageSchema { - private FieldSchema fieldSchema; - - public void setFieldSchema(FieldSchema fieldSchema) { - this.fieldSchema = fieldSchema; - } - - @Override - public void writeTo(Output output, Object message) throws IOException { - fieldSchema.writeTo(output, message); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapperAsFieldSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapperAsFieldSchema.java new file mode 100644 index 00000000000..fdb737ea194 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/PropertyWrapperAsFieldSchema.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.MessageReadSchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.MessageWriteSchema; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +/** + * + */ +public class PropertyWrapperAsFieldSchema extends FieldSchema { + private final SchemaEx schema; + + private final FieldSchema fieldSchema; + + protected final Getter getter; + + protected final Setter setter; + + public PropertyWrapperAsFieldSchema(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaEx schema) { + super(protoField, propertyDescriptor.getJavaType()); + this.schema = schema; + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + + if (schema instanceof MessageWriteSchema) { + fieldSchema = ((MessageWriteSchema) schema).getMainPojoFieldMaps().getFieldByNumber(1); + return; + } + + fieldSchema = ((MessageReadSchema) schema).getFieldMap().getFieldByNumber(1); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + output.writeObject(tag, tagSize, message, fieldSchema::writeTo); + } + + @Override + public void writeTo(OutputEx output, Object value) throws IOException { + output.writeObject(tag, tagSize, value, fieldSchema::writeTo); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PropertyWrapper wrapper = new PropertyWrapper<>(); + input.mergeObject(wrapper, schema); + setter.set(message, wrapper.getValue()); + return input.readFieldNumber(); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/ProtoSchemaUtils.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/ProtoSchemaUtils.java deleted file mode 100644 index f6e1d4edb52..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/ProtoSchemaUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import io.protostuff.WireFormat.FieldType; -import io.protostuff.compiler.model.ScalarFieldType; - -public final class ProtoSchemaUtils { - public static FieldType convert(io.protostuff.compiler.model.FieldType fieldType) { - if (fieldType.isEnum()) { - return FieldType.ENUM; - } - - if (fieldType.isScalar()) { - switch ((ScalarFieldType) fieldType) { - case INT32: - return FieldType.INT32; - case INT64: - return FieldType.INT64; - case UINT32: - return FieldType.UINT32; - case UINT64: - return FieldType.UINT64; - case SINT32: - return FieldType.SINT32; - case SINT64: - return FieldType.SINT64; - case FIXED32: - return FieldType.FIXED32; - case FIXED64: - return FieldType.FIXED64; - case SFIXED32: - return FieldType.SFIXED32; - case SFIXED64: - return FieldType.SFIXED64; - case FLOAT: - return FieldType.FLOAT; - case DOUBLE: - return FieldType.DOUBLE; - case BOOL: - return FieldType.BOOL; - case STRING: - return FieldType.STRING; - case BYTES: - return FieldType.BYTES; - default: - throw new IllegalStateException("bug: miss process of " + fieldType); - } - } - - if (fieldType.isMessage()) { - return FieldType.MESSAGE; - } - - throw new IllegalStateException("bug: miss process of " + fieldType); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/RepeatedSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/RepeatedSchema.java deleted file mode 100644 index fad45643808..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/RepeatedSchema.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.io.IOException; -import java.util.Collection; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class RepeatedSchema extends FieldSchema { - private final FieldSchema elementSchema; - - public RepeatedSchema(Field protoField, FieldSchema elementSchema) { - super(protoField); - this.elementSchema = elementSchema; - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Collection) { - @SuppressWarnings("unchecked") - Collection list = (Collection) value; - for (Object element : list) { - elementSchema.writeTo(output, element); - } - return; - } - - if (value.getClass().isArray()) { - for (Object element : (Object[]) value) { - elementSchema.writeTo(output, element); - } - return; - } - - throwNotSupportValue(value); - } - - @Override - public Object readFrom(Input input) { - throw new UnsupportedOperationException(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - Collection collection = getOrCreateFieldValue(message); - collection.add(elementSchema.readFrom(input)); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaCreateContext.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaCreateContext.java deleted file mode 100644 index f30cb88ba3b..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaCreateContext.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; - -import java.util.HashMap; -import java.util.Map; - -import io.protostuff.runtime.MessageSchema; - -public class SchemaCreateContext { - // key is short message name - private Map schemas = new HashMap<>(); - -// private List messageAsFieldSchemas = new ArrayList<>(); - - public Map getSchemas() { - return schemas; - } - -// public void addMessageAsFieldSchema(MessageAsFieldSchema messageAsFieldSchema) { -// messageAsFieldSchemas.add(messageAsFieldSchema); -// } - -// public void resolvePlaceholders() { -// for (MessageAsFieldSchema messageAsFieldSchema : messageAsFieldSchemas) { -// messageAsFieldSchema.resolvePlaceholder(); -// } -// } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaManager.java index fe9978d5858..5d583954ca0 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/SchemaManager.java @@ -16,87 +16,202 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema; +import static org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils.isAnyField; +import static org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils.isWrapProperty; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.bean.MapGetter; +import org.apache.servicecomb.foundation.common.utils.bean.MapSetter; import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.BoolSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.BytesSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.DoubleSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.Fixed32Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.Fixed64Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.FloatSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.Int32Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.Int64Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.SFixed32Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.SFixed64Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.SInt32Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.SInt64Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.StringSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.UInt32Schema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.scalar.UInt64Schema; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnySchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.map.MapEntry; +import org.apache.servicecomb.foundation.protobuf.internal.schema.map.MapSchema; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.protostuff.SchemaEx; import io.protostuff.compiler.model.Field; -import io.protostuff.compiler.model.FieldContainer; import io.protostuff.compiler.model.Message; import io.protostuff.compiler.model.Proto; -import io.protostuff.compiler.model.ScalarFieldType; -import io.protostuff.runtime.MessageSchema; +import io.protostuff.runtime.FieldMapEx; +import io.protostuff.runtime.FieldSchema; -public class SchemaManager { +public abstract class SchemaManager { protected final ProtoMapper protoMapper; protected final Proto proto; + // key is canonical message name + ":" + canonical type name + protected final Map> canonicalSchemas = new ConcurrentHashMapEx<>(); + + // key is canonical message name + ":" + canonical type name + protected final Map> canonicalSchemasCreated = new ConcurrentHashMapEx<>(); + public SchemaManager(ProtoMapper protoMapper) { this.protoMapper = protoMapper; this.proto = protoMapper.getProto(); } - protected boolean isAnyField(Field protoField, boolean repeated) { - return !repeated && protoField.getType().getCanonicalName().equals(ProtoConst.ANY.getCanonicalName()); + protected String generateCacheKey(Message message, JavaType javaType) { + return message.getCanonicalName() + ":" + javaType.toCanonical(); + } + + protected abstract SchemaEx newMessageSchema(Message message, JavaType javaType); + + protected abstract SchemaEx newMessageSchema(Message message, Map types); + + protected abstract FieldSchema createScalarField(Field protoField, PropertyDescriptor propertyDescriptor); + + @SuppressWarnings("unchecked") + protected SchemaEx getOrCreateMessageSchema(Message message, Map types) { + String cacheKey = generateCacheKey(message, ProtoConst.MAP_TYPE); + return (SchemaEx) canonicalSchemasCreated.computeIfAbsent(cacheKey, key -> createMessageSchema(message, types)); + } + + @SuppressWarnings("unchecked") + protected SchemaEx getOrCreateMessageSchema(Message message, JavaType javaType) { + String cacheKey = generateCacheKey(message, javaType); + return (SchemaEx) canonicalSchemasCreated.computeIfAbsent(cacheKey, + key -> createMessageSchema(message, javaType)); + } + + @SuppressWarnings("unchecked") + protected SchemaEx createMessageSchema(Message message, Map types) { + String cacheKey = generateCacheKey(message, ProtoConst.MAP_TYPE); + SchemaEx schema = (SchemaEx) canonicalSchemas.get(cacheKey); + if (schema != null) { + return schema; + } + + schema = newMessageSchema(message, types); + canonicalSchemas.put(cacheKey, schema); + + schema.init(); + return schema; } - public boolean isWrapProperty(FieldContainer fieldContainer) { - return fieldContainer.getCommentLines().contains(ProtoConst.ANNOTATION_WRAP_PROPERTY); + @SuppressWarnings("unchecked") + protected SchemaEx createMessageSchema(Message message, JavaType javaType) { + String cacheKey = generateCacheKey(message, javaType); + SchemaEx schema = (SchemaEx) canonicalSchemas.get(cacheKey); + if (schema != null) { + return schema; + } + + schema = newMessageSchema(message, javaType); + canonicalSchemas.put(cacheKey, schema); + + schema.init(); + return schema; } - protected MessageSchema newMessageSchema(Message message) { - return new MessageSchema(); + protected FieldSchema createMapFieldSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (javaType.isJavaLangObject()) { + javaType = ProtoConst.MAP_TYPE; + } + + JavaType entryType = TypeFactory.defaultInstance().constructParametricType(MapEntry.class, + javaType.getKeyType(), + javaType.getContentType()); + SchemaEx> entrySchema = createMessageSchema((Message) protoField.getType(), + entryType); + return new MapSchema<>(protoField, propertyDescriptor, entrySchema); } - protected FieldSchema createScalarField(Field protoField) { - switch ((ScalarFieldType) protoField.getType()) { - case INT32: - return new Int32Schema(protoField); - case UINT32: - return new UInt32Schema(protoField); - case SINT32: - return new SInt32Schema(protoField); - case FIXED32: - return new Fixed32Schema(protoField); - case SFIXED32: - return new SFixed32Schema(protoField); - case INT64: - return new Int64Schema(protoField); - case UINT64: - return new UInt64Schema(protoField); - case SINT64: - return new SInt64Schema(protoField); - case FIXED64: - return new Fixed64Schema(protoField); - case SFIXED64: - return new SFixed64Schema(protoField); - case FLOAT: - return new FloatSchema(protoField); - case DOUBLE: - return new DoubleSchema(protoField); - case BOOL: - return new BoolSchema(protoField); - case STRING: - return new StringSchema(protoField); - case BYTES: - return new BytesSchema(protoField); - default: - throw new IllegalStateException("unknown proto field type: " + protoField.getType()); + // normal message write from or read to a map + public FieldMapEx> createMapFields(Message message) { + List>> fieldSchemas = new ArrayList<>(); + for (Field protoField : message.getFields()) { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(); + propertyDescriptor.setJavaType(ProtoConst.OBJECT_TYPE); + propertyDescriptor.setGetter(new MapGetter<>(protoField.getName())); + propertyDescriptor.setSetter(new MapSetter<>(protoField.getName())); + + FieldSchema> fieldSchema = createSchemaField(protoField, propertyDescriptor); + fieldSchemas.add(fieldSchema); } + + return FieldMapEx.createFieldMap(fieldSchemas); } + + public FieldMapEx> createMapFields(Message message, Map types) { + List>> fieldSchemas = new ArrayList<>(); + for (Field protoField : message.getFields()) { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(); + + JavaType javaType = getParameterType(types, protoField.getName()); + if (javaType.isPrimitive()) { + javaType = TypeFactory.defaultInstance().constructType(ClassUtils.primitiveToWrapper(javaType.getRawClass())); + } + propertyDescriptor.setJavaType(javaType); + propertyDescriptor.setGetter(new MapGetter<>(protoField.getName())); + propertyDescriptor.setSetter(new MapSetter<>(protoField.getName())); + + FieldSchema> fieldSchema = createSchemaField(protoField, propertyDescriptor); + fieldSchemas.add(fieldSchema); + } + + return FieldMapEx.createFieldMap(fieldSchemas); + } + + private JavaType getParameterType(Map types, String parameterName) { + + if (types.get(parameterName) != null) { + return TypeFactory.defaultInstance().constructType(types.get(parameterName)); + } + + throw new IllegalArgumentException( + String.format("not found type info for parameter name [%s]", parameterName)); + } + + public FieldSchema createSchemaField(Field protoField, PropertyDescriptor propertyDescriptor) { + // map is a special repeated + if (protoField.isMap()) { + return createMapFieldSchema(protoField, propertyDescriptor); + } + + if (protoField.isRepeated()) { + return createRepeatedSchema(protoField, propertyDescriptor); + } + + if (isAnyField(protoField)) { + return new AnySchema<>(protoMapper, protoField, propertyDescriptor); + } + + if (protoField.getType().isScalar()) { + return createScalarField(protoField, propertyDescriptor); + } + + // message + if (protoField.getType().isMessage()) { + SchemaEx messageSchema = createMessageSchema((Message) protoField.getType(), + propertyDescriptor.getJavaType()); + if (isWrapProperty((Message) protoField.getType())) { + return new PropertyWrapperAsFieldSchema<>(protoField, propertyDescriptor, messageSchema); + } + + return new MessageAsFieldSchema<>(protoField, propertyDescriptor, messageSchema); + } + + if (protoField.isOneofPart()) { + throw new IllegalStateException("not IMPL oneof now."); + } + + ProtoUtils.throwNotSupportWrite(protoField, propertyDescriptor.getJavaType().getRawClass()); + return null; + } + + protected abstract FieldSchema createRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor); } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntry.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntry.java similarity index 99% rename from foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntry.java rename to foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntry.java index afd5307a2ab..36178def784 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/AnyEntry.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntry.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.foundation.protobuf.internal.schema; +package org.apache.servicecomb.foundation.protobuf.internal.schema.any; public class AnyEntry { private String typeUrl; diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java new file mode 100644 index 00000000000..4fc8fd5e58a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnyEntrySchema.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.any; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.SchemaWriter; +import io.protostuff.WireFormat; +import io.protostuff.compiler.model.Message; + +public class AnyEntrySchema implements SchemaEx { + private final ProtoMapper protoMapper; + + // key is message short name + private final Map> anyEntrySserializers = new ConcurrentHashMapEx<>(); + + // key is message canonical name + private final Map> rootDeserializers = new ConcurrentHashMapEx<>(); + + private final int keyTag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); + + private final int valueTag = WireFormat.makeTag(2, WireFormat.WIRETYPE_LENGTH_DELIMITED); + + private final Type anyTargetType; + + public AnyEntrySchema(ProtoMapper protoMapper, Type type) { + this.protoMapper = protoMapper; + this.anyTargetType = type; + } + + @Override + public void init() { + + } + + @Override + public Object newMessage() { + return new PropertyWrapper<>(); + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public void mergeFrom(InputEx input, Object message) throws IOException { + input.readFieldNumber(); + String typeUrl = input.readString(); + + input.readFieldNumber(); + byte[] bytes = input.readByteArray(); + + input.readFieldNumber(); + + if (message instanceof PropertyWrapper) { + if (typeUrl.startsWith(ProtoConst.PACK_SCHEMA)) { + ((PropertyWrapper) message).setValue(standardUnpack(typeUrl, bytes)); + } else { + ((PropertyWrapper) message).setValue(jsonExtendMergeFrom(typeUrl, bytes)); + } + } else if (message instanceof AnyEntry) { + ((AnyEntry) message).setTypeUrl(typeUrl); + ((AnyEntry) message).setValue(bytes); + } + } + + public Object deserialize(InputEx input) throws IOException { + AnyEntry anyEntry = new AnyEntry(); + input.mergeObject(anyEntry, this); + + if (anyEntry.getTypeUrl().startsWith(ProtoConst.PACK_SCHEMA)) { + return standardUnpack(anyEntry.getTypeUrl(), anyEntry.getValue()); + } + + return jsonExtendMergeFrom(anyEntry.getTypeUrl(), anyEntry.getValue()); + } + + @SuppressWarnings("unchecked") + protected Object standardUnpack(String typeUrl, byte[] bytes) throws IOException { + String msgCanonicalName = typeUrl.substring(ProtoConst.PACK_SCHEMA.length()); + RootDeserializer valueDeserializer = rootDeserializers + .computeIfAbsent(msgCanonicalName, this::createRootDeserializerFromCanonicaName); + Object value = valueDeserializer.deserialize(bytes); + if (value instanceof Map) { + ((Map) value).put(ProtoConst.JSON_ID_NAME, valueDeserializer.getSchema().messageName()); + } + return value; + } + + protected RootDeserializer createRootDeserializerFromCanonicaName(String msgCanonicalName) { + Message message = protoMapper.getMessageFromCanonicaName(msgCanonicalName); + if (message == null) { + throw new IllegalStateException( + "can not find proto message to create deserializer, name=" + msgCanonicalName); + } + + JavaType javaType = protoMapper.getAnyTypes() + .getOrDefault(msgCanonicalName, constructRuntimeType(ProtoConst.MAP_TYPE)); + return protoMapper.createRootDeserializer(message, javaType); + } + + protected Object jsonExtendMergeFrom(String typeUrl, byte[] bytes) throws IOException { + try { + return protoMapper.getJsonMapper() + .readValue(bytes, Class.forName(typeUrl.substring(ProtoConst.JSON_SCHEMA.length()))); + } catch (ClassNotFoundException e) { + return protoMapper.getJsonMapper() + .readValue(bytes, constructRuntimeType(ProtoConst.OBJECT_TYPE)); + } + } + + private JavaType constructRuntimeType(JavaType defaultType) { + if (this.anyTargetType == null) { + return defaultType; + } else { + return TypeFactory.defaultInstance().constructType(anyTargetType); + } + } + + protected String getInputActualTypeName(Object input) { + if (!(input instanceof Map)) { + return input.getClass().getSimpleName(); + } + + // @JsonTypeInfo(use = Id.NAME) + Object actualTypeName = ((Map) input).get(ProtoConst.JSON_ID_NAME); + if (actualTypeName instanceof String) { + return (String) actualTypeName; + } + + return null; + } + + /** + *
+   * if message is type of CustomGeneric<User>
+   * we can not get any information of "User" from message.getClass()
+   *
+   * when use with ServiceComb
+   * proto definition convert from swagger, the proto type will be "CustomGenericUser"
+   * is not match to "CustomGeneric"
+   * so message will be serialized with json schema
+   * 
+ * @param output + * @param value + * @throws IOException + */ + @Override + public void writeTo(OutputEx output, Object value) throws IOException { + String actualTypeName = getInputActualTypeName(value); + SchemaWriter entryWriter = actualTypeName == null ? this::jsonExtend : anyEntrySserializers + .computeIfAbsent(actualTypeName, n -> createEntryWriter(n, value)); + entryWriter.writeTo(output, value); + } + + private SchemaWriter createEntryWriter(String actualTypeName, Object _value) { + Message message = protoMapper.getProto().getMessage(actualTypeName); + if (message == null) { + // not standard, protobuf can not support or not define this type , just extend + return this::jsonExtend; + } + + // standard pack + RootSerializer valueSerializer = protoMapper.createRootSerializer(message, _value.getClass()); + String valueCanonicalName = message.getCanonicalName(); + return (output, value) -> standardPack(output, value, valueCanonicalName, valueSerializer); + } + + protected void standardPack(OutputEx output, Object message, String canonicalName, RootSerializer valueSerializer) + throws IOException { + output.writeString(keyTag, 1, ProtoConst.PACK_SCHEMA + canonicalName); + + byte[] bytes = valueSerializer.serialize(message); + output.writeByteArray(valueTag, 1, bytes); + } + + protected void jsonExtend(OutputEx output, Object input) throws IOException { + output.writeString(keyTag, 1, ProtoConst.JSON_SCHEMA + input.getClass().getName()); + + byte[] bytes = protoMapper.getJsonMapper().writeValueAsBytes(input); + output.writeByteArray(valueTag, 1, bytes); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java new file mode 100644 index 00000000000..87cbba9633c --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/any/AnySchema.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.any; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class AnySchema extends FieldSchema { + private final AnyEntrySchema anyEntrySchema; + + private final Getter getter; + + private final Setter setter; + + public AnySchema(ProtoMapper protoMapper, Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + + this.anyEntrySchema = new AnyEntrySchema(protoMapper, null); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public final int mergeFrom(InputEx input, T message) throws IOException { + Object anyValue = anyEntrySchema.deserialize(input); + setter.set(message, anyValue); + + return input.readFieldNumber(); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + Object anyEntry = getter.get(message); + if (anyEntry == null) { + return; + } + + output.writeObject(tag, tagSize, anyEntry, anyEntrySchema); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + output.writeObject(tag, tagSize, value, anyEntrySchema); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java index 1bfb0d58b5c..23b9d85a01d 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/DeserializerSchemaManager.java @@ -16,181 +16,247 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; +import static org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils.isWrapProperty; + +import java.lang.reflect.Type; import java.util.Map; -import org.apache.servicecomb.foundation.common.utils.bean.MapGetter; -import org.apache.servicecomb.foundation.common.utils.bean.MapSetter; +import org.apache.servicecomb.foundation.common.utils.TypesUtil; import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; -import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptor; -import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanFactory; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; -import org.apache.servicecomb.foundation.protobuf.internal.schema.AnySchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.MapSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.MessageAsFieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.PropertyWrapMessageAsFieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.RepeatedSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.SchemaCreateContext; import org.apache.servicecomb.foundation.protobuf.internal.schema.SchemaManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnyEntrySchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.AnyRepeatedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.BytesRepeatedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.MessageRepeatedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.PropertyWrapperRepeatedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.StringRepeatedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.impl.BoolNotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.impl.BoolPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.impl.DoubleNotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.impl.DoublePackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.enums.EnumNotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.enums.EnumPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.impl.FloatNotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.impl.FloatPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.Fixed32NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.Fixed32PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.Int32NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.Int32PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.SFixed32NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.SFixed32PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.SInt32NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.SInt32PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.UInt32NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl.UInt32PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.Fixed64NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.Fixed64PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.Int64NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.Int64PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.SFixed64NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.SFixed64PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.SInt64NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.SInt64PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.UInt64NotPackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl.UInt64PackedReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.BoolReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.BytesReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.DoubleReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.EnumsReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.Fixed32ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.Fixed64ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.FloatReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.Int32ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.Int64ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.SFixed32ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.SFixed64ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.SInt32ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.SInt64ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.StringReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.UInt32ReadSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.UInt64ReadSchemas; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; +import io.protostuff.SchemaEx; import io.protostuff.compiler.model.Field; import io.protostuff.compiler.model.Message; -import io.protostuff.runtime.MessageSchema; -import io.protostuff.runtime.RuntimeEnv; +import io.protostuff.compiler.model.ScalarFieldType; +import io.protostuff.runtime.FieldSchema; public class DeserializerSchemaManager extends SchemaManager { - private static final Logger LOGGER = LoggerFactory.getLogger(DeserializerSchemaManager.class); - public DeserializerSchemaManager(ProtoMapper protoMapper) { super(protoMapper); } - public RootDeserializer createRootDeserializer(JavaType javaType, String shortMessageName) { - Message message = proto.getMessage(shortMessageName); - if (message == null) { - throw new IllegalStateException("can not find proto message to create deserializer, name=" + shortMessageName); - } - - return createRootDeserializer(javaType, message); - } - - public RootDeserializer createRootDeserializer(JavaType javaType, Message message) { - SchemaCreateContext context = new SchemaCreateContext(); - MessageSchema schema = createSchema(context, javaType, message); - - BeanDescriptor beanDescriptor = protoMapper.getBeanDescriptorManager().getOrCreateBeanDescriptor(javaType); - return new RootDeserializer(beanDescriptor, schema); + public RootDeserializer createRootDeserializer(Message message, Map types) { + SchemaEx messageSchema = getOrCreateMessageSchema(message, types); + return new RootDeserializer<>(messageSchema); } - public MessageSchema createSchema(SchemaCreateContext context, JavaType javaType, Message message) { - MessageSchema schema = context.getSchemas().get(message.getName()); - if (schema != null) { - return schema; + @SuppressWarnings({"rawtypes", "unchecked"}) + public RootDeserializer createRootDeserializer(Message message, Type type) { + if (ProtoUtils.isAnyMessage(message)) { + SchemaEx messageSchema = new AnyEntrySchema(protoMapper, type); + return new RootDeserializer(messageSchema); } - - schema = newMessageSchema(message); - context.getSchemas().put(message.getName(), schema); - - doCreateSchema(context, schema, javaType, message); - return schema; + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + SchemaEx messageSchema = getOrCreateMessageSchema(message, javaType); + return new RootDeserializer<>(messageSchema); } - @SuppressWarnings("unchecked") - protected void doCreateSchema(SchemaCreateContext context, MessageSchema schema, - JavaType javaType, - Message message) { - if (javaType.isJavaLangObject()) { - javaType = TypeFactory.defaultInstance().constructType(Map.class); - } - if (Map.class.isAssignableFrom(javaType.getRawClass())) { - doCreateSchemaToMap(context, schema, javaType, message); - return; - } + @Override + protected SchemaEx newMessageSchema(Message message, Map types) { + return new MessageReadSchema<>(protoMapper, message, types); + } - if (isWrapProperty(message) && (!javaType.getRawClass().equals(PropertyWrapper.class))) { - javaType = TypeFactory.defaultInstance().constructParametricType(PropertyWrapper.class, javaType); - } - BeanDescriptor beanDescriptor = protoMapper.getBeanDescriptorManager().getOrCreateBeanDescriptor(javaType); - - List> fieldSchemas = new ArrayList<>(); - for (PropertyDescriptor propertyDescriptor : beanDescriptor.getPropertyDescriptors().values()) { - Field protoField = message.getField(propertyDescriptor.getName()); - if (protoField == null) { - LOGGER.info("java field {}:{} not exist in proto message {}, ignore it.", - beanDescriptor.getJavaType().getRawClass().getName(), - propertyDescriptor.getName(), message.getCanonicalName()); - continue; - } - if (propertyDescriptor.getSetter() == null) { - LOGGER.info("no setter for java field {}:{} in proto message {}, ignore it.", - beanDescriptor.getJavaType().getRawClass().getName(), - propertyDescriptor.getName(), message.getCanonicalName()); - continue; + @Override + protected SchemaEx newMessageSchema(Message message, JavaType javaType) { + if (ProtoUtils.isWrapProperty(message) && javaType.getRawClass() != PropertyWrapper.class) { + Field protoField = message.getField(1); + if (javaType.isJavaLangObject()) { + javaType = + protoField.isRepeated() && !protoField.isMap() ? ProtoConst.LIST_TYPE + : ProtoConst.MAP_TYPE; } - FieldSchema fieldSchema = createSchemaField(context, propertyDescriptor.getJavaType(), protoField, - protoField.isRepeated()); - fieldSchema.setGetter(propertyDescriptor.getGetter()); - fieldSchema.setSetter(propertyDescriptor.getSetter()); - if (isAnyField(protoField, protoField.isRepeated())) { - fieldSchema.setFactory(BeanFactory::mapFactory); + if (javaType.isPrimitive()) { + javaType = TypeFactory.defaultInstance() + .constructParametricType(PropertyWrapper.class, TypesUtil.primitiveJavaTypeToWrapper(javaType)); } else { - fieldSchema.setFactory(propertyDescriptor.getFactory()); + javaType = TypeFactory.defaultInstance().constructParametricType(PropertyWrapper.class, javaType); } - fieldSchemas.add(fieldSchema); } - schema.init(protoMapper, (Class) javaType.getRawClass(), - fieldSchemas, - RuntimeEnv.newInstantiator((Class) javaType.getRawClass()), message); - } - - @SuppressWarnings("unchecked") - protected void doCreateSchemaToMap(SchemaCreateContext context, - MessageSchema schema, JavaType mapJavaType, - Message message) { - List> fieldSchemas = new ArrayList<>(); - for (Field protoField : message.getFields()) { - FieldSchema fieldSchema = createSchemaField(context, mapJavaType, protoField, protoField.isRepeated()); - fieldSchema.setGetter(new MapGetter(protoField.getName())); - fieldSchema.setSetter(new MapSetter(protoField.getName())); - fieldSchema.setFactory(BeanFactory.createFactory(protoField)); - fieldSchemas.add(fieldSchema); + if (javaType.isJavaLangObject()) { + javaType = ProtoConst.MAP_TYPE; } - schema.init(protoMapper, (Class) mapJavaType.getRawClass(), - fieldSchemas, - RuntimeEnv.newInstantiator((Class) (Object) LinkedHashMap.class), message); + return new MessageReadSchema<>(protoMapper, message, javaType); } - protected FieldSchema createSchemaField(SchemaCreateContext context, JavaType javaType, Field protoField, - boolean repeated) { - if (protoField.isMap()) { - Message entryMessage = (Message) protoField.getType(); - FieldSchema keySchema = createSchemaField(context, javaType.getKeyType(), entryMessage.getField(1), false); - FieldSchema valueSchema = createSchemaField(context, javaType.getContentType(), entryMessage.getField(2), false); - return new MapSchema(protoField, keySchema, valueSchema); + protected FieldSchema createScalarField(Field protoField, PropertyDescriptor propertyDescriptor) { + if (protoField.getType().isEnum()) { + return EnumsReadSchemas.create(protoField, propertyDescriptor); } - if (protoField.isOneofPart()) { - throw new IllegalStateException("not IMPL oneof now."); + switch ((ScalarFieldType) protoField.getType()) { + case INT32: + return Int32ReadSchemas.create(protoField, propertyDescriptor); + case UINT32: + return UInt32ReadSchemas.create(protoField, propertyDescriptor); + case SINT32: + return SInt32ReadSchemas.create(protoField, propertyDescriptor); + case FIXED32: + return Fixed32ReadSchemas.create(protoField, propertyDescriptor); + case SFIXED32: + return SFixed32ReadSchemas.create(protoField, propertyDescriptor); + case INT64: + return Int64ReadSchemas.create(protoField, propertyDescriptor); + case UINT64: + return UInt64ReadSchemas.create(protoField, propertyDescriptor); + case SINT64: + return SInt64ReadSchemas.create(protoField, propertyDescriptor); + case FIXED64: + return Fixed64ReadSchemas.create(protoField, propertyDescriptor); + case SFIXED64: + return SFixed64ReadSchemas.create(protoField, propertyDescriptor); + case FLOAT: + return FloatReadSchemas.create(protoField, propertyDescriptor); + case DOUBLE: + return DoubleReadSchemas.create(protoField, propertyDescriptor); + case BOOL: + return BoolReadSchemas.create(protoField, propertyDescriptor); + case STRING: + return StringReadSchemas.create(protoField, propertyDescriptor); + case BYTES: + return BytesReadSchemas.create(protoField, propertyDescriptor); + default: + throw new IllegalStateException("unknown proto field type: " + protoField.getType()); } + } - if (repeated) { - FieldSchema schema = createSchemaField(context, javaType.getContentType(), protoField, false); - return new RepeatedSchema(protoField, schema); + @Override + protected FieldSchema createRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + boolean packed = ProtoUtils.isPacked(protoField); + if (protoField.getType().isEnum()) { + return packed ? EnumPackedReadSchemas.create(protoField, propertyDescriptor) : + EnumNotPackedReadSchemas.create(protoField, propertyDescriptor); } - if (isAnyField(protoField, repeated)) { - return new AnySchema(protoMapper, protoField); + if (protoField.getType().isScalar()) { + switch ((ScalarFieldType) protoField.getType()) { + case INT32: + return packed ? Int32PackedReadSchemas.create(protoField, propertyDescriptor) : + Int32NotPackedReadSchemas.create(protoField, propertyDescriptor); + case UINT32: + return packed ? UInt32PackedReadSchemas.create(protoField, propertyDescriptor) : + UInt32NotPackedReadSchemas.create(protoField, propertyDescriptor); + case SINT32: + return packed ? SInt32PackedReadSchemas.create(protoField, propertyDescriptor) : + SInt32NotPackedReadSchemas.create(protoField, propertyDescriptor); + case FIXED32: + return packed ? Fixed32PackedReadSchemas.create(protoField, propertyDescriptor) : + Fixed32NotPackedReadSchemas.create(protoField, propertyDescriptor); + case SFIXED32: + return packed ? SFixed32PackedReadSchemas.create(protoField, propertyDescriptor) : + SFixed32NotPackedReadSchemas.create(protoField, propertyDescriptor); + case INT64: + return packed ? Int64PackedReadSchemas.create(protoField, propertyDescriptor) : + Int64NotPackedReadSchemas.create(protoField, propertyDescriptor); + case UINT64: + return packed ? UInt64PackedReadSchemas.create(protoField, propertyDescriptor) : + UInt64NotPackedReadSchemas.create(protoField, propertyDescriptor); + case SINT64: + return packed ? SInt64PackedReadSchemas.create(protoField, propertyDescriptor) : + SInt64NotPackedReadSchemas.create(protoField, propertyDescriptor); + case FIXED64: + return packed ? Fixed64PackedReadSchemas.create(protoField, propertyDescriptor) : + Fixed64NotPackedReadSchemas.create(protoField, propertyDescriptor); + case SFIXED64: + return packed ? SFixed64PackedReadSchemas.create(protoField, propertyDescriptor) : + SFixed64NotPackedReadSchemas.create(protoField, propertyDescriptor); + case FLOAT: + return packed ? FloatPackedReadSchemas.create(protoField, propertyDescriptor) : + FloatNotPackedReadSchemas.create(protoField, propertyDescriptor); + case DOUBLE: + return packed ? DoublePackedReadSchemas.create(protoField, propertyDescriptor) : + DoubleNotPackedReadSchemas.create(protoField, propertyDescriptor); + case BOOL: + return packed ? BoolPackedReadSchemas.create(protoField, propertyDescriptor) : + BoolNotPackedReadSchemas.create(protoField, propertyDescriptor); + case STRING: + return StringRepeatedReadSchemas.create(protoField, propertyDescriptor); + case BYTES: + return BytesRepeatedReadSchemas.create(protoField, propertyDescriptor); + default: + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + } } - if (protoField.getType().isEnum()) { - return new EnumDeserializerSchema(protoField, javaType); + if (ProtoUtils.isAnyField(protoField)) { + AnyEntrySchema anyEntrySchema = new AnyEntrySchema(protoMapper, null); + return AnyRepeatedReadSchemas.create(protoField, propertyDescriptor, anyEntrySchema); } - if (protoField.getType().isScalar()) { - return createScalarField(protoField); - } + if (protoField.getType().isMessage()) { + JavaType contentType = propertyDescriptor.getJavaType().getContentType(); + if (contentType == null) { + contentType = ProtoConst.OBJECT_TYPE; + } + SchemaEx contentSchema = createMessageSchema((Message) protoField.getType(), contentType); + if (isWrapProperty((Message) protoField.getType())) { + return PropertyWrapperRepeatedReadSchemas.create(protoField, propertyDescriptor, contentSchema); + } - // message - MessageSchema messageSchema = createSchema(context, javaType, (Message) protoField.getType()); - MessageAsFieldSchema messageAsFieldSchema; - if (isWrapProperty((Message) protoField.getType())) { - messageAsFieldSchema = new PropertyWrapMessageAsFieldSchema(protoField, messageSchema); - } else { - messageAsFieldSchema = new MessageAsFieldSchema(protoField, messageSchema); + return MessageRepeatedReadSchemas.create(protoField, propertyDescriptor, contentSchema); } - return messageAsFieldSchema; + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/EnumDeserializerSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/EnumDeserializerSchema.java deleted file mode 100644 index 943372dab88..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/EnumDeserializerSchema.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import com.fasterxml.jackson.databind.JavaType; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; -import io.protostuff.compiler.model.Type; - -public class EnumDeserializerSchema extends FieldSchema { - private final JavaType javaType; - - private Map> enumValues = new HashMap<>(); - - public EnumDeserializerSchema(Field protoField, JavaType javaType) { - super(protoField); - this.javaType = javaType; - - if (!javaType.isEnumType()) { - return; - } - - try { - Method method = javaType.getRawClass().getMethod("values"); - method.setAccessible(true); - Object[] values = (Object[]) method.invoke(null); - for (Object value : values) { - Enum enumValue = (Enum) value; - enumValues.put(enumValue.ordinal(), enumValue); - } - } catch (Throwable e) { - throw new IllegalStateException( - "Failed to collect enum values, class=" + javaType.getRawClass().getName(), e); - } - } - - @Override - public void writeTo(Output output, Object message) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public Object readFrom(Input input) throws IOException { - int ordinal = input.readInt32(); - if (javaType.isEnumType()) { - return enumValues.get(ordinal); - } - - return ordinal; - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - int ordinal = input.readInt32(); - - if (javaType.isEnumType()) { - Enum enumValue = enumValues.get(ordinal); - if (enumValue != null) { - setter.set(message, enumValue); - return; - } - - throw new IllegalStateException( - String.format("invalid enum ordinal value %d for %s, proto field=%s:%s", - ordinal, - javaType.getRawClass().getName(), - ((Type) protoField.getParent()).getCanonicalName(), - protoField.getName())); - } - - setter.set(message, ordinal); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/MessageReadSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/MessageReadSchema.java new file mode 100644 index 00000000000..68990c29865 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/MessageReadSchema.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Message; +import io.protostuff.runtime.FieldMapEx; +import io.protostuff.runtime.FieldSchema; +import io.protostuff.runtime.RuntimeEnv; +import io.protostuff.runtime.RuntimeEnv.Instantiator; + +/** + *
+ * map.put("user", new User())
+ * root write from map, but user should write from pojo
+ * so one schema should support dynamic and concrete logic at the same time
+ * 
+ */ +public class MessageReadSchema implements SchemaEx { + private static final Logger LOGGER = LoggerFactory.getLogger(MessageReadSchema.class); + + protected final ProtoMapper protoMapper; + + protected final Message message; + + private FieldMapEx fieldMap; + + private final Instantiator instantiator; + + private JavaType javaType; + + Map argumentsTypes; + + private boolean argumentsRoot = false; + + @SuppressWarnings("unchecked") + public MessageReadSchema(ProtoMapper protoMapper, Message message, Map argumentsTypes) { + this.argumentsRoot = true; + this.protoMapper = protoMapper; + this.message = message; + this.argumentsTypes = argumentsTypes; + this.instantiator = RuntimeEnv.newInstantiator((Class) ProtoConst.MAP_TYPE.getRawClass()); + } + + @SuppressWarnings("unchecked") + public MessageReadSchema(ProtoMapper protoMapper, Message message, JavaType javaType) { + this.protoMapper = protoMapper; + this.message = message; + this.javaType = javaType; + if (javaType.isJavaLangObject() || Map.class.isAssignableFrom(javaType.getRawClass())) { + javaType = ProtoConst.MAP_TYPE; + } + this.instantiator = RuntimeEnv.newInstantiator((Class) javaType.getRawClass()); + } + + public Message getMessage() { + return message; + } + + @Override + public T newMessage() { + return instantiator.newInstance(); + } + + @Override + public String messageName() { + return message.getName(); + } + + public FieldMapEx getFieldMap() { + return fieldMap; + } + + @SuppressWarnings("unchecked") + @Override + public void init() { + if (argumentsRoot) { + this.fieldMap = (FieldMapEx) protoMapper.getDeserializerSchemaManager() + .createMapFields(message, argumentsTypes); + return; + } + + if (Map.class.isAssignableFrom(javaType.getRawClass())) { + this.fieldMap = (FieldMapEx) protoMapper.getDeserializerSchemaManager() + .createMapFields(message); + return; + } + + this.createFieldMap(); + } + + private void createFieldMap() { + DeserializerSchemaManager deserializerSchemaManager = protoMapper.getDeserializerSchemaManager(); + BeanDescriptor beanDescriptor = protoMapper.getBeanDescriptorManager().getOrCreateBeanDescriptor(javaType); + + List> fieldSchemas = new ArrayList<>(); + for (PropertyDescriptor propertyDescriptor : beanDescriptor.getPropertyDescriptors().values()) { + Field protoField = message.getField(propertyDescriptor.getName()); + if (protoField == null) { + LOGGER.info("java field {}:{} not exist in proto message {}, ignore it.", + beanDescriptor.getJavaType().getRawClass().getName(), + propertyDescriptor.getName(), message.getCanonicalName()); + continue; + } + if (propertyDescriptor.getSetter() == null) { + LOGGER.info("no setter for java field {}:{} in proto message {}, ignore it.", + beanDescriptor.getJavaType().getRawClass().getName(), + propertyDescriptor.getName(), message.getCanonicalName()); + continue; + } + + FieldSchema fieldSchema = deserializerSchemaManager.createSchemaField(protoField, propertyDescriptor); + fieldSchemas.add(fieldSchema); + } + + this.fieldMap = FieldMapEx.createFieldMap(fieldSchemas); + } + + @Override + public void mergeFrom(InputEx input, T message) throws IOException { + FieldSchema fieldSchema = null; + try { + for (int n = input.readFieldNumber(); n != 0; ) { + fieldSchema = fieldMap.getFieldByNumber(n); + if (fieldSchema != null) { + n = fieldSchema.mergeFrom(input, message); + continue; + } + + input.handleUnknownField(n); + n = input.readFieldNumber(); + } + } catch (Throwable e) { + if (fieldSchema != null) { + Field protoField = fieldSchema.getProtoField(); + LOGGER.error("Failed to mergeFrom, field={}:{}, type={}, error {}", + protoField.getType().getCanonicalName(), + protoField.getName(), + protoField.getTypeName(), + e.getMessage()); + } + throw e; + } + } + + @Override + public void writeTo(OutputEx output, Object value) throws IOException { + throw new UnsupportedOperationException(); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractPrimitiveReaders.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractPrimitiveReaders.java new file mode 100644 index 00000000000..e43f6b61d11 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractPrimitiveReaders.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated; + +import io.protostuff.compiler.model.Field; + +public abstract class AbstractPrimitiveReaders extends + AbstractReaders { + public RepeatedReader> primitiveArrayReader; + + @SuppressWarnings("unchecked") + public AbstractPrimitiveReaders(Field protoField) { + super(protoField); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractReaders.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractReaders.java new file mode 100644 index 00000000000..0143c12af70 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/AbstractReaders.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated; + +import static org.apache.servicecomb.foundation.common.utils.ReflectUtils.getFieldArgument; + +import java.util.Collection; + +import io.protostuff.compiler.model.Field; + +public abstract class AbstractReaders { + protected final Field protoField; + + protected final int fieldNumber; + + public RepeatedReader> collectionReader; + + public final Class arrayClass; + + @SuppressWarnings("unchecked") + public AbstractReaders(Field protoField) { + this(protoField, null); + } + + public AbstractReaders(Field protoField, Class arrayClass) { + this.protoField = protoField; + this.fieldNumber = protoField.getTag(); + + if (arrayClass == null) { + arrayClass = getFieldArgument(this.getClass(), "arrayClass"); + } + this.arrayClass = arrayClass; + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/PrimitiveArrayBuilderWrapper.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/PrimitiveArrayBuilderWrapper.java new file mode 100644 index 00000000000..1478e152268 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/PrimitiveArrayBuilderWrapper.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +public class PrimitiveArrayBuilderWrapper { + private final PrimitiveArrayBuilder builder; + + private T array; + + public PrimitiveArrayBuilderWrapper(PrimitiveArrayBuilder builder) { + this.builder = builder; + } + + public T getArray() { + return array; + } + + public void setArray(T array) { + this.array = array; + } + + public PrimitiveArrayBuilder getBuilder() { + return builder; + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReadSchemas.java new file mode 100644 index 00000000000..e03a7efd579 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReadSchemas.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class RepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (readers.arrayClass.isAssignableFrom(javaType.getRawClass())) { + return new ArrayRepeatedSchema<>(protoField, propertyDescriptor, readers); + } + + if (Collection.class.isAssignableFrom(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new CollectionRepeatedSchema<>(protoField, propertyDescriptor, readers); + } + + ProtoUtils.throwNotSupportMerge(protoField, javaType); + return null; + } + + static class AbstractRepeatedSchema extends FieldSchema { + protected final AbstractReaders readers; + + public AbstractRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.readers = readers; + } + } + + static class CollectionRepeatedSchema extends AbstractRepeatedSchema { + private final Getter> getter; + + private final Setter> setter; + + public CollectionRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractReaders readers) { + super(protoField, propertyDescriptor, readers); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public final int mergeFrom(InputEx input, T message) throws IOException { + Collection collection = getter.get(message); + if (collection == null) { + if (Set.class.equals(javaType.getRawClass())) { + collection = new HashSet<>(); + } else { + collection = new ArrayList<>(); + } + setter.set(message, collection); + } + + return readers.collectionReader.read(input, collection); + } + } + + static class ArrayRepeatedSchema extends AbstractRepeatedSchema { + private final Getter getter; + + private final Setter setter; + + public ArrayRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractReaders readers) { + super(protoField, propertyDescriptor, readers); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @SuppressWarnings("unchecked") + @Override + public final int mergeFrom(InputEx input, T message) throws IOException { + ELE_TYPE[] array = getter.get(message); + Collection collection = array == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(array)); + int fieldNumber = readers.collectionReader.read(input, collection); + + ELE_TYPE[] newArray = (ELE_TYPE[]) Array.newInstance(readers.arrayClass.getComponentType(), collection.size()); + setter.set(message, collection.toArray(newArray)); + return fieldNumber; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReader.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReader.java new file mode 100644 index 00000000000..fec171f4483 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/RepeatedReader.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated; + +import java.io.IOException; + +import io.protostuff.InputEx; + +public interface RepeatedReader { + int read(InputEx input, T value) throws IOException; +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java new file mode 100644 index 00000000000..cdfba2a422b --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/AnyRepeatedReadSchemas.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnyEntrySchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class AnyRepeatedReadSchemas { + private static class MessageReaders extends AbstractReaders { + public MessageReaders(Field protoField, AnyEntrySchema anyEntrySchema) { + super(protoField); + + collectionReader = (input, collection) -> { + while (true) { + Object value = anyEntrySchema.deserialize(input); + collection.add(value); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AnyEntrySchema anyEntrySchema) { + return RepeatedReadSchemas.create(protoField, propertyDescriptor, new MessageReaders(protoField, anyEntrySchema)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/BytesRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/BytesRepeatedReadSchemas.java new file mode 100644 index 00000000000..c1534c99851 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/BytesRepeatedReadSchemas.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BytesRepeatedReadSchemas { + private static class BytesReaders extends AbstractReaders { + public BytesReaders(Field protoField) { + super(protoField); + + collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readByteArray()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedReadSchemas.create(protoField, propertyDescriptor, new BytesReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/MessageRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/MessageRepeatedReadSchemas.java new file mode 100644 index 00000000000..7f6dfa7c874 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/MessageRepeatedReadSchemas.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import io.protostuff.SchemaReader; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class MessageRepeatedReadSchemas { + private static class MessageReaders extends AbstractReaders { + public MessageReaders(Field protoField, SchemaReader elementSchema) { + super(protoField); + + collectionReader = (input, collection) -> { + while (true) { + Object value = input.mergeObject(null, elementSchema); + collection.add(value); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaReader elementSchema) { + return RepeatedReadSchemas.create(protoField, propertyDescriptor, new MessageReaders(protoField, elementSchema)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/PropertyWrapperRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/PropertyWrapperRepeatedReadSchemas.java new file mode 100644 index 00000000000..0307fb92d63 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/PropertyWrapperRepeatedReadSchemas.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import io.protostuff.SchemaReader; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class PropertyWrapperRepeatedReadSchemas { + private static class PropertyWrapperReaders extends AbstractReaders { + public PropertyWrapperReaders(Field protoField, SchemaReader elementSchema) { + super(protoField); + + collectionReader = (input, collection) -> { + while (true) { + PropertyWrapper wrapper = new PropertyWrapper<>(); + input.mergeObject(wrapper, elementSchema); + collection.add(wrapper.getValue()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaReader elementSchema) { + return RepeatedReadSchemas + .create(protoField, propertyDescriptor, new PropertyWrapperReaders(protoField, elementSchema)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/StringRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/StringRepeatedReadSchemas.java new file mode 100644 index 00000000000..2f64516f7e4 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/StringRepeatedReadSchemas.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class StringRepeatedReadSchemas { + private static class StringReaders extends AbstractReaders { + public StringReaders(Field protoField) { + super(protoField); + + collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readString()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedReadSchemas.create(protoField, propertyDescriptor, new StringReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/BoolRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/BoolRepeatedReadSchemas.java new file mode 100644 index 00000000000..cca38bbb756 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/BoolRepeatedReadSchemas.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.PrimitiveArrayBuilderWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolRepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (boolean[].class.equals(javaType.getRawClass())) { + return new BoolPrimitiveArray<>(protoField, propertyDescriptor, readers); + } + + return RepeatedReadSchemas.create(protoField, propertyDescriptor, readers); + } + + static class BoolPrimitiveArray extends FieldSchema { + private final Getter getter; + + private final Setter setter; + + private final AbstractPrimitiveReaders readers; + + public BoolPrimitiveArray(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + this.readers = readers; + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PrimitiveArrayBuilderWrapper builderWrapper = new PrimitiveArrayBuilderWrapper<>( + input.getArrayBuilders().getBooleanBuilder()); + + int fieldNumber = readers.primitiveArrayReader.read(input, builderWrapper); + boolean[] newValue = builderWrapper.getArray(); + newValue = mergeArray(getter.get(message), newValue); + setter.set(message, newValue); + + return fieldNumber; + } + + private boolean[] mergeArray(boolean[] oldValue, boolean[] newValue) { + if (oldValue == null || oldValue.length == 0) { + return newValue; + } + + return concatArray(oldValue, newValue); + } + + private boolean[] concatArray(boolean[] oldValue, boolean[] newValue) { + int len1 = oldValue.length; + int len2 = newValue.length; + boolean[] result = Arrays.copyOf(oldValue, len1 + len2); + System.arraycopy(newValue, 0, result, len1, len2); + return result; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolNotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolNotPackedReadSchemas.java new file mode 100644 index 00000000000..1aea9b54636 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolNotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.BoolRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolNotPackedReadSchemas { + private static class BoolNotPackedReaders extends AbstractPrimitiveReaders { + public BoolNotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + boolean[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readBool(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readBool()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return BoolRepeatedReadSchemas.create(protoField, propertyDescriptor, new BoolNotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolPackedReadSchemas.java new file mode 100644 index 00000000000..5eb91e57604 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/bools/impl/BoolPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.bools.BoolRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolPackedReadSchemas { + private static class BoolPackedReaders extends AbstractPrimitiveReaders { + public BoolPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + boolean[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedBool(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedBool()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return BoolRepeatedReadSchemas.create(protoField, propertyDescriptor, new BoolPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/DoubleRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/DoubleRepeatedReadSchemas.java new file mode 100644 index 00000000000..68d8f997168 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/DoubleRepeatedReadSchemas.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.PrimitiveArrayBuilderWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoubleRepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (double[].class.equals(javaType.getRawClass())) { + return new PrimitiveArraySchema<>(protoField, propertyDescriptor, readers); + } + + return RepeatedReadSchemas.create(protoField, propertyDescriptor, readers); + } + + static class PrimitiveArraySchema extends FieldSchema { + private final Getter getter; + + private final Setter setter; + + private final AbstractPrimitiveReaders readers; + + public PrimitiveArraySchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + this.readers = readers; + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PrimitiveArrayBuilderWrapper builderWrapper = new PrimitiveArrayBuilderWrapper<>( + input.getArrayBuilders().getDoubleBuilder()); + + int fieldNumber = readers.primitiveArrayReader.read(input, builderWrapper); + double[] newValue = builderWrapper.getArray(); + newValue = mergeArray(getter.get(message), newValue); + setter.set(message, newValue); + + return fieldNumber; + } + + public double[] mergeArray(double[] oldValue, double[] newValue) { + if (oldValue == null || oldValue.length == 0) { + return newValue; + } + + return concatArray(oldValue, newValue); + } + + private double[] concatArray(double[] oldValue, double[] newValue) { + int len1 = oldValue.length; + int len2 = newValue.length; + double[] result = Arrays.copyOf(oldValue, len1 + len2); + System.arraycopy(newValue, 0, result, len1, len2); + return result; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoubleNotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoubleNotPackedReadSchemas.java new file mode 100644 index 00000000000..67d4c35ac00 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoubleNotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.DoubleRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoubleNotPackedReadSchemas { + private static class NotPackedReaders extends AbstractPrimitiveReaders { + public NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + double[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readDouble(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readDouble()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return DoubleRepeatedReadSchemas.create(protoField, propertyDescriptor, new NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoublePackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoublePackedReadSchemas.java new file mode 100644 index 00000000000..e2608f43b9e --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/doubles/impl/DoublePackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.doubles.DoubleRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoublePackedReadSchemas { + private static class DoublePackedReaders extends AbstractPrimitiveReaders { + public DoublePackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + double[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedDouble(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedDouble()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return DoubleRepeatedReadSchemas.create(protoField, propertyDescriptor, new DoublePackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumNotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumNotPackedReadSchemas.java new file mode 100644 index 00000000000..a05f3ad671d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumNotPackedReadSchemas.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.enums; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumNotPackedReadSchemas { + private static class EnumNotPackedReaders extends AbstractReaders> { + private final EnumMeta enumMeta; + + public EnumNotPackedReaders(Field protoField, JavaType javaType) { + super(protoField, EnumSchemaUtils.constructEnumArrayClass(javaType)); + this.enumMeta = new EnumMeta(protoField, javaType.getContentType()); + + collectionReader = (input, collection) -> { + while (true) { + int value = input.readEnum(); + Enum enumValue = enumMeta.getEnumByValue(value); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum value %d for %s, proto field=%s:%s", + value, + javaType.getRawClass().getName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + collection.add(enumValue); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + private static class EnumIntNotPackedSchema extends FieldSchema { + private final Getter> getter; + + private final Setter> setter; + + public EnumIntNotPackedSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + Collection collection = getter.get(message); + if (collection == null) { + collection = new ArrayList<>(); + setter.set(message, collection); + } + + while (true) { + int value = input.readEnum(); + collection.add(value); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (javaType.isJavaLangObject()) { + return new EnumIntNotPackedSchema<>(protoField, propertyDescriptor); + } + + return RepeatedReadSchemas + .create(protoField, propertyDescriptor, new EnumNotPackedReaders(protoField, propertyDescriptor.getJavaType())); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumPackedReadSchemas.java new file mode 100644 index 00000000000..8a98a18c292 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumPackedReadSchemas.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.enums; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumPackedReadSchemas { + private static class EnumPackedReaders extends AbstractReaders> { + private final EnumMeta enumMeta; + + public EnumPackedReaders(Field protoField, JavaType javaType) { + super(protoField, EnumSchemaUtils.constructEnumArrayClass(javaType)); + this.enumMeta = new EnumMeta(protoField, javaType.getContentType()); + + collectionReader = (input, collection) -> { + while (true) { + int value = input.readPackedEnum(); + Enum enumValue = enumMeta.getEnumByValue(value); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum value %d for %s, proto field=%s:%s", + value, + javaType.getRawClass().getName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + collection.add(enumValue); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + private static class EnumIntPackedSchema extends FieldSchema { + private final Getter> getter; + + private final Setter> setter; + + public EnumIntPackedSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + Collection collection = getter.get(message); + if (collection == null) { + collection = new ArrayList<>(); + setter.set(message, collection); + } + + while (true) { + int value = input.readPackedEnum(); + collection.add(value); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (javaType.isJavaLangObject()) { + return new EnumIntPackedSchema<>(protoField, propertyDescriptor); + } + + return RepeatedReadSchemas + .create(protoField, propertyDescriptor, new EnumPackedReaders(protoField, propertyDescriptor.getJavaType())); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumSchemaUtils.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumSchemaUtils.java new file mode 100644 index 00000000000..399a4b2df6c --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/enums/EnumSchemaUtils.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.enums; + +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; + +import com.fasterxml.jackson.databind.JavaType; + +public final class EnumSchemaUtils { + private EnumSchemaUtils() { + } + + public static T constructEnumArrayClass(JavaType javaType) { + if (javaType.isArrayType()) { + return ReflectUtils.constructArrayType(javaType.getContentType().getRawClass()); + } + + return ReflectUtils.constructArrayType(Object.class); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/FloatRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/FloatRepeatedReadSchemas.java new file mode 100644 index 00000000000..82b6d131772 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/FloatRepeatedReadSchemas.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.PrimitiveArrayBuilderWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatRepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (float[].class.equals(javaType.getRawClass())) { + return new FloatPrimitiveArraySchema<>(protoField, propertyDescriptor, readers); + } + + return RepeatedReadSchemas.create(protoField, propertyDescriptor, readers); + } + + static class FloatPrimitiveArraySchema extends FieldSchema { + private final Getter getter; + + private final Setter setter; + + private final AbstractPrimitiveReaders readers; + + public FloatPrimitiveArraySchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + this.readers = readers; + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PrimitiveArrayBuilderWrapper builderWrapper = new PrimitiveArrayBuilderWrapper<>( + input.getArrayBuilders().getFloatBuilder()); + + int fieldNumber = readers.primitiveArrayReader.read(input, builderWrapper); + float[] newValue = builderWrapper.getArray(); + newValue = mergeArray(getter.get(message), newValue); + setter.set(message, newValue); + + return fieldNumber; + } + + public float[] mergeArray(float[] oldValue, float[] newValue) { + if (oldValue == null || oldValue.length == 0) { + return newValue; + } + + return concatArray(oldValue, newValue); + } + + private float[] concatArray(float[] oldValue, float[] newValue) { + int len1 = oldValue.length; + int len2 = newValue.length; + float[] result = Arrays.copyOf(oldValue, len1 + len2); + System.arraycopy(newValue, 0, result, len1, len2); + return result; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatNotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatNotPackedReadSchemas.java new file mode 100644 index 00000000000..8f8c2e12bf8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatNotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.FloatRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatNotPackedReadSchemas { + private static class FloatNotPackedReaders extends AbstractPrimitiveReaders { + public FloatNotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + float[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readFloat(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readFloat()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return FloatRepeatedReadSchemas.create(protoField, propertyDescriptor, new FloatNotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatPackedReadSchemas.java new file mode 100644 index 00000000000..2e5a15a47f3 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/floats/impl/FloatPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.floats.FloatRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatPackedReadSchemas { + private static class FloatPackedReaders extends AbstractPrimitiveReaders { + public FloatPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + float[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedFloat(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedFloat()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return FloatRepeatedReadSchemas.create(protoField, propertyDescriptor, new FloatPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/IntRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/IntRepeatedReadSchemas.java new file mode 100644 index 00000000000..cd0000d46e1 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/IntRepeatedReadSchemas.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.PrimitiveArrayBuilderWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class IntRepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int[].class.equals(javaType.getRawClass())) { + return new IntPrimitiveArraySchema<>(protoField, propertyDescriptor, readers); + } + + return RepeatedReadSchemas.create(protoField, propertyDescriptor, readers); + } + + static class IntPrimitiveArraySchema extends FieldSchema { + private final Getter getter; + + private final Setter setter; + + private final AbstractPrimitiveReaders readers; + + public IntPrimitiveArraySchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + this.readers = readers; + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PrimitiveArrayBuilderWrapper builderWrapper = new PrimitiveArrayBuilderWrapper<>( + input.getArrayBuilders().getIntBuilder()); + + int fieldNumber = readers.primitiveArrayReader.read(input, builderWrapper); + int[] newValue = builderWrapper.getArray(); + newValue = mergeArray(getter.get(message), newValue); + setter.set(message, newValue); + + return fieldNumber; + } + + public int[] mergeArray(int[] oldValue, int[] newValue) { + if (oldValue == null || oldValue.length == 0) { + return newValue; + } + + return concatArray(oldValue, newValue); + } + + private int[] concatArray(int[] oldValue, int[] newValue) { + int len1 = oldValue.length; + int len2 = newValue.length; + int[] result = Arrays.copyOf(oldValue, len1 + len2); + System.arraycopy(newValue, 0, result, len1, len2); + return result; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32NotPackedReadSchemas.java new file mode 100644 index 00000000000..acbdc796b6a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32NotPackedReadSchemas { + private static class NotPackedReaders extends AbstractPrimitiveReaders { + public NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readFixed32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readFixed32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32PackedReadSchemas.java new file mode 100644 index 00000000000..f8d25de95a7 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Fixed32PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32PackedReadSchemas { + private static class Fixed32PackedReaders extends AbstractPrimitiveReaders { + public Fixed32PackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedFixed32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedFixed32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new Fixed32PackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32NotPackedReadSchemas.java new file mode 100644 index 00000000000..e5e86f96660 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int32NotPackedReadSchemas { + private static class Int32NotPackedReaders extends AbstractPrimitiveReaders { + public Int32NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new Int32NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32PackedReadSchemas.java new file mode 100644 index 00000000000..b578aea5aad --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/Int32PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int32PackedReadSchemas { + private static class Int32PackedReaders extends AbstractPrimitiveReaders { + public Int32PackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new Int32PackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32NotPackedReadSchemas.java new file mode 100644 index 00000000000..2ddf02fe23a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32NotPackedReadSchemas { + private static class NotPackedReaders extends AbstractPrimitiveReaders { + public NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readSFixed32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readSFixed32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32PackedReadSchemas.java new file mode 100644 index 00000000000..a4be7f8f739 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SFixed32PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32PackedReadSchemas { + private static class SFixed32PackedReaders extends AbstractPrimitiveReaders { + public SFixed32PackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedSFixed32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedSFixed32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new SFixed32PackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32NotPackedReadSchemas.java new file mode 100644 index 00000000000..3918c128216 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32NotPackedReadSchemas { + private static class SInt32NotPackedReaders extends AbstractPrimitiveReaders { + public SInt32NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readSInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readSInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new SInt32NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32PackedReadSchemas.java new file mode 100644 index 00000000000..ff7984e266a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/SInt32PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32PackedReadSchemas { + private static class SInt32PackedReaders extends AbstractPrimitiveReaders { + public SInt32PackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedSInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedSInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new SInt32PackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32NotPackedReadSchemas.java new file mode 100644 index 00000000000..dbd719c2773 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32NotPackedReadSchemas { + private static class UInt32NotPackedReaders extends AbstractPrimitiveReaders { + public UInt32NotPackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readUInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readUInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new UInt32NotPackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32PackedReadSchemas.java new file mode 100644 index 00000000000..3afff304c77 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/ints/impl/UInt32PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.ints.IntRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32PackedReadSchemas { + private static class UInt32PackedReaders extends AbstractPrimitiveReaders { + public UInt32PackedReaders(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + int[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedUInt32(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedUInt32()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return IntRepeatedReadSchemas.create(protoField, propertyDescriptor, new UInt32PackedReaders(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/LongRepeatedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/LongRepeatedReadSchemas.java new file mode 100644 index 00000000000..08308307c16 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/LongRepeatedReadSchemas.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.PrimitiveArrayBuilderWrapper; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.RepeatedReadSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class LongRepeatedReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long[].class.equals(javaType.getRawClass())) { + return new LongPrimitiveArraySchema<>(protoField, propertyDescriptor, readers); + } + + return RepeatedReadSchemas.create(protoField, propertyDescriptor, readers); + } + + static class LongPrimitiveArraySchema extends FieldSchema { + private final Getter getter; + + private final Setter setter; + + private final AbstractPrimitiveReaders readers; + + public LongPrimitiveArraySchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveReaders readers) { + super(protoField, propertyDescriptor.getJavaType()); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + this.readers = readers; + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + PrimitiveArrayBuilderWrapper builderWrapper = new PrimitiveArrayBuilderWrapper<>( + input.getArrayBuilders().getLongBuilder()); + + int fieldNumber = readers.primitiveArrayReader.read(input, builderWrapper); + long[] newValue = builderWrapper.getArray(); + newValue = mergeArray(getter.get(message), newValue); + setter.set(message, newValue); + + return fieldNumber; + } + + public long[] mergeArray(long[] oldValue, long[] newValue) { + if (oldValue == null || oldValue.length == 0) { + return newValue; + } + + return concatArray(oldValue, newValue); + } + + private long[] concatArray(long[] oldValue, long[] newValue) { + int len1 = oldValue.length; + int len2 = newValue.length; + long[] result = Arrays.copyOf(oldValue, len1 + len2); + System.arraycopy(newValue, 0, result, len1, len2); + return result; + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64NotPackedReadSchemas.java new file mode 100644 index 00000000000..b02112d82e7 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64NotPackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readFixed64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readFixed64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64PackedReadSchemas.java new file mode 100644 index 00000000000..9e768d84917 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Fixed64PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64PackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedFixed64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedFixed64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64NotPackedReadSchemas.java new file mode 100644 index 00000000000..c4c6a126fc1 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64NotPackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64PackedReadSchemas.java new file mode 100644 index 00000000000..051b8bc4620 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/Int64PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64PackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64NotPackedReadSchemas.java new file mode 100644 index 00000000000..606dd9712d8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64NotPackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readSFixed64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readSFixed64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64PackedReadSchemas.java new file mode 100644 index 00000000000..85c13b7ef70 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SFixed64PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64PackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedSFixed64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedSFixed64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64NotPackedReadSchemas.java new file mode 100644 index 00000000000..3f23c9be383 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64NotPackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readSInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readSInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64PackedReadSchemas.java new file mode 100644 index 00000000000..a23da754371 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/SInt64PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64PackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedSInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedSInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64NotPackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64NotPackedReadSchemas.java new file mode 100644 index 00000000000..482db0cc10d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64NotPackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64NotPackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readUInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readUInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64PackedReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64PackedReadSchemas.java new file mode 100644 index 00000000000..faceeea7cc1 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/repeated/impl/longs/impl/UInt64PackedReadSchemas.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.AbstractPrimitiveReaders; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.repeated.impl.longs.LongRepeatedReadSchemas; + +import com.fasterxml.jackson.databind.util.PrimitiveArrayBuilder; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64PackedReadSchemas { + private static class Readers extends AbstractPrimitiveReaders { + public Readers(Field protoField) { + super(protoField); + + this.primitiveArrayReader = (input, builderWrapper) -> { + PrimitiveArrayBuilder builder = builderWrapper.getBuilder(); + long[] chunk = builder.resetAndStart(); + int ix = 0; + + while (true) { + if (ix >= chunk.length) { + chunk = builder.appendCompletedChunk(chunk, ix); + ix = 0; + } + chunk[ix++] = input.readPackedUInt64(); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + builderWrapper.setArray(builder.completeAndClearBuffer(chunk, ix)); + return fieldNumber; + } + } + }; + + this.collectionReader = (input, collection) -> { + while (true) { + collection.add(input.readPackedUInt64()); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return LongRepeatedReadSchemas.create(protoField, propertyDescriptor, new Readers(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/AbstractScalarReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/AbstractScalarReadSchemas.java new file mode 100644 index 00000000000..345fd477df2 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/AbstractScalarReadSchemas.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class AbstractScalarReadSchemas { + abstract static class AbstractIntSchema extends FieldSchema { + protected final Setter setter; + + public AbstractIntSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + } + + abstract static class AbstractLongSchema extends FieldSchema { + protected final Setter setter; + + public AbstractLongSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BoolReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BoolReadSchemas.java new file mode 100644 index 00000000000..a6b1e75f40a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BoolReadSchemas.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.BoolSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (boolean.class.equals(javaType.getRawClass())) { + return new BooleanPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Boolean.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new BooleanSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class BooleanSchema extends FieldSchema { + private final Setter setter; + + public BooleanSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + boolean value = input.readBool(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class BooleanPrimitiveSchema extends FieldSchema { + private final BoolSetter setter; + + public BooleanPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + boolean value = input.readBool(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BytesReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BytesReadSchemas.java new file mode 100644 index 00000000000..9c4ec6cdd3e --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/BytesReadSchemas.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BytesReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (byte[].class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new BytesSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class BytesSchema extends FieldSchema { + private final Setter setter; + + public BytesSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + byte[] value = input.readByteArray(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/DoubleReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/DoubleReadSchemas.java new file mode 100644 index 00000000000..dbac060b730 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/DoubleReadSchemas.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.DoubleSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoubleReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (double.class.equals(javaType.getRawClass())) { + return new DoublePrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Double.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new DoubleSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class DoubleSchema extends FieldSchema { + private final Setter setter; + + public DoubleSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + double value = input.readDouble(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class DoublePrimitiveSchema extends FieldSchema { + private final DoubleSetter setter; + + public DoublePrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + double value = input.readDouble(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/EnumsReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/EnumsReadSchemas.java new file mode 100644 index 00000000000..64022ac324f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/EnumsReadSchemas.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.base.DynamicEnum; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumsReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (javaType.isEnumType()) { + return new EnumSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new IntEnumSchema<>(protoField, propertyDescriptor); + } + + if (int.class.equals(javaType.getRawClass())) { + return new IntPrimitiveEnumSchema<>(protoField, propertyDescriptor); + } + + if (javaType.isTypeOrSubTypeOf(DynamicEnum.class)) { + return new DynamicEnumSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class EnumSchema extends FieldSchema { + private final Setter> setter; + + private final EnumMeta enumMeta; + + public EnumSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + enumMeta = new EnumMeta(protoField, javaType); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + Enum enumValue = enumMeta.getEnumByValue(value); + if (enumValue != null) { + setter.set(message, enumValue); + return input.readFieldNumber(); + } + + throw new IllegalStateException( + String.format("invalid enum value %d for %s, proto field=%s:%s", + value, + javaType.getRawClass().getName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + } + + private static class DynamicEnumSchema extends FieldSchema { + public DynamicEnumSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + throw new IllegalStateException( + String.format("currently, protobuf not support dynamic enum, type=%s, proto field=%s:%s", + javaType.getRawClass().getName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + } + + private static class IntEnumSchema extends FieldSchema { + private final Setter setter; + + public IntEnumSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class IntPrimitiveEnumSchema extends FieldSchema { + private final IntSetter setter; + + public IntPrimitiveEnumSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed32ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed32ReadSchemas.java new file mode 100644 index 00000000000..37a9a4b4911 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed32ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractIntSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int.class.equals(javaType.getRawClass())) { + return new Fixed32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new Fixed32Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class Fixed32Schema extends AbstractIntSchema { + public Fixed32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readFixed32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class Fixed32PrimitiveSchema extends FieldSchema { + protected final IntSetter setter; + + public Fixed32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readFixed32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed64ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed64ReadSchemas.java new file mode 100644 index 00000000000..ddd1cbf6911 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Fixed64ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractLongSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long.class.equals(javaType.getRawClass())) { + return new Fixed64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new Fixed64Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class Fixed64Schema extends AbstractLongSchema { + public Fixed64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readFixed64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class Fixed64PrimitiveSchema extends FieldSchema { + protected final LongSetter setter; + + public Fixed64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readFixed64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/FloatReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/FloatReadSchemas.java new file mode 100644 index 00000000000..46879c17b7a --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/FloatReadSchemas.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.FloatSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (float.class.equals(javaType.getRawClass())) { + return new FloatPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Float.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new FloatSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class FloatSchema extends FieldSchema { + private final Setter setter; + + public FloatSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + float value = input.readFloat(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class FloatPrimitiveSchema extends FieldSchema { + private final FloatSetter setter; + + public FloatPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + float value = input.readFloat(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int32ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int32ReadSchemas.java new file mode 100644 index 00000000000..644102f23a0 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int32ReadSchemas.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.ByteSetter; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.common.utils.bean.ShortSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractIntSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int32ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int.class.equals(javaType.getRawClass())) { + return new IntFieldIntPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (short.class.equals(javaType.getRawClass())) { + return new ShortFieldIntPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (byte.class.equals(javaType.getRawClass())) { + return new ByteFieldIntPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) || Byte.class.equals(javaType.getRawClass()) || Short.class + .equals(javaType.getRawClass()) || javaType + .isJavaLangObject()) { + return new Int32Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class Int32Schema extends AbstractIntSchema { + public Int32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + if (Byte.class.equals(javaType.getRawClass())) { + setter.set(message, (byte) value); + } else if (Short.class.equals(javaType.getRawClass())) { + setter.set(message, (short) value); + } else { + setter.set(message, value); + } + return input.readFieldNumber(); + } + } + + private static class IntFieldIntPrimitiveSchema extends FieldSchema { + protected final IntSetter setter; + + public IntFieldIntPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class ShortFieldIntPrimitiveSchema extends FieldSchema { + protected final ShortSetter setter; + + public ShortFieldIntPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + setter.set(message, (short) value); + return input.readFieldNumber(); + } + } + + private static class ByteFieldIntPrimitiveSchema extends FieldSchema { + protected final ByteSetter setter; + + public ByteFieldIntPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readInt32(); + setter.set(message, (byte) value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int64ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int64ReadSchemas.java new file mode 100644 index 00000000000..0befd0a7a26 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/Int64ReadSchemas.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; + +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractLongSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long.class.equals(javaType.getRawClass())) { + return new LongFiledLongPrimitiveSchema<>(protoField, propertyDescriptor); + } + + return new Int64Schema<>(protoField, propertyDescriptor); + } + + private static class Int64Schema extends AbstractLongSchema { + public Int64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readInt64(); + if (Date.class.equals(javaType.getRawClass())) { + setter.set(message, new Date(value)); + } else if (LocalDate.class.equals(javaType.getRawClass())) { + setter.set(message, LocalDate.ofEpochDay(value)); + } else if (LocalDateTime.class.equals(javaType.getRawClass())) { + setter.set(message, LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.UTC)); + } else { + setter.set(message, value); + } + return input.readFieldNumber(); + } + } + + private static class LongFiledLongPrimitiveSchema extends FieldSchema { + protected final LongSetter setter; + + public LongFiledLongPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readInt64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed32ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed32ReadSchemas.java new file mode 100644 index 00000000000..dcd6530f6a4 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed32ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractIntSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int.class.equals(javaType.getRawClass())) { + return new SFixed32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new SFixed32Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class SFixed32Schema extends AbstractIntSchema { + public SFixed32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSFixed32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class SFixed32PrimitiveSchema extends FieldSchema { + protected final IntSetter setter; + + public SFixed32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSFixed32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed64ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed64ReadSchemas.java new file mode 100644 index 00000000000..f1d4f8fc882 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SFixed64ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractLongSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long.class.equals(javaType.getRawClass())) { + return new SFixed64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new SFixed64Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class SFixed64Schema extends AbstractLongSchema { + public SFixed64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readSFixed64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class SFixed64PrimitiveSchema extends FieldSchema { + protected final LongSetter setter; + + public SFixed64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readSFixed64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt32ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt32ReadSchemas.java new file mode 100644 index 00000000000..8252e2a96ca --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt32ReadSchemas.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.ByteSetter; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.common.utils.bean.ShortSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractIntSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int.class.equals(javaType.getRawClass())) { + return new SInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (short.class.equals(javaType.getRawClass())) { + return new ShortFieldSInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (byte.class.equals(javaType.getRawClass())) { + return new ByteFieldSInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) + || Byte.class.equals(javaType.getRawClass()) + || Short.class.equals(javaType.getRawClass()) + || javaType.isJavaLangObject()) { + return new SInt32Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class SInt32Schema extends AbstractIntSchema { + public SInt32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSInt32(); + if (Byte.class.equals(javaType.getRawClass())) { + setter.set(message, (byte) value); + } else if (Short.class.equals(javaType.getRawClass())) { + setter.set(message, (short) value); + } else { + setter.set(message, value); + } + return input.readFieldNumber(); + } + } + + private static class SInt32PrimitiveSchema extends FieldSchema { + protected final IntSetter setter; + + public SInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class ShortFieldSInt32PrimitiveSchema extends FieldSchema { + protected final ShortSetter setter; + + public ShortFieldSInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSInt32(); + setter.set(message, (short) value); + return input.readFieldNumber(); + } + } + + private static class ByteFieldSInt32PrimitiveSchema extends FieldSchema { + protected final ByteSetter setter; + + public ByteFieldSInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readSInt32(); + setter.set(message, (byte) value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt64ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt64ReadSchemas.java new file mode 100644 index 00000000000..ff3c80c150c --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/SInt64ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractLongSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long.class.equals(javaType.getRawClass())) { + return new SInt64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new SInt64Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class SInt64Schema extends AbstractLongSchema { + public SInt64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readSInt64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class SInt64PrimitiveSchema extends FieldSchema { + protected final LongSetter setter; + + public SInt64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readSInt64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/StringReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/StringReadSchemas.java new file mode 100644 index 00000000000..7b1f0a441b0 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/StringReadSchemas.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.servicecomb.foundation.common.utils.bean.CharSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class StringReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + + if (char.class.equals(javaType.getRawClass())) { + return new CharFieldStringSchema<>(protoField, propertyDescriptor); + } + + if (String.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject() || Character.class + .equals(javaType.getRawClass())) { + return new StringSchema<>(protoField, propertyDescriptor); + } + + if (BigDecimal.class.equals(javaType.getRawClass())) { + return new BigDecimalSchema<>(protoField, propertyDescriptor); + } + + if (BigInteger.class.equals(javaType.getRawClass())) { + return new BigIntegerSchema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class StringSchema extends FieldSchema { + private final Setter setter; + + public StringSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + String value = input.readString(); + if (char.class + .equals(javaType.getRawClass()) || Character.class.equals(javaType.getRawClass())) { + setter.set(message, value.toCharArray()[0]); + } else { + setter.set(message, value); + } + return input.readFieldNumber(); + } + } + + private static class CharFieldStringSchema extends FieldSchema { + private final CharSetter setter; + + public CharFieldStringSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + String value = input.readString(); + setter.set(message, value.toCharArray()[0]); + return input.readFieldNumber(); + } + } + + private static class BigDecimalSchema extends FieldSchema { + private final Setter setter; + + public BigDecimalSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + String value = input.readString(); + setter.set(message, new BigDecimal(value)); + return input.readFieldNumber(); + } + } + + private static class BigIntegerSchema extends FieldSchema { + private final Setter setter; + + public BigIntegerSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + String value = input.readString(); + setter.set(message, new BigInteger(value)); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt32ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt32ReadSchemas.java new file mode 100644 index 00000000000..61ef71b64e4 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt32ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractIntSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (int.class.equals(javaType.getRawClass())) { + return new UInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new UInt32Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class UInt32Schema extends AbstractIntSchema { + public UInt32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readUInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class UInt32PrimitiveSchema extends FieldSchema { + protected final IntSetter setter; + + public UInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + int value = input.readUInt32(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt64ReadSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt64ReadSchemas.java new file mode 100644 index 00000000000..0a098a7152f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/deserializer/scalar/UInt64ReadSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.LongSetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.scalar.AbstractScalarReadSchemas.AbstractLongSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64ReadSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (long.class.equals(javaType.getRawClass())) { + return new UInt64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(javaType.getRawClass()) || javaType.isJavaLangObject()) { + return new UInt64Schema<>(protoField, propertyDescriptor); + } + + ProtoUtils.throwNotSupportMerge(protoField, propertyDescriptor.getJavaType()); + return null; + } + + private static class UInt64Schema extends AbstractLongSchema { + public UInt64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readUInt64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } + + private static class UInt64PrimitiveSchema extends FieldSchema { + protected final LongSetter setter; + + public UInt64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public int mergeFrom(InputEx input, T message) throws IOException { + long value = input.readUInt64(); + setter.set(message, value); + return input.readFieldNumber(); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntry.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntry.java new file mode 100644 index 00000000000..b4b1ee75c9b --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntry.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.map; + +import java.util.Map.Entry; + +import com.fasterxml.jackson.annotation.JsonSetter; + +public class MapEntry implements Entry { + private K key; + + private V value; + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public V setValue(V value) { + this.value = value; + return value; + } + + @JsonSetter("value") + public void valueSetter(V value) { + this.value = value; + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntrySchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntrySchema.java new file mode 100644 index 00000000000..7f575ce11af --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapEntrySchema.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.map; + +import java.io.IOException; +import java.util.Map.Entry; + +import org.apache.servicecomb.foundation.protobuf.internal.schema.deserializer.MessageReadSchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.MessageWriteSchema; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.runtime.FieldSchema; + +public class MapEntrySchema implements SchemaEx> { + private final FieldSchema> keySchema; + + private final FieldSchema> valueSchema; + + public MapEntrySchema(SchemaEx> entrySchema) { + if (entrySchema instanceof MessageWriteSchema) { + keySchema = ((MessageWriteSchema>) entrySchema).getMainPojoFieldMaps().getFieldByNumber(1); + valueSchema = ((MessageWriteSchema>) entrySchema).getMainPojoFieldMaps() + .getFieldByNumber(2); + return; + } + + keySchema = ((MessageReadSchema>) entrySchema).getFieldMap().getFieldByNumber(1); + valueSchema = ((MessageReadSchema>) entrySchema).getFieldMap().getFieldByNumber(2); + } + + @Override + public void init() { + + } + + @Override + public void mergeFrom(InputEx input, Entry message) throws IOException { + input.readFieldNumber(); + keySchema.mergeFrom(input, message); + valueSchema.mergeFrom(input, message); + } + + @Override + public void writeTo(OutputEx output, Entry value) throws IOException { + keySchema.writeTo(output, value.getKey()); + valueSchema.writeTo(output, value.getValue()); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapSchema.java new file mode 100644 index 00000000000..38d269c6d23 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/map/MapSchema.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.map; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class MapSchema extends FieldSchema { + private final Getter> getter; + + private final Setter> setter; + + private final SchemaEx> entrySchema; + + public MapSchema(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaEx> entrySchema) { + super(protoField, propertyDescriptor.getJavaType()); + this.entrySchema = new MapEntrySchema(entrySchema); + this.getter = propertyDescriptor.getGetter(); + this.setter = propertyDescriptor.getSetter(); + } + + @Override + public final int mergeFrom(InputEx input, T message) throws IOException { + Map map = getter.get(message); + if (map == null) { + map = new LinkedHashMap<>(); + setter.set(message, map); + } + + Entry entry = new MapEntry<>(); + while (true) { + input.mergeObject(entry, entrySchema); + map.put(entry.getKey(), entry.getValue()); + entry.setValue(null); + + int fieldNumber = input.readFieldNumber(); + if (fieldNumber != this.fieldNumber) { + return fieldNumber; + } + } + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Map map = getter.get(message); + if (map == null) { + return; + } + + writeMap(output, map); + } + + @SuppressWarnings("unchecked") + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + writeMap(output, (Map) value); + } + + private void writeMap(OutputEx output, Map map) throws IOException { + for (Entry entry : map.entrySet()) { + if (entry.getKey() == null || entry.getValue() == null) { + continue; + } + + output.writeObject(tag, tagSize, entry, entrySchema); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BoolSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BoolSchema.java deleted file mode 100644 index 3d5fc604c47..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BoolSchema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class BoolSchema extends FieldSchema { - public BoolSchema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readBool(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readBool()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Boolean) { - output.writeBool(number, (Boolean) value, repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - boolean v = Boolean.parseBoolean(((String[]) value)[0]); - output.writeBool(number, v, repeated); - return; - } - - if (value instanceof String) { - boolean v = Boolean.parseBoolean((String) value); - output.writeBool(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BytesSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BytesSchema.java deleted file mode 100644 index e354c7eef95..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/BytesSchema.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class BytesSchema extends FieldSchema { - public BytesSchema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readByteArray(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readByteArray()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof byte[]) { - output.writeByteArray(number, (byte[]) value, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/DoubleSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/DoubleSchema.java deleted file mode 100644 index 45dbce32ee8..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/DoubleSchema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class DoubleSchema extends FieldSchema { - public DoubleSchema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readDouble(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readDouble()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeDouble(number, ((Number) value).doubleValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - double v = Double.parseDouble(((String[]) value)[0]); - output.writeDouble(number, v, repeated); - return; - } - - if (value instanceof String) { - double v = Double.parseDouble((String) value); - output.writeDouble(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed32Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed32Schema.java deleted file mode 100644 index 168f39dc86a..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed32Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class Fixed32Schema extends FieldSchema { - public Fixed32Schema(Field field) { - super(field); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeFixed32(number, ((Number) value).intValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - int v = Integer.parseInt(((String[]) value)[0], 10); - output.writeFixed32(number, v, repeated); - return; - } - - if (value instanceof String) { - int v = Integer.parseInt((String) value, 10); - output.writeFixed32(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readFixed32(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readFixed32()); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed64Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed64Schema.java deleted file mode 100644 index 36138d070b2..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Fixed64Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class Fixed64Schema extends FieldSchema { - public Fixed64Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readFixed64(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readFixed64()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeFixed64(number, ((Number) value).longValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - long v = Long.parseLong(((String[]) value)[0], 10); - output.writeFixed64(number, v, repeated); - return; - } - - if (value instanceof String) { - long v = Long.parseLong((String) value, 10); - output.writeFixed64(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/FloatSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/FloatSchema.java deleted file mode 100644 index d587d40d018..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/FloatSchema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class FloatSchema extends FieldSchema { - public FloatSchema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readFloat(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readFloat()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeFloat(number, ((Number) value).floatValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - float v = Float.parseFloat(((String[]) value)[0]); - output.writeFloat(number, v, repeated); - return; - } - - if (value instanceof String) { - float v = Float.parseFloat((String) value); - output.writeFloat(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int32Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int32Schema.java deleted file mode 100644 index 526e85084e0..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int32Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class Int32Schema extends FieldSchema { - public Int32Schema(Field protoField) { - super(protoField); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readInt32(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readInt32()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeInt32(number, ((Number) value).intValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - int v = Integer.parseInt(((String[]) value)[0], 10); - output.writeInt32(number, v, repeated); - return; - } - - if (value instanceof String) { - int v = Integer.parseInt((String) value, 10); - output.writeInt32(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int64Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int64Schema.java deleted file mode 100644 index 91b6d61a384..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/Int64Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class Int64Schema extends FieldSchema { - public Int64Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readInt64(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readInt64()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeInt64(number, ((Number) value).longValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - long v = Long.parseLong(((String[]) value)[0], 10); - output.writeInt64(number, v, repeated); - return; - } - - if (value instanceof String) { - long v = Long.parseLong((String) value, 10); - output.writeInt64(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed32Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed32Schema.java deleted file mode 100644 index c51758db2a9..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed32Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class SFixed32Schema extends FieldSchema { - public SFixed32Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readSFixed32(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readSFixed32()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeSFixed32(number, ((Number) value).intValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - int v = Integer.parseInt(((String[]) value)[0], 10); - output.writeSFixed32(number, v, repeated); - return; - } - - if (value instanceof String) { - int v = Integer.parseInt((String) value, 10); - output.writeSFixed32(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed64Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed64Schema.java deleted file mode 100644 index 97502ad6c72..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SFixed64Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class SFixed64Schema extends FieldSchema { - public SFixed64Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readSFixed64(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readSFixed64()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeSFixed64(number, ((Number) value).longValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - long v = Long.parseLong(((String[]) value)[0], 10); - output.writeSFixed64(number, v, repeated); - return; - } - - if (value instanceof String) { - long v = Long.parseLong((String) value, 10); - output.writeSFixed64(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt32Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt32Schema.java deleted file mode 100644 index 602ba082aaa..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt32Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class SInt32Schema extends FieldSchema { - public SInt32Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readSInt32(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readSInt32()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeSInt32(number, ((Number) value).intValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - int v = Integer.parseInt(((String[]) value)[0], 10); - output.writeSInt32(number, v, repeated); - return; - } - - if (value instanceof String) { - int v = Integer.parseInt((String) value, 10); - output.writeSInt32(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt64Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt64Schema.java deleted file mode 100644 index 2401b80de6c..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/SInt64Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class SInt64Schema extends FieldSchema { - public SInt64Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readSInt64(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readSInt64()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeSInt64(number, ((Number) value).longValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - long v = Long.parseLong(((String[]) value)[0], 10); - output.writeSInt64(number, v, repeated); - return; - } - - if (value instanceof String) { - long v = Long.parseLong((String) value, 10); - output.writeSInt64(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/StringSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/StringSchema.java deleted file mode 100644 index 1b15520b98a..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/StringSchema.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class StringSchema extends FieldSchema { - public StringSchema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readString(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readString()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof String) { - output.writeString(number, (String) value, repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - output.writeString(number, ((String[]) value)[0], repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt32Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt32Schema.java deleted file mode 100644 index 215fccba06c..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt32Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class UInt32Schema extends FieldSchema { - public UInt32Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readUInt32(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readUInt32()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeUInt32(number, ((Number) value).intValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - int v = Integer.parseInt(((String[]) value)[0], 10); - output.writeUInt32(number, v, repeated); - return; - } - - if (value instanceof String) { - int v = Integer.parseInt((String) value, 10); - output.writeUInt32(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt64Schema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt64Schema.java deleted file mode 100644 index 4c57d293aac..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/UInt64Schema.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.Field; - -public class UInt64Schema extends FieldSchema { - public UInt64Schema(Field field) { - super(field); - } - - @Override - public Object readFrom(Input input) throws IOException { - return input.readUInt64(); - } - - @Override - public void mergeFrom(Input input, Object message) throws IOException { - setter.set(message, input.readUInt64()); - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Number) { - output.writeUInt64(number, ((Number) value).longValue(), repeated); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - long v = Long.parseLong(((String[]) value)[0], 10); - output.writeUInt64(number, v, repeated); - return; - } - - if (value instanceof String) { - long v = Long.parseLong((String) value, 10); - output.writeUInt64(number, v, repeated); - return; - } - - throwNotSupportValue(value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/EnumSerializerSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/EnumSerializerSchema.java deleted file mode 100644 index 31f3862a2f8..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/EnumSerializerSchema.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; - -import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Input; -import io.protostuff.Output; -import io.protostuff.compiler.model.EnumConstant; -import io.protostuff.compiler.model.Field; -import io.protostuff.compiler.model.Type; - -public class EnumSerializerSchema extends FieldSchema { - private Map enumNameToValueMap = new HashMap<>(); - - private Set enumValueSet = new HashSet<>(); - - public EnumSerializerSchema(Field field) { - super(field); - io.protostuff.compiler.model.Enum enumType = (io.protostuff.compiler.model.Enum) field.getType(); - for (EnumConstant enumConstant : enumType.getConstants()) { - enumNameToValueMap.put(enumConstant.getName(), enumConstant.getValue()); - enumValueSet.add(enumConstant.getValue()); - } - } - - @Override - public void writeTo(Output output, Object value) throws IOException { - if (value == null) { - return; - } - - if (value instanceof Enum) { - // already be a Enum, need to check if it is a valid Enum? - // wrong case: - // expect a Color enum, but be a Sharp enum?, who will do this? - // for safe, check it...... - serializeFromString(output, ((Enum) value).name()); - return; - } - - if (value instanceof Number) { - // need to check if it is a valid number - // because maybe come from http request - serializeFromNumber(output, ((Number) value).intValue()); - return; - } - - if (value instanceof String[]) { - if (((String[]) value).length == 0) { - return; - } - - serializeFromString(output, ((String[]) value)[0]); - return; - } - - if (value instanceof String) { - serializeFromString(output, (String) value); - return; - } - - throwNotSupportValue(value); - } - - - protected void serializeFromNumber(Output output, int enumValue) throws IOException { - if (!enumValueSet.contains(enumValue)) { - throw new IllegalStateException( - String.format("invalid enum value %d for proto %s, field=%s:%s", - enumValue, - protoField.getTypeName(), - ((Type) protoField.getParent()).getCanonicalName(), - protoField.getName())); - } - - output.writeInt32(number, enumValue, repeated); - } - - protected void serializeFromString(Output output, String enumName) throws IOException { - Integer v = enumNameToValueMap.get(enumName); - if (v == null) { - throw new IllegalStateException( - String.format("invalid enum name %s for proto %s, field=%s:%s", - enumName, - protoField.getTypeName(), - ((Type) protoField.getParent()).getCanonicalName(), - protoField.getName())); - } - output.writeInt32(number, v, repeated); - } - - @Override - public Object readFrom(Input input) { - throw new UnsupportedOperationException(); - } - - @Override - public void mergeFrom(Input input, Object message) { - throw new UnsupportedOperationException(); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/MessageWriteSchema.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/MessageWriteSchema.java new file mode 100644 index 00000000000..ccab4d81f82 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/MessageWriteSchema.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.protobuf.ProtoMapper; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.BeanDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.InputEx; +import io.protostuff.OutputEx; +import io.protostuff.SchemaEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Message; +import io.protostuff.runtime.FieldMapEx; +import io.protostuff.runtime.FieldSchema; + +/** + *
+ * map.put("user", new User())
+ * root write from map, but user should write from pojo
+ * so one schema should support dynamic and concrete logic at the same time
+ * 
+ */ +public class MessageWriteSchema implements SchemaEx { + protected final ProtoMapper protoMapper; + + protected final Message message; + + private final JavaType javaType; + + // mostly, one message only relate to one pojo + private final Class mainPojoCls; + + private FieldMapEx mainPojoFieldMaps; + + private FieldMapEx> mapFieldMaps; + + // if not equals to mainPojoCls, then will find from pojoFieldMaps + private final Map, FieldMapEx> pojoFieldMaps = new ConcurrentHashMapEx<>(); + + @SuppressWarnings("unchecked") + public MessageWriteSchema(ProtoMapper protoMapper, Message message, JavaType javaType) { + this.protoMapper = protoMapper; + this.message = message; + this.javaType = javaType; + this.mainPojoCls = (Class) javaType.getRawClass(); + } + + public Message getMessage() { + return message; + } + + @Override + public T newMessage() { + throw new UnsupportedOperationException(); + } + + @Override + public String messageName() { + return message.getName(); + } + + public JavaType getJavaType() { + return javaType; + } + + public Class getMainPojoCls() { + return mainPojoCls; + } + + public FieldMapEx getMainPojoFieldMaps() { + return mainPojoFieldMaps; + } + + @Override + public void init() { + this.mapFieldMaps = protoMapper.getSerializerSchemaManager().createMapFields(message); + + if (ProtoUtils.isWrapProperty(message)) { + this.mainPojoFieldMaps = createPropertyWrapperFields(javaType); + return; + } + + this.mainPojoFieldMaps = createPojoFields(javaType); + } + + private FieldMapEx createPropertyWrapperFields(JavaType javaType) { + Field protoField = message.getField(1); + + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(); + propertyDescriptor.setName(protoField.getName()); + propertyDescriptor.setJavaType(javaType); + + FieldSchema fieldSchema = protoMapper.getSerializerSchemaManager() + .createSchemaField(protoField, propertyDescriptor); + return FieldMapEx.createFieldMap(Arrays.asList(fieldSchema)); + } + + private FieldMapEx createPojoFields(Type type) { + SerializerSchemaManager serializerSchemaManager = protoMapper.getSerializerSchemaManager(); + BeanDescriptor beanDescriptor = protoMapper.getBeanDescriptorManager().getOrCreateBeanDescriptor(type); + + List> fieldSchemas = new ArrayList<>(); + for (Field protoField : message.getFields()) { + PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get(protoField.getName()); + if (propertyDescriptor == null) { + continue; + } + + Object getter = propertyDescriptor.getGetter(); + if (getter == null) { + continue; + } + + FieldSchema fieldSchema = serializerSchemaManager.createSchemaField(protoField, propertyDescriptor); + fieldSchemas.add(fieldSchema); + } + + return FieldMapEx.createFieldMap(fieldSchemas); + } + + @SuppressWarnings("unchecked") + @Override + public void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Map) { + writeFromMap(output, (Map) value); + return; + } + + if (mainPojoCls == value.getClass()) { + writeFromMainPojo(output, (T) value); + return; + } + + writeDynamicPojo(output, value); + } + + private void writeFromMainPojo(OutputEx output, T value) throws IOException { + for (FieldSchema fieldSchema : mainPojoFieldMaps.getFields()) { + fieldSchema.getAndWriteTo(output, value); + } + } + + @SuppressWarnings("unchecked") + private void writeDynamicPojo(OutputEx output, Object dynamicValue) throws IOException { + FieldMapEx fieldMapEx = (FieldMapEx) this.pojoFieldMaps + .computeIfAbsent(dynamicValue.getClass(), this::createPojoFields); + + T value = (T) dynamicValue; + for (FieldSchema fieldSchema : fieldMapEx.getFields()) { + fieldSchema.getAndWriteTo(output, value); + } + } + + protected final void writeFromMap(OutputEx output, Map map) throws IOException { + for (Entry entry : map.entrySet()) { + if (entry.getValue() == null) { + continue; + } + + FieldSchema> fieldSchema = mapFieldMaps.getFieldByName(entry.getKey()); + if (fieldSchema != null) { + fieldSchema.writeTo(output, entry.getValue()); + } + } + } + + @Override + public void mergeFrom(InputEx input, T message) throws IOException { + throw new UnsupportedOperationException(); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/PojoFieldSerializer.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/PojoFieldSerializer.java deleted file mode 100644 index baa2b9cc4dc..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/PojoFieldSerializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; - -import java.io.IOException; - -import org.apache.servicecomb.foundation.common.utils.bean.Getter; -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; - -import io.protostuff.Output; - -public class PojoFieldSerializer { - private final Getter getter; - - private final FieldSchema fieldSchema; - - public PojoFieldSerializer(Getter getter, FieldSchema fieldSchema) { - this.getter = getter; - this.fieldSchema = fieldSchema; - } - - - public void writeTo(Output output, Object instance) throws IOException { - Object value = getter.get(instance); - if (value == null) { - return; - } - - fieldSchema.writeTo(output, value); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/ProtoStreamOutput.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/ProtoStreamOutput.java deleted file mode 100644 index d6e45cb4011..00000000000 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/ProtoStreamOutput.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import io.protostuff.ByteString; -import io.protostuff.LinkedBuffer; -import io.protostuff.Output; -import io.protostuff.ProtobufOutput; -import io.protostuff.Schema; - -public class ProtoStreamOutput implements Output { - private final LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - - private final ProtobufOutput output = new ProtobufOutput(linkedBuffer); - - public byte[] toBytes() { - return output.toByteArray(); - } - - public final void writeInt64(int fieldNumber, long value, boolean repeated) throws IOException { - if (value != 0) { - output.writeInt64(fieldNumber, value, repeated); - } - } - - public final void writeUInt64(int fieldNumber, long value, boolean repeated) throws IOException { - if (value != 0) { - output.writeUInt64(fieldNumber, value, repeated); - } - } - - public final void writeSInt64(int fieldNumber, long value, boolean repeated) throws IOException { - if (value != 0) { - output.writeSInt64(fieldNumber, value, repeated); - } - } - - public final void writeFixed64(int fieldNumber, long value, boolean repeated) throws IOException { - if (value != 0) { - output.writeFixed64(fieldNumber, value, repeated); - } - } - - public final void writeSFixed64(int fieldNumber, long value, boolean repeated) throws IOException { - if (value != 0) { - output.writeSFixed64(fieldNumber, value, repeated); - } - } - - public final void writeInt32(int fieldNumber, int value, boolean repeated) throws IOException { - if (value != 0) { - output.writeInt32(fieldNumber, value, repeated); - } - } - - public final void writeUInt32(int fieldNumber, int value, boolean repeated) throws IOException { - if (value != 0) { - output.writeUInt32(fieldNumber, value, repeated); - } - } - - public final void writeSInt32(int fieldNumber, int value, boolean repeated) throws IOException { - if (value != 0) { - output.writeSInt32(fieldNumber, value, repeated); - } - } - - public final void writeFixed32(int fieldNumber, int value, boolean repeated) throws IOException { - if (value != 0) { - output.writeFixed32(fieldNumber, value, repeated); - } - } - - public final void writeSFixed32(int fieldNumber, int value, boolean repeated) throws IOException { - if (value != 0) { - output.writeSFixed32(fieldNumber, value, repeated); - } - } - - public final void writeFloat(int fieldNumber, float value, boolean repeated) throws IOException { - if (value != 0) { - output.writeFloat(fieldNumber, value, repeated); - } - } - - public final void writeDouble(int fieldNumber, double value, boolean repeated) throws IOException { - if (value != 0) { - output.writeDouble(fieldNumber, value, repeated); - } - } - - public final void writeBool(int fieldNumber, boolean value, boolean repeated) throws IOException { - if (value) { - output.writeBool(fieldNumber, value, repeated); - } - } - - @Override - public void writeEnum(int fieldNumber, int value, boolean repeated) throws IOException { - - } - - // write from String[0], maybe null - public final void writeString(int fieldNumber, @Nullable String value, boolean repeated) throws IOException { - if (value != null && !value.isEmpty()) { - output.writeString(fieldNumber, value, repeated); - } - } - - @Override - public void writeBytes(int fieldNumber, ByteString value, boolean repeated) throws IOException { - output.writeBytes(fieldNumber, value, repeated); - } - - public final void writeByteArray(int fieldNumber, @Nonnull byte[] value, boolean repeated) throws IOException { - output.writeByteArray(fieldNumber, value, repeated); - } - - @Override - public void writeByteRange(boolean utf8String, int fieldNumber, byte[] value, int offset, int length, - boolean repeated) throws IOException { - output.writeByteRange(utf8String, fieldNumber, value, offset, length, repeated); - } - - @Override - public void writeObject(int fieldNumber, T value, Schema schema, boolean repeated) throws IOException { - output.writeObject(fieldNumber, value, schema, repeated); - } - - @Override - public void writeBytes(int fieldNumber, ByteBuffer value, boolean repeated) throws IOException { - output.writeBytes(fieldNumber, value, repeated); - } -} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java index 85cf7a94ab1..d63944e3423 100644 --- a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/SerializerSchemaManager.java @@ -16,121 +16,225 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import static org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils.isWrapProperty; + +import java.lang.reflect.Type; import java.util.Map; import org.apache.servicecomb.foundation.protobuf.ProtoMapper; import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import org.apache.servicecomb.foundation.protobuf.internal.schema.AnySchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.MapSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.MessageAsFieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.PropertyWrapMessageAsFieldSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.PropertyWrapMessageSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.RepeatedSchema; -import org.apache.servicecomb.foundation.protobuf.internal.schema.SchemaCreateContext; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; import org.apache.servicecomb.foundation.protobuf.internal.schema.SchemaManager; - +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnyEntrySchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.any.AnySchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.AnyRepeatedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.BytesRepeatedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.MessagesRepeatedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.PropertyWrapperRepeatedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.StringsRepeatedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.bools.BoolNotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.bools.BoolPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.doubles.DoubleNotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.doubles.DoublePackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.enums.EnumNotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.enums.EnumPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.floats.FloatNotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.floats.FloatPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.Fixed32NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.Fixed32PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.Int32NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.Int32PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.SFixed32NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.SFixed32PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.SInt32NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.SInt32PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.UInt32NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints.UInt32PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.Fixed64NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.Fixed64PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.Int64NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.Int64PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.SFixed64NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.SFixed64PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.SInt64NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.SInt64PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.UInt64NotPackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs.UInt64PackedWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.BoolWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.BytesWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.DoubleWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.EnumWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.Fixed32WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.Fixed64WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.FloatWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.Int32WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.Int64WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.SFixed32WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.SFixed64WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.SInt32WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.SInt64WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.StringWriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.UInt32WriteSchemas; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar.UInt64WriteSchemas; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.protostuff.SchemaEx; import io.protostuff.compiler.model.Field; import io.protostuff.compiler.model.Message; -import io.protostuff.runtime.MessageSchema; +import io.protostuff.compiler.model.ScalarFieldType; +import io.protostuff.runtime.FieldSchema; public class SerializerSchemaManager extends SchemaManager { - // key is short message name - private Map schemas = new HashMap<>(); - - private Map canonicalSchemas = new HashMap<>(); - public SerializerSchemaManager(ProtoMapper protoMapper) { super(protoMapper); - - buildSchemas(); } - public RootSerializer findRootSerializer(String shortMessageName) { - return schemas.get(shortMessageName); + public RootSerializer createRootSerializer(Message message, Type type) { + if (ProtoUtils.isAnyMessage(message)) { + SchemaEx messageSchema = new AnyEntrySchema(protoMapper, type); + return new RootSerializer(messageSchema); + } + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + SchemaEx messageSchema = getOrCreateMessageSchema(message, javaType); + return new RootSerializer(messageSchema); } - public RootSerializer findRootSerializerByCanonical(String canonicalMessageName) { - return canonicalSchemas.get(canonicalMessageName); + public RootSerializer createRootSerializer(Message message, Map types) { + throw new IllegalStateException("not implemented"); } - protected void buildSchemas() { - SchemaCreateContext context = new SchemaCreateContext(); - for (Message message : proto.getMessages()) { - RootSerializer rootSerializer = createRootSerializer(context, message); - schemas.put(message.getName(), rootSerializer); - canonicalSchemas.put(message.getCanonicalName(), rootSerializer); - } + @Override + protected SchemaEx newMessageSchema(Message message, JavaType javaType) { + return new MessageWriteSchema<>(protoMapper, message, javaType); } - protected RootSerializer createRootSerializer(SchemaCreateContext context, Message message) { - MessageSchema schema = createSchema(context, message); - if (isWrapProperty(message)) { - FieldSchema fieldSchema = (FieldSchema) schema.getFields().get(0); - schema = new PropertyWrapMessageSchema(); - ((PropertyWrapMessageSchema) schema).setFieldSchema(fieldSchema); - } - return new RootSerializer(schema); + @Override + protected SchemaEx newMessageSchema(Message message, Map types) { + throw new IllegalStateException("not implemented"); } - protected MessageSchema createSchema(SchemaCreateContext context, Message message) { - MessageSchema schema = context.getSchemas().get(message.getName()); - if (schema != null) { - return schema; + protected FieldSchema createScalarField(Field protoField, PropertyDescriptor propertyDescriptor) { + if (protoField.getType().isEnum()) { + return EnumWriteSchemas.create(protoField, propertyDescriptor); } - schema = newMessageSchema(message); - context.getSchemas().put(message.getName(), schema); - - List> fieldSchemas = new ArrayList<>(); - for (Field protoField : message.getFields()) { - FieldSchema fieldSchema = createSchemaField(context, protoField, protoField.isRepeated()); - fieldSchemas.add(fieldSchema); + switch ((ScalarFieldType) protoField.getType()) { + case INT32: + return Int32WriteSchemas.create(protoField, propertyDescriptor); + case UINT32: + return UInt32WriteSchemas.create(protoField, propertyDescriptor); + case SINT32: + return SInt32WriteSchemas.create(protoField, propertyDescriptor); + case FIXED32: + return Fixed32WriteSchemas.create(protoField, propertyDescriptor); + case SFIXED32: + return SFixed32WriteSchemas.create(protoField, propertyDescriptor); + case INT64: + return Int64WriteSchemas.create(protoField, propertyDescriptor); + case UINT64: + return UInt64WriteSchemas.create(protoField, propertyDescriptor); + case SINT64: + return SInt64WriteSchemas.create(protoField, propertyDescriptor); + case FIXED64: + return Fixed64WriteSchemas.create(protoField, propertyDescriptor); + case SFIXED64: + return SFixed64WriteSchemas.create(protoField, propertyDescriptor); + case FLOAT: + return FloatWriteSchemas.create(protoField, propertyDescriptor); + case DOUBLE: + return DoubleWriteSchemas.create(protoField, propertyDescriptor); + case BOOL: + return BoolWriteSchemas.create(protoField, propertyDescriptor); + case STRING: + return StringWriteSchemas.create(protoField, propertyDescriptor); + case BYTES: + return BytesWriteSchemas.create(protoField, propertyDescriptor); + default: + throw new IllegalStateException("unknown proto field type: " + protoField.getType()); } - schema.init(protoMapper, fieldSchemas, message); - return schema; } - protected FieldSchema createSchemaField(SchemaCreateContext context, Field protoField, boolean repeated) { - if (protoField.isMap()) { - Message entryMessage = (Message) protoField.getType(); - FieldSchema keySchema = createSchemaField(context, entryMessage.getField(1), false); - FieldSchema valueSchema = createSchemaField(context, entryMessage.getField(2), false); - return new MapSchema(protoField, keySchema, valueSchema); - } - - if (protoField.isOneofPart()) { - throw new IllegalStateException("not IMPL oneof now."); - } - - if (repeated) { - FieldSchema schema = createSchemaField(context, protoField, false); - return new RepeatedSchema(protoField, schema); + @Override + protected FieldSchema createRepeatedSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + boolean packed = ProtoUtils.isPacked(protoField); + if (protoField.getType().isEnum()) { + return packed ? EnumPackedWriteSchemas.create(protoField, propertyDescriptor) : + EnumNotPackedWriteSchemas.create(protoField, propertyDescriptor); } - if (isAnyField(protoField, repeated)) { - return new AnySchema(protoMapper, protoField); + if (protoField.getType().isScalar()) { + switch ((ScalarFieldType) protoField.getType()) { + case INT32: + return packed ? Int32PackedWriteSchemas.create(protoField, propertyDescriptor) : + Int32NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case UINT32: + return packed ? UInt32PackedWriteSchemas.create(protoField, propertyDescriptor) : + UInt32NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case SINT32: + return packed ? SInt32PackedWriteSchemas.create(protoField, propertyDescriptor) : + SInt32NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case FIXED32: + return packed ? Fixed32PackedWriteSchemas.create(protoField, propertyDescriptor) : + Fixed32NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case SFIXED32: + return packed ? SFixed32PackedWriteSchemas.create(protoField, propertyDescriptor) : + SFixed32NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case INT64: + return packed ? Int64PackedWriteSchemas.create(protoField, propertyDescriptor) : + Int64NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case UINT64: + return packed ? UInt64PackedWriteSchemas.create(protoField, propertyDescriptor) : + UInt64NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case SINT64: + return packed ? SInt64PackedWriteSchemas.create(protoField, propertyDescriptor) : + SInt64NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case FIXED64: + return packed ? Fixed64PackedWriteSchemas.create(protoField, propertyDescriptor) : + Fixed64NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case SFIXED64: + return packed ? SFixed64PackedWriteSchemas.create(protoField, propertyDescriptor) : + SFixed64NotPackedWriteSchemas.create(protoField, propertyDescriptor); + case FLOAT: + return packed ? FloatPackedWriteSchemas.create(protoField, propertyDescriptor) : + FloatNotPackedWriteSchemas.create(protoField, propertyDescriptor); + case DOUBLE: + return packed ? DoublePackedWriteSchemas.create(protoField, propertyDescriptor) : + DoubleNotPackedWriteSchemas.create(protoField, propertyDescriptor); + case BOOL: + return packed ? BoolPackedWriteSchemas.create(protoField, propertyDescriptor) : + BoolNotPackedWriteSchemas.create(protoField, propertyDescriptor); + case STRING: + return StringsRepeatedWriteSchemas.create(protoField, propertyDescriptor); + case BYTES: + return BytesRepeatedWriteSchemas.create(protoField, propertyDescriptor); + default: + ProtoUtils.throwNotSupportWrite(protoField, propertyDescriptor.getJavaType().getRawClass()); + } } - if (protoField.getType().isEnum()) { - return new EnumSerializerSchema(protoField); + if (ProtoUtils.isAnyField(protoField)) { + FieldSchema anySchema = new AnySchema<>(protoMapper, protoField, propertyDescriptor); + return AnyRepeatedWriteSchemas.create(protoField, propertyDescriptor, anySchema); } - if (protoField.getType().isScalar()) { - return createScalarField(protoField); + if (protoField.getType().isMessage()) { + JavaType contentType = propertyDescriptor.getJavaType().getContentType(); + if (contentType == null) { + contentType = ProtoConst.OBJECT_TYPE; + } + SchemaEx contentSchema = createMessageSchema((Message) protoField.getType(), contentType); + if (isWrapProperty((Message) protoField.getType())) { + return PropertyWrapperRepeatedWriteSchemas.create(protoField, propertyDescriptor, contentSchema); + } + + return MessagesRepeatedWriteSchemas.create(protoField, propertyDescriptor, contentSchema); } - // message - MessageSchema messageSchema = createSchema(context, (Message) protoField.getType()); - MessageAsFieldSchema messageAsFieldSchema; - if (isWrapProperty((Message) protoField.getType())) { - messageAsFieldSchema = new PropertyWrapMessageAsFieldSchema(protoField, messageSchema); - } else { - messageAsFieldSchema = new MessageAsFieldSchema(protoField, messageSchema); - } - return messageAsFieldSchema; + ProtoUtils.throwNotSupportWrite(protoField, propertyDescriptor.getJavaType().getRawClass()); + return null; } } diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractPrimitiveWriters.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractPrimitiveWriters.java new file mode 100644 index 00000000000..e244797ea9f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractPrimitiveWriters.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated; + +import static org.apache.servicecomb.foundation.common.utils.ReflectUtils.getFieldArgument; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; + +import io.protostuff.OutputEx; +import io.protostuff.SchemaWriter; +import io.protostuff.compiler.model.Field; + +public abstract class AbstractPrimitiveWriters extends + AbstractWriters { + public SchemaWriter primitiveArrayWriter; + + public final Class primitiveArrayClass; + + @SuppressWarnings("unchecked") + public AbstractPrimitiveWriters(Field protoField) { + super(protoField); + + this.primitiveArrayClass = getFieldArgument(this.getClass(), "primitiveArrayClass"); + } + + @SuppressWarnings("unchecked") + public final void dynamicWriteTo(OutputEx output, Object value) throws IOException { + // from normal model + if (primitiveArrayClass.isInstance(value)) { + primitiveArrayWriter.writeTo(output, (PRIMITIVE_ARRAY) value); + return; + } + + if (arrayClass.isInstance(value)) { + arrayWriter.writeTo(output, (PRIMITIVE_WRAPPER[]) value); + return; + } + + if (value instanceof Collection) { + collectionWriter.writeTo(output, (Collection) value); + return; + } + + // from http request + if (value instanceof String[]) { + stringArrayWriter.writeTo(output, (String[]) value); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractWriters.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractWriters.java new file mode 100644 index 00000000000..bb784ff7632 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/AbstractWriters.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated; + +import static org.apache.servicecomb.foundation.common.utils.ReflectUtils.getFieldArgument; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; + +import io.protostuff.OutputEx; +import io.protostuff.ProtobufOutputEx; +import io.protostuff.SchemaWriter; +import io.protostuff.WireFormat; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldTypeUtils; + +public abstract class AbstractWriters { + protected final Field protoField; + + protected final int tag; + + protected final int tagSize; + + public SchemaWriter arrayWriter; + + public SchemaWriter> collectionWriter; + + public SchemaWriter stringArrayWriter; + + public final Class arrayClass; + + @SuppressWarnings("unchecked") + public AbstractWriters(Field protoField) { + this(protoField, null); + } + + public AbstractWriters(Field protoField, Class arrayClass) { + this.protoField = protoField; + int wireType = ProtoUtils.isPacked(protoField) && protoField.isRepeated() ? WireFormat.WIRETYPE_LENGTH_DELIMITED + : FieldTypeUtils.convert(protoField.getType()).wireType; + this.tag = WireFormat.makeTag(protoField.getTag(), wireType); + this.tagSize = ProtobufOutputEx.computeRawVarint32Size(tag); + + if (arrayClass == null) { + arrayClass = getFieldArgument(this.getClass(), "arrayWriter"); + } + this.arrayClass = arrayClass; + } + + @SuppressWarnings("unchecked") + public void dynamicWriteTo(OutputEx output, Object value) throws IOException { + if (value instanceof Collection) { + collectionWriter.writeTo(output, (Collection) value); + return; + } + + // from normal model + if (arrayClass.isInstance(value)) { + arrayWriter.writeTo(output, (T[]) value); + return; + } + + // from http request + if (value instanceof String[]) { + stringArrayWriter.writeTo(output, (String[]) value); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedPrimitiveWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedPrimitiveWriteSchemas.java new file mode 100644 index 00000000000..8b01e83f8d8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedPrimitiveWriteSchemas.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas.DynamicSchema; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class RepeatedPrimitiveWriteSchemas { + public static FieldSchema create(Field protoField, + PropertyDescriptor propertyDescriptor, + AbstractPrimitiveWriters writers) { + JavaType javaType = propertyDescriptor.getJavaType(); + if (writers.primitiveArrayClass == javaType.getRawClass()) { + return new PrimitiveArraySchema<>(protoField, propertyDescriptor, writers); + } + + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, writers); + } + + private static class PrimitiveArraySchema extends + DynamicSchema { + private final Getter getter; + + private final AbstractPrimitiveWriters primitiveWriters; + + public PrimitiveArraySchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractPrimitiveWriters writers) { + super(protoField, propertyDescriptor, writers); + this.getter = propertyDescriptor.getGetter(); + this.primitiveWriters = writers; + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + PRIMITIVE_ARRAY value = getter.get(message); + if (value == null) { + return; + } + + primitiveWriters.primitiveArrayWriter.writeTo(output, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedWriteSchemas.java new file mode 100644 index 00000000000..5d0a332a09e --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/RepeatedWriteSchemas.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class RepeatedWriteSchemas { + public static FieldSchema create(Field protoField, + PropertyDescriptor propertyDescriptor, + AbstractWriters writers) { + return new CollectionSchema<>(protoField, propertyDescriptor, writers); + } + + static class DynamicSchema extends FieldSchema { + protected final AbstractWriters writers; + + @SuppressWarnings("unchecked") + public DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractWriters writers) { + super(protoField, propertyDescriptor.getJavaType()); + + this.writers = writers; + } + + @SuppressWarnings("unchecked") + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + writers.dynamicWriteTo(output, value); + } + } + + private static class CollectionSchema extends DynamicSchema { + private final Getter getter; + + public CollectionSchema(Field protoField, PropertyDescriptor propertyDescriptor, + AbstractWriters writers) { + super(protoField, propertyDescriptor, writers); + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value == null) { + return; + } + this.writeTo(output, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/AnyRepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/AnyRepeatedWriteSchemas.java new file mode 100644 index 00000000000..03324385c64 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/AnyRepeatedWriteSchemas.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class AnyRepeatedWriteSchemas { + private static class AnyWriters extends AbstractWriters { + public AnyWriters(Field protoField, FieldSchema anySchema) { + super(protoField); + + arrayWriter = (output, array) -> { + for (Object element : array) { + if (element != null) { + anySchema.writeTo(output, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (Object element : collection) { + if (element != null) { + anySchema.writeTo(output, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + @SuppressWarnings("unchecked") + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + FieldSchema anySchema) { + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, new AnyWriters<>(protoField, anySchema)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/BytesRepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/BytesRepeatedWriteSchemas.java new file mode 100644 index 00000000000..64c009cf2fe --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/BytesRepeatedWriteSchemas.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BytesRepeatedWriteSchemas { + private static class BytesWriters extends AbstractWriters { + public BytesWriters(Field protoField) { + super(protoField); + + arrayWriter = (output, array) -> { + for (byte[] element : array) { + if (element != null) { + output.writeByteArray(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (byte[] element : collection) { + if (element != null) { + output.writeByteArray(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + @SuppressWarnings("unchecked") + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, new BytesWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/MessagesRepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/MessagesRepeatedWriteSchemas.java new file mode 100644 index 00000000000..702a849eef2 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/MessagesRepeatedWriteSchemas.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl; + +import java.lang.reflect.Array; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.MessageWriteSchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import io.protostuff.SchemaWriter; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class MessagesRepeatedWriteSchemas { + private static class MessageWriters extends AbstractWriters { + @SuppressWarnings("unchecked") + public MessageWriters(Field protoField, SchemaWriter elementSchema) { + super(protoField, + (Class) Array.newInstance(((MessageWriteSchema) elementSchema).getMainPojoCls(), 0) + .getClass()); + + arrayWriter = (output, array) -> { + for (Object element : array) { + if (element != null) { + output.writeObject(tag, tagSize, element, elementSchema); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (Object element : collection) { + if (element != null) { + output.writeObject(tag, tagSize, element, elementSchema); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + @SuppressWarnings("unchecked") + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaWriter elementSchema) { + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, new MessageWriters(protoField, elementSchema)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/PropertyWrapperRepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/PropertyWrapperRepeatedWriteSchemas.java new file mode 100644 index 00000000000..829fd94d155 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/PropertyWrapperRepeatedWriteSchemas.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl; + +import java.lang.reflect.Array; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.MessageWriteSchema; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.SchemaWriter; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class PropertyWrapperRepeatedWriteSchemas { + private static class PropertyWrapperWriters extends AbstractWriters { + public PropertyWrapperWriters(Field protoField, SchemaWriter elementSchema, Class arrayClass) { + super(protoField, arrayClass); + + FieldSchema fieldSchema = + (elementSchema instanceof MessageWriteSchema) ? ((MessageWriteSchema) elementSchema) + .getMainPojoFieldMaps() + .getFieldByNumber(1) : null; + arrayWriter = (output, array) -> { + for (Object element : array) { + if (element != null) { + output.writeObject(tag, tagSize, element, fieldSchema::writeTo); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (Object element : collection) { + if (element != null) { + output.writeObject(tag, tagSize, element, fieldSchema::writeTo); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + @SuppressWarnings("unchecked") + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor, + SchemaWriter elementSchema) { + JavaType contentType = propertyDescriptor.getJavaType().getContentType(); + Class contentClass = contentType == null ? Object.class : (Class) contentType.getRawClass(); + Class arrayClass = (Class) Array.newInstance(contentClass, 0).getClass(); + return RepeatedWriteSchemas + .create(protoField, propertyDescriptor, new PropertyWrapperWriters(protoField, elementSchema, arrayClass)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/StringsRepeatedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/StringsRepeatedWriteSchemas.java new file mode 100644 index 00000000000..16e71edcda0 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/StringsRepeatedWriteSchemas.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class StringsRepeatedWriteSchemas { + private static class StringWriters extends AbstractWriters { + public StringWriters(Field protoField) { + super(protoField); + + arrayWriter = (output, array) -> { + for (String element : array) { + if (element != null) { + output.writeString(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (String element : collection) { + if (element != null) { + output.writeString(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + @SuppressWarnings("unchecked") + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, new StringWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolNotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolNotPackedWriteSchemas.java new file mode 100644 index 00000000000..64d024bc279 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolNotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.bools; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolNotPackedWriteSchemas { + private static class BoolNotPackedWriters extends AbstractPrimitiveWriters { + public BoolNotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, boolean[] array) -> { + for (boolean element : array) { + output.writeBool(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Boolean[] array) -> { + for (Boolean element : array) { + if (element != null) { + output.writeBool(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Boolean element : collection) { + if (element != null) { + output.writeBool(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + boolean parsedValue = Boolean.parseBoolean(element); + output.writeBool(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new BoolNotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolPackedWriteSchemas.java new file mode 100644 index 00000000000..699e82e4f06 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/bools/BoolPackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.bools; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolPackedWriteSchemas { + private static class BoolPackedWriters extends AbstractPrimitiveWriters { + public BoolPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (boolean element : array) { + output.writePackedBool(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Boolean element : array) { + if (element != null) { + output.writePackedBool(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Boolean element : collection) { + if (element != null) { + output.writePackedBool(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + boolean parsedValue = Boolean.parseBoolean(element); + output.writePackedBool(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new BoolPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoubleNotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoubleNotPackedWriteSchemas.java new file mode 100644 index 00000000000..1bafb7c690f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoubleNotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.doubles; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoubleNotPackedWriteSchemas { + private static class DoubleNotPackedWriters extends AbstractPrimitiveWriters { + public DoubleNotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, double[] array) -> { + for (double element : array) { + output.writeDouble(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Double[] array) -> { + for (Double element : array) { + if (element != null) { + output.writeDouble(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Double element : collection) { + if (element != null) { + output.writeDouble(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + double parsedValue = Double.parseDouble(element); + output.writeDouble(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new DoubleNotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoublePackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoublePackedWriteSchemas.java new file mode 100644 index 00000000000..7de41eb5709 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/doubles/DoublePackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.doubles; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoublePackedWriteSchemas { + private static class DoublePackedWriters extends AbstractPrimitiveWriters { + public DoublePackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (double element : array) { + output.writePackedDouble(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Double element : array) { + if (element != null) { + output.writePackedDouble(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Double element : collection) { + if (element != null) { + output.writePackedDouble(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + double parsedValue = Double.parseDouble(element); + output.writePackedDouble(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new DoublePackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumNotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumNotPackedWriteSchemas.java new file mode 100644 index 00000000000..220c9e03953 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumNotPackedWriteSchemas.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.enums; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumNotPackedWriteSchemas { + private static class EnumNotPackedWriters extends AbstractWriters> { + private final EnumMeta enumMeta; + + @SuppressWarnings("unchecked") + public EnumNotPackedWriters(Field protoField, JavaType javaType) { + super(protoField, ReflectUtils.constructArrayType(Enum.class)); + this.enumMeta = new EnumMeta(protoField, javaType); + + arrayWriter = (output, array) -> { + for (Enum element : array) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + String name = element.name(); + Integer enumValue = enumMeta.getValueByName(name); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + name, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeEnum(tag, tagSize, enumValue); + } + }; + + collectionWriter = (output, collection) -> { + if (collection.isEmpty()) { + return; + } + + Object first = collection.iterator().next(); + if (first.getClass().isEnum()) { + writeEnumCollection(output, collection); + return; + } + + if (first.getClass() == String.class) { + writeStringCollection(output, (Collection) (Object) collection); + return; + } + + writeIntCollection(output, (Collection) (Object) collection); + }; + + stringArrayWriter = (output, array) -> { + for (String element : array) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + Integer enumValue = enumMeta.getValueByName(element); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + element, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeEnum(tag, tagSize, enumValue); + } + }; + } + + private void writeStringCollection(OutputEx output, Collection collection) throws IOException { + for (String element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + Integer enumValue = enumMeta.getValueByName(element); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + element, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeEnum(tag, tagSize, enumValue); + } + } + + private void writeIntCollection(OutputEx output, Collection collection) throws IOException { + for (Number element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + output.writeInt32(tag, tagSize, element.intValue()); + } + } + + private void writeEnumCollection(OutputEx output, Collection> collection) throws IOException { + for (Enum element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + String name = element.name(); + Integer enumValue = enumMeta.getValueByName(name); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + name, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeEnum(tag, tagSize, enumValue); + } + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedWriteSchemas.create(protoField, propertyDescriptor, + new EnumNotPackedWriters(protoField, propertyDescriptor.getJavaType())); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumPackedWriteSchemas.java new file mode 100644 index 00000000000..36b270c25c8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/enums/EnumPackedWriteSchemas.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.enums; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedWriteSchemas; + +import com.fasterxml.jackson.databind.JavaType; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumPackedWriteSchemas { + private static class EnumsPackedWriters extends AbstractWriters> { + private final EnumMeta enumMeta; + + @SuppressWarnings("unchecked") + public EnumsPackedWriters(Field protoField, JavaType javaType) { + super(protoField, ReflectUtils.constructArrayType(Enum.class)); + this.enumMeta = new EnumMeta(protoField, javaType); + + arrayWriter = (o, value) -> o.writeObject(tag, tagSize, value, (output, array) -> { + for (Enum element : array) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + String name = element.name(); + Integer enumValue = enumMeta.getValueByName(name); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + name, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writePackedEnum(enumValue); + } + }); + + collectionWriter = (o, value) -> o.writeObject(tag, tagSize, value, (output, collection) -> { + Object first = collection.iterator().next(); + if (first.getClass().isEnum()) { + writeEnumCollection(output, collection); + return; + } + + if (first.getClass() == String.class) { + writeStringCollection(output, (Collection) (Object) collection); + return; + } + + writeIntCollection(output, (Collection) (Object) collection); + }); + + stringArrayWriter = (o, value) -> o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + Integer enumValue = enumMeta.getValueByName(element); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + element, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writePackedEnum(enumValue); + } + }); + } + + private void writeStringCollection(OutputEx output, Collection collection) throws IOException { + for (String element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + Integer enumValue = enumMeta.getValueByName(element); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + element, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writePackedEnum(enumValue); + } + } + + private void writeIntCollection(OutputEx output, Collection collection) throws IOException { + for (Number element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + output.writePackedInt32(element.intValue()); + } + } + + private void writeEnumCollection(OutputEx output, Collection> collection) throws IOException { + for (Enum element : collection) { + if (element == null) { + ProtoUtils.throwNotSupportNullElement(protoField); + return; + } + + String name = element.name(); + Integer enumValue = enumMeta.getValueByName(name); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + name, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writePackedEnum(enumValue); + } + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedWriteSchemas + .create(protoField, propertyDescriptor, new EnumsPackedWriters(protoField, propertyDescriptor.getJavaType())); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatNotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatNotPackedWriteSchemas.java new file mode 100644 index 00000000000..82f2f377565 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatNotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.floats; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatNotPackedWriteSchemas { + private static class FloatNotPackedWriters extends AbstractPrimitiveWriters { + public FloatNotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, float[] array) -> { + for (float element : array) { + output.writeFloat(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Float[] array) -> { + for (Float element : array) { + if (element != null) { + output.writeFloat(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Float element : collection) { + if (element != null) { + output.writeFloat(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + float parsedValue = Float.parseFloat(element); + output.writeFloat(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new FloatNotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatPackedWriteSchemas.java new file mode 100644 index 00000000000..5d6d2d4c29e --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/floats/FloatPackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.floats; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatPackedWriteSchemas { + private static class FloatPackedWriters extends AbstractPrimitiveWriters { + public FloatPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (float element : array) { + output.writePackedFloat(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Float element : array) { + if (element != null) { + output.writePackedFloat(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Float element : collection) { + if (element != null) { + output.writePackedFloat(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + float parsedValue = Float.parseFloat(element); + output.writePackedFloat(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new FloatPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32NotPackedWriteSchemas.java new file mode 100644 index 00000000000..4e05ac2fe64 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32NotPackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32NotPackedWriteSchemas { + private static class Fixed32NotPackedWriters extends AbstractPrimitiveWriters { + public Fixed32NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, int[] array) -> { + for (int element : array) { + output.writeFixed32(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Integer[] array) -> { + for (Integer element : array) { + if (element != null) { + output.writeFixed32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writeFixed32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writeFixed32(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas + .create(protoField, propertyDescriptor, new Fixed32NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32PackedWriteSchemas.java new file mode 100644 index 00000000000..9a5c99569a4 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Fixed32PackedWriteSchemas.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32PackedWriteSchemas { + private static class Fixed32PackedWriters extends AbstractPrimitiveWriters { + public Fixed32PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (int element : array) { + output.writePackedFixed32(element); + } + }); + }; + + arrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Integer element : array) { + if (element != null) { + output.writePackedFixed32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + collectionWriter = (o, value) -> { + if (value.isEmpty()) { + return; + } + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writePackedFixed32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + stringArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writePackedFixed32(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Fixed32PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32NotPackedWriteSchemas.java new file mode 100644 index 00000000000..55d61bf4bf9 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int32NotPackedWriteSchemas { + private static class Int32NotPackedWriters extends AbstractPrimitiveWriters { + public Int32NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, int[] array) -> { + for (int element : array) { + output.writeInt32(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Integer[] array) -> { + for (Integer element : array) { + if (element != null) { + output.writeInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writeInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writeInt32(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Int32NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32PackedWriteSchemas.java new file mode 100644 index 00000000000..5f8b8568b27 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/Int32PackedWriteSchemas.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int32PackedWriteSchemas { + private static class Int32PackedWriters extends AbstractPrimitiveWriters { + public Int32PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (int element : array) { + output.writePackedInt32(element); + } + }); + }; + + arrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Integer element : array) { + if (element != null) { + output.writePackedInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + collectionWriter = (o, value) -> { + if (value.isEmpty()) { + return; + } + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writePackedInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + stringArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writePackedInt32(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Int32PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32NotPackedWriteSchemas.java new file mode 100644 index 00000000000..2bf91cf5221 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32NotPackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32NotPackedWriteSchemas { + private static class SFixed32NotPackedWriters extends AbstractPrimitiveWriters { + public SFixed32NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, int[] array) -> { + for (int element : array) { + output.writeSFixed32(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Integer[] array) -> { + for (Integer element : array) { + if (element != null) { + output.writeSFixed32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writeSFixed32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writeSFixed32(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas + .create(protoField, propertyDescriptor, new SFixed32NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32PackedWriteSchemas.java new file mode 100644 index 00000000000..7e0272e5ae6 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SFixed32PackedWriteSchemas.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32PackedWriteSchemas { + private static class SFixed32PackedWriters extends AbstractPrimitiveWriters { + public SFixed32PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (int element : array) { + output.writePackedSFixed32(element); + } + }); + }; + + arrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Integer element : array) { + if (element != null) { + output.writePackedSFixed32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + collectionWriter = (o, value) -> { + if (value.isEmpty()) { + return; + } + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writePackedSFixed32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + stringArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writePackedSFixed32(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SFixed32PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32NotPackedWriteSchemas.java new file mode 100644 index 00000000000..a1ce05dd544 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32NotPackedWriteSchemas { + private static class SInt32NotPackedWriters extends AbstractPrimitiveWriters { + public SInt32NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, int[] array) -> { + for (int element : array) { + output.writeSInt32(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Integer[] array) -> { + for (Integer element : array) { + if (element != null) { + output.writeSInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writeSInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writeSInt32(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SInt32NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32PackedWriteSchemas.java new file mode 100644 index 00000000000..202ae2f0068 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/SInt32PackedWriteSchemas.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32PackedWriteSchemas { + private static class SInt32PackedWriters extends AbstractPrimitiveWriters { + public SInt32PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (int element : array) { + output.writePackedSInt32(element); + } + }); + }; + + arrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Integer element : array) { + if (element != null) { + output.writePackedSInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + collectionWriter = (o, value) -> { + if (value.isEmpty()) { + return; + } + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writePackedSInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + stringArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writePackedSInt32(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SInt32PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32NotPackedWriteSchemas.java new file mode 100644 index 00000000000..daffa24eea2 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32NotPackedWriteSchemas { + private static class UInt32NotPackedWriters extends AbstractPrimitiveWriters { + public UInt32NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, int[] array) -> { + for (int element : array) { + output.writeUInt32(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Integer[] array) -> { + for (Integer element : array) { + if (element != null) { + output.writeUInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writeUInt32(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writeUInt32(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new UInt32NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32PackedWriteSchemas.java new file mode 100644 index 00000000000..61be0eed41e --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/ints/UInt32PackedWriteSchemas.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.ints; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32PackedWriteSchemas { + private static class UInt32PackedWriters extends AbstractPrimitiveWriters { + public UInt32PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (int element : array) { + output.writePackedUInt32(element); + } + }); + }; + + arrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Integer element : array) { + if (element != null) { + output.writePackedUInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + collectionWriter = (o, value) -> { + if (value.isEmpty()) { + return; + } + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Integer element : collection) { + if (element != null) { + output.writePackedUInt32(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + + stringArrayWriter = (o, value) -> { + if (value.length == 0) { + return; + } + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + int parsedValue = Integer.parseInt(element, 10); + output.writePackedUInt32(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new UInt32PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64NotPackedWriteSchemas.java new file mode 100644 index 00000000000..63bbaa053b8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64NotPackedWriteSchemas.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64NotPackedWriteSchemas { + private static class Fixed64NotPackedWriters extends AbstractPrimitiveWriters { + public Fixed64NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (output, array) -> { + for (long element : array) { + output.writeFixed64(tag, tagSize, element); + } + }; + + arrayWriter = (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writeFixed64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writeFixed64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writeFixed64(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas + .create(protoField, propertyDescriptor, new Fixed64NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64PackedWriteSchemas.java new file mode 100644 index 00000000000..35271482dc2 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Fixed64PackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64PackedWriteSchemas { + private static class Fixed64PackedWriters extends AbstractPrimitiveWriters { + public Fixed64PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (long element : array) { + output.writePackedFixed64(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writePackedFixed64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writePackedFixed64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writePackedFixed64(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Fixed64PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64NotPackedWriteSchemas.java new file mode 100644 index 00000000000..2c7f6a708b5 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64NotPackedWriteSchemas { + private static class Int64NotPackedWriters extends AbstractPrimitiveWriters { + public Int64NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, long[] array) -> { + for (long element : array) { + output.writeInt64(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Long[] array) -> { + for (Long element : array) { + if (element != null) { + output.writeInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Long element : collection) { + if (element != null) { + output.writeInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writeInt64(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Int64NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64PackedWriteSchemas.java new file mode 100644 index 00000000000..1cc9f48f374 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/Int64PackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64PackedWriteSchemas { + private static class Int64PackedWriters extends AbstractPrimitiveWriters { + public Int64PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (long element : array) { + output.writePackedInt64(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writePackedInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writePackedInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writePackedInt64(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new Int64PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64NotPackedWriteSchemas.java new file mode 100644 index 00000000000..1b0ba7cf44c --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64NotPackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64NotPackedWriteSchemas { + private static class SFixed64NotPackedWriters extends AbstractPrimitiveWriters { + public SFixed64NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, long[] array) -> { + for (long element : array) { + output.writeSFixed64(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Long[] array) -> { + for (Long element : array) { + if (element != null) { + output.writeSFixed64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Long element : collection) { + if (element != null) { + output.writeSFixed64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writeSFixed64(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas + .create(protoField, propertyDescriptor, new SFixed64NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64PackedWriteSchemas.java new file mode 100644 index 00000000000..b33c5efcd82 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SFixed64PackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64PackedWriteSchemas { + private static class SFixed64PackedWriters extends AbstractPrimitiveWriters { + public SFixed64PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (long element : array) { + output.writePackedSFixed64(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writePackedSFixed64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writePackedSFixed64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writePackedSFixed64(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SFixed64PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64NotPackedWriteSchemas.java new file mode 100644 index 00000000000..95e8db52016 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64NotPackedWriteSchemas { + private static class SInt64NotPackedWriters extends AbstractPrimitiveWriters { + public SInt64NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, long[] array) -> { + for (long element : array) { + output.writeSInt64(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Long[] array) -> { + for (Long element : array) { + if (element != null) { + output.writeSInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Long element : collection) { + if (element != null) { + output.writeSInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writeSInt64(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SInt64NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64PackedWriteSchemas.java new file mode 100644 index 00000000000..429e2314b33 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/SInt64PackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64PackedWriteSchemas { + private static class SInt64PackedWriters extends AbstractPrimitiveWriters { + public SInt64PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (long element : array) { + output.writePackedSInt64(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writePackedSInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writePackedSInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writePackedSInt64(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new SInt64PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64NotPackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64NotPackedWriteSchemas.java new file mode 100644 index 00000000000..ebc10b21cdf --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64NotPackedWriteSchemas.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import java.util.Collection; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64NotPackedWriteSchemas { + private static class UInt64NotPackedWriters extends AbstractPrimitiveWriters { + public UInt64NotPackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (OutputEx output, long[] array) -> { + for (long element : array) { + output.writeUInt64(tag, tagSize, element); + } + }; + + arrayWriter = (OutputEx output, Long[] array) -> { + for (Long element : array) { + if (element != null) { + output.writeUInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + collectionWriter = (OutputEx output, Collection collection) -> { + for (Long element : collection) { + if (element != null) { + output.writeUInt64(tag, tagSize, element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + + stringArrayWriter = (OutputEx output, String[] array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writeUInt64(tag, tagSize, parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }; + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new UInt64NotPackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64PackedWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64PackedWriteSchemas.java new file mode 100644 index 00000000000..95511a44f0d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/repeated/impl/longs/UInt64PackedWriteSchemas.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.impl.longs; + +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.AbstractPrimitiveWriters; +import org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.repeated.RepeatedPrimitiveWriteSchemas; + +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64PackedWriteSchemas { + private static class UInt64PackedWriters extends AbstractPrimitiveWriters { + public UInt64PackedWriters(Field protoField) { + super(protoField); + + primitiveArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (long element : array) { + output.writePackedUInt64(element); + } + }); + + arrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (Long element : array) { + if (element != null) { + output.writePackedUInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + collectionWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, collection) -> { + for (Long element : collection) { + if (element != null) { + output.writePackedUInt64(element); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + + stringArrayWriter = (o, value) -> + o.writeObject(tag, tagSize, value, (output, array) -> { + for (String element : array) { + if (element != null) { + long parsedValue = Long.parseLong(element, 10); + output.writePackedUInt64(parsedValue); + continue; + } + + ProtoUtils.throwNotSupportNullElement(protoField); + } + }); + } + } + + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + return RepeatedPrimitiveWriteSchemas.create(protoField, propertyDescriptor, new UInt64PackedWriters(protoField)); + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BoolWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BoolWriteSchemas.java new file mode 100644 index 00000000000..6c57b6f2211 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BoolWriteSchemas.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.BoolGetter; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BoolWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (boolean.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new BooleanPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Boolean.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new BooleanSchema<>(protoField, propertyDescriptor); + } + + return new BooleanSchema<>(protoField, propertyDescriptor); + } + + private static class BooleanDynamicSchema extends FieldSchema { + public BooleanDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Boolean) { + output.writeScalarBool(tag, tagSize, (boolean) value); + return; + } + + if (value instanceof Number) { + output.writeScalarBool(tag, tagSize, ((Number) value).longValue() == 1); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + boolean parsedValue = Boolean.parseBoolean(((String[]) value)[0]); + output.writeScalarBool(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + boolean parsedValue = Boolean.parseBoolean((String) value); + output.writeScalarBool(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class BooleanSchema extends BooleanDynamicSchema { + protected final Getter getter; + + public BooleanSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class BooleanPrimitiveSchema extends BooleanDynamicSchema { + private final BoolGetter primitiveGetter; + + public BooleanPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + boolean value = primitiveGetter.get(message); + output.writeScalarBool(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BytesWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BytesWriteSchemas.java new file mode 100644 index 00000000000..865e4a7c70f --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/BytesWriteSchemas.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class BytesWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (byte[].class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new BytesSchema<>(protoField, propertyDescriptor); + } + + return new BytesSchema<>(protoField, propertyDescriptor); + } + + private static class BytesDynamicSchema extends FieldSchema { + public BytesDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof byte[]) { + output.writeByteArray(tag, tagSize, (byte[]) value); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class BytesSchema extends BytesDynamicSchema { + protected final Getter getter; + + public BytesSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/DoubleWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/DoubleWriteSchemas.java new file mode 100644 index 00000000000..8e1c5baece5 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/DoubleWriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.DoubleGetter; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class DoubleWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (double.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new DoublePrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Double.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new DoubleSchema<>(protoField, propertyDescriptor); + } + + return new DoubleSchema<>(protoField, propertyDescriptor); + } + + private static class DoubleDynamicSchema extends FieldSchema { + public DoubleDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarDouble(tag, tagSize, ((Number) value).doubleValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + double parsedValue = Double.parseDouble(((String[]) value)[0]); + output.writeScalarDouble(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + double parsedValue = Double.parseDouble((String) value); + output.writeScalarDouble(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class DoubleSchema extends DoubleDynamicSchema { + protected final Getter getter; + + public DoubleSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class DoublePrimitiveSchema extends DoubleDynamicSchema { + private final DoubleGetter primitiveGetter; + + public DoublePrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + double value = primitiveGetter.get(message); + output.writeScalarDouble(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/EnumWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/EnumWriteSchemas.java new file mode 100644 index 00000000000..8b4f82f858d --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/EnumWriteSchemas.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.base.DynamicEnum; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; +import org.apache.servicecomb.foundation.protobuf.internal.schema.EnumMeta; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.compiler.model.Type; +import io.protostuff.runtime.FieldSchema; + +public class EnumWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (propertyDescriptor.getJavaType().isEnumType()) { + return new EnumSchema<>(protoField, propertyDescriptor); + } + + return new EnumSchema<>(protoField, propertyDescriptor); + } + + private static class EnumDynamicSchema extends FieldSchema { + private final EnumMeta enumMeta; + + public EnumDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + this.enumMeta = new EnumMeta(protoField, javaType); + } + + protected final void numberWrite(OutputEx output, Number value) throws IOException { + int enumValue = value.intValue(); + if (!enumMeta.containsValue(enumValue)) { + throw new IllegalStateException( + String.format("invalid enum value %d for proto %s, field=%s:%s", + enumValue, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeScalarInt32(tag, tagSize, enumValue); + } + + protected final void stringWrite(OutputEx output, String enumName) throws IOException { + Integer enumValue = enumMeta.getValueByName(enumName); + if (enumValue == null) { + throw new IllegalStateException( + String.format("invalid enum name %s for proto %s, field=%s:%s", + enumName, + protoField.getTypeName(), + ((Type) protoField.getParent()).getCanonicalName(), + protoField.getName())); + } + + output.writeScalarInt32(tag, tagSize, enumValue); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Enum) { + stringWrite(output, ((Enum) value).name()); + return; + } + + if (value instanceof DynamicEnum) { + // protobuf can not support unknown enum, because protobuf encode enum as tag value + writeTo(output, ((DynamicEnum) value).getValue()); + return; + } + + if (value instanceof Number) { + // need to check if it is a valid number + // because maybe come from http request + numberWrite(output, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + + stringWrite(output, ((String[]) value)[0]); + return; + } + + if (value instanceof String) { + stringWrite(output, (String) value); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class EnumSchema extends EnumDynamicSchema { + protected final Getter getter; + + public EnumSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed32WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed32WriteSchemas.java new file mode 100644 index 00000000000..cee4c90cb23 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed32WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed32WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (int.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new Fixed32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new Fixed32Schema<>(protoField, propertyDescriptor); + } + + return new Fixed32Schema<>(protoField, propertyDescriptor); + } + + private static class Fixed32DynamicSchema extends FieldSchema { + public Fixed32DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarFixed32(tag, tagSize, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + int parsedValue = Integer.parseInt(((String[]) value)[0], 10); + output.writeScalarFixed32(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + int parsedValue = Integer.parseInt((String) value, 10); + output.writeScalarFixed32(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class Fixed32Schema extends Fixed32DynamicSchema { + protected final Getter getter; + + public Fixed32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class Fixed32PrimitiveSchema extends Fixed32DynamicSchema { + private final IntGetter primitiveGetter; + + public Fixed32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + int value = primitiveGetter.get(message); + output.writeScalarFixed32(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed64WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed64WriteSchemas.java new file mode 100644 index 00000000000..22d982b1ce1 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Fixed64WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Fixed64WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new Fixed64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new Fixed64Schema<>(protoField, propertyDescriptor); + } + + return new Fixed64Schema<>(protoField, propertyDescriptor); + } + + private static class Fixed64DynamicSchema extends FieldSchema { + public Fixed64DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarFixed64(tag, tagSize, ((Number) value).longValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + long parsedValue = Long.parseLong(((String[]) value)[0], 10); + output.writeScalarFixed64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + long parsedValue = Long.parseLong((String) value, 10); + output.writeScalarFixed64(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class Fixed64Schema extends Fixed64DynamicSchema { + protected final Getter getter; + + public Fixed64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class Fixed64PrimitiveSchema extends Fixed64DynamicSchema { + private final LongGetter primitiveGetter; + + public Fixed64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + long value = primitiveGetter.get(message); + output.writeScalarFixed64(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/FloatWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/FloatWriteSchemas.java new file mode 100644 index 00000000000..b9e41053250 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/FloatWriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.FloatGetter; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class FloatWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (float.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new FloatPrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Float.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new FloatSchema<>(protoField, propertyDescriptor); + } + + return new FloatSchema<>(protoField, propertyDescriptor); + } + + private static class FloatDynamicSchema extends FieldSchema { + public FloatDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarFloat(tag, tagSize, ((Number) value).floatValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + float parsedValue = Float.parseFloat(((String[]) value)[0]); + output.writeScalarFloat(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + float parsedValue = Float.parseFloat((String) value); + output.writeScalarFloat(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class FloatSchema extends FloatDynamicSchema { + protected final Getter getter; + + public FloatSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = javaType.isPrimitive() ? null : propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class FloatPrimitiveSchema extends FloatDynamicSchema { + private final FloatGetter primitiveGetter; + + public FloatPrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + float value = primitiveGetter.get(message); + output.writeScalarFloat(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int32WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int32WriteSchemas.java new file mode 100644 index 00000000000..9172823efe9 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int32WriteSchemas.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.ByteGetter; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.common.utils.bean.ShortGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public final class Int32WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (int.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new IntFieldInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (short.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new ShortFieldInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (byte.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new ByteFieldInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + return new Int32Schema<>(protoField, propertyDescriptor); + } + + private static class Int32DynamicSchema extends FieldSchema { + public Int32DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarInt32(tag, tagSize, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + int parsedValue = Integer.parseInt(((String[]) value)[0], 10); + output.writeScalarInt32(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + if (((String) value).isEmpty()) { + return; + } + int parsedValue = Integer.parseInt((String) value, 10); + output.writeScalarInt32(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class Int32Schema extends Int32DynamicSchema { + protected final Getter getter; + + public Int32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static final class IntFieldInt32PrimitiveSchema extends Int32DynamicSchema { + private final IntGetter primitiveGetter; + + public IntFieldInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + int value = primitiveGetter.get(message); + output.writeScalarInt32(tag, tagSize, value); + } + } + + private static final class ShortFieldInt32PrimitiveSchema extends Int32DynamicSchema { + private final ShortGetter primitiveGetter; + + public ShortFieldInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + short value = primitiveGetter.get(message); + output.writeScalarInt32(tag, tagSize, value); + } + } + + private static final class ByteFieldInt32PrimitiveSchema extends Int32DynamicSchema { + private final ByteGetter primitiveGetter; + + public ByteFieldInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + byte value = primitiveGetter.get(message); + output.writeScalarInt32(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int64WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int64WriteSchemas.java new file mode 100644 index 00000000000..d85810524e8 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/Int64WriteSchemas.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoField; +import java.util.Date; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class Int64WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new Int64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + return new Int64Schema<>(protoField, propertyDescriptor); + } + + private static class Int64DynamicSchema extends FieldSchema { + public Int64DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarInt64(tag, tagSize, ((Number) value).longValue()); + return; + } + + if (value instanceof Date) { + long parsedValue = ((Date) value).getTime(); + output.writeScalarInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof LocalDate) { + long parsedValue = ((LocalDate) value).getLong(ChronoField.EPOCH_DAY); + output.writeScalarInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof LocalDateTime) { + long parsedValue = ((LocalDateTime) value).toInstant(ZoneOffset.UTC).toEpochMilli(); + output.writeScalarInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + long parsedValue; + if (((String) value).contains(":")) { + // from edge, ISO8601 date time, e.g. 2022-05-31T09:16:38.941Z + OffsetDateTime offsetDateTime = OffsetDateTime.parse((String) value); + parsedValue = offsetDateTime.toInstant().toEpochMilli(); + } else { + parsedValue = Long.parseLong((String) value, 10); + } + output.writeScalarInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + long parsedValue = Long.parseLong(((String[]) value)[0], 10); + output.writeScalarInt64(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class Int64Schema extends Int64DynamicSchema { + protected final Getter getter; + + public Int64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + this.writeTo(output, value); + } + } + } + + private static final class Int64PrimitiveSchema extends Int64DynamicSchema { + private final LongGetter primitiveGetter; + + public Int64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public void getAndWriteTo(OutputEx output, T message) throws IOException { + long value = primitiveGetter.get(message); + output.writeScalarInt64(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed32WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed32WriteSchemas.java new file mode 100644 index 00000000000..3cbbd8c7a40 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed32WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed32WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (int.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SFixed32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SFixed32Schema<>(protoField, propertyDescriptor); + } + + return new SFixed32Schema<>(protoField, propertyDescriptor); + } + + private static class SFixed32DynamicSchema extends FieldSchema { + public SFixed32DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarSFixed32(tag, tagSize, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + int parsedValue = Integer.parseInt(((String[]) value)[0], 10); + output.writeScalarSFixed32(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + int parsedValue = Integer.parseInt((String) value, 10); + output.writeScalarSFixed32(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class SFixed32Schema extends SFixed32DynamicSchema { + protected final Getter getter; + + public SFixed32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class SFixed32PrimitiveSchema extends SFixed32DynamicSchema { + private final IntGetter primitiveGetter; + + public SFixed32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + int value = primitiveGetter.get(message); + output.writeScalarSFixed32(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed64WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed64WriteSchemas.java new file mode 100644 index 00000000000..2f0a4bef028 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SFixed64WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SFixed64WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SFixed64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SFixed64Schema<>(protoField, propertyDescriptor); + } + + return new SFixed64Schema<>(protoField, propertyDescriptor); + } + + private static class SFixed64DynamicSchema extends FieldSchema { + public SFixed64DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarSFixed64(tag, tagSize, ((Number) value).longValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + long parsedValue = Long.parseLong(((String[]) value)[0], 10); + output.writeScalarSFixed64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + long parsedValue = Long.parseLong((String) value, 10); + output.writeScalarSFixed64(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class SFixed64Schema extends SFixed64DynamicSchema { + protected final Getter getter; + + public SFixed64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class SFixed64PrimitiveSchema extends SFixed64DynamicSchema { + private final LongGetter primitiveGetter; + + public SFixed64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + long value = primitiveGetter.get(message); + output.writeScalarSFixed64(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt32WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt32WriteSchemas.java new file mode 100644 index 00000000000..f3d2e1ad3fc --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt32WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt32WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (int.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SInt32Schema<>(protoField, propertyDescriptor); + } + + return new SInt32Schema<>(protoField, propertyDescriptor); + } + + private static class SInt32DynamicSchema extends FieldSchema { + public SInt32DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarSInt32(tag, tagSize, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + int parsedValue = Integer.parseInt(((String[]) value)[0], 10); + output.writeScalarSInt32(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + int parsedValue = Integer.parseInt((String) value, 10); + output.writeScalarSInt32(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class SInt32Schema extends SInt32DynamicSchema { + protected final Getter getter; + + public SInt32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class SInt32PrimitiveSchema extends SInt32DynamicSchema { + private final IntGetter primitiveGetter; + + public SInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + int value = primitiveGetter.get(message); + output.writeScalarSInt32(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt64WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt64WriteSchemas.java new file mode 100644 index 00000000000..b935e261e54 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/SInt64WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class SInt64WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SInt64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new SInt64Schema<>(protoField, propertyDescriptor); + } + + return new SInt64Schema<>(protoField, propertyDescriptor); + } + + private static class SInt64DynamicSchema extends FieldSchema { + public SInt64DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarSInt64(tag, tagSize, ((Number) value).longValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + long parsedValue = Long.parseLong(((String[]) value)[0], 10); + output.writeScalarSInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + long parsedValue = Long.parseLong((String) value, 10); + output.writeScalarSInt64(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class SInt64Schema extends SInt64DynamicSchema { + protected final Getter getter; + + public SInt64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class SInt64PrimitiveSchema extends SInt64DynamicSchema { + private final LongGetter primitiveGetter; + + public SInt64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + long value = primitiveGetter.get(message); + output.writeScalarSInt64(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/StringWriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/StringWriteSchemas.java new file mode 100644 index 00000000000..7df329b849b --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/StringWriteSchemas.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.servicecomb.foundation.common.utils.bean.CharGetter; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class StringWriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (char.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new CharFieldStringSchema<>(protoField, propertyDescriptor); + } + + if (String.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new StringSchema<>(protoField, propertyDescriptor); + } + + return new StringSchema<>(protoField, propertyDescriptor); + } + + private static class StringDynamicSchema extends FieldSchema { + public StringDynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof String) { + output.writeScalarString(tag, tagSize, (String) value); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + output.writeScalarString(tag, tagSize, ((String[]) value)[0]); + return; + } + + if (value instanceof Character) { + output.writeScalarString(tag, tagSize, String.valueOf((char) value)); + return; + } + + if (value instanceof BigDecimal || value instanceof BigInteger) { + output.writeScalarString(tag, tagSize, value.toString()); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class StringSchema extends StringDynamicSchema { + protected final Getter getter; + + public StringSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class CharFieldStringSchema extends StringDynamicSchema { + protected final CharGetter getter; + + public CharFieldStringSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + char value = getter.get(message); + writeTo(output, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt32WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt32WriteSchemas.java new file mode 100644 index 00000000000..6a163bef021 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt32WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt32WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (int.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new UInt32PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Integer.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new UInt32Schema<>(protoField, propertyDescriptor); + } + + return new UInt32Schema<>(protoField, propertyDescriptor); + } + + private static class UInt32DynamicSchema extends FieldSchema { + public UInt32DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarUInt32(tag, tagSize, ((Number) value).intValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + int parsedValue = Integer.parseInt(((String[]) value)[0], 10); + output.writeScalarUInt32(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + int parsedValue = Integer.parseInt((String) value, 10); + output.writeScalarUInt32(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class UInt32Schema extends UInt32DynamicSchema { + protected final Getter getter; + + public UInt32Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class UInt32PrimitiveSchema extends UInt32DynamicSchema { + private final IntGetter primitiveGetter; + + public UInt32PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + int value = primitiveGetter.get(message); + output.writeScalarUInt32(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt64WriteSchemas.java b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt64WriteSchemas.java new file mode 100644 index 00000000000..e8a449f4875 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/scalar/UInt64WriteSchemas.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer.scalar; + +import java.io.IOException; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.LongGetter; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoUtils; +import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyDescriptor; + +import io.protostuff.OutputEx; +import io.protostuff.compiler.model.Field; +import io.protostuff.runtime.FieldSchema; + +public class UInt64WriteSchemas { + public static FieldSchema create(Field protoField, PropertyDescriptor propertyDescriptor) { + if (long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new UInt64PrimitiveSchema<>(protoField, propertyDescriptor); + } + + if (Long.class.equals(propertyDescriptor.getJavaType().getRawClass())) { + return new UInt64Schema<>(protoField, propertyDescriptor); + } + + return new UInt64Schema<>(protoField, propertyDescriptor); + } + + private static class UInt64DynamicSchema extends FieldSchema { + public UInt64DynamicSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor.getJavaType()); + } + + @Override + public final void writeTo(OutputEx output, Object value) throws IOException { + if (value instanceof Number) { + output.writeScalarUInt64(tag, tagSize, ((Number) value).longValue()); + return; + } + + if (value instanceof String[]) { + if (((String[]) value).length == 0) { + return; + } + long parsedValue = Long.parseLong(((String[]) value)[0], 10); + output.writeScalarUInt64(tag, tagSize, parsedValue); + return; + } + + if (value instanceof String) { + long parsedValue = Long.parseLong((String) value, 10); + output.writeScalarUInt64(tag, tagSize, parsedValue); + return; + } + + ProtoUtils.throwNotSupportWrite(protoField, value); + } + } + + private static class UInt64Schema extends UInt64DynamicSchema { + protected final Getter getter; + + public UInt64Schema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + this.getter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + Object value = getter.get(message); + if (value != null) { + writeTo(output, value); + } + } + } + + private static class UInt64PrimitiveSchema extends UInt64DynamicSchema { + private final LongGetter primitiveGetter; + + public UInt64PrimitiveSchema(Field protoField, PropertyDescriptor propertyDescriptor) { + super(protoField, propertyDescriptor); + + primitiveGetter = propertyDescriptor.getGetter(); + } + + @Override + public final void getAndWriteTo(OutputEx output, T message) throws IOException { + long value = primitiveGetter.get(message); + output.writeScalarUInt64(tag, tagSize, value); + } + } +} diff --git a/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/notice.txt b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/notice.txt new file mode 100644 index 00000000000..0b6783a90c6 --- /dev/null +++ b/foundations/foundation-protobuf/src/main/java/org/apache/servicecomb/foundation/protobuf/notice.txt @@ -0,0 +1,18 @@ +1.List或List这种结构是PB不支持的 + 类似的场景,只要PB文件解析出错,说明本schema不支持PB相关的传输:highway/grpc等等 +2.反序列化,支持java类型为数组,不一定要求是Collection +3.原子类型的序列化/反序列化,(主要是原子数组?) + + +3.应该只有文件相关的场景,才是真正的不支持 + +------------- +优化: + 1.支持用户泛型 + 2. + +不兼容: + 1.数组编码规则从protoStuff变成标准的protobuf + +不确定: + 1.List/List/Map>/Map规则应该也有变化,是否有变化,从protoStuff变成标准protobuf diff --git a/foundations/foundation-protobuf/src/main/resources/google/protobuf/any.proto b/foundations/foundation-protobuf/src/main/resources/google/protobuf/any.proto new file mode 100644 index 00000000000..c89243178af --- /dev/null +++ b/foundations/foundation-protobuf/src/main/resources/google/protobuf/any.proto @@ -0,0 +1,161 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/foundations/foundation-protobuf/src/main/resources/google/protobuf/empty.proto b/foundations/foundation-protobuf/src/main/resources/google/protobuf/empty.proto new file mode 100644 index 00000000000..b87c89dcfce --- /dev/null +++ b/foundations/foundation-protobuf/src/main/resources/google/protobuf/empty.proto @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/emptypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +message Empty {} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/TestISODateTimeParsing.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/TestISODateTimeParsing.java new file mode 100644 index 00000000000..8fa797724b9 --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/TestISODateTimeParsing.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf; + +import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.util.Date; +import java.util.TimeZone; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestISODateTimeParsing { + @Test + public void testParseStringToDate() { + SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'hh:mm:ssZ"); + sdf.setTimeZone(TimeZone.getTimeZone("EST")); + + OffsetDateTime offsetDateTime = OffsetDateTime.parse("2022-05-31T09:16:38.941Z"); + Date d = Date.from(offsetDateTime.toInstant()); + String date = sdf.format(d); + Assertions.assertEquals("2022-05-151T04:16:38-0500", date); + + offsetDateTime = OffsetDateTime.parse("2022-05-31T09:16:38.941+00:00"); + d = Date.from(offsetDateTime.toInstant()); + date = sdf.format(d); + Assertions.assertEquals("2022-05-151T04:16:38-0500", date); + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/compatibility/TestCompatibilityOfImplementations.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/compatibility/TestCompatibilityOfImplementations.java new file mode 100644 index 00000000000..62fedeaf68e --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/compatibility/TestCompatibilityOfImplementations.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.protobuf.compatibility; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; +import org.apache.servicecomb.foundation.protobuf.internal.model.Root; +import org.apache.servicecomb.foundation.protobuf.performance.ProtubufCodecEngine; +import org.apache.servicecomb.foundation.protobuf.performance.engine.Protobuf; +import org.apache.servicecomb.foundation.protobuf.performance.engine.ScbWeak; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestCompatibilityOfImplementations { + static final ProtubufCodecEngine scbWeak = new ScbWeak(); + + static final ProtubufCodecEngine protobuf = new Protobuf(); + + @Test + @SuppressWarnings("unchecked") + public void testEmptyCollection() throws Exception { + ProtobufRoot.Root.Builder builder = ProtobufRoot.Root.newBuilder(); + byte[] values = protobuf.serialize(builder); + Assertions.assertEquals(values.length, 0); + ProtobufRoot.Root.Builder o = (ProtobufRoot.Root.Builder) protobuf.deserialize(values); + Assertions.assertTrue(o.getFixed32SNotPackedList().isEmpty()); + + builder = ProtobufRoot.Root.newBuilder().addFixed32SNotPacked(30); + values = protobuf.serialize(builder); + Assertions.assertArrayEquals(new byte[] {(byte) -123, (byte) 6, (byte) 30, (byte) 0, (byte) 0, (byte) 0}, values); + o = (ProtobufRoot.Root.Builder) protobuf.deserialize(values); + Assertions.assertEquals(30, (int) o.getFixed32SNotPackedList().get(0)); + + Root root = new Root(); + root.setFixed32sNotPacked(new ArrayList<>()); + values = scbWeak.serialize(root); + Assertions.assertEquals(values.length, 0); + Map newRootMap = (Map) scbWeak.deserialize(values); + Assertions.assertNull(newRootMap.get("fixed32sNotPacked")); // This is different , because depends on default model initializer + + List iValues = new ArrayList<>(); + iValues.add(30); + root.setFixed32sNotPacked(iValues); + values = scbWeak.serialize(root); + Assertions.assertArrayEquals(new byte[] {(byte) -123, (byte) 6, (byte) 30, (byte) 0, (byte) 0, (byte) 0}, values); + newRootMap = (Map) scbWeak.deserialize(values); + Assertions.assertEquals(30, (int) ((List) newRootMap.get("fixed32sNotPacked")).get(0)); + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestModelWrap.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestModelWrap.java index 94937c2550e..fd19fd8f033 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestModelWrap.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestModelWrap.java @@ -18,7 +18,7 @@ import java.io.IOException; import java.util.Arrays; -import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -26,10 +26,10 @@ import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import org.junit.Assert; -import org.junit.Test; import io.vertx.core.json.Json; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestModelWrap { protected static ProtoMapperFactory factory = new ProtoMapperFactory(); @@ -72,20 +72,43 @@ public static class PojoModel { public Map>> mapMapMapUser; public void init() { - listListUser = Arrays.asList(Arrays.asList(user)); - listMapUser = Arrays.asList(Collections.singletonMap(user.name, user)); - mapListUser = Collections.singletonMap("k1", Arrays.asList(user)); - mapMapUser = Collections.singletonMap("k1", Collections.singletonMap(user.name, user)); - - listListListUser = Arrays.asList(Arrays.asList(Arrays.asList(user))); - listListMapUser = Arrays.asList(Arrays.asList(Collections.singletonMap(user.name, user))); - listMapListUser = Arrays.asList(Collections.singletonMap("k1", Arrays.asList(user))); - listMapMapUser = Arrays.asList(Collections.singletonMap("k1", Collections.singletonMap(user.name, user))); - mapListListUser = Collections.singletonMap("k1", Arrays.asList(Arrays.asList(user))); - mapListMapUser = Collections.singletonMap("k1", Arrays.asList(Collections.singletonMap(user.name, user))); - mapMapListUser = Collections.singletonMap("k1", Collections.singletonMap("k1", Arrays.asList(user))); - mapMapMapUser = Collections - .singletonMap("k1", Collections.singletonMap("k1", Collections.singletonMap(user.name, user))); + List listUser = Arrays.asList(user, user); + + Map mapUser = new LinkedHashMap<>(); + mapUser.put("k1", user); + mapUser.put("k2", user); + + listListUser = Arrays.asList(listUser, listUser); + listMapUser = Arrays.asList(mapUser, mapUser); + + mapListUser = new LinkedHashMap<>(); + mapListUser.put("k1", listUser); + mapListUser.put("k2", listUser); + + mapMapUser = new LinkedHashMap<>(); + mapMapUser.put("k1", mapUser); + mapMapUser.put("k2", mapUser); + + listListListUser = Arrays.asList(listListUser, listListUser); + listListMapUser = Arrays.asList(listMapUser, listMapUser); + listMapListUser = Arrays.asList(mapListUser, mapListUser); + listMapMapUser = Arrays.asList(mapMapUser, mapMapUser); + + mapListListUser = new LinkedHashMap<>(); + mapListListUser.put("k1", listListUser); + mapListListUser.put("k2", listListUser); + + mapListMapUser = new LinkedHashMap<>(); + mapListMapUser.put("k1", listMapUser); + mapListMapUser.put("k2", listMapUser); + + mapMapListUser = new LinkedHashMap<>(); + mapMapListUser.put("k1", mapListUser); + mapMapListUser.put("k2", mapListUser); + + mapMapMapUser = new LinkedHashMap<>(); + mapMapMapUser.put("k1", mapMapUser); + mapMapMapUser.put("k2", mapMapUser); } } @@ -133,19 +156,36 @@ public void init() { ProtoMapMapUser protoMapMapUser = new ProtoMapMapUser(); protoMapMapUser.init(); - listListUser = Arrays.asList(protoListUser); - listMapUser = Arrays.asList(protoMapUser); - mapListUser = Collections.singletonMap("k1", protoListUser); - mapMapUser = Collections.singletonMap("k1", protoMapUser); - - listListListUser = Arrays.asList(protoListListUser); - listListMapUser = Arrays.asList(protoListMapUser); - listMapListUser = Arrays.asList(protoMapListUser); - listMapMapUser = Arrays.asList(protoMapMapUser); - mapListListUser = Collections.singletonMap("k1", protoListListUser); - mapListMapUser = Collections.singletonMap("k1", protoListMapUser); - mapMapListUser = Collections.singletonMap("k1", protoMapListUser); - mapMapMapUser = Collections.singletonMap("k1", protoMapMapUser); + listListUser = Arrays.asList(protoListUser, protoListUser); + listMapUser = Arrays.asList(protoMapUser, protoMapUser); + mapListUser = new LinkedHashMap<>(); + mapListUser.put("k1", protoListUser); + mapListUser.put("k2", protoListUser); + + mapMapUser = new LinkedHashMap<>(); + mapMapUser.put("k1", protoMapUser); + mapMapUser.put("k2", protoMapUser); + + listListListUser = Arrays.asList(protoListListUser, protoListListUser); + listListMapUser = Arrays.asList(protoListMapUser, protoListMapUser); + listMapListUser = Arrays.asList(protoMapListUser, protoMapListUser); + listMapMapUser = Arrays.asList(protoMapMapUser, protoMapMapUser); + + mapListListUser = new LinkedHashMap<>(); + mapListListUser.put("k1", protoListListUser); + mapListListUser.put("k2", protoListListUser); + + mapListMapUser = new LinkedHashMap<>(); + mapListMapUser.put("k1", protoListMapUser); + mapListMapUser.put("k2", protoListMapUser); + + mapMapListUser = new LinkedHashMap<>(); + mapMapListUser.put("k1", protoMapListUser); + mapMapListUser.put("k2", protoMapListUser); + + mapMapMapUser = new LinkedHashMap<>(); + mapMapMapUser.put("k1", protoMapMapUser); + mapMapMapUser.put("k2", protoMapMapUser); } } @@ -155,7 +195,7 @@ public static class ProtoListListUser { public void init() { ProtoListUser protoListUser = new ProtoListUser(); protoListUser.init(); - value = Arrays.asList(protoListUser); + value = Arrays.asList(protoListUser, protoListUser); } } @@ -165,7 +205,7 @@ public static class ProtoListMapUser { public void init() { ProtoMapUser protoMapUser = new ProtoMapUser(); protoMapUser.init(); - value = Arrays.asList(protoMapUser); + value = Arrays.asList(protoMapUser, protoMapUser); } } @@ -175,7 +215,9 @@ public static class ProtoMapListUser { public void init() { ProtoListUser protoListUser = new ProtoListUser(); protoListUser.init(); - value = Collections.singletonMap("k1", protoListUser); + value = new LinkedHashMap<>(); + value.put("k1", protoListUser); + value.put("k2", protoListUser); } } @@ -185,7 +227,9 @@ public static class ProtoMapMapUser { public void init() { ProtoMapUser protoMapUser = new ProtoMapUser(); protoMapUser.init(); - value = Collections.singletonMap("k1", protoMapUser); + value = new LinkedHashMap<>(); + value.put("k1", protoMapUser); + value.put("k2", protoMapUser); } } @@ -193,7 +237,7 @@ public static class ProtoListUser { public List value; public void init() { - value = Arrays.asList(user); + value = Arrays.asList(user, user); } } @@ -201,20 +245,26 @@ public static class ProtoMapUser { public Map value; public void init() { - value = Collections.singletonMap(user.name, user); + value = new LinkedHashMap<>(); + value.put("k1", user); + value.put("k2", user); } } @SuppressWarnings("unchecked") @Test public void pojoModel() throws IOException { - RootSerializer pojoSerializer = modelProtoMapper.findRootSerializer("PojoModel"); - RootDeserializer pojoMapDeserializer = modelProtoMapper.createRootDeserializer(Map.class, "PojoModel"); - RootDeserializer pojoModelDeserializer = modelProtoMapper.createRootDeserializer(PojoModel.class, "PojoModel"); - - RootSerializer protoSerializer = modelProtoMapper.findRootSerializer("ProtoModel"); - RootDeserializer protoMapDeserializer = modelProtoMapper.createRootDeserializer(Map.class, "ProtoModel"); - RootDeserializer protoModelDeserializer = modelProtoMapper.createRootDeserializer(ProtoModel.class, "ProtoModel"); + RootSerializer pojoSerializer = modelProtoMapper.createRootSerializer("PojoModel", PojoModel.class); + RootDeserializer> pojoMapDeserializer = modelProtoMapper + .createRootDeserializer("PojoModel", Map.class); + RootDeserializer pojoModelDeserializer = modelProtoMapper + .createRootDeserializer("PojoModel", PojoModel.class); + + RootSerializer protoSerializer = modelProtoMapper.createRootSerializer("ProtoModel", ProtoModel.class); + RootDeserializer> protoMapDeserializer = modelProtoMapper + .createRootDeserializer("ProtoModel", Map.class); + RootDeserializer protoModelDeserializer = modelProtoMapper + .createRootDeserializer("ProtoModel", ProtoModel.class); PojoModel pojoModel = new PojoModel(); pojoModel.init(); @@ -228,20 +278,20 @@ public void pojoModel() throws IOException { // serialize byte[] bytes = protoSerializer.serialize(protoModel); - Assert.assertArrayEquals(bytes, protoSerializer.serialize(mapFromProtoModel)); - Assert.assertArrayEquals(bytes, pojoSerializer.serialize(pojoModel)); - Assert.assertArrayEquals(bytes, pojoSerializer.serialize(mapFromPojoModel)); + Assertions.assertArrayEquals(bytes, protoSerializer.serialize(mapFromProtoModel)); + Assertions.assertArrayEquals(bytes, pojoSerializer.serialize(pojoModel)); + Assertions.assertArrayEquals(bytes, pojoSerializer.serialize(mapFromPojoModel)); // deserialize pojoModel PojoModel newPojoModel = pojoModelDeserializer.deserialize(bytes); - Assert.assertEquals(jsonPojoModel, Json.encode(newPojoModel)); + Assertions.assertEquals(jsonPojoModel, Json.encode(newPojoModel)); Map mapFromNewPojoModel = pojoMapDeserializer.deserialize(bytes); - Assert.assertEquals(jsonPojoModel, Json.encode(mapFromNewPojoModel)); + Assertions.assertEquals(jsonPojoModel, Json.encode(mapFromNewPojoModel)); // deserialize protoModel ProtoModel newProtoModel = protoModelDeserializer.deserialize(bytes); - Assert.assertEquals(jsonProtoModel, Json.encode(newProtoModel)); + Assertions.assertEquals(jsonProtoModel, Json.encode(newProtoModel)); Map mapFromNewProtoModel = protoMapDeserializer.deserialize(bytes); - Assert.assertEquals(jsonProtoModel, Json.encode(mapFromNewProtoModel)); + Assertions.assertEquals(jsonProtoModel, Json.encode(mapFromNewProtoModel)); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestSchemaBase.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestSchemaBase.java index 8ba7186ed17..6353815df6d 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestSchemaBase.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/TestSchemaBase.java @@ -24,26 +24,37 @@ import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; import org.apache.servicecomb.foundation.protobuf.RootSerializer; +import org.apache.servicecomb.foundation.protobuf.internal.model.PrimitiveArrays; +import org.apache.servicecomb.foundation.protobuf.internal.model.PrimitiveWrapperArrays; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; import org.apache.servicecomb.foundation.protobuf.internal.model.Root; -import org.apache.servicecomb.foundation.protobuf.internal.schema.FieldSchema; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.rules.ExpectedException; + +import io.protostuff.compiler.model.Field; +import org.junit.jupiter.api.Assertions; public class TestSchemaBase { protected static ProtoMapperFactory factory = new ProtoMapperFactory(); protected static ProtoMapper protoMapper = factory.createFromName("protobufRoot.proto"); - protected static RootSerializer rootSerializer = protoMapper.findRootSerializer("Root"); + protected static RootSerializer rootSerializer = protoMapper.createRootSerializer("Root", Root.class); + + protected static RootDeserializer rootDeserializer = protoMapper.createRootDeserializer("Root", Root.class); + + protected static RootSerializer primitiveArraysSerializer = protoMapper + .createRootSerializer("Root", PrimitiveArrays.class); + + protected static RootDeserializer primitiveArraysDeserializer = protoMapper + .createRootDeserializer("Root", PrimitiveArrays.class); - protected static RootDeserializer rootDeserializer = protoMapper.createRootDeserializer(Root.class, "Root"); + protected static RootSerializer primitiveWrapperArraysSerializer = protoMapper + .createRootSerializer("Root", PrimitiveWrapperArrays.class); - protected static RootDeserializer mapRootDeserializer = protoMapper.createRootDeserializer(Map.class, "Root"); + protected static RootDeserializer primitiveWrapperArraysDeserializer = protoMapper + .createRootDeserializer("Root", PrimitiveWrapperArrays.class); - @Rule - public ExpectedException expectedException = ExpectedException.none(); + protected static RootDeserializer> mapRootDeserializer = protoMapper + .createRootDeserializer("Root", Map.class); protected Object scbRoot; @@ -57,13 +68,66 @@ public class TestSchemaBase { protected byte[] protobufBytes; - protected FieldSchema serFieldSchema; + protected String primitiveFieldName; + + protected Field primitiveProtoField; + + protected String fieldName; + + protected Field protoField; - protected FieldSchema deserFieldSchema; + protected void initFields(String primitiveFieldName, String fieldName) { + this.primitiveFieldName = primitiveFieldName; + if (primitiveFieldName != null) { + primitiveProtoField = protoMapper.getProto().getMessage("Root").getField(primitiveFieldName); + } + + initField(fieldName); + } protected void initField(String fieldName) { - serFieldSchema = (FieldSchema) rootSerializer.getSchema().getFieldByName(fieldName); - deserFieldSchema = (FieldSchema) rootDeserializer.getSchema().getFieldByName(fieldName); + this.fieldName = fieldName; + if (fieldName != null) { + protoField = protoMapper.getProto().getMessage("Root").getField(fieldName); + } + } + + protected void checkRepeatedWithPrimitive() throws Exception { + check(); + + check(primitiveArraysDeserializer, mapRootDeserializer, primitiveArraysSerializer, false); + String primitiveFieldName = scbMap.keySet().iterator().next(); + java.lang.reflect.Field primitiveField = PrimitiveArrays.class.getDeclaredField(primitiveFieldName); + primitiveField.setAccessible(true); + Object primitiveArray = primitiveField.get(scbRoot); + + check(primitiveWrapperArraysDeserializer, mapRootDeserializer, primitiveWrapperArraysSerializer, false); + String wrapperFieldName = scbMap.keySet().iterator().next(); + java.lang.reflect.Field wrapperField = PrimitiveWrapperArrays.class.getDeclaredField(wrapperFieldName); + wrapperField.setAccessible(true); + Object[] array = (Object[]) wrapperField.get(scbRoot); + + // dynamic strings + String[] strings = new String[array.length]; + for (int idx = 0; idx < array.length; idx++) { + strings[idx] = array[idx].toString(); + } + scbMap.clear(); + scbMap.put(primitiveFieldName, strings); + scbMapBytes = primitiveArraysSerializer.serialize(scbMap); + Assertions.assertArrayEquals(protobufBytes, scbMapBytes); + + // dynamic primitive array + scbMap.clear(); + scbMap.put(primitiveFieldName, primitiveArray); + scbMapBytes = primitiveArraysSerializer.serialize(scbMap); + Assertions.assertArrayEquals(protobufBytes, scbMapBytes); + + // dynamic array + scbMap.clear(); + scbMap.put(primitiveFieldName, array); + scbMapBytes = primitiveArraysSerializer.serialize(scbMap); + Assertions.assertArrayEquals(protobufBytes, scbMapBytes); } protected void check() throws IOException { @@ -74,28 +138,29 @@ protected void check(boolean print) throws IOException { check(rootDeserializer, mapRootDeserializer, rootSerializer, print); } - protected void check(RootDeserializer deserializer, RootDeserializer mapDeserializer, RootSerializer serializer, + protected void check(RootDeserializer deserializer, RootDeserializer> mapDeserializer, + RootSerializer serializer, boolean print) throws IOException { // 1.standard protobuf serialize to bytes protobufBytes = builder.build().toByteArray(); // 2.weak type deserialize scbMap = mapDeserializer.deserialize(protobufBytes); // 3.weak type serialize - scbMapBytes = rootSerializer.serialize(scbMap); + scbMapBytes = serializer.serialize(scbMap); // 4.strong type deserialize scbRoot = deserializer.deserialize(scbMapBytes); // 5.strong type serialize - scbRootBytes = rootSerializer.serialize(scbRoot); + scbRootBytes = serializer.serialize(scbRoot); if (print) { System.out.println("scbRoot bytes:" + Hex.encodeHexString(scbRootBytes)); System.out.println("scbRoot len :" + scbRootBytes.length); - System.out.println("scbMap bytes :" + Hex.encodeHexString(scbRootBytes)); - System.out.println("scbMap len :" + scbRootBytes.length); + System.out.println("scbMap bytes :" + Hex.encodeHexString(scbMapBytes)); + System.out.println("scbMap len :" + scbMapBytes.length); System.out.println("protobuf :" + Hex.encodeHexString(protobufBytes)); System.out.println("protobuf len :" + protobufBytes.length); } - Assert.assertArrayEquals(protobufBytes, scbMapBytes); - Assert.assertArrayEquals(protobufBytes, scbRootBytes); + Assertions.assertArrayEquals(protobufBytes, scbMapBytes); + Assertions.assertArrayEquals(protobufBytes, scbRootBytes); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/bean/TestBeanDescriptorManager.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/bean/TestBeanDescriptorManager.java index dff8e421e01..60054c021d0 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/bean/TestBeanDescriptorManager.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/bean/TestBeanDescriptorManager.java @@ -19,10 +19,14 @@ import java.lang.reflect.Method; import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.foundation.common.utils.bean.IntGetter; +import org.apache.servicecomb.foundation.common.utils.bean.IntSetter; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestBeanDescriptorManager { public static class Model { @@ -91,47 +95,51 @@ public void generic() { BeanDescriptor beanDescriptor = beanDescriptorManager .getOrCreateBeanDescriptor(method.getGenericParameterTypes()[0]); - Assert.assertEquals(String.class, beanDescriptor.getPropertyDescriptors().get("value").getJavaType().getRawClass()); + Assertions.assertEquals(String.class, beanDescriptor.getPropertyDescriptors().get("value").getJavaType().getRawClass()); } @Test public void getOrCreate() { - Assert.assertSame(beanDescriptor, beanDescriptorManager.getOrCreateBeanDescriptor(Model.class)); - Assert.assertSame(Model.class, beanDescriptor.getJavaType().getRawClass()); + Assertions.assertSame(beanDescriptor, beanDescriptorManager.getOrCreateBeanDescriptor(Model.class)); + Assertions.assertSame(Model.class, beanDescriptor.getJavaType().getRawClass()); } + @SuppressWarnings("unchecked") @Test - public void both() throws Throwable { + public void both() { PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get("both"); - propertyDescriptor.getSetter().set(model, 1); - Assert.assertEquals(1, propertyDescriptor.getGetter().get(model)); - Assert.assertEquals(1, model.getBoth()); + ((IntSetter) propertyDescriptor.getSetter()).set(model, 1); + Assertions.assertEquals(1, ((IntGetter) propertyDescriptor.getGetter()).get(model)); + Assertions.assertEquals(1, model.getBoth()); } + @SuppressWarnings("unchecked") @Test - public void onlyGet() throws Throwable { + public void onlyGet() { PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get("onlyGet"); - Assert.assertNull(propertyDescriptor.getSetter()); + Assertions.assertNull(propertyDescriptor.getSetter()); model.onlyGet(1); - Assert.assertEquals(1, propertyDescriptor.getGetter().get(model)); - Assert.assertEquals(1, model.getOnlyGet()); + Assertions.assertEquals(1, ((IntGetter) propertyDescriptor.getGetter()).get(model)); + Assertions.assertEquals(1, model.getOnlyGet()); } + @SuppressWarnings("unchecked") @Test - public void onlySet() throws Throwable { + public void onlySet() { PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get("onlySet"); - Assert.assertNull(propertyDescriptor.getGetter()); + Assertions.assertNull(propertyDescriptor.getGetter()); - propertyDescriptor.getSetter().set(model, 1); - Assert.assertEquals(1, model.onlySet()); + ((IntSetter) propertyDescriptor.getSetter()).set(model, 1); + Assertions.assertEquals(1, model.onlySet()); } + @SuppressWarnings("unchecked") @Test - public void direct() throws Throwable { + public void direct() { PropertyDescriptor propertyDescriptor = beanDescriptor.getPropertyDescriptors().get("direct"); - propertyDescriptor.getSetter().set(model, 1); - Assert.assertEquals(1, propertyDescriptor.getGetter().get(model)); - Assert.assertEquals(1, model.direct); + ((Setter) propertyDescriptor.getSetter()).set(model, 1); + Assertions.assertEquals(1, (int) ((Getter) propertyDescriptor.getGetter()).get(model)); + Assertions.assertEquals(1, model.direct); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/CustomGeneric.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/CustomGeneric.java index 5cbb1ef788f..c57579ed18e 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/CustomGeneric.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/CustomGeneric.java @@ -18,4 +18,4 @@ public class CustomGeneric { public T user; -} \ No newline at end of file +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveArrays.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveArrays.java new file mode 100644 index 00000000000..fdaa1f536e2 --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveArrays.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License")Packed; you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.model; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; + +public class PrimitiveArrays { + private int[] int32sPacked; + + private long[] int64sPacked; + + private int[] uint32sPacked; + + private long[] uint64sPacked; + + private int[] sint32sPacked; + + private long[] sint64sPacked; + + private int[] fixed32sPacked; + + private long[] fixed64sPacked; + + private int[] sfixed32sPacked; + + private long[] sfixed64sPacked; + + private float[] floatsPacked; + + private double[] doublesPacked; + + private boolean[] boolsPacked; + + private Color[] colorsPacked; + + private int[] int32sNotPacked; + + private long[] int64sNotPacked; + + private int[] uint32sNotPacked; + + private long[] uint64sNotPacked; + + private int[] sint32sNotPacked; + + private long[] sint64sNotPacked; + + private int[] fixed32sNotPacked; + + private long[] fixed64sNotPacked; + + private int[] sfixed32sNotPacked; + + private long[] sfixed64sNotPacked; + + private float[] floatsNotPacked; + + private double[] doublesNotPacked; + + private boolean[] boolsNotPacked; + + private Color[] colorsNotPacked; + + public int[] getInt32sPacked() { + return int32sPacked; + } + + public void setInt32sPacked(int[] int32sPacked) { + this.int32sPacked = int32sPacked; + } + + public long[] getInt64sPacked() { + return int64sPacked; + } + + public void setInt64sPacked(long[] int64sPacked) { + this.int64sPacked = int64sPacked; + } + + public int[] getUint32sPacked() { + return uint32sPacked; + } + + public void setUint32sPacked(int[] uint32sPacked) { + this.uint32sPacked = uint32sPacked; + } + + public long[] getUint64sPacked() { + return uint64sPacked; + } + + public void setUint64sPacked(long[] uint64sPacked) { + this.uint64sPacked = uint64sPacked; + } + + public int[] getSint32sPacked() { + return sint32sPacked; + } + + public void setSint32sPacked(int[] sint32sPacked) { + this.sint32sPacked = sint32sPacked; + } + + public long[] getSint64sPacked() { + return sint64sPacked; + } + + public void setSint64sPacked(long[] sint64sPacked) { + this.sint64sPacked = sint64sPacked; + } + + public int[] getFixed32sPacked() { + return fixed32sPacked; + } + + public void setFixed32sPacked(int[] fixed32sPacked) { + this.fixed32sPacked = fixed32sPacked; + } + + public long[] getFixed64sPacked() { + return fixed64sPacked; + } + + public void setFixed64sPacked(long[] fixed64sPacked) { + this.fixed64sPacked = fixed64sPacked; + } + + public int[] getSfixed32sPacked() { + return sfixed32sPacked; + } + + public void setSfixed32sPacked(int[] sfixed32sPacked) { + this.sfixed32sPacked = sfixed32sPacked; + } + + public long[] getSfixed64sPacked() { + return sfixed64sPacked; + } + + public void setSfixed64sPacked(long[] sfixed64sPacked) { + this.sfixed64sPacked = sfixed64sPacked; + } + + public float[] getFloatsPacked() { + return floatsPacked; + } + + public void setFloatsPacked(float[] floatsPacked) { + this.floatsPacked = floatsPacked; + } + + public double[] getDoublesPacked() { + return doublesPacked; + } + + public void setDoublesPacked(double[] doublesPacked) { + this.doublesPacked = doublesPacked; + } + + public boolean[] getBoolsPacked() { + return boolsPacked; + } + + public void setBoolsPacked(boolean[] boolsPacked) { + this.boolsPacked = boolsPacked; + } + + public int[] getInt32sNotPacked() { + return int32sNotPacked; + } + + public void setInt32sNotPacked(int[] int32sNotPacked) { + this.int32sNotPacked = int32sNotPacked; + } + + public long[] getInt64sNotPacked() { + return int64sNotPacked; + } + + public void setInt64sNotPacked(long[] int64sNotPacked) { + this.int64sNotPacked = int64sNotPacked; + } + + public int[] getUint32sNotPacked() { + return uint32sNotPacked; + } + + public void setUint32sNotPacked(int[] uint32sNotPacked) { + this.uint32sNotPacked = uint32sNotPacked; + } + + public long[] getUint64sNotPacked() { + return uint64sNotPacked; + } + + public void setUint64sNotPacked(long[] uint64sNotPacked) { + this.uint64sNotPacked = uint64sNotPacked; + } + + public int[] getSint32sNotPacked() { + return sint32sNotPacked; + } + + public void setSint32sNotPacked(int[] sint32sNotPacked) { + this.sint32sNotPacked = sint32sNotPacked; + } + + public long[] getSint64sNotPacked() { + return sint64sNotPacked; + } + + public void setSint64sNotPacked(long[] sint64sNotPacked) { + this.sint64sNotPacked = sint64sNotPacked; + } + + public int[] getFixed32sNotPacked() { + return fixed32sNotPacked; + } + + public void setFixed32sNotPacked(int[] fixed32sNotPacked) { + this.fixed32sNotPacked = fixed32sNotPacked; + } + + public long[] getFixed64sNotPacked() { + return fixed64sNotPacked; + } + + public void setFixed64sNotPacked(long[] fixed64sNotPacked) { + this.fixed64sNotPacked = fixed64sNotPacked; + } + + public int[] getSfixed32sNotPacked() { + return sfixed32sNotPacked; + } + + public void setSfixed32sNotPacked(int[] sfixed32sNotPacked) { + this.sfixed32sNotPacked = sfixed32sNotPacked; + } + + public long[] getSfixed64sNotPacked() { + return sfixed64sNotPacked; + } + + public void setSfixed64sNotPacked(long[] sfixed64sNotPacked) { + this.sfixed64sNotPacked = sfixed64sNotPacked; + } + + public float[] getFloatsNotPacked() { + return floatsNotPacked; + } + + public void setFloatsNotPacked(float[] floatsNotPacked) { + this.floatsNotPacked = floatsNotPacked; + } + + public double[] getDoublesNotPacked() { + return doublesNotPacked; + } + + public void setDoublesNotPacked(double[] doublesNotPacked) { + this.doublesNotPacked = doublesNotPacked; + } + + public boolean[] getBoolsNotPacked() { + return boolsNotPacked; + } + + public void setBoolsNotPacked(boolean[] boolsNotPacked) { + this.boolsNotPacked = boolsNotPacked; + } + + public Color[] getColorsPacked() { + return colorsPacked; + } + + public void setColorsPacked(Color[] colorsPacked) { + this.colorsPacked = colorsPacked; + } + + public Color[] getColorsNotPacked() { + return colorsNotPacked; + } + + public void setColorsNotPacked(Color[] colorsNotPacked) { + this.colorsNotPacked = colorsNotPacked; + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveWrapperArrays.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveWrapperArrays.java new file mode 100644 index 00000000000..23392a9ef30 --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/PrimitiveWrapperArrays.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License")Packed; you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.model; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; + +public class PrimitiveWrapperArrays { + private Integer[] int32sPacked; + + private Long[] int64sPacked; + + private Integer[] uint32sPacked; + + private Long[] uint64sPacked; + + private Integer[] sint32sPacked; + + private Long[] sint64sPacked; + + private Integer[] fixed32sPacked; + + private Long[] fixed64sPacked; + + private Integer[] sfixed32sPacked; + + private Long[] sfixed64sPacked; + + private Float[] floatsPacked; + + private Double[] doublesPacked; + + private Boolean[] boolsPacked; + + private Color[] colorsPacked; + + private Integer[] int32sNotPacked; + + private Long[] int64sNotPacked; + + private Integer[] uint32sNotPacked; + + private Long[] uint64sNotPacked; + + private Integer[] sint32sNotPacked; + + private Long[] sint64sNotPacked; + + private Integer[] fixed32sNotPacked; + + private Long[] fixed64sNotPacked; + + private Integer[] sfixed32sNotPacked; + + private Long[] sfixed64sNotPacked; + + private Float[] floatsNotPacked; + + private Double[] doublesNotPacked; + + private Boolean[] boolsNotPacked; + + private Color[] colorsNotPacked; + + public Integer[] getInt32sPacked() { + return int32sPacked; + } + + public void setInt32sPacked(Integer[] int32sPacked) { + this.int32sPacked = int32sPacked; + } + + public Long[] getInt64sPacked() { + return int64sPacked; + } + + public void setInt64sPacked(Long[] int64sPacked) { + this.int64sPacked = int64sPacked; + } + + public Integer[] getUint32sPacked() { + return uint32sPacked; + } + + public void setUint32sPacked(Integer[] uint32sPacked) { + this.uint32sPacked = uint32sPacked; + } + + public Long[] getUint64sPacked() { + return uint64sPacked; + } + + public void setUint64sPacked(Long[] uint64sPacked) { + this.uint64sPacked = uint64sPacked; + } + + public Integer[] getSint32sPacked() { + return sint32sPacked; + } + + public void setSint32sPacked(Integer[] sint32sPacked) { + this.sint32sPacked = sint32sPacked; + } + + public Long[] getSint64sPacked() { + return sint64sPacked; + } + + public void setSint64sPacked(Long[] sint64sPacked) { + this.sint64sPacked = sint64sPacked; + } + + public Integer[] getFixed32sPacked() { + return fixed32sPacked; + } + + public void setFixed32sPacked(Integer[] fixed32sPacked) { + this.fixed32sPacked = fixed32sPacked; + } + + public Long[] getFixed64sPacked() { + return fixed64sPacked; + } + + public void setFixed64sPacked(Long[] fixed64sPacked) { + this.fixed64sPacked = fixed64sPacked; + } + + public Integer[] getSfixed32sPacked() { + return sfixed32sPacked; + } + + public void setSfixed32sPacked(Integer[] sfixed32sPacked) { + this.sfixed32sPacked = sfixed32sPacked; + } + + public Long[] getSfixed64sPacked() { + return sfixed64sPacked; + } + + public void setSfixed64sPacked(Long[] sfixed64sPacked) { + this.sfixed64sPacked = sfixed64sPacked; + } + + public Float[] getFloatsPacked() { + return floatsPacked; + } + + public void setFloatsPacked(Float[] floatsPacked) { + this.floatsPacked = floatsPacked; + } + + public Double[] getDoublesPacked() { + return doublesPacked; + } + + public void setDoublesPacked(Double[] doublesPacked) { + this.doublesPacked = doublesPacked; + } + + public Boolean[] getBoolsPacked() { + return boolsPacked; + } + + public void setBoolsPacked(Boolean[] boolsPacked) { + this.boolsPacked = boolsPacked; + } + + public Integer[] getInt32sNotPacked() { + return int32sNotPacked; + } + + public void setInt32sNotPacked(Integer[] int32sNotPacked) { + this.int32sNotPacked = int32sNotPacked; + } + + public Long[] getInt64sNotPacked() { + return int64sNotPacked; + } + + public void setInt64sNotPacked(Long[] int64sNotPacked) { + this.int64sNotPacked = int64sNotPacked; + } + + public Integer[] getUint32sNotPacked() { + return uint32sNotPacked; + } + + public void setUint32sNotPacked(Integer[] uint32sNotPacked) { + this.uint32sNotPacked = uint32sNotPacked; + } + + public Long[] getUint64sNotPacked() { + return uint64sNotPacked; + } + + public void setUint64sNotPacked(Long[] uint64sNotPacked) { + this.uint64sNotPacked = uint64sNotPacked; + } + + public Integer[] getSint32sNotPacked() { + return sint32sNotPacked; + } + + public void setSint32sNotPacked(Integer[] sint32sNotPacked) { + this.sint32sNotPacked = sint32sNotPacked; + } + + public Long[] getSint64sNotPacked() { + return sint64sNotPacked; + } + + public void setSint64sNotPacked(Long[] sint64sNotPacked) { + this.sint64sNotPacked = sint64sNotPacked; + } + + public Integer[] getFixed32sNotPacked() { + return fixed32sNotPacked; + } + + public void setFixed32sNotPacked(Integer[] fixed32sNotPacked) { + this.fixed32sNotPacked = fixed32sNotPacked; + } + + public Long[] getFixed64sNotPacked() { + return fixed64sNotPacked; + } + + public void setFixed64sNotPacked(Long[] fixed64sNotPacked) { + this.fixed64sNotPacked = fixed64sNotPacked; + } + + public Integer[] getSfixed32sNotPacked() { + return sfixed32sNotPacked; + } + + public void setSfixed32sNotPacked(Integer[] sfixed32sNotPacked) { + this.sfixed32sNotPacked = sfixed32sNotPacked; + } + + public Long[] getSfixed64sNotPacked() { + return sfixed64sNotPacked; + } + + public void setSfixed64sNotPacked(Long[] sfixed64sNotPacked) { + this.sfixed64sNotPacked = sfixed64sNotPacked; + } + + public Float[] getFloatsNotPacked() { + return floatsNotPacked; + } + + public void setFloatsNotPacked(Float[] floatsNotPacked) { + this.floatsNotPacked = floatsNotPacked; + } + + public Double[] getDoublesNotPacked() { + return doublesNotPacked; + } + + public void setDoublesNotPacked(Double[] doublesNotPacked) { + this.doublesNotPacked = doublesNotPacked; + } + + public Boolean[] getBoolsNotPacked() { + return boolsNotPacked; + } + + public void setBoolsNotPacked(Boolean[] boolsNotPacked) { + this.boolsNotPacked = boolsNotPacked; + } + + public Color[] getColorsPacked() { + return colorsPacked; + } + + public void setColorsPacked(Color[] colorsPacked) { + this.colorsPacked = colorsPacked; + } + + public Color[] getColorsNotPacked() { + return colorsNotPacked; + } + + public void setColorsNotPacked(Color[] colorsNotPacked) { + this.colorsNotPacked = colorsNotPacked; + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java deleted file mode 100644 index ec7def6200f..00000000000 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java +++ /dev/null @@ -1,5033 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: protobufRoot.proto - -package org.apache.servicecomb.foundation.protobuf.internal.model; - -@SuppressWarnings({"all", "cast"}) -public final class ProtobufRoot { - private ProtobufRoot() { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistryLite registry) { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - registerAllExtensions( - (com.google.protobuf.ExtensionRegistryLite) registry); - } - - /** - * Protobuf enum {@code org.apache.servicecomb.foundation.protobuf.internal.model.Color} - */ - public enum Color - implements com.google.protobuf.ProtocolMessageEnum { - /** - * RED = 0; - */ - RED(0), - /** - * YELLOW = 1; - */ - YELLOW(1), - /** - * BLUE = 2; - */ - BLUE(2), - UNRECOGNIZED(-1),; - - /** - * RED = 0; - */ - public static final int RED_VALUE = 0; - - /** - * YELLOW = 1; - */ - public static final int YELLOW_VALUE = 1; - - /** - * BLUE = 2; - */ - public static final int BLUE_VALUE = 2; - - - public final int getNumber() { - if (this == UNRECOGNIZED) { - throw new IllegalArgumentException( - "Can't get the number of an unknown enum value."); - } - return value; - } - - /** - * @deprecated Use {@link #forNumber(int)} instead. - */ - @Deprecated - public static Color valueOf(int value) { - return forNumber(value); - } - - public static Color forNumber(int value) { - switch (value) { - case 0: - return RED; - case 1: - return YELLOW; - case 2: - return BLUE; - default: - return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - - private static final com.google.protobuf.Internal.EnumLiteMap< - Color> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public Color findValueByNumber(int number) { - return Color.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - return getDescriptor().getValues().get(ordinal()); - } - - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - - public static final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return ProtobufRoot.getDescriptor().getEnumTypes().get(0); - } - - private static final Color[] VALUES = values(); - - public static Color valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - if (desc.getIndex() == -1) { - return UNRECOGNIZED; - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private Color(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:org.apache.servicecomb.foundation.protobuf.internal.model.Color) - } - - public interface RootOrBuilder extends - // @@protoc_insertion_point(interface_extends:org.apache.servicecomb.foundation.protobuf.internal.model.Root) - com.google.protobuf.MessageOrBuilder { - - /** - * int32 int32 = 1; - */ - int getInt32(); - - /** - * int64 int64 = 2; - */ - long getInt64(); - - /** - * uint32 uint32 = 3; - */ - int getUint32(); - - /** - * uint64 uint64 = 4; - */ - long getUint64(); - - /** - * sint32 sint32 = 5; - */ - int getSint32(); - - /** - * sint64 sint64 = 6; - */ - long getSint64(); - - /** - * fixed32 fixed32 = 7; - */ - int getFixed32(); - - /** - * fixed64 fixed64 = 8; - */ - long getFixed64(); - - /** - * sfixed32 sfixed32 = 9; - */ - int getSfixed32(); - - /** - * sfixed64 sfixed64 = 10; - */ - long getSfixed64(); - - /** - * float floatValue = 11; - */ - float getFloatValue(); - - /** - * double doubleValue = 12; - */ - double getDoubleValue(); - - /** - * bool bool = 13; - */ - boolean getBool(); - - /** - * string string = 14; - */ - String getString(); - - /** - * string string = 14; - */ - com.google.protobuf.ByteString - getStringBytes(); - - /** - * bytes bytes = 15; - */ - com.google.protobuf.ByteString getBytes(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - int getColorValue(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - Color getColor(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - boolean hasUser(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - User getUser(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - UserOrBuilder getUserOrBuilder(); - - /** - * map<string, string> ssMap = 18; - */ - int getSsMapCount(); - - /** - * map<string, string> ssMap = 18; - */ - boolean containsSsMap( - String key); - - /** - * Use {@link #getSsMapMap()} instead. - */ - @Deprecated - java.util.Map - getSsMap(); - - /** - * map<string, string> ssMap = 18; - */ - java.util.Map - getSsMapMap(); - - /** - * map<string, string> ssMap = 18; - */ - - String getSsMapOrDefault( - String key, - String defaultValue); - - /** - * map<string, string> ssMap = 18; - */ - - String getSsMapOrThrow( - String key); - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - int getSpMapCount(); - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - boolean containsSpMap( - String key); - - /** - * Use {@link #getSpMapMap()} instead. - */ - @Deprecated - java.util.Map - getSpMap(); - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - java.util.Map - getSpMapMap(); - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - User getSpMapOrDefault( - String key, - User defaultValue); - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - User getSpMapOrThrow( - String key); - - /** - * repeated string sList = 20; - */ - java.util.List - getSListList(); - - /** - * repeated string sList = 20; - */ - int getSListCount(); - - /** - * repeated string sList = 20; - */ - String getSList(int index); - - /** - * repeated string sList = 20; - */ - com.google.protobuf.ByteString - getSListBytes(int index); - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - java.util.List - getPListList(); - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - User getPList(int index); - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - int getPListCount(); - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - java.util.List - getPListOrBuilderList(); - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - UserOrBuilder getPListOrBuilder( - int index); - - /** - * .google.protobuf.Any any = 22; - */ - boolean hasAny(); - - /** - * .google.protobuf.Any any = 22; - */ - com.google.protobuf.Any getAny(); - - /** - * .google.protobuf.Any any = 22; - */ - com.google.protobuf.AnyOrBuilder getAnyOrBuilder(); - - /** - * repeated .google.protobuf.Any anys = 23; - */ - java.util.List - getAnysList(); - - /** - * repeated .google.protobuf.Any anys = 23; - */ - com.google.protobuf.Any getAnys(int index); - - /** - * repeated .google.protobuf.Any anys = 23; - */ - int getAnysCount(); - - /** - * repeated .google.protobuf.Any anys = 23; - */ - java.util.List - getAnysOrBuilderList(); - - /** - * repeated .google.protobuf.Any anys = 23; - */ - com.google.protobuf.AnyOrBuilder getAnysOrBuilder( - int index); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - boolean hasTypeRecursive(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - Root getTypeRecursive(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - RootOrBuilder getTypeRecursiveOrBuilder(); - } - - /** - * Protobuf type {@code org.apache.servicecomb.foundation.protobuf.internal.model.Root} - */ - public static final class Root extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:org.apache.servicecomb.foundation.protobuf.internal.model.Root) - RootOrBuilder { - private static final long serialVersionUID = 0L; - - // Use Root.newBuilder() to construct. - private Root(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - - private Root() { - int32_ = 0; - int64_ = 0L; - uint32_ = 0; - uint64_ = 0L; - sint32_ = 0; - sint64_ = 0L; - fixed32_ = 0; - fixed64_ = 0L; - sfixed32_ = 0; - sfixed64_ = 0L; - floatValue_ = 0F; - doubleValue_ = 0D; - bool_ = false; - string_ = ""; - bytes_ = com.google.protobuf.ByteString.EMPTY; - color_ = 0; - sList_ = com.google.protobuf.LazyStringArrayList.EMPTY; - pList_ = java.util.Collections.emptyList(); - anys_ = java.util.Collections.emptyList(); - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - - private Root( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 8: { - - int32_ = input.readInt32(); - break; - } - case 16: { - - int64_ = input.readInt64(); - break; - } - case 24: { - - uint32_ = input.readUInt32(); - break; - } - case 32: { - - uint64_ = input.readUInt64(); - break; - } - case 40: { - - sint32_ = input.readSInt32(); - break; - } - case 48: { - - sint64_ = input.readSInt64(); - break; - } - case 61: { - - fixed32_ = input.readFixed32(); - break; - } - case 65: { - - fixed64_ = input.readFixed64(); - break; - } - case 77: { - - sfixed32_ = input.readSFixed32(); - break; - } - case 81: { - - sfixed64_ = input.readSFixed64(); - break; - } - case 93: { - - floatValue_ = input.readFloat(); - break; - } - case 97: { - - doubleValue_ = input.readDouble(); - break; - } - case 104: { - - bool_ = input.readBool(); - break; - } - case 114: { - String s = input.readStringRequireUtf8(); - - string_ = s; - break; - } - case 122: { - - bytes_ = input.readBytes(); - break; - } - case 128: { - int rawValue = input.readEnum(); - - color_ = rawValue; - break; - } - case 138: { - User.Builder subBuilder = null; - if (user_ != null) { - subBuilder = user_.toBuilder(); - } - user_ = input.readMessage(User.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(user_); - user_ = subBuilder.buildPartial(); - } - - break; - } - case 146: { - if (!((mutable_bitField0_ & 0x00020000) == 0x00020000)) { - ssMap_ = com.google.protobuf.MapField.newMapField( - SsMapDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00020000; - } - com.google.protobuf.MapEntry - ssMap__ = input.readMessage( - SsMapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - ssMap_.getMutableMap().put( - ssMap__.getKey(), ssMap__.getValue()); - break; - } - case 154: { - if (!((mutable_bitField0_ & 0x00040000) == 0x00040000)) { - spMap_ = com.google.protobuf.MapField.newMapField( - SpMapDefaultEntryHolder.defaultEntry); - mutable_bitField0_ |= 0x00040000; - } - com.google.protobuf.MapEntry - spMap__ = input.readMessage( - SpMapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry); - spMap_.getMutableMap().put( - spMap__.getKey(), spMap__.getValue()); - break; - } - case 162: { - String s = input.readStringRequireUtf8(); - if (!((mutable_bitField0_ & 0x00080000) == 0x00080000)) { - sList_ = new com.google.protobuf.LazyStringArrayList(); - mutable_bitField0_ |= 0x00080000; - } - sList_.add(s); - break; - } - case 170: { - if (!((mutable_bitField0_ & 0x00100000) == 0x00100000)) { - pList_ = new java.util.ArrayList<>(); - mutable_bitField0_ |= 0x00100000; - } - pList_.add( - input.readMessage(User.parser(), extensionRegistry)); - break; - } - case 178: { - com.google.protobuf.Any.Builder subBuilder = null; - if (any_ != null) { - subBuilder = any_.toBuilder(); - } - any_ = input.readMessage(com.google.protobuf.Any.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(any_); - any_ = subBuilder.buildPartial(); - } - - break; - } - case 186: { - if (!((mutable_bitField0_ & 0x00400000) == 0x00400000)) { - anys_ = new java.util.ArrayList<>(); - mutable_bitField0_ |= 0x00400000; - } - anys_.add( - input.readMessage(com.google.protobuf.Any.parser(), extensionRegistry)); - break; - } - case 194: { - Builder subBuilder = null; - if (typeRecursive_ != null) { - subBuilder = typeRecursive_.toBuilder(); - } - typeRecursive_ = input.readMessage(Root.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(typeRecursive_); - typeRecursive_ = subBuilder.buildPartial(); - } - - break; - } - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00080000) == 0x00080000)) { - sList_ = sList_.getUnmodifiableView(); - } - if (((mutable_bitField0_ & 0x00100000) == 0x00100000)) { - pList_ = java.util.Collections.unmodifiableList(pList_); - } - if (((mutable_bitField0_ & 0x00400000) == 0x00400000)) { - anys_ = java.util.Collections.unmodifiableList(anys_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - @Override - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 18: - return internalGetSsMap(); - case 19: - return internalGetSpMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - @Override - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Root.class, Builder.class); - } - - private int bitField0_; - - public static final int INT32_FIELD_NUMBER = 1; - - private int int32_; - - /** - * int32 int32 = 1; - */ - public int getInt32() { - return int32_; - } - - public static final int INT64_FIELD_NUMBER = 2; - - private long int64_; - - /** - * int64 int64 = 2; - */ - public long getInt64() { - return int64_; - } - - public static final int UINT32_FIELD_NUMBER = 3; - - private int uint32_; - - /** - * uint32 uint32 = 3; - */ - public int getUint32() { - return uint32_; - } - - public static final int UINT64_FIELD_NUMBER = 4; - - private long uint64_; - - /** - * uint64 uint64 = 4; - */ - public long getUint64() { - return uint64_; - } - - public static final int SINT32_FIELD_NUMBER = 5; - - private int sint32_; - - /** - * sint32 sint32 = 5; - */ - public int getSint32() { - return sint32_; - } - - public static final int SINT64_FIELD_NUMBER = 6; - - private long sint64_; - - /** - * sint64 sint64 = 6; - */ - public long getSint64() { - return sint64_; - } - - public static final int FIXED32_FIELD_NUMBER = 7; - - private int fixed32_; - - /** - * fixed32 fixed32 = 7; - */ - public int getFixed32() { - return fixed32_; - } - - public static final int FIXED64_FIELD_NUMBER = 8; - - private long fixed64_; - - /** - * fixed64 fixed64 = 8; - */ - public long getFixed64() { - return fixed64_; - } - - public static final int SFIXED32_FIELD_NUMBER = 9; - - private int sfixed32_; - - /** - * sfixed32 sfixed32 = 9; - */ - public int getSfixed32() { - return sfixed32_; - } - - public static final int SFIXED64_FIELD_NUMBER = 10; - - private long sfixed64_; - - /** - * sfixed64 sfixed64 = 10; - */ - public long getSfixed64() { - return sfixed64_; - } - - public static final int FLOATVALUE_FIELD_NUMBER = 11; - - private float floatValue_; - - /** - * float floatValue = 11; - */ - public float getFloatValue() { - return floatValue_; - } - - public static final int DOUBLEVALUE_FIELD_NUMBER = 12; - - private double doubleValue_; - - /** - * double doubleValue = 12; - */ - public double getDoubleValue() { - return doubleValue_; - } - - public static final int BOOL_FIELD_NUMBER = 13; - - private boolean bool_; - - /** - * bool bool = 13; - */ - public boolean getBool() { - return bool_; - } - - public static final int STRING_FIELD_NUMBER = 14; - - private volatile Object string_; - - /** - * string string = 14; - */ - public String getString() { - Object ref = string_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - string_ = s; - return s; - } - } - - /** - * string string = 14; - */ - public com.google.protobuf.ByteString - getStringBytes() { - Object ref = string_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - string_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int BYTES_FIELD_NUMBER = 15; - - private com.google.protobuf.ByteString bytes_; - - /** - * bytes bytes = 15; - */ - public com.google.protobuf.ByteString getBytes() { - return bytes_; - } - - public static final int COLOR_FIELD_NUMBER = 16; - - private int color_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public int getColorValue() { - return color_; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public Color getColor() { - @SuppressWarnings("deprecation") - Color result = Color.valueOf(color_); - return result == null ? Color.UNRECOGNIZED : result; - } - - public static final int USER_FIELD_NUMBER = 17; - - private User user_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public boolean hasUser() { - return user_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public User getUser() { - return user_ == null ? User.getDefaultInstance() : user_; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public UserOrBuilder getUserOrBuilder() { - return getUser(); - } - - public static final int SSMAP_FIELD_NUMBER = 18; - - private static final class SsMapDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - String, String> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.STRING, - ""); - } - - private com.google.protobuf.MapField< - String, String> ssMap_; - - private com.google.protobuf.MapField - internalGetSsMap() { - if (ssMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SsMapDefaultEntryHolder.defaultEntry); - } - return ssMap_; - } - - public int getSsMapCount() { - return internalGetSsMap().getMap().size(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public boolean containsSsMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - return internalGetSsMap().getMap().containsKey(key); - } - - /** - * Use {@link #getSsMapMap()} instead. - */ - @Deprecated - public java.util.Map getSsMap() { - return getSsMapMap(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public java.util.Map getSsMapMap() { - return internalGetSsMap().getMap(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public String getSsMapOrDefault( - String key, - String defaultValue) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSsMap().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - - /** - * map<string, string> ssMap = 18; - */ - - public String getSsMapOrThrow( - String key) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSsMap().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public static final int SPMAP_FIELD_NUMBER = 19; - - private static final class SpMapDefaultEntryHolder { - static final com.google.protobuf.MapEntry< - String, User> defaultEntry = - com.google.protobuf.MapEntry - .newDefaultInstance( - ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_descriptor, - com.google.protobuf.WireFormat.FieldType.STRING, - "", - com.google.protobuf.WireFormat.FieldType.MESSAGE, - User.getDefaultInstance()); - } - - private com.google.protobuf.MapField< - String, User> spMap_; - - private com.google.protobuf.MapField - internalGetSpMap() { - if (spMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SpMapDefaultEntryHolder.defaultEntry); - } - return spMap_; - } - - public int getSpMapCount() { - return internalGetSpMap().getMap().size(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public boolean containsSpMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - return internalGetSpMap().getMap().containsKey(key); - } - - /** - * Use {@link #getSpMapMap()} instead. - */ - @Deprecated - public java.util.Map getSpMap() { - return getSpMapMap(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public java.util.Map getSpMapMap() { - return internalGetSpMap().getMap(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public User getSpMapOrDefault( - String key, - User defaultValue) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSpMap().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public User getSpMapOrThrow( - String key) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSpMap().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public static final int SLIST_FIELD_NUMBER = 20; - - private com.google.protobuf.LazyStringList sList_; - - /** - * repeated string sList = 20; - */ - public com.google.protobuf.ProtocolStringList - getSListList() { - return sList_; - } - - /** - * repeated string sList = 20; - */ - public int getSListCount() { - return sList_.size(); - } - - /** - * repeated string sList = 20; - */ - public String getSList(int index) { - return sList_.get(index); - } - - /** - * repeated string sList = 20; - */ - public com.google.protobuf.ByteString - getSListBytes(int index) { - return sList_.getByteString(index); - } - - public static final int PLIST_FIELD_NUMBER = 21; - - private java.util.List pList_; - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public java.util.List getPListList() { - return pList_; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public java.util.List - getPListOrBuilderList() { - return pList_; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public int getPListCount() { - return pList_.size(); - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public User getPList(int index) { - return pList_.get(index); - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public UserOrBuilder getPListOrBuilder( - int index) { - return pList_.get(index); - } - - public static final int ANY_FIELD_NUMBER = 22; - - private com.google.protobuf.Any any_; - - /** - * .google.protobuf.Any any = 22; - */ - public boolean hasAny() { - return any_ != null; - } - - /** - * .google.protobuf.Any any = 22; - */ - public com.google.protobuf.Any getAny() { - return any_ == null ? com.google.protobuf.Any.getDefaultInstance() : any_; - } - - /** - * .google.protobuf.Any any = 22; - */ - public com.google.protobuf.AnyOrBuilder getAnyOrBuilder() { - return getAny(); - } - - public static final int ANYS_FIELD_NUMBER = 23; - - private java.util.List anys_; - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public java.util.List getAnysList() { - return anys_; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public java.util.List - getAnysOrBuilderList() { - return anys_; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public int getAnysCount() { - return anys_.size(); - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.Any getAnys(int index) { - return anys_.get(index); - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.AnyOrBuilder getAnysOrBuilder( - int index) { - return anys_.get(index); - } - - public static final int TYPERECURSIVE_FIELD_NUMBER = 24; - - private Root typeRecursive_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public boolean hasTypeRecursive() { - return typeRecursive_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Root getTypeRecursive() { - return typeRecursive_ == null ? Root.getDefaultInstance() : typeRecursive_; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public RootOrBuilder getTypeRecursiveOrBuilder() { - return getTypeRecursive(); - } - - private byte memoizedIsInitialized = -1; - - @Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) { - return true; - } - if (isInitialized == 0) { - return false; - } - - memoizedIsInitialized = 1; - return true; - } - - @Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (int32_ != 0) { - output.writeInt32(1, int32_); - } - if (int64_ != 0L) { - output.writeInt64(2, int64_); - } - if (uint32_ != 0) { - output.writeUInt32(3, uint32_); - } - if (uint64_ != 0L) { - output.writeUInt64(4, uint64_); - } - if (sint32_ != 0) { - output.writeSInt32(5, sint32_); - } - if (sint64_ != 0L) { - output.writeSInt64(6, sint64_); - } - if (fixed32_ != 0) { - output.writeFixed32(7, fixed32_); - } - if (fixed64_ != 0L) { - output.writeFixed64(8, fixed64_); - } - if (sfixed32_ != 0) { - output.writeSFixed32(9, sfixed32_); - } - if (sfixed64_ != 0L) { - output.writeSFixed64(10, sfixed64_); - } - if (floatValue_ != 0F) { - output.writeFloat(11, floatValue_); - } - if (doubleValue_ != 0D) { - output.writeDouble(12, doubleValue_); - } - if (bool_ != false) { - output.writeBool(13, bool_); - } - if (!getStringBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 14, string_); - } - if (!bytes_.isEmpty()) { - output.writeBytes(15, bytes_); - } - if (color_ != Color.RED.getNumber()) { - output.writeEnum(16, color_); - } - if (user_ != null) { - output.writeMessage(17, getUser()); - } - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetSsMap(), - SsMapDefaultEntryHolder.defaultEntry, - 18); - com.google.protobuf.GeneratedMessageV3 - .serializeStringMapTo( - output, - internalGetSpMap(), - SpMapDefaultEntryHolder.defaultEntry, - 19); - for (int i = 0; i < sList_.size(); i++) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 20, sList_.getRaw(i)); - } - for (int i = 0; i < pList_.size(); i++) { - output.writeMessage(21, pList_.get(i)); - } - if (any_ != null) { - output.writeMessage(22, getAny()); - } - for (int i = 0; i < anys_.size(); i++) { - output.writeMessage(23, anys_.get(i)); - } - if (typeRecursive_ != null) { - output.writeMessage(24, getTypeRecursive()); - } - unknownFields.writeTo(output); - } - - @Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) { - return size; - } - - size = 0; - if (int32_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeInt32Size(1, int32_); - } - if (int64_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeInt64Size(2, int64_); - } - if (uint32_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(3, uint32_); - } - if (uint64_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(4, uint64_); - } - if (sint32_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeSInt32Size(5, sint32_); - } - if (sint64_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeSInt64Size(6, sint64_); - } - if (fixed32_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeFixed32Size(7, fixed32_); - } - if (fixed64_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeFixed64Size(8, fixed64_); - } - if (sfixed32_ != 0) { - size += com.google.protobuf.CodedOutputStream - .computeSFixed32Size(9, sfixed32_); - } - if (sfixed64_ != 0L) { - size += com.google.protobuf.CodedOutputStream - .computeSFixed64Size(10, sfixed64_); - } - if (floatValue_ != 0F) { - size += com.google.protobuf.CodedOutputStream - .computeFloatSize(11, floatValue_); - } - if (doubleValue_ != 0D) { - size += com.google.protobuf.CodedOutputStream - .computeDoubleSize(12, doubleValue_); - } - if (bool_ != false) { - size += com.google.protobuf.CodedOutputStream - .computeBoolSize(13, bool_); - } - if (!getStringBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(14, string_); - } - if (!bytes_.isEmpty()) { - size += com.google.protobuf.CodedOutputStream - .computeBytesSize(15, bytes_); - } - if (color_ != Color.RED.getNumber()) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(16, color_); - } - if (user_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(17, getUser()); - } - for (java.util.Map.Entry entry - : internalGetSsMap().getMap().entrySet()) { - com.google.protobuf.MapEntry - ssMap__ = SsMapDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(18, ssMap__); - } - for (java.util.Map.Entry entry - : internalGetSpMap().getMap().entrySet()) { - com.google.protobuf.MapEntry - spMap__ = SpMapDefaultEntryHolder.defaultEntry.newBuilderForType() - .setKey(entry.getKey()) - .setValue(entry.getValue()) - .build(); - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(19, spMap__); - } - { - int dataSize = 0; - for (int i = 0; i < sList_.size(); i++) { - dataSize += computeStringSizeNoTag(sList_.getRaw(i)); - } - size += dataSize; - size += 2 * getSListList().size(); - } - for (int i = 0; i < pList_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(21, pList_.get(i)); - } - if (any_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(22, getAny()); - } - for (int i = 0; i < anys_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(23, anys_.get(i)); - } - if (typeRecursive_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(24, getTypeRecursive()); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Root)) { - return super.equals(obj); - } - Root other = (Root) obj; - - boolean result = true; - result = result && (getInt32() - == other.getInt32()); - result = result && (getInt64() - == other.getInt64()); - result = result && (getUint32() - == other.getUint32()); - result = result && (getUint64() - == other.getUint64()); - result = result && (getSint32() - == other.getSint32()); - result = result && (getSint64() - == other.getSint64()); - result = result && (getFixed32() - == other.getFixed32()); - result = result && (getFixed64() - == other.getFixed64()); - result = result && (getSfixed32() - == other.getSfixed32()); - result = result && (getSfixed64() - == other.getSfixed64()); - result = result && ( - Float.floatToIntBits(getFloatValue()) - == Float.floatToIntBits( - other.getFloatValue())); - result = result && ( - Double.doubleToLongBits(getDoubleValue()) - == Double.doubleToLongBits( - other.getDoubleValue())); - result = result && (getBool() - == other.getBool()); - result = result && getString() - .equals(other.getString()); - result = result && getBytes() - .equals(other.getBytes()); - result = result && color_ == other.color_; - result = result && (hasUser() == other.hasUser()); - if (hasUser()) { - result = result && getUser() - .equals(other.getUser()); - } - result = result && internalGetSsMap().equals( - other.internalGetSsMap()); - result = result && internalGetSpMap().equals( - other.internalGetSpMap()); - result = result && getSListList() - .equals(other.getSListList()); - result = result && getPListList() - .equals(other.getPListList()); - result = result && (hasAny() == other.hasAny()); - if (hasAny()) { - result = result && getAny() - .equals(other.getAny()); - } - result = result && getAnysList() - .equals(other.getAnysList()); - result = result && (hasTypeRecursive() == other.hasTypeRecursive()); - if (hasTypeRecursive()) { - result = result && getTypeRecursive() - .equals(other.getTypeRecursive()); - } - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + INT32_FIELD_NUMBER; - hash = (53 * hash) + getInt32(); - hash = (37 * hash) + INT64_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getInt64()); - hash = (37 * hash) + UINT32_FIELD_NUMBER; - hash = (53 * hash) + getUint32(); - hash = (37 * hash) + UINT64_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getUint64()); - hash = (37 * hash) + SINT32_FIELD_NUMBER; - hash = (53 * hash) + getSint32(); - hash = (37 * hash) + SINT64_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getSint64()); - hash = (37 * hash) + FIXED32_FIELD_NUMBER; - hash = (53 * hash) + getFixed32(); - hash = (37 * hash) + FIXED64_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getFixed64()); - hash = (37 * hash) + SFIXED32_FIELD_NUMBER; - hash = (53 * hash) + getSfixed32(); - hash = (37 * hash) + SFIXED64_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - getSfixed64()); - hash = (37 * hash) + FLOATVALUE_FIELD_NUMBER; - hash = (53 * hash) + Float.floatToIntBits( - getFloatValue()); - hash = (37 * hash) + DOUBLEVALUE_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashLong( - Double.doubleToLongBits(getDoubleValue())); - hash = (37 * hash) + BOOL_FIELD_NUMBER; - hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( - getBool()); - hash = (37 * hash) + STRING_FIELD_NUMBER; - hash = (53 * hash) + getString().hashCode(); - hash = (37 * hash) + BYTES_FIELD_NUMBER; - hash = (53 * hash) + getBytes().hashCode(); - hash = (37 * hash) + COLOR_FIELD_NUMBER; - hash = (53 * hash) + color_; - if (hasUser()) { - hash = (37 * hash) + USER_FIELD_NUMBER; - hash = (53 * hash) + getUser().hashCode(); - } - if (!internalGetSsMap().getMap().isEmpty()) { - hash = (37 * hash) + SSMAP_FIELD_NUMBER; - hash = (53 * hash) + internalGetSsMap().hashCode(); - } - if (!internalGetSpMap().getMap().isEmpty()) { - hash = (37 * hash) + SPMAP_FIELD_NUMBER; - hash = (53 * hash) + internalGetSpMap().hashCode(); - } - if (getSListCount() > 0) { - hash = (37 * hash) + SLIST_FIELD_NUMBER; - hash = (53 * hash) + getSListList().hashCode(); - } - if (getPListCount() > 0) { - hash = (37 * hash) + PLIST_FIELD_NUMBER; - hash = (53 * hash) + getPListList().hashCode(); - } - if (hasAny()) { - hash = (37 * hash) + ANY_FIELD_NUMBER; - hash = (53 * hash) + getAny().hashCode(); - } - if (getAnysCount() > 0) { - hash = (37 * hash) + ANYS_FIELD_NUMBER; - hash = (53 * hash) + getAnysList().hashCode(); - } - if (hasTypeRecursive()) { - hash = (37 * hash) + TYPERECURSIVE_FIELD_NUMBER; - hash = (53 * hash) + getTypeRecursive().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static Root parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static Root parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static Root parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static Root parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static Root parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static Root parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static Root parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static Root parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static Root parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - - public static Root parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - - public static Root parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static Root parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @Override - public Builder newBuilderForType() { - return newBuilder(); - } - - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - - public static Builder newBuilder(Root prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - - @Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - - /** - * Protobuf type {@code org.apache.servicecomb.foundation.protobuf.internal.model.Root} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:org.apache.servicecomb.foundation.protobuf.internal.model.Root) - RootOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor; - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMapField( - int number) { - switch (number) { - case 18: - return internalGetSsMap(); - case 19: - return internalGetSpMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - @SuppressWarnings({"rawtypes"}) - protected com.google.protobuf.MapField internalGetMutableMapField( - int number) { - switch (number) { - case 18: - return internalGetMutableSsMap(); - case 19: - return internalGetMutableSpMap(); - default: - throw new RuntimeException( - "Invalid map field number: " + number); - } - } - - @Override - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_fieldAccessorTable - .ensureFieldAccessorsInitialized( - Root.class, Builder.class); - } - - // Construct using org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot.Root.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - getPListFieldBuilder(); - getAnysFieldBuilder(); - } - } - - @Override - public Builder clear() { - super.clear(); - int32_ = 0; - - int64_ = 0L; - - uint32_ = 0; - - uint64_ = 0L; - - sint32_ = 0; - - sint64_ = 0L; - - fixed32_ = 0; - - fixed64_ = 0L; - - sfixed32_ = 0; - - sfixed64_ = 0L; - - floatValue_ = 0F; - - doubleValue_ = 0D; - - bool_ = false; - - string_ = ""; - - bytes_ = com.google.protobuf.ByteString.EMPTY; - - color_ = 0; - - if (userBuilder_ == null) { - user_ = null; - } else { - user_ = null; - userBuilder_ = null; - } - internalGetMutableSsMap().clear(); - internalGetMutableSpMap().clear(); - sList_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00080000); - if (pListBuilder_ == null) { - pList_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00100000); - } else { - pListBuilder_.clear(); - } - if (anyBuilder_ == null) { - any_ = null; - } else { - any_ = null; - anyBuilder_ = null; - } - if (anysBuilder_ == null) { - anys_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00400000); - } else { - anysBuilder_.clear(); - } - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = null; - } else { - typeRecursive_ = null; - typeRecursiveBuilder_ = null; - } - return this; - } - - @Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor; - } - - @Override - public Root getDefaultInstanceForType() { - return Root.getDefaultInstance(); - } - - @Override - public Root build() { - Root result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @Override - public Root buildPartial() { - Root result = new Root(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - result.int32_ = int32_; - result.int64_ = int64_; - result.uint32_ = uint32_; - result.uint64_ = uint64_; - result.sint32_ = sint32_; - result.sint64_ = sint64_; - result.fixed32_ = fixed32_; - result.fixed64_ = fixed64_; - result.sfixed32_ = sfixed32_; - result.sfixed64_ = sfixed64_; - result.floatValue_ = floatValue_; - result.doubleValue_ = doubleValue_; - result.bool_ = bool_; - result.string_ = string_; - result.bytes_ = bytes_; - result.color_ = color_; - if (userBuilder_ == null) { - result.user_ = user_; - } else { - result.user_ = userBuilder_.build(); - } - result.ssMap_ = internalGetSsMap(); - result.ssMap_.makeImmutable(); - result.spMap_ = internalGetSpMap(); - result.spMap_.makeImmutable(); - if (((bitField0_ & 0x00080000) == 0x00080000)) { - sList_ = sList_.getUnmodifiableView(); - bitField0_ = (bitField0_ & ~0x00080000); - } - result.sList_ = sList_; - if (pListBuilder_ == null) { - if (((bitField0_ & 0x00100000) == 0x00100000)) { - pList_ = java.util.Collections.unmodifiableList(pList_); - bitField0_ = (bitField0_ & ~0x00100000); - } - result.pList_ = pList_; - } else { - result.pList_ = pListBuilder_.build(); - } - if (anyBuilder_ == null) { - result.any_ = any_; - } else { - result.any_ = anyBuilder_.build(); - } - if (anysBuilder_ == null) { - if (((bitField0_ & 0x00400000) == 0x00400000)) { - anys_ = java.util.Collections.unmodifiableList(anys_); - bitField0_ = (bitField0_ & ~0x00400000); - } - result.anys_ = anys_; - } else { - result.anys_ = anysBuilder_.build(); - } - if (typeRecursiveBuilder_ == null) { - result.typeRecursive_ = typeRecursive_; - } else { - result.typeRecursive_ = typeRecursiveBuilder_.build(); - } - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - @Override - public Builder clone() { - return (Builder) super.clone(); - } - - @Override - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - - @Override - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - - @Override - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - - @Override - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - - @Override - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - - @Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof Root) { - return mergeFrom((Root) other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(Root other) { - if (other == Root.getDefaultInstance()) { - return this; - } - if (other.getInt32() != 0) { - setInt32(other.getInt32()); - } - if (other.getInt64() != 0L) { - setInt64(other.getInt64()); - } - if (other.getUint32() != 0) { - setUint32(other.getUint32()); - } - if (other.getUint64() != 0L) { - setUint64(other.getUint64()); - } - if (other.getSint32() != 0) { - setSint32(other.getSint32()); - } - if (other.getSint64() != 0L) { - setSint64(other.getSint64()); - } - if (other.getFixed32() != 0) { - setFixed32(other.getFixed32()); - } - if (other.getFixed64() != 0L) { - setFixed64(other.getFixed64()); - } - if (other.getSfixed32() != 0) { - setSfixed32(other.getSfixed32()); - } - if (other.getSfixed64() != 0L) { - setSfixed64(other.getSfixed64()); - } - if (other.getFloatValue() != 0F) { - setFloatValue(other.getFloatValue()); - } - if (other.getDoubleValue() != 0D) { - setDoubleValue(other.getDoubleValue()); - } - if (other.getBool() != false) { - setBool(other.getBool()); - } - if (!other.getString().isEmpty()) { - string_ = other.string_; - onChanged(); - } - if (other.getBytes() != com.google.protobuf.ByteString.EMPTY) { - setBytes(other.getBytes()); - } - if (other.color_ != 0) { - setColorValue(other.getColorValue()); - } - if (other.hasUser()) { - mergeUser(other.getUser()); - } - internalGetMutableSsMap().mergeFrom( - other.internalGetSsMap()); - internalGetMutableSpMap().mergeFrom( - other.internalGetSpMap()); - if (!other.sList_.isEmpty()) { - if (sList_.isEmpty()) { - sList_ = other.sList_; - bitField0_ = (bitField0_ & ~0x00080000); - } else { - ensureSListIsMutable(); - sList_.addAll(other.sList_); - } - onChanged(); - } - if (pListBuilder_ == null) { - if (!other.pList_.isEmpty()) { - if (pList_.isEmpty()) { - pList_ = other.pList_; - bitField0_ = (bitField0_ & ~0x00100000); - } else { - ensurePListIsMutable(); - pList_.addAll(other.pList_); - } - onChanged(); - } - } else { - if (!other.pList_.isEmpty()) { - if (pListBuilder_.isEmpty()) { - pListBuilder_.dispose(); - pListBuilder_ = null; - pList_ = other.pList_; - bitField0_ = (bitField0_ & ~0x00100000); - pListBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getPListFieldBuilder() : null; - } else { - pListBuilder_.addAllMessages(other.pList_); - } - } - } - if (other.hasAny()) { - mergeAny(other.getAny()); - } - if (anysBuilder_ == null) { - if (!other.anys_.isEmpty()) { - if (anys_.isEmpty()) { - anys_ = other.anys_; - bitField0_ = (bitField0_ & ~0x00400000); - } else { - ensureAnysIsMutable(); - anys_.addAll(other.anys_); - } - onChanged(); - } - } else { - if (!other.anys_.isEmpty()) { - if (anysBuilder_.isEmpty()) { - anysBuilder_.dispose(); - anysBuilder_ = null; - anys_ = other.anys_; - bitField0_ = (bitField0_ & ~0x00400000); - anysBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getAnysFieldBuilder() : null; - } else { - anysBuilder_.addAllMessages(other.anys_); - } - } - } - if (other.hasTypeRecursive()) { - mergeTypeRecursive(other.getTypeRecursive()); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - @Override - public final boolean isInitialized() { - return true; - } - - @Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Root parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (Root) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private int bitField0_; - - private int int32_; - - /** - * int32 int32 = 1; - */ - public int getInt32() { - return int32_; - } - - /** - * int32 int32 = 1; - */ - public Builder setInt32(int value) { - - int32_ = value; - onChanged(); - return this; - } - - /** - * int32 int32 = 1; - */ - public Builder clearInt32() { - - int32_ = 0; - onChanged(); - return this; - } - - private long int64_; - - /** - * int64 int64 = 2; - */ - public long getInt64() { - return int64_; - } - - /** - * int64 int64 = 2; - */ - public Builder setInt64(long value) { - - int64_ = value; - onChanged(); - return this; - } - - /** - * int64 int64 = 2; - */ - public Builder clearInt64() { - - int64_ = 0L; - onChanged(); - return this; - } - - private int uint32_; - - /** - * uint32 uint32 = 3; - */ - public int getUint32() { - return uint32_; - } - - /** - * uint32 uint32 = 3; - */ - public Builder setUint32(int value) { - - uint32_ = value; - onChanged(); - return this; - } - - /** - * uint32 uint32 = 3; - */ - public Builder clearUint32() { - - uint32_ = 0; - onChanged(); - return this; - } - - private long uint64_; - - /** - * uint64 uint64 = 4; - */ - public long getUint64() { - return uint64_; - } - - /** - * uint64 uint64 = 4; - */ - public Builder setUint64(long value) { - - uint64_ = value; - onChanged(); - return this; - } - - /** - * uint64 uint64 = 4; - */ - public Builder clearUint64() { - - uint64_ = 0L; - onChanged(); - return this; - } - - private int sint32_; - - /** - * sint32 sint32 = 5; - */ - public int getSint32() { - return sint32_; - } - - /** - * sint32 sint32 = 5; - */ - public Builder setSint32(int value) { - - sint32_ = value; - onChanged(); - return this; - } - - /** - * sint32 sint32 = 5; - */ - public Builder clearSint32() { - - sint32_ = 0; - onChanged(); - return this; - } - - private long sint64_; - - /** - * sint64 sint64 = 6; - */ - public long getSint64() { - return sint64_; - } - - /** - * sint64 sint64 = 6; - */ - public Builder setSint64(long value) { - - sint64_ = value; - onChanged(); - return this; - } - - /** - * sint64 sint64 = 6; - */ - public Builder clearSint64() { - - sint64_ = 0L; - onChanged(); - return this; - } - - private int fixed32_; - - /** - * fixed32 fixed32 = 7; - */ - public int getFixed32() { - return fixed32_; - } - - /** - * fixed32 fixed32 = 7; - */ - public Builder setFixed32(int value) { - - fixed32_ = value; - onChanged(); - return this; - } - - /** - * fixed32 fixed32 = 7; - */ - public Builder clearFixed32() { - - fixed32_ = 0; - onChanged(); - return this; - } - - private long fixed64_; - - /** - * fixed64 fixed64 = 8; - */ - public long getFixed64() { - return fixed64_; - } - - /** - * fixed64 fixed64 = 8; - */ - public Builder setFixed64(long value) { - - fixed64_ = value; - onChanged(); - return this; - } - - /** - * fixed64 fixed64 = 8; - */ - public Builder clearFixed64() { - - fixed64_ = 0L; - onChanged(); - return this; - } - - private int sfixed32_; - - /** - * sfixed32 sfixed32 = 9; - */ - public int getSfixed32() { - return sfixed32_; - } - - /** - * sfixed32 sfixed32 = 9; - */ - public Builder setSfixed32(int value) { - - sfixed32_ = value; - onChanged(); - return this; - } - - /** - * sfixed32 sfixed32 = 9; - */ - public Builder clearSfixed32() { - - sfixed32_ = 0; - onChanged(); - return this; - } - - private long sfixed64_; - - /** - * sfixed64 sfixed64 = 10; - */ - public long getSfixed64() { - return sfixed64_; - } - - /** - * sfixed64 sfixed64 = 10; - */ - public Builder setSfixed64(long value) { - - sfixed64_ = value; - onChanged(); - return this; - } - - /** - * sfixed64 sfixed64 = 10; - */ - public Builder clearSfixed64() { - - sfixed64_ = 0L; - onChanged(); - return this; - } - - private float floatValue_; - - /** - * float floatValue = 11; - */ - public float getFloatValue() { - return floatValue_; - } - - /** - * float floatValue = 11; - */ - public Builder setFloatValue(float value) { - - floatValue_ = value; - onChanged(); - return this; - } - - /** - * float floatValue = 11; - */ - public Builder clearFloatValue() { - - floatValue_ = 0F; - onChanged(); - return this; - } - - private double doubleValue_; - - /** - * double doubleValue = 12; - */ - public double getDoubleValue() { - return doubleValue_; - } - - /** - * double doubleValue = 12; - */ - public Builder setDoubleValue(double value) { - - doubleValue_ = value; - onChanged(); - return this; - } - - /** - * double doubleValue = 12; - */ - public Builder clearDoubleValue() { - - doubleValue_ = 0D; - onChanged(); - return this; - } - - private boolean bool_; - - /** - * bool bool = 13; - */ - public boolean getBool() { - return bool_; - } - - /** - * bool bool = 13; - */ - public Builder setBool(boolean value) { - - bool_ = value; - onChanged(); - return this; - } - - /** - * bool bool = 13; - */ - public Builder clearBool() { - - bool_ = false; - onChanged(); - return this; - } - - private Object string_ = ""; - - /** - * string string = 14; - */ - public String getString() { - Object ref = string_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - string_ = s; - return s; - } else { - return (String) ref; - } - } - - /** - * string string = 14; - */ - public com.google.protobuf.ByteString - getStringBytes() { - Object ref = string_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - string_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string string = 14; - */ - public Builder setString( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - string_ = value; - onChanged(); - return this; - } - - /** - * string string = 14; - */ - public Builder clearString() { - - string_ = getDefaultInstance().getString(); - onChanged(); - return this; - } - - /** - * string string = 14; - */ - public Builder setStringBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - string_ = value; - onChanged(); - return this; - } - - private com.google.protobuf.ByteString bytes_ = com.google.protobuf.ByteString.EMPTY; - - /** - * bytes bytes = 15; - */ - public com.google.protobuf.ByteString getBytes() { - return bytes_; - } - - /** - * bytes bytes = 15; - */ - public Builder setBytes(com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - - bytes_ = value; - onChanged(); - return this; - } - - /** - * bytes bytes = 15; - */ - public Builder clearBytes() { - - bytes_ = getDefaultInstance().getBytes(); - onChanged(); - return this; - } - - private int color_ = 0; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public int getColorValue() { - return color_; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public Builder setColorValue(int value) { - color_ = value; - onChanged(); - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public Color getColor() { - @SuppressWarnings("deprecation") - Color result = Color.valueOf(color_); - return result == null ? Color.UNRECOGNIZED : result; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public Builder setColor(Color value) { - if (value == null) { - throw new NullPointerException(); - } - - color_ = value.getNumber(); - onChanged(); - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Color color = 16; - */ - public Builder clearColor() { - - color_ = 0; - onChanged(); - return this; - } - - private User user_ = null; - - private com.google.protobuf.SingleFieldBuilderV3< - User, User.Builder, UserOrBuilder> userBuilder_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public boolean hasUser() { - return userBuilder_ != null || user_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public User getUser() { - if (userBuilder_ == null) { - return user_ == null ? User.getDefaultInstance() : user_; - } else { - return userBuilder_.getMessage(); - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public Builder setUser(User value) { - if (userBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - user_ = value; - onChanged(); - } else { - userBuilder_.setMessage(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public Builder setUser( - User.Builder builderForValue) { - if (userBuilder_ == null) { - user_ = builderForValue.build(); - onChanged(); - } else { - userBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public Builder mergeUser(User value) { - if (userBuilder_ == null) { - if (user_ != null) { - user_ = - User.newBuilder(user_).mergeFrom(value).buildPartial(); - } else { - user_ = value; - } - onChanged(); - } else { - userBuilder_.mergeFrom(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public Builder clearUser() { - if (userBuilder_ == null) { - user_ = null; - onChanged(); - } else { - user_ = null; - userBuilder_ = null; - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public User.Builder getUserBuilder() { - - onChanged(); - return getUserFieldBuilder().getBuilder(); - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - public UserOrBuilder getUserOrBuilder() { - if (userBuilder_ != null) { - return userBuilder_.getMessageOrBuilder(); - } else { - return user_ == null ? - User.getDefaultInstance() : user_; - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.User user = 17; - */ - private com.google.protobuf.SingleFieldBuilderV3< - User, User.Builder, UserOrBuilder> - getUserFieldBuilder() { - if (userBuilder_ == null) { - userBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>( - getUser(), - getParentForChildren(), - isClean()); - user_ = null; - } - return userBuilder_; - } - - private com.google.protobuf.MapField< - String, String> ssMap_; - - private com.google.protobuf.MapField - internalGetSsMap() { - if (ssMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SsMapDefaultEntryHolder.defaultEntry); - } - return ssMap_; - } - - private com.google.protobuf.MapField - internalGetMutableSsMap() { - onChanged(); - if (ssMap_ == null) { - ssMap_ = com.google.protobuf.MapField.newMapField( - SsMapDefaultEntryHolder.defaultEntry); - } - if (!ssMap_.isMutable()) { - ssMap_ = ssMap_.copy(); - } - return ssMap_; - } - - public int getSsMapCount() { - return internalGetSsMap().getMap().size(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public boolean containsSsMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - return internalGetSsMap().getMap().containsKey(key); - } - - /** - * Use {@link #getSsMapMap()} instead. - */ - @Deprecated - public java.util.Map getSsMap() { - return getSsMapMap(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public java.util.Map getSsMapMap() { - return internalGetSsMap().getMap(); - } - - /** - * map<string, string> ssMap = 18; - */ - - public String getSsMapOrDefault( - String key, - String defaultValue) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSsMap().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - - /** - * map<string, string> ssMap = 18; - */ - - public String getSsMapOrThrow( - String key) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSsMap().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearSsMap() { - internalGetMutableSsMap().getMutableMap() - .clear(); - return this; - } - - /** - * map<string, string> ssMap = 18; - */ - - public Builder removeSsMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - internalGetMutableSsMap().getMutableMap() - .remove(key); - return this; - } - - /** - * Use alternate mutation accessors instead. - */ - @Deprecated - public java.util.Map - getMutableSsMap() { - return internalGetMutableSsMap().getMutableMap(); - } - - /** - * map<string, string> ssMap = 18; - */ - public Builder putSsMap( - String key, - String value) { - if (key == null) { - throw new NullPointerException(); - } - if (value == null) { - throw new NullPointerException(); - } - internalGetMutableSsMap().getMutableMap() - .put(key, value); - return this; - } - - /** - * map<string, string> ssMap = 18; - */ - - public Builder putAllSsMap( - java.util.Map values) { - internalGetMutableSsMap().getMutableMap() - .putAll(values); - return this; - } - - private com.google.protobuf.MapField< - String, User> spMap_; - - private com.google.protobuf.MapField - internalGetSpMap() { - if (spMap_ == null) { - return com.google.protobuf.MapField.emptyMapField( - SpMapDefaultEntryHolder.defaultEntry); - } - return spMap_; - } - - private com.google.protobuf.MapField - internalGetMutableSpMap() { - onChanged(); - if (spMap_ == null) { - spMap_ = com.google.protobuf.MapField.newMapField( - SpMapDefaultEntryHolder.defaultEntry); - } - if (!spMap_.isMutable()) { - spMap_ = spMap_.copy(); - } - return spMap_; - } - - public int getSpMapCount() { - return internalGetSpMap().getMap().size(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public boolean containsSpMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - return internalGetSpMap().getMap().containsKey(key); - } - - /** - * Use {@link #getSpMapMap()} instead. - */ - @Deprecated - public java.util.Map getSpMap() { - return getSpMapMap(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public java.util.Map getSpMapMap() { - return internalGetSpMap().getMap(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public User getSpMapOrDefault( - String key, - User defaultValue) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSpMap().getMap(); - return map.containsKey(key) ? map.get(key) : defaultValue; - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public User getSpMapOrThrow( - String key) { - if (key == null) { - throw new NullPointerException(); - } - java.util.Map map = - internalGetSpMap().getMap(); - if (!map.containsKey(key)) { - throw new IllegalArgumentException(); - } - return map.get(key); - } - - public Builder clearSpMap() { - internalGetMutableSpMap().getMutableMap() - .clear(); - return this; - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public Builder removeSpMap( - String key) { - if (key == null) { - throw new NullPointerException(); - } - internalGetMutableSpMap().getMutableMap() - .remove(key); - return this; - } - - /** - * Use alternate mutation accessors instead. - */ - @Deprecated - public java.util.Map - getMutableSpMap() { - return internalGetMutableSpMap().getMutableMap(); - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - public Builder putSpMap( - String key, - User value) { - if (key == null) { - throw new NullPointerException(); - } - if (value == null) { - throw new NullPointerException(); - } - internalGetMutableSpMap().getMutableMap() - .put(key, value); - return this; - } - - /** - * map<string, .org.apache.servicecomb.foundation.protobuf.internal.model.User> spMap = 19; - */ - - public Builder putAllSpMap( - java.util.Map values) { - internalGetMutableSpMap().getMutableMap() - .putAll(values); - return this; - } - - private com.google.protobuf.LazyStringList sList_ = com.google.protobuf.LazyStringArrayList.EMPTY; - - private void ensureSListIsMutable() { - if (!((bitField0_ & 0x00080000) == 0x00080000)) { - sList_ = new com.google.protobuf.LazyStringArrayList(sList_); - bitField0_ |= 0x00080000; - } - } - - /** - * repeated string sList = 20; - */ - public com.google.protobuf.ProtocolStringList - getSListList() { - return sList_.getUnmodifiableView(); - } - - /** - * repeated string sList = 20; - */ - public int getSListCount() { - return sList_.size(); - } - - /** - * repeated string sList = 20; - */ - public String getSList(int index) { - return sList_.get(index); - } - - /** - * repeated string sList = 20; - */ - public com.google.protobuf.ByteString - getSListBytes(int index) { - return sList_.getByteString(index); - } - - /** - * repeated string sList = 20; - */ - public Builder setSList( - int index, String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureSListIsMutable(); - sList_.set(index, value); - onChanged(); - return this; - } - - /** - * repeated string sList = 20; - */ - public Builder addSList( - String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureSListIsMutable(); - sList_.add(value); - onChanged(); - return this; - } - - /** - * repeated string sList = 20; - */ - public Builder addAllSList( - Iterable values) { - ensureSListIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, sList_); - onChanged(); - return this; - } - - /** - * repeated string sList = 20; - */ - public Builder clearSList() { - sList_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00080000); - onChanged(); - return this; - } - - /** - * repeated string sList = 20; - */ - public Builder addSListBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - ensureSListIsMutable(); - sList_.add(value); - onChanged(); - return this; - } - - private java.util.List pList_ = - java.util.Collections.emptyList(); - - private void ensurePListIsMutable() { - if (!((bitField0_ & 0x00100000) == 0x00100000)) { - pList_ = new java.util.ArrayList<>(pList_); - bitField0_ |= 0x00100000; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - User, User.Builder, UserOrBuilder> pListBuilder_; - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public java.util.List getPListList() { - if (pListBuilder_ == null) { - return java.util.Collections.unmodifiableList(pList_); - } else { - return pListBuilder_.getMessageList(); - } - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public int getPListCount() { - if (pListBuilder_ == null) { - return pList_.size(); - } else { - return pListBuilder_.getCount(); - } - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public User getPList(int index) { - if (pListBuilder_ == null) { - return pList_.get(index); - } else { - return pListBuilder_.getMessage(index); - } - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder setPList( - int index, User value) { - if (pListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePListIsMutable(); - pList_.set(index, value); - onChanged(); - } else { - pListBuilder_.setMessage(index, value); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder setPList( - int index, User.Builder builderForValue) { - if (pListBuilder_ == null) { - ensurePListIsMutable(); - pList_.set(index, builderForValue.build()); - onChanged(); - } else { - pListBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder addPList(User value) { - if (pListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePListIsMutable(); - pList_.add(value); - onChanged(); - } else { - pListBuilder_.addMessage(value); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder addPList( - int index, User value) { - if (pListBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePListIsMutable(); - pList_.add(index, value); - onChanged(); - } else { - pListBuilder_.addMessage(index, value); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder addPList( - User.Builder builderForValue) { - if (pListBuilder_ == null) { - ensurePListIsMutable(); - pList_.add(builderForValue.build()); - onChanged(); - } else { - pListBuilder_.addMessage(builderForValue.build()); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder addPList( - int index, User.Builder builderForValue) { - if (pListBuilder_ == null) { - ensurePListIsMutable(); - pList_.add(index, builderForValue.build()); - onChanged(); - } else { - pListBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder addAllPList( - Iterable values) { - if (pListBuilder_ == null) { - ensurePListIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, pList_); - onChanged(); - } else { - pListBuilder_.addAllMessages(values); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder clearPList() { - if (pListBuilder_ == null) { - pList_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00100000); - onChanged(); - } else { - pListBuilder_.clear(); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public Builder removePList(int index) { - if (pListBuilder_ == null) { - ensurePListIsMutable(); - pList_.remove(index); - onChanged(); - } else { - pListBuilder_.remove(index); - } - return this; - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public User.Builder getPListBuilder( - int index) { - return getPListFieldBuilder().getBuilder(index); - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public UserOrBuilder getPListOrBuilder( - int index) { - if (pListBuilder_ == null) { - return pList_.get(index); - } else { - return pListBuilder_.getMessageOrBuilder(index); - } - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public java.util.List - getPListOrBuilderList() { - if (pListBuilder_ != null) { - return pListBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(pList_); - } - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public User.Builder addPListBuilder() { - return getPListFieldBuilder().addBuilder( - User.getDefaultInstance()); - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public User.Builder addPListBuilder( - int index) { - return getPListFieldBuilder().addBuilder( - index, User.getDefaultInstance()); - } - - /** - * repeated .org.apache.servicecomb.foundation.protobuf.internal.model.User pList = 21; - */ - public java.util.List - getPListBuilderList() { - return getPListFieldBuilder().getBuilderList(); - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - User, User.Builder, UserOrBuilder> - getPListFieldBuilder() { - if (pListBuilder_ == null) { - pListBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<>( - pList_, - ((bitField0_ & 0x00100000) == 0x00100000), - getParentForChildren(), - isClean()); - pList_ = null; - } - return pListBuilder_; - } - - private com.google.protobuf.Any any_ = null; - - private com.google.protobuf.SingleFieldBuilderV3< - com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> anyBuilder_; - - /** - * .google.protobuf.Any any = 22; - */ - public boolean hasAny() { - return anyBuilder_ != null || any_ != null; - } - - /** - * .google.protobuf.Any any = 22; - */ - public com.google.protobuf.Any getAny() { - if (anyBuilder_ == null) { - return any_ == null ? com.google.protobuf.Any.getDefaultInstance() : any_; - } else { - return anyBuilder_.getMessage(); - } - } - - /** - * .google.protobuf.Any any = 22; - */ - public Builder setAny(com.google.protobuf.Any value) { - if (anyBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - any_ = value; - onChanged(); - } else { - anyBuilder_.setMessage(value); - } - - return this; - } - - /** - * .google.protobuf.Any any = 22; - */ - public Builder setAny( - com.google.protobuf.Any.Builder builderForValue) { - if (anyBuilder_ == null) { - any_ = builderForValue.build(); - onChanged(); - } else { - anyBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - - /** - * .google.protobuf.Any any = 22; - */ - public Builder mergeAny(com.google.protobuf.Any value) { - if (anyBuilder_ == null) { - if (any_ != null) { - any_ = - com.google.protobuf.Any.newBuilder(any_).mergeFrom(value).buildPartial(); - } else { - any_ = value; - } - onChanged(); - } else { - anyBuilder_.mergeFrom(value); - } - - return this; - } - - /** - * .google.protobuf.Any any = 22; - */ - public Builder clearAny() { - if (anyBuilder_ == null) { - any_ = null; - onChanged(); - } else { - any_ = null; - anyBuilder_ = null; - } - - return this; - } - - /** - * .google.protobuf.Any any = 22; - */ - public com.google.protobuf.Any.Builder getAnyBuilder() { - - onChanged(); - return getAnyFieldBuilder().getBuilder(); - } - - /** - * .google.protobuf.Any any = 22; - */ - public com.google.protobuf.AnyOrBuilder getAnyOrBuilder() { - if (anyBuilder_ != null) { - return anyBuilder_.getMessageOrBuilder(); - } else { - return any_ == null ? - com.google.protobuf.Any.getDefaultInstance() : any_; - } - } - - /** - * .google.protobuf.Any any = 22; - */ - private com.google.protobuf.SingleFieldBuilderV3< - com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> - getAnyFieldBuilder() { - if (anyBuilder_ == null) { - anyBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>( - getAny(), - getParentForChildren(), - isClean()); - any_ = null; - } - return anyBuilder_; - } - - private java.util.List anys_ = - java.util.Collections.emptyList(); - - private void ensureAnysIsMutable() { - if (!((bitField0_ & 0x00400000) == 0x00400000)) { - anys_ = new java.util.ArrayList<>(anys_); - bitField0_ |= 0x00400000; - } - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> anysBuilder_; - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public java.util.List getAnysList() { - if (anysBuilder_ == null) { - return java.util.Collections.unmodifiableList(anys_); - } else { - return anysBuilder_.getMessageList(); - } - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public int getAnysCount() { - if (anysBuilder_ == null) { - return anys_.size(); - } else { - return anysBuilder_.getCount(); - } - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.Any getAnys(int index) { - if (anysBuilder_ == null) { - return anys_.get(index); - } else { - return anysBuilder_.getMessage(index); - } - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder setAnys( - int index, com.google.protobuf.Any value) { - if (anysBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAnysIsMutable(); - anys_.set(index, value); - onChanged(); - } else { - anysBuilder_.setMessage(index, value); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder setAnys( - int index, com.google.protobuf.Any.Builder builderForValue) { - if (anysBuilder_ == null) { - ensureAnysIsMutable(); - anys_.set(index, builderForValue.build()); - onChanged(); - } else { - anysBuilder_.setMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder addAnys(com.google.protobuf.Any value) { - if (anysBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAnysIsMutable(); - anys_.add(value); - onChanged(); - } else { - anysBuilder_.addMessage(value); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder addAnys( - int index, com.google.protobuf.Any value) { - if (anysBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensureAnysIsMutable(); - anys_.add(index, value); - onChanged(); - } else { - anysBuilder_.addMessage(index, value); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder addAnys( - com.google.protobuf.Any.Builder builderForValue) { - if (anysBuilder_ == null) { - ensureAnysIsMutable(); - anys_.add(builderForValue.build()); - onChanged(); - } else { - anysBuilder_.addMessage(builderForValue.build()); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder addAnys( - int index, com.google.protobuf.Any.Builder builderForValue) { - if (anysBuilder_ == null) { - ensureAnysIsMutable(); - anys_.add(index, builderForValue.build()); - onChanged(); - } else { - anysBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder addAllAnys( - Iterable values) { - if (anysBuilder_ == null) { - ensureAnysIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, anys_); - onChanged(); - } else { - anysBuilder_.addAllMessages(values); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder clearAnys() { - if (anysBuilder_ == null) { - anys_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00400000); - onChanged(); - } else { - anysBuilder_.clear(); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public Builder removeAnys(int index) { - if (anysBuilder_ == null) { - ensureAnysIsMutable(); - anys_.remove(index); - onChanged(); - } else { - anysBuilder_.remove(index); - } - return this; - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.Any.Builder getAnysBuilder( - int index) { - return getAnysFieldBuilder().getBuilder(index); - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.AnyOrBuilder getAnysOrBuilder( - int index) { - if (anysBuilder_ == null) { - return anys_.get(index); - } else { - return anysBuilder_.getMessageOrBuilder(index); - } - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public java.util.List - getAnysOrBuilderList() { - if (anysBuilder_ != null) { - return anysBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(anys_); - } - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.Any.Builder addAnysBuilder() { - return getAnysFieldBuilder().addBuilder( - com.google.protobuf.Any.getDefaultInstance()); - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public com.google.protobuf.Any.Builder addAnysBuilder( - int index) { - return getAnysFieldBuilder().addBuilder( - index, com.google.protobuf.Any.getDefaultInstance()); - } - - /** - * repeated .google.protobuf.Any anys = 23; - */ - public java.util.List - getAnysBuilderList() { - return getAnysFieldBuilder().getBuilderList(); - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder> - getAnysFieldBuilder() { - if (anysBuilder_ == null) { - anysBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<>( - anys_, - ((bitField0_ & 0x00400000) == 0x00400000), - getParentForChildren(), - isClean()); - anys_ = null; - } - return anysBuilder_; - } - - private Root typeRecursive_ = null; - - private com.google.protobuf.SingleFieldBuilderV3< - Root, Builder, RootOrBuilder> typeRecursiveBuilder_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public boolean hasTypeRecursive() { - return typeRecursiveBuilder_ != null || typeRecursive_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Root getTypeRecursive() { - if (typeRecursiveBuilder_ == null) { - return typeRecursive_ == null ? Root.getDefaultInstance() : typeRecursive_; - } else { - return typeRecursiveBuilder_.getMessage(); - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Builder setTypeRecursive(Root value) { - if (typeRecursiveBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - typeRecursive_ = value; - onChanged(); - } else { - typeRecursiveBuilder_.setMessage(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Builder setTypeRecursive( - Builder builderForValue) { - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = builderForValue.build(); - onChanged(); - } else { - typeRecursiveBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Builder mergeTypeRecursive(Root value) { - if (typeRecursiveBuilder_ == null) { - if (typeRecursive_ != null) { - typeRecursive_ = - Root.newBuilder(typeRecursive_).mergeFrom(value).buildPartial(); - } else { - typeRecursive_ = value; - } - onChanged(); - } else { - typeRecursiveBuilder_.mergeFrom(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Builder clearTypeRecursive() { - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = null; - onChanged(); - } else { - typeRecursive_ = null; - typeRecursiveBuilder_ = null; - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public Builder getTypeRecursiveBuilder() { - - onChanged(); - return getTypeRecursiveFieldBuilder().getBuilder(); - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - public RootOrBuilder getTypeRecursiveOrBuilder() { - if (typeRecursiveBuilder_ != null) { - return typeRecursiveBuilder_.getMessageOrBuilder(); - } else { - return typeRecursive_ == null ? - Root.getDefaultInstance() : typeRecursive_; - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 24; - */ - private com.google.protobuf.SingleFieldBuilderV3< - Root, Builder, RootOrBuilder> - getTypeRecursiveFieldBuilder() { - if (typeRecursiveBuilder_ == null) { - typeRecursiveBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>( - getTypeRecursive(), - getParentForChildren(), - isClean()); - typeRecursive_ = null; - } - return typeRecursiveBuilder_; - } - - @Override - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - @Override - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - // @@protoc_insertion_point(builder_scope:org.apache.servicecomb.foundation.protobuf.internal.model.Root) - } - - // @@protoc_insertion_point(class_scope:org.apache.servicecomb.foundation.protobuf.internal.model.Root) - private static final Root DEFAULT_INSTANCE; - - static { - DEFAULT_INSTANCE = new Root(); - } - - public static Root getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @Override - public Root parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Root(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @Override - public Root getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - } - - public interface UserOrBuilder extends - // @@protoc_insertion_point(interface_extends:org.apache.servicecomb.foundation.protobuf.internal.model.User) - com.google.protobuf.MessageOrBuilder { - - /** - * string name = 1; - */ - String getName(); - - /** - * string name = 1; - */ - com.google.protobuf.ByteString - getNameBytes(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - boolean hasTypeRecursive(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - Root getTypeRecursive(); - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - RootOrBuilder getTypeRecursiveOrBuilder(); - } - - /** - * Protobuf type {@code org.apache.servicecomb.foundation.protobuf.internal.model.User} - */ - public static final class User extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:org.apache.servicecomb.foundation.protobuf.internal.model.User) - UserOrBuilder { - private static final long serialVersionUID = 0L; - - // Use User.newBuilder() to construct. - private User(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - - private User() { - name_ = ""; - } - - @Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - - private User( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - if (extensionRegistry == null) { - throw new NullPointerException(); - } - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - String s = input.readStringRequireUtf8(); - - name_ = s; - break; - } - case 18: { - Root.Builder subBuilder = null; - if (typeRecursive_ != null) { - subBuilder = typeRecursive_.toBuilder(); - } - typeRecursive_ = input.readMessage(Root.parser(), extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(typeRecursive_); - typeRecursive_ = subBuilder.buildPartial(); - } - - break; - } - default: { - if (!parseUnknownFieldProto3( - input, unknownFields, extensionRegistry, tag)) { - done = true; - } - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor; - } - - @Override - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_fieldAccessorTable - .ensureFieldAccessorsInitialized( - User.class, Builder.class); - } - - public static final int NAME_FIELD_NUMBER = 1; - - private volatile Object name_; - - /** - * string name = 1; - */ - public String getName() { - Object ref = name_; - if (ref instanceof String) { - return (String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - name_ = s; - return s; - } - } - - /** - * string name = 1; - */ - public com.google.protobuf.ByteString - getNameBytes() { - Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TYPERECURSIVE_FIELD_NUMBER = 2; - - private Root typeRecursive_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public boolean hasTypeRecursive() { - return typeRecursive_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Root getTypeRecursive() { - return typeRecursive_ == null ? Root.getDefaultInstance() : typeRecursive_; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public RootOrBuilder getTypeRecursiveOrBuilder() { - return getTypeRecursive(); - } - - private byte memoizedIsInitialized = -1; - - @Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) { - return true; - } - if (isInitialized == 0) { - return false; - } - - memoizedIsInitialized = 1; - return true; - } - - @Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!getNameBytes().isEmpty()) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_); - } - if (typeRecursive_ != null) { - output.writeMessage(2, getTypeRecursive()); - } - unknownFields.writeTo(output); - } - - @Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) { - return size; - } - - size = 0; - if (!getNameBytes().isEmpty()) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_); - } - if (typeRecursive_ != null) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(2, getTypeRecursive()); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof User)) { - return super.equals(obj); - } - User other = (User) obj; - - boolean result = true; - result = result && getName() - .equals(other.getName()); - result = result && (hasTypeRecursive() == other.hasTypeRecursive()); - if (hasTypeRecursive()) { - result = result && getTypeRecursive() - .equals(other.getTypeRecursive()); - } - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + NAME_FIELD_NUMBER; - hash = (53 * hash) + getName().hashCode(); - if (hasTypeRecursive()) { - hash = (37 * hash) + TYPERECURSIVE_FIELD_NUMBER; - hash = (53 * hash) + getTypeRecursive().hashCode(); - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static User parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static User parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static User parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static User parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static User parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static User parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static User parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static User parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static User parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - - public static User parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - - public static User parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static User parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @Override - public Builder newBuilderForType() { - return newBuilder(); - } - - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - - public static Builder newBuilder(User prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - - @Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @Override - protected Builder newBuilderForType( - BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - - /** - * Protobuf type {@code org.apache.servicecomb.foundation.protobuf.internal.model.User} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:org.apache.servicecomb.foundation.protobuf.internal.model.User) - UserOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor; - } - - @Override - protected FieldAccessorTable - internalGetFieldAccessorTable() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_fieldAccessorTable - .ensureFieldAccessorsInitialized( - User.class, Builder.class); - } - - // Construct using org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot.User.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - - @Override - public Builder clear() { - super.clear(); - name_ = ""; - - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = null; - } else { - typeRecursive_ = null; - typeRecursiveBuilder_ = null; - } - return this; - } - - @Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return ProtobufRoot.internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor; - } - - @Override - public User getDefaultInstanceForType() { - return User.getDefaultInstance(); - } - - @Override - public User build() { - User result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @Override - public User buildPartial() { - User result = new User(this); - result.name_ = name_; - if (typeRecursiveBuilder_ == null) { - result.typeRecursive_ = typeRecursive_; - } else { - result.typeRecursive_ = typeRecursiveBuilder_.build(); - } - onBuilt(); - return result; - } - - @Override - public Builder clone() { - return (Builder) super.clone(); - } - - @Override - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - - @Override - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - - @Override - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - - @Override - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - - @Override - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - - @Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof User) { - return mergeFrom((User) other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(User other) { - if (other == User.getDefaultInstance()) { - return this; - } - if (!other.getName().isEmpty()) { - name_ = other.name_; - onChanged(); - } - if (other.hasTypeRecursive()) { - mergeTypeRecursive(other.getTypeRecursive()); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - @Override - public final boolean isInitialized() { - return true; - } - - @Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - User parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (User) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private Object name_ = ""; - - /** - * string name = 1; - */ - public String getName() { - Object ref = name_; - if (!(ref instanceof String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - String s = bs.toStringUtf8(); - name_ = s; - return s; - } else { - return (String) ref; - } - } - - /** - * string name = 1; - */ - public com.google.protobuf.ByteString - getNameBytes() { - Object ref = name_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (String) ref); - name_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * string name = 1; - */ - public Builder setName( - String value) { - if (value == null) { - throw new NullPointerException(); - } - - name_ = value; - onChanged(); - return this; - } - - /** - * string name = 1; - */ - public Builder clearName() { - - name_ = getDefaultInstance().getName(); - onChanged(); - return this; - } - - /** - * string name = 1; - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - checkByteStringIsUtf8(value); - - name_ = value; - onChanged(); - return this; - } - - private Root typeRecursive_ = null; - - private com.google.protobuf.SingleFieldBuilderV3< - Root, Root.Builder, RootOrBuilder> typeRecursiveBuilder_; - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public boolean hasTypeRecursive() { - return typeRecursiveBuilder_ != null || typeRecursive_ != null; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Root getTypeRecursive() { - if (typeRecursiveBuilder_ == null) { - return typeRecursive_ == null ? Root.getDefaultInstance() : typeRecursive_; - } else { - return typeRecursiveBuilder_.getMessage(); - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Builder setTypeRecursive(Root value) { - if (typeRecursiveBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - typeRecursive_ = value; - onChanged(); - } else { - typeRecursiveBuilder_.setMessage(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Builder setTypeRecursive( - Root.Builder builderForValue) { - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = builderForValue.build(); - onChanged(); - } else { - typeRecursiveBuilder_.setMessage(builderForValue.build()); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Builder mergeTypeRecursive(Root value) { - if (typeRecursiveBuilder_ == null) { - if (typeRecursive_ != null) { - typeRecursive_ = - Root.newBuilder(typeRecursive_).mergeFrom(value).buildPartial(); - } else { - typeRecursive_ = value; - } - onChanged(); - } else { - typeRecursiveBuilder_.mergeFrom(value); - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Builder clearTypeRecursive() { - if (typeRecursiveBuilder_ == null) { - typeRecursive_ = null; - onChanged(); - } else { - typeRecursive_ = null; - typeRecursiveBuilder_ = null; - } - - return this; - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public Root.Builder getTypeRecursiveBuilder() { - - onChanged(); - return getTypeRecursiveFieldBuilder().getBuilder(); - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - public RootOrBuilder getTypeRecursiveOrBuilder() { - if (typeRecursiveBuilder_ != null) { - return typeRecursiveBuilder_.getMessageOrBuilder(); - } else { - return typeRecursive_ == null ? - Root.getDefaultInstance() : typeRecursive_; - } - } - - /** - * .org.apache.servicecomb.foundation.protobuf.internal.model.Root typeRecursive = 2; - */ - private com.google.protobuf.SingleFieldBuilderV3< - Root, Root.Builder, RootOrBuilder> - getTypeRecursiveFieldBuilder() { - if (typeRecursiveBuilder_ == null) { - typeRecursiveBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>( - getTypeRecursive(), - getParentForChildren(), - isClean()); - typeRecursive_ = null; - } - return typeRecursiveBuilder_; - } - - @Override - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFieldsProto3(unknownFields); - } - - @Override - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - // @@protoc_insertion_point(builder_scope:org.apache.servicecomb.foundation.protobuf.internal.model.User) - } - - // @@protoc_insertion_point(class_scope:org.apache.servicecomb.foundation.protobuf.internal.model.User) - private static final User DEFAULT_INSTANCE; - - static { - DEFAULT_INSTANCE = new User(); - } - - public static User getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @Override - public User parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new User(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @Override - public User getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - } - - private static final com.google.protobuf.Descriptors.Descriptor - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor; - - private static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_descriptor; - - private static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_descriptor; - - private static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_fieldAccessorTable; - - private static final com.google.protobuf.Descriptors.Descriptor - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor; - - private static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { - return descriptor; - } - - private static com.google.protobuf.Descriptors.FileDescriptor - descriptor; - - static { - String[] descriptorData = { - "\n\022protobufRoot.proto\0229org.apache.service" + - "comb.foundation.protobuf.internal.model\032" + - "\031google/protobuf/any.proto\"\361\007\n\004Root\022\r\n\005i" + - "nt32\030\001 \001(\005\022\r\n\005int64\030\002 \001(\003\022\016\n\006uint32\030\003 \001(" + - "\r\022\016\n\006uint64\030\004 \001(\004\022\016\n\006sint32\030\005 \001(\021\022\016\n\006sin" + - "t64\030\006 \001(\022\022\017\n\007fixed32\030\007 \001(\007\022\017\n\007fixed64\030\010 " + - "\001(\006\022\020\n\010sfixed32\030\t \001(\017\022\020\n\010sfixed64\030\n \001(\020\022" + - "\022\n\nfloatValue\030\013 \001(\002\022\023\n\013doubleValue\030\014 \001(\001" + - "\022\014\n\004bool\030\r \001(\010\022\016\n\006string\030\016 \001(\t\022\r\n\005bytes\030" + - "\017 \001(\014\022O\n\005color\030\020 \001(\0162@.org.apache.servic" + - "ecomb.foundation.protobuf.internal.model" + - ".Color\022M\n\004user\030\021 \001(\0132?.org.apache.servic" + - "ecomb.foundation.protobuf.internal.model" + - ".User\022Y\n\005ssMap\030\022 \003(\0132J.org.apache.servic" + - "ecomb.foundation.protobuf.internal.model" + - ".Root.SsMapEntry\022Y\n\005spMap\030\023 \003(\0132J.org.ap" + - "ache.servicecomb.foundation.protobuf.int" + - "ernal.model.Root.SpMapEntry\022\r\n\005sList\030\024 \003" + - "(\t\022N\n\005pList\030\025 \003(\0132?.org.apache.serviceco" + - "mb.foundation.protobuf.internal.model.Us" + - "er\022!\n\003any\030\026 \001(\0132\024.google.protobuf.Any\022\"\n" + - "\004anys\030\027 \003(\0132\024.google.protobuf.Any\022V\n\rtyp" + - "eRecursive\030\030 \001(\0132?.org.apache.servicecom" + - "b.foundation.protobuf.internal.model.Roo" + - "t\032,\n\nSsMapEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 " + - "\001(\t:\0028\001\032m\n\nSpMapEntry\022\013\n\003key\030\001 \001(\t\022N\n\005va" + - "lue\030\002 \001(\0132?.org.apache.servicecomb.found" + - "ation.protobuf.internal.model.User:\0028\001\"l" + - "\n\004User\022\014\n\004name\030\001 \001(\t\022V\n\rtypeRecursive\030\002 " + - "\001(\0132?.org.apache.servicecomb.foundation." + - "protobuf.internal.model.Root*&\n\005Color\022\007\n" + - "\003RED\020\000\022\n\n\006YELLOW\020\001\022\010\n\004BLUE\020\002b\006proto3" - }; - com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = - new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { - public com.google.protobuf.ExtensionRegistry assignDescriptors( - com.google.protobuf.Descriptors.FileDescriptor root) { - descriptor = root; - return null; - } - }; - com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - com.google.protobuf.AnyProto.getDescriptor(), - }, assigner); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor = - getDescriptor().getMessageTypes().get(0); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor, - new String[] {"Int32", "Int64", "Uint32", "Uint64", "Sint32", "Sint64", "Fixed32", "Fixed64", "Sfixed32", - "Sfixed64", "FloatValue", "DoubleValue", "Bool", "String", "Bytes", "Color", "User", "SsMap", "SpMap", - "SList", "PList", "Any", "Anys", "TypeRecursive",}); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_descriptor = - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor.getNestedTypes() - .get(0); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SsMapEntry_descriptor, - new String[] {"Key", "Value",}); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_descriptor = - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_descriptor.getNestedTypes() - .get(1); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_Root_SpMapEntry_descriptor, - new String[] {"Key", "Value",}); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor = - getDescriptor().getMessageTypes().get(1); - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_org_apache_servicecomb_foundation_protobuf_internal_model_User_descriptor, - new String[] {"Name", "TypeRecursive",}); - com.google.protobuf.AnyProto.getDescriptor(); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/Root.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/Root.java index ddb4f07e010..9bca6e5cdbb 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/Root.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/Root.java @@ -21,54 +21,214 @@ import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import io.protostuff.Tag; + +/** + * Tag annotation is only for protoStuff, not necessary for ServiceComb codec + */ public class Root { + @Tag(1) private int int32; + @Tag(2) private long int64; + @Tag(3) private int uint32; + @Tag(4) private long uint64; + @Tag(5) private int sint32; + @Tag(6) private long sint64; + @Tag(7) private int fixed32; + @Tag(8) private long fixed64; + @Tag(9) private int sfixed32; + @Tag(10) private long sfixed64; + @Tag(11) private float floatValue; + @Tag(12) private double doubleValue; + @Tag(13) private boolean bool; + @Tag(20) + private Integer objInt32; + + @Tag(21) + private Long objInt64; + + @Tag(22) + private Integer objUint32; + + @Tag(23) + private Long objUint64; + + @Tag(24) + private Integer objSint32; + + @Tag(25) + private Long objSint64; + + @Tag(26) + private Integer objFixed32; + + @Tag(27) + private Long objFixed64; + + @Tag(28) + private Integer objSfixed32; + + @Tag(29) + private Long objSfixed64; + + @Tag(30) + private Float objFloatValue; + + @Tag(31) + private Double objDoubleValue; + + @Tag(32) + private Boolean objBool; + + @Tag(40) private String string; + @Tag(41) private byte[] bytes; + @Tag(42) private Color color; + @Tag(43) private User user; + @Tag(44) + private Root typeRecursive; + + @Tag(50) + private Object any; + + @Tag(51) + private List anys; + + @Tag(60) private Map ssMap; + @Tag(61) + private Map sint32Map; + + @Tag(62) private Map spMap; - private List sList; + // repeated packed + @Tag(70) + private List int32sPacked; - private List pList; + @Tag(71) + private List int64sPacked; - private Object any; + @Tag(72) + private List uint32sPacked; - private List anys; + @Tag(73) + private List uint64sPacked; - private Root typeRecursive; + @Tag(74) + private List sint32sPacked; + + @Tag(75) + private List sint64sPacked; + + @Tag(76) + private List fixed32sPacked; + + @Tag(77) + private List fixed64sPacked; + + @Tag(78) + private List sfixed32sPacked; + + @Tag(79) + private List sfixed64sPacked; + + @Tag(80) + private List floatsPacked; + + @Tag(81) + private List doublesPacked; + + @Tag(82) + private List boolsPacked; + + @Tag(83) + private List colorsPacked; + + // repeated not packed + @Tag(90) + private List int32sNotPacked; + + @Tag(91) + private List int64sNotPacked; + + @Tag(92) + private List uint32sNotPacked; + + @Tag(93) + private List uint64sNotPacked; + + @Tag(94) + private List sint32sNotPacked; + + @Tag(95) + private List sint64sNotPacked; + + @Tag(96) + private List fixed32sNotPacked; + + @Tag(97) + private List fixed64sNotPacked; + + @Tag(98) + private List sfixed32sNotPacked; + + @Tag(99) + private List sfixed64sNotPacked; + + @Tag(100) + private List floatsNotPacked; + + @Tag(101) + private List doublesNotPacked; + + @Tag(102) + private List boolsNotPacked; + + @Tag(103) + private List colorsNotPacked; + + @Tag(110) + private List strings; + + @Tag(111) + private List bytess; + + @Tag(112) + private List users; public int getInt32() { return int32; @@ -222,22 +382,6 @@ public void setSpMap(Map spMap) { this.spMap = spMap; } - public List getsList() { - return sList; - } - - public void setsList(List sList) { - this.sList = sList; - } - - public List getpList() { - return pList; - } - - public void setpList(List pList) { - this.pList = pList; - } - public Object getAny() { return any; } @@ -261,4 +405,365 @@ public Root getTypeRecursive() { public void setTypeRecursive(Root typeRecursive) { this.typeRecursive = typeRecursive; } + + public List getInt32sPacked() { + return int32sPacked; + } + + public void setInt32sPacked(List int32sPacked) { + this.int32sPacked = int32sPacked; + } + + public List getInt64sPacked() { + return int64sPacked; + } + + public void setInt64sPacked(List int64sPacked) { + this.int64sPacked = int64sPacked; + } + + public List getUint32sPacked() { + return uint32sPacked; + } + + public void setUint32sPacked(List uint32sPacked) { + this.uint32sPacked = uint32sPacked; + } + + public List getUint64sPacked() { + return uint64sPacked; + } + + public void setUint64sPacked(List uint64sPacked) { + this.uint64sPacked = uint64sPacked; + } + + public List getSint32sPacked() { + return sint32sPacked; + } + + public void setSint32sPacked(List sint32sPacked) { + this.sint32sPacked = sint32sPacked; + } + + public List getSint64sPacked() { + return sint64sPacked; + } + + public void setSint64sPacked(List sint64sPacked) { + this.sint64sPacked = sint64sPacked; + } + + public List getFixed32sPacked() { + return fixed32sPacked; + } + + public void setFixed32sPacked(List fixed32sPacked) { + this.fixed32sPacked = fixed32sPacked; + } + + public List getFixed64sPacked() { + return fixed64sPacked; + } + + public void setFixed64sPacked(List fixed64sPacked) { + this.fixed64sPacked = fixed64sPacked; + } + + public List getSfixed32sPacked() { + return sfixed32sPacked; + } + + public void setSfixed32sPacked(List sfixed32sPacked) { + this.sfixed32sPacked = sfixed32sPacked; + } + + public List getSfixed64sPacked() { + return sfixed64sPacked; + } + + public void setSfixed64sPacked(List sfixed64sPacked) { + this.sfixed64sPacked = sfixed64sPacked; + } + + public List getFloatsPacked() { + return floatsPacked; + } + + public void setFloatsPacked(List floatsPacked) { + this.floatsPacked = floatsPacked; + } + + public List getDoublesPacked() { + return doublesPacked; + } + + public void setDoublesPacked(List doublesPacked) { + this.doublesPacked = doublesPacked; + } + + public List getBoolsPacked() { + return boolsPacked; + } + + public void setBoolsPacked(List boolsPacked) { + this.boolsPacked = boolsPacked; + } + + public List getColorsPacked() { + return colorsPacked; + } + + public void setColorsPacked(List colorsPacked) { + this.colorsPacked = colorsPacked; + } + + public List getInt32sNotPacked() { + return int32sNotPacked; + } + + public void setInt32sNotPacked(List int32sNotPacked) { + this.int32sNotPacked = int32sNotPacked; + } + + public List getInt64sNotPacked() { + return int64sNotPacked; + } + + public void setInt64sNotPacked(List int64sNotPacked) { + this.int64sNotPacked = int64sNotPacked; + } + + public List getUint32sNotPacked() { + return uint32sNotPacked; + } + + public void setUint32sNotPacked(List uint32sNotPacked) { + this.uint32sNotPacked = uint32sNotPacked; + } + + public List getUint64sNotPacked() { + return uint64sNotPacked; + } + + public void setUint64sNotPacked(List uint64sNotPacked) { + this.uint64sNotPacked = uint64sNotPacked; + } + + public List getSint32sNotPacked() { + return sint32sNotPacked; + } + + public void setSint32sNotPacked(List sint32sNotPacked) { + this.sint32sNotPacked = sint32sNotPacked; + } + + public List getSint64sNotPacked() { + return sint64sNotPacked; + } + + public void setSint64sNotPacked(List sint64sNotPacked) { + this.sint64sNotPacked = sint64sNotPacked; + } + + public List getFixed32sNotPacked() { + return fixed32sNotPacked; + } + + public void setFixed32sNotPacked(List fixed32sNotPacked) { + this.fixed32sNotPacked = fixed32sNotPacked; + } + + public List getFixed64sNotPacked() { + return fixed64sNotPacked; + } + + public void setFixed64sNotPacked(List fixed64sNotPacked) { + this.fixed64sNotPacked = fixed64sNotPacked; + } + + public List getSfixed32sNotPacked() { + return sfixed32sNotPacked; + } + + public void setSfixed32sNotPacked(List sfixed32sNotPacked) { + this.sfixed32sNotPacked = sfixed32sNotPacked; + } + + public List getSfixed64sNotPacked() { + return sfixed64sNotPacked; + } + + public void setSfixed64sNotPacked(List sfixed64sNotPacked) { + this.sfixed64sNotPacked = sfixed64sNotPacked; + } + + public List getFloatsNotPacked() { + return floatsNotPacked; + } + + public void setFloatsNotPacked(List floatsNotPacked) { + this.floatsNotPacked = floatsNotPacked; + } + + public List getDoublesNotPacked() { + return doublesNotPacked; + } + + public void setDoublesNotPacked(List doublesNotPacked) { + this.doublesNotPacked = doublesNotPacked; + } + + public List getBoolsNotPacked() { + return boolsNotPacked; + } + + public void setBoolsNotPacked(List boolsNotPacked) { + this.boolsNotPacked = boolsNotPacked; + } + + public List getColorsNotPacked() { + return colorsNotPacked; + } + + public void setColorsNotPacked( + List colorsNotPacked) { + this.colorsNotPacked = colorsNotPacked; + } + + public List getStrings() { + return strings; + } + + public void setStrings(List strings) { + this.strings = strings; + } + + public List getBytess() { + return bytess; + } + + public void setBytess(List bytess) { + this.bytess = bytess; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public Integer getObjInt32() { + return objInt32; + } + + public void setObjInt32(Integer objInt32) { + this.objInt32 = objInt32; + } + + public Long getObjInt64() { + return objInt64; + } + + public void setObjInt64(Long objInt64) { + this.objInt64 = objInt64; + } + + public Integer getObjUint32() { + return objUint32; + } + + public void setObjUint32(Integer objUint32) { + this.objUint32 = objUint32; + } + + public Long getObjUint64() { + return objUint64; + } + + public void setObjUint64(Long objUint64) { + this.objUint64 = objUint64; + } + + public Integer getObjSint32() { + return objSint32; + } + + public void setObjSint32(Integer objSint32) { + this.objSint32 = objSint32; + } + + public Long getObjSint64() { + return objSint64; + } + + public void setObjSint64(Long objSint64) { + this.objSint64 = objSint64; + } + + public Integer getObjFixed32() { + return objFixed32; + } + + public void setObjFixed32(Integer objFixed32) { + this.objFixed32 = objFixed32; + } + + public Long getObjFixed64() { + return objFixed64; + } + + public void setObjFixed64(Long objFixed64) { + this.objFixed64 = objFixed64; + } + + public Integer getObjSfixed32() { + return objSfixed32; + } + + public void setObjSfixed32(Integer objSfixed32) { + this.objSfixed32 = objSfixed32; + } + + public Long getObjSfixed64() { + return objSfixed64; + } + + public void setObjSfixed64(Long objSfixed64) { + this.objSfixed64 = objSfixed64; + } + + public Float getObjFloatValue() { + return objFloatValue; + } + + public void setObjFloatValue(Float objFloatValue) { + this.objFloatValue = objFloatValue; + } + + public Double getObjDoubleValue() { + return objDoubleValue; + } + + public void setObjDoubleValue(Double objDoubleValue) { + this.objDoubleValue = objDoubleValue; + } + + public Boolean isObjBool() { + return objBool; + } + + public void setObjBool(Boolean objBool) { + this.objBool = objBool; + } + + public Map getSint32Map() { + return sint32Map; + } + + public void setSint32Map(Map sint32Map) { + this.sint32Map = sint32Map; + } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/User.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/User.java index 642d38128b1..06c7d2e8e69 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/User.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/model/User.java @@ -21,6 +21,13 @@ public class User { private Root typeRecursive; + public User() { + } + + public User(String name) { + this.name = name; + } + public String getName() { return name; } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/parser/TestProtoParser.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/parser/TestProtoParser.java index f3fdfd536c7..268281b9104 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/parser/TestProtoParser.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/parser/TestProtoParser.java @@ -16,31 +16,30 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.parser; -import java.io.IOException; -import java.net.URL; - -import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; - import com.google.common.base.MoreObjects; - import io.protostuff.compiler.model.Proto; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; public class TestProtoParser { @Test public void parse() throws IOException { URL url = Thread.currentThread().getContextClassLoader().getResource("protobufRoot.proto"); - String content = IOUtils.toString(url); + String content = IOUtils.toString(url, StandardCharsets.UTF_8); ProtoParser parser = new ProtoParser(); Proto protoFromContent = parser.parseFromContent(content); Proto protoFromName = parser.parse("protobufRoot.proto"); - Assert.assertNotNull(protoFromContent.getMessage("Root")); - Assert.assertNotNull(protoFromContent.getMessage("User")); + Assertions.assertNotNull(protoFromContent.getMessage("Root")); + Assertions.assertNotNull(protoFromContent.getMessage("User")); - Assert.assertEquals(MoreObjects.toStringHelper(protoFromContent) + Assertions.assertEquals(MoreObjects.toStringHelper(protoFromContent) .omitNullValues() .add("messages", protoFromContent.getMessages()) .toString(), diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java index fb2868ebf31..8bcbddd9d30 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestAnySchema.java @@ -22,23 +22,23 @@ import java.util.Map; import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst; import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; import org.apache.servicecomb.foundation.protobuf.internal.model.Root; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; import com.google.protobuf.Any; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestAnySchema extends TestSchemaBase { - public TestAnySchema() { - initField("any"); - } - @Test public void empty() throws Throwable { - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); + scbMap = new HashMap<>(); + scbMap.put("any", null); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); } @Test @@ -56,7 +56,7 @@ public void anys_json() throws IOException { scbRootBytes = rootSerializer.serialize(root); root = rootDeserializer.deserialize(scbRootBytes); - Assert.assertThat(root.getAnys(), Matchers.contains("abc", "123")); + MatcherAssert.assertThat(root.getAnys(), Matchers.contains("abc", "123")); } @Test @@ -65,11 +65,11 @@ public void pack() throws Throwable { check(); Map map = new HashMap<>(); - map.put("@type", "User"); + map.put(ProtoConst.JSON_ID_NAME, "User"); map.put("name", "n1"); Root root = new Root(); root.setAny(map); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(root)); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(root)); } @SuppressWarnings("unchecked") @@ -82,12 +82,12 @@ public void json_fromMapWithoutType() throws Throwable { scbRootBytes = rootSerializer.serialize(root); root = rootDeserializer.deserialize(scbRootBytes); - Assert.assertThat(root.getAny(), Matchers.instanceOf(Map.class)); - Assert.assertThat((Map) root.getAny(), Matchers.hasEntry("name", "n1")); + MatcherAssert.assertThat(root.getAny(), Matchers.instanceOf(Map.class)); + MatcherAssert.assertThat((Map) root.getAny(), Matchers.hasEntry("name", "n1")); - RootDeserializer deserializer = protoMapper.createRootDeserializer(Map.class, "Root"); + RootDeserializer> deserializer = protoMapper.createRootDeserializer("Root", Map.class); map = deserializer.deserialize(scbRootBytes); - Assert.assertThat((Map) map.get("any"), Matchers.hasEntry("name", "n1")); + MatcherAssert.assertThat((Map) map.get("any"), Matchers.hasEntry("name", "n1")); } @Test @@ -97,6 +97,6 @@ public void json() throws Throwable { scbRootBytes = rootSerializer.serialize(root); root = rootDeserializer.deserialize(scbRootBytes); - Assert.assertEquals("abc", root.getAny()); + Assertions.assertEquals("abc", root.getAny()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMapSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMapSchema.java index cdd9e524600..1013f3a6cf8 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMapSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMapSchema.java @@ -21,7 +21,7 @@ import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class TestMapSchema extends TestSchemaBase { @Test diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMessageSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMessageSchema.java index 8da3a5d7142..4e504540874 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMessageSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestMessageSchema.java @@ -24,32 +24,31 @@ import org.apache.servicecomb.foundation.protobuf.internal.model.CustomGeneric; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestMessageSchema extends TestSchemaBase { @Test public void empty() throws Throwable { check(); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(null)); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(null)); } @Test public void generic() throws Throwable { JavaType javaType = TypeFactory.defaultInstance().constructParametricType(CustomGeneric.class, User.class); - RootDeserializer genericDeserializer = protoMapper.createRootDeserializer(javaType, "Root"); + RootDeserializer> genericDeserializer = protoMapper.createRootDeserializer("Root", javaType); builder.setUser(ProtobufRoot.User.newBuilder().setName("name1").build()); check(genericDeserializer, mapRootDeserializer, rootSerializer, false); @SuppressWarnings("unchecked") CustomGeneric generic = (CustomGeneric) scbRoot; - Assert.assertThat(generic.user, Matchers.instanceOf(User.class)); + Assertions.assertNotNull(generic.user); } @Test @@ -71,6 +70,6 @@ public void normal() throws Throwable { map.put("notExist", null); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestRepeatedSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestRepeatedSchema.java index 48e4c054329..a26156a3778 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestRepeatedSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/TestRepeatedSchema.java @@ -16,35 +16,227 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot.Color; +import org.apache.servicecomb.foundation.protobuf.internal.model.User; + +import com.google.protobuf.ByteString; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestRepeatedSchema extends TestSchemaBase { public static class RootWithArray { - public String[] sList; + public byte[][] bytess; + + public String[] strings; + + public User[] users; + } + + @Test + public void fixed32s() throws Exception { + builder.addAllFixed32SPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void fixed32sNotPacked() throws Exception { + builder.addAllFixed32SNotPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sfixed32s() throws Exception { + builder.addAllSfixed32SPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sfixed32sNotPacked() throws Exception { + builder.addAllSfixed32SNotPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void int32s() throws Exception { + builder.addAllInt32SPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void int32sNotPacked() throws Exception { + builder.addAllInt32SNotPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sint32s() throws Exception { + builder.addAllSint32SPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sint32sNotPacked() throws Exception { + builder.addAllSint32SNotPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void uint32s() throws Exception { + builder.addAllUint32SPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void uint32sNotPacked() throws Exception { + builder.addAllUint32SNotPacked(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void fixed64s() throws Exception { + builder.addAllFixed64SPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void fixed64sNotPacked() throws Exception { + builder.addAllFixed64SNotPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sfixed64s() throws Exception { + builder.addAllSfixed64SPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sfixed64sNotPacked() throws Exception { + builder.addAllSfixed64SNotPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void int64s() throws Exception { + builder.addAllInt64SPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); } @Test - public void sList() throws Throwable { + public void int64sNotPacked() throws Exception { + builder.addAllInt64SNotPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sint64s() throws Exception { + builder.addAllSint64SPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void sint64sNotPacked() throws Exception { + builder.addAllSint64SNotPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void uint64s() throws Exception { + builder.addAllUint64SPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void uint64sNotPacked() throws Exception { + builder.addAllUint64SNotPacked(Arrays.asList(Long.MIN_VALUE, 0L, Long.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void floats() throws Exception { + builder.addAllFloatsPacked(Arrays.asList(Float.MIN_VALUE, (float) 0.0, Float.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void floatsNotPacked() throws Exception { + builder.addAllFloatsNotPacked(Arrays.asList(Float.MIN_VALUE, (float) 0.0, Float.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void doubles() throws Exception { + builder.addAllDoublesPacked(Arrays.asList(Double.MIN_VALUE, 0.0, Double.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void doublesNotPacked() throws Exception { + builder.addAllDoublesNotPacked(Arrays.asList(Double.MIN_VALUE, 0.0, Double.MAX_VALUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void bools() throws Exception { + builder.addAllBoolsPacked(Arrays.asList(Boolean.FALSE, Boolean.TRUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void boolsNotPacked() throws Exception { + builder.addAllBoolsNotPacked(Arrays.asList(Boolean.FALSE, Boolean.TRUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void enums() throws Exception { + builder.addAllColorsPacked(Arrays.asList(Color.RED, Color.BLUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void enumsNotPacked() throws Exception { + builder.addAllColorsNotPacked(Arrays.asList(Color.RED, Color.BLUE)); + checkRepeatedWithPrimitive(); + } + + @Test + public void bytess() throws Throwable { + List sList = Arrays.asList("v1".getBytes(StandardCharsets.UTF_8), "v2".getBytes(StandardCharsets.UTF_8)); + builder.addAllBytess(Arrays.asList(ByteString.copyFromUtf8("v1"), ByteString.copyFromUtf8("v2"))); + check(); + + RootWithArray rootWithArray = new RootWithArray(); + rootWithArray.bytess = sList.toArray(new byte[0][]); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(rootWithArray)); + } + + @Test + public void strings() throws Throwable { List sList = Arrays.asList("v1", "v2"); - builder.addAllSList(sList); + builder.addAllStrings(sList); check(); RootWithArray rootWithArray = new RootWithArray(); - rootWithArray.sList = (String[]) sList.toArray(); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(rootWithArray)); + rootWithArray.strings = sList.toArray(new String[0]); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(rootWithArray)); } @Test - public void pList() throws Throwable { - builder.addPList(ProtobufRoot.User.newBuilder().setName("name1").build()); - builder.addPList(ProtobufRoot.User.newBuilder().setName("name2").build()); + public void users() throws Throwable { + builder.addUsers(ProtobufRoot.User.newBuilder().setName("name1").build()); + builder.addUsers(ProtobufRoot.User.newBuilder().setName("name2").build()); check(); + + RootWithArray rootWithArray = new RootWithArray(); + rootWithArray.users = new User[] {new User("name1"), new User("name2")}; + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(rootWithArray)); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBoolSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBoolSchema.java index fd9df9f57fb..5862c723bfc 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBoolSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBoolSchema.java @@ -16,15 +16,16 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; +import java.util.HashMap; + import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestBoolSchema extends TestSchemaBase { public TestBoolSchema() { - initField("bool"); + initFields("bool", "objBool"); } @Test @@ -35,7 +36,7 @@ public void testTrue() throws Throwable { // equalsIgnoreCase doTestFromString("true"); - doTestFromString("trUe"); + doTestFromString("true"); } @Test @@ -51,28 +52,34 @@ public void testFalse() throws Throwable { protected void doTestFromString(String value) throws Throwable { // string[] - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(new String[] {value})); + scbMap = new HashMap<>(); + scbMap.put("bool", new String[] {value}); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(scbMap)); // string - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(value)); + scbMap.put("bool", value); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(scbMap)); } @Test public void nullOrEmpty() throws Throwable { // null - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); + scbMap = new HashMap<>(); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); // empty string[] - Assert.assertEquals(0, serFieldSchema.writeTo(new String[] {}).length); + scbMap.put("bool", new String[] {}); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); } @Test public void type_invalid() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto bool, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:bool")); - - serFieldSchema.writeTo(new User()); + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("bool", new User()); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto bool, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:bool", + exception.getMessage()); } } - diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBytesSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBytesSchema.java index d9465820173..db350e87596 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBytesSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestBytesSchema.java @@ -16,13 +16,14 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; +import java.util.HashMap; + import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; import com.google.protobuf.ByteString; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestBytesSchema extends TestSchemaBase { public TestBytesSchema() { @@ -34,17 +35,16 @@ public void normal() throws Throwable { byte[] value = "abc".getBytes(); builder.setBytes(ByteString.copyFrom(value)); check(); - - // null - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); } @Test - public void type_invalid() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto bytes, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:bytes")); - - serFieldSchema.writeTo(new User()); + public void type_invalid() { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("bytes", new User()); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto bytes, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:bytes", + exception.getMessage()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestDoubleSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestDoubleSchema.java index 28fa06206e9..2946db9d097 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestDoubleSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestDoubleSchema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestDoubleSchema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "doubleValue"; + public TestDoubleSchema() { minValue = Double.MIN_VALUE; maxValue = Double.MAX_VALUE; - super.init(); + initFields("doubleValue", "objDoubleValue"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestEnumSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestEnumSchema.java new file mode 100644 index 00000000000..4c70eb2e40e --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestEnumSchema.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; +import org.apache.servicecomb.foundation.protobuf.internal.model.User; +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestEnumSchema extends TestSchemaBase { + @Test + public void empty() throws Throwable { + // null + scbMap = new HashMap<>(); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); + + // empty string[] + scbMap.put("color", new String[] {}); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); + } + + public static class EnumRoot { + private int color; + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + } + } + + @Test + public void normal() throws Throwable { + builder.setColorValue(2); + check(); + + Map map = new HashMap<>(); + map.put("color", Color.BLUE); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); + + map.put("color", 2); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); + + map.put("color", new String[] {"BLUE"}); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); + + map.put("color", "BLUE"); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); + + EnumRoot enumRoot = protoMapper.createRootDeserializer("Root", EnumRoot.class).deserialize(protobufBytes); + Assertions.assertEquals(2, enumRoot.color); + } + + enum Sharp { + ROUND + } + + @Test + public void fromInvalidEnum() throws Throwable { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("color", Sharp.ROUND); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("invalid enum name ROUND for proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color", exception.getMessage()); + } + + @Test + public void fromInvalidNumber() { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("color", 3); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("invalid enum value 3 for proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color", exception.getMessage()); + } + + @Test + public void type_invalid() { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("color", new User()); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color", + exception.getMessage()); + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed32Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed32Schema.java index 20f67ac8087..81dedd363c1 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed32Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed32Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestFixed32Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "fixed32"; + public TestFixed32Schema() { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; - super.init(); + initFields("fixed32", "objFixed32"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed64Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed64Schema.java index fdc14786f8b..03ea489b263 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed64Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFixed64Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestFixed64Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "fixed64"; + public TestFixed64Schema() { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; - super.init(); + initFields("fixed64", "objFixed64"); } -} \ No newline at end of file +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFloatSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFloatSchema.java index 9cfab25d5f7..14bf8d7c9dd 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFloatSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestFloatSchema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestFloatSchema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "floatValue"; + public TestFloatSchema() { minValue = Float.MIN_VALUE; maxValue = Float.MAX_VALUE; - super.init(); + initFields("floatValue", "objFloatValue"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt32Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt32Schema.java index c4bd0c23182..100d51cdf8f 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt32Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt32Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestInt32Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "int32"; + public TestInt32Schema() { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; - super.init(); + initFields("int32", "objInt32"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt64Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt64Schema.java index 68fa3b283ee..9e6f9095c57 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt64Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestInt64Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestInt64Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "int64"; + public TestInt64Schema() { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; - super.init(); + initFields("int64", "objInt64"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestNumberBaseSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestNumberBaseSchema.java index 2abc07c47bf..fd9a236a089 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestNumberBaseSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestNumberBaseSchema.java @@ -16,55 +16,59 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; +import java.io.IOException; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.Locale; import org.apache.servicecomb.foundation.common.utils.ReflectUtils; import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; -import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; +import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; +import io.protostuff.compiler.model.Field; import io.protostuff.compiler.model.Type; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Ignore +@Disabled public abstract class TestNumberBaseSchema extends TestSchemaBase { - protected String fieldName; - protected Object minValue; protected Object maxValue; - public TestNumberBaseSchema() { - init(); - } - - protected void init() { - initField(fieldName); - } - @Test public void normal() throws Throwable { - // normal - Object value = doTestNormal(); + byte[] primitiveBytes = doTestPojoNormal(primitiveFieldName); + byte[] bytes = doTestPojoNormal(fieldName); + doTestMapNormal(primitiveFieldName, maxValue, primitiveBytes); + doTestMapNormal(fieldName, maxValue, bytes); + } + + private void doTestMapNormal(String field, Object value, byte[] expectBytes) throws IOException { // null - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); + scbMap = new HashMap<>(); + scbMap.put(field, null); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); // empty string[] - Assert.assertEquals(0, serFieldSchema.writeTo(new String[] {}).length); + scbMap.put(field, new String[] {}); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); // string[] - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(new String[] {String.valueOf(value)})); + scbMap.put(field, new String[] {String.valueOf(value)}); + Assertions.assertArrayEquals(expectBytes, rootSerializer.serialize(scbMap)); // string - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(String.valueOf(value))); + scbMap.put(field, String.valueOf(value)); + Assertions.assertArrayEquals(expectBytes, rootSerializer.serialize(scbMap)); } - protected Object doTestNormal() throws Throwable { - String setName = "set" + fieldName.substring(0, 1).toUpperCase(Locale.US) + fieldName.substring(1); + private byte[] doTestPojoNormal(String name) throws Throwable { + builder = ProtobufRoot.Root.newBuilder(); + String setName = "set" + name.substring(0, 1).toUpperCase(Locale.US) + name.substring(1); Method builderSetter = ReflectUtils.findMethod(builder.getClass(), setName); builderSetter.invoke(builder, minValue); @@ -73,35 +77,67 @@ protected Object doTestNormal() throws Throwable { builderSetter.invoke(builder, maxValue); check(); - return maxValue; + return protobufBytes; + } + + @Test + public void primitiveStrings_invalid() throws Throwable { + strings_invalid(primitiveProtoField); } @Test public void strings_invalid() throws Throwable { - expectedException.expect(NumberFormatException.class); - expectedException.expectMessage(Matchers.is("For input string: \"a\"")); + strings_invalid(protoField); + } - serFieldSchema.writeTo(new String[] {"a"}); + private void strings_invalid(Field field) { + NumberFormatException exception = Assertions.assertThrows(NumberFormatException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put(field.getName(), new String[] {"a"}); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("For input string: \"a\"", exception.getMessage()); + } + + @Test + public void primitiveString_invalid() throws Throwable { + string_invalid(primitiveProtoField); } @Test public void string_invalid() throws Throwable { - expectedException.expect(NumberFormatException.class); - expectedException.expectMessage(Matchers.is("For input string: \"a\"")); + string_invalid(protoField); + } + + private void string_invalid(Field field) { + NumberFormatException exception = Assertions.assertThrows(NumberFormatException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put(field.getName(), "a"); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("For input string: \"a\"", exception.getMessage()); + } - serFieldSchema.writeTo("a"); + @Test + public void primitiveType_invalid() { + type_invalid(primitiveProtoField); } @Test public void type_invalid() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is(String.format("not support serialize from %s to proto %s, field=%s:%s", - User.class.getName(), - serFieldSchema.getProtoField().getTypeName(), - ((Type) serFieldSchema.getProtoField().getParent()).getCanonicalName(), - serFieldSchema.getProtoField().getName()))); + type_invalid(protoField); + } - serFieldSchema.writeTo(new User()); + private void type_invalid(Field field) { + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put(field.getName(), new User()); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals(String.format("not support serialize from %s to proto %s, field=%s:%s", + User.class.getName(), + field.getTypeName(), + ((Type) field.getParent()).getCanonicalName(), + field.getName()), exception.getMessage()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed32Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed32Schema.java index 005ab6de933..b719dba66ba 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed32Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed32Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestSFixed32Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "sfixed32"; + public TestSFixed32Schema() { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; - super.init(); + initFields("sfixed32", "objSfixed32"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed64Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed64Schema.java index 414e5edfbe8..09dc99b01e0 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed64Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSFixed64Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestSFixed64Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "sfixed64"; + public TestSFixed64Schema() { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; - super.init(); + initFields("sfixed64", "objSfixed64"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt32Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt32Schema.java index 7382bbef83f..ab03f49a9fb 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt32Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt32Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestSInt32Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "sint32"; + public TestSInt32Schema() { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; - super.init(); + initFields("sint32", "objSint32"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt64Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt64Schema.java index d1ce32caf07..f9b3de402cc 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt64Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestSInt64Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestSInt64Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "sint64"; + public TestSInt64Schema() { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; - super.init(); + initFields("sint64", "objSint64"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestStringSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestStringSchema.java index 4eaea11095d..c1084568350 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestStringSchema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestStringSchema.java @@ -16,17 +16,14 @@ */ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; +import java.util.HashMap; + import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestStringSchema extends TestSchemaBase { - public TestStringSchema() { - initField("string"); - } - @Test public void normal() throws Throwable { String value = "abc"; @@ -34,27 +31,34 @@ public void normal() throws Throwable { check(); // string[] - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(new String[] {value})); + scbMap = new HashMap<>(); + scbMap.put("string", new String[] {value}); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(scbMap)); // string - Assert.assertArrayEquals(protobufBytes, serFieldSchema.writeTo(value)); + scbMap.put("string", value); + Assertions.assertArrayEquals(protobufBytes, rootSerializer.serialize(scbMap)); } @Test public void nullOrEmpty() throws Throwable { // null - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); + scbMap = new HashMap<>(); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); // empty string[] - Assert.assertEquals(0, serFieldSchema.writeTo(new String[] {}).length); + scbMap.put("string", new String[] {}); + Assertions.assertEquals(0, rootSerializer.serialize(scbMap).length); } @Test public void type_invalid() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto string, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:string")); - - serFieldSchema.writeTo(new User()); + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, () -> { + scbMap = new HashMap<>(); + scbMap.put("string", new User()); + rootSerializer.serialize(scbMap); + }); + Assertions.assertEquals("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto string, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:string", + exception.getMessage()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt32Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt32Schema.java index 84c196383ce..5456ff0985c 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt32Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt32Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestUInt32Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "uint32"; + public TestUInt32Schema() { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; - super.init(); + initFields("uint32", "objUint32"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt64Schema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt64Schema.java index f22d8105688..6235a4b3e24 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt64Schema.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/scalar/TestUInt64Schema.java @@ -17,11 +17,9 @@ package org.apache.servicecomb.foundation.protobuf.internal.schema.scalar; public class TestUInt64Schema extends TestNumberBaseSchema { - @Override - protected void init() { - fieldName = "uint64"; + public TestUInt64Schema() { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; - super.init(); + initFields("uint64", "objUint64"); } -} \ No newline at end of file +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/TestEnumSerializerSchema.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/TestEnumSerializerSchema.java deleted file mode 100644 index 85ec3f771ea..00000000000 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/internal/schema/serializer/TestEnumSerializerSchema.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.protobuf.internal.schema.serializer; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.protobuf.internal.TestSchemaBase; -import org.apache.servicecomb.foundation.protobuf.internal.model.User; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestEnumSerializerSchema extends TestSchemaBase { - public TestEnumSerializerSchema() { - initField("color"); - } - - @Test - public void empty() throws Throwable { - Assert.assertEquals(0, serFieldSchema.writeTo(null).length); - Assert.assertEquals(0, serFieldSchema.writeTo(new String[0]).length); - } - - @Test - public void normal() throws Throwable { - builder.setColorValue(2); - check(); - - Map map = new HashMap<>(); - map.put("color", 2); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); - - map.put("color", new String[] {"BLUE"}); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); - - map.put("color", "BLUE"); - Assert.assertArrayEquals(protobufBytes, rootSerializer.serialize(map)); - } - - enum Sharp { - ROUND - } - - @Test - public void fromInvalidEnum() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("invalid enum name ROUND for proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color")); - - serFieldSchema.writeTo(Sharp.ROUND); - } - - @Test - public void fromInvalidNumber() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("invalid enum value 3 for proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color")); - - serFieldSchema.writeTo(3); - } - - @Test - public void type_invalid() throws Throwable { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("not support serialize from org.apache.servicecomb.foundation.protobuf.internal.model.User to proto Color, field=org.apache.servicecomb.foundation.protobuf.internal.model.Root:color")); - - serFieldSchema.writeTo(new User()); - } -} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestBase.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestBase.java index c8c810c6505..c73caf9a327 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestBase.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestBase.java @@ -79,25 +79,25 @@ private TestEngineResult runOneEngine(ProtubufCodecEngine engine, Object model, { long msStart = System.currentTimeMillis(); for (int idx = 0; idx < count; idx++) { - engineResult.serBytes = engine.serialize(model); + engineResult.serializeBytes = engine.serialize(model); } long msEnd = System.currentTimeMillis(); - engineResult.msSerTime = msEnd - msStart; + engineResult.msSerializeTime = msEnd - msStart; } // deserialize { long msStart = System.currentTimeMillis(); for (int idx = 0; idx < count; idx++) { - engineResult.deserResult = engine.deserialize(engineResult.serBytes); + engineResult.deserializeResult = engine.deserialize(engineResult.serializeBytes); } long msEnd = System.currentTimeMillis(); - engineResult.msDeserTime = msEnd - msStart; + engineResult.msDeserializeTime = msEnd - msStart; } - engineResult.deserResultBytes = engine.serialize(engineResult.deserResult); + engineResult.deserializeResultBytes = engine.serialize(engineResult.deserializeResult); return engineResult; } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestEngineResult.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestEngineResult.java index ffa08506df7..f02ee12092a 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestEngineResult.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestEngineResult.java @@ -20,14 +20,14 @@ public class TestEngineResult { public String engineName; // serialize - public long msSerTime; + public long msSerializeTime; - public byte[] serBytes; + public byte[] serializeBytes; // deserialize - public long msDeserTime; + public long msDeserializeTime; - public Object deserResult; + public Object deserializeResult; - public byte[] deserResultBytes; + public byte[] deserializeResultBytes; } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestProtoPerformance.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestProtoPerformance.java index 276821e975d..98e2f5b7855 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestProtoPerformance.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/TestProtoPerformance.java @@ -21,6 +21,7 @@ import org.apache.servicecomb.foundation.protobuf.performance.cases.Empty; import org.apache.servicecomb.foundation.protobuf.performance.cases.Map; import org.apache.servicecomb.foundation.protobuf.performance.cases.Mixed; +import org.apache.servicecomb.foundation.protobuf.performance.cases.Pojo; import org.apache.servicecomb.foundation.protobuf.performance.cases.PojoList; import org.apache.servicecomb.foundation.protobuf.performance.cases.Scalars; import org.apache.servicecomb.foundation.protobuf.performance.cases.SimpleList; @@ -36,17 +37,20 @@ public static void main(String[] args) throws IOException { + " so should be much slower than the test results"); System.out.println("2.protoStuff\n" + " some scenes, there is no field but have getter or setter, so we can not use unsafe to access field\n" - + " so we disable protoStuff unsafe feature"); + + " so we disable protoStuff unsafe feature\n\n" + + " for repeated fields, protoStuff have better performance, but not compatible to protobuf\n"); System.out.println("3.jackson\n" - + " not support map, so skip map in map/mixed test"); + + " not support map/any/recursive, ignore related fields"); System.out.println("4.serialize result size\n" + " ScbStrong/ScbWeak/Protobuf have the same and smaller size, because skip all default/null value"); + System.setProperty("protostuff.runtime.use_sun_misc_unsafe", "false"); int count = 50_0000; printResult(new Empty().run(count)); printResult(new Scalars().run(count)); + printResult(new Pojo().run(count)); printResult(new SimpleList().run(count)); printResult(new PojoList().run(count)); printResult(new Map().run(count)); @@ -57,18 +61,21 @@ private static void printResult(TestResult result) { String strFmt = Strings.repeat("%-11s", result.engineResults.size()); String numberFmt = Strings.repeat("%-11d", result.engineResults.size()); - System.out.println(result.name + ":"); - System.out.printf(" " + strFmt + "\n", + System.out.println(result.name + ": "); + System.out.printf(" " + strFmt + "\n", result.engineResults.stream().map(r -> r.engineName).toArray()); - System.out.printf("ser time(ms) :" + numberFmt + "\n", - result.engineResults.stream().map(r -> r.msSerTime).toArray()); - System.out.printf("ser len :" + numberFmt + "\n", - result.engineResults.stream().map(r -> r.serBytes.length).toArray()); + System.out.printf("serialize time(ms) : " + numberFmt + "\n", + result.engineResults.stream().map(r -> r.msSerializeTime).toArray()); + System.out.printf("serialize len : " + numberFmt + "\n", + result.engineResults.stream().map(r -> r.serializeBytes.length).toArray()); + + System.out.printf("deserialize time(ms): " + numberFmt + "\n", + result.engineResults.stream().map(r -> r.msDeserializeTime).toArray()); + System.out.printf("deserialize->serialize len: " + numberFmt + "\n", + result.engineResults.stream().map(r -> r.deserializeResultBytes.length).toArray()); - System.out.printf("deser time(ms):" + numberFmt + "\n", - result.engineResults.stream().map(r -> r.msDeserTime).toArray()); - System.out.printf("deser-ser len :" + numberFmt + "\n\n", - result.engineResults.stream().map(r -> r.deserResultBytes.length).toArray()); + System.out.printf("serialize+deserialize(ms) : " + numberFmt + "\n\n", + result.engineResults.stream().map(r -> r.msSerializeTime + r.msDeserializeTime).toArray()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Mixed.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Mixed.java index 9201e7b007e..9cc09534b80 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Mixed.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Mixed.java @@ -17,40 +17,133 @@ package org.apache.servicecomb.foundation.protobuf.performance.cases; import java.util.Arrays; -import java.util.HashMap; +import java.util.LinkedHashMap; +import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot; import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot.User; import org.apache.servicecomb.foundation.protobuf.performance.TestBase; import org.apache.servicecomb.foundation.test.scaffolding.model.Color; public class Mixed extends TestBase { public Mixed() { - pojoRoot.setInt32(1); - pojoRoot.setInt64(1L); + pojoRoot.setInt32(10000); + pojoRoot.setInt64(20000L); + pojoRoot.setUint32(30000); + pojoRoot.setUint64(40000L); + pojoRoot.setSint32(50000); + pojoRoot.setSint64(60000L); + pojoRoot.setFixed32(70000); + pojoRoot.setFixed64(80000L); + pojoRoot.setSfixed32(90000); + pojoRoot.setSfixed64(100000L); + pojoRoot.setFloatValue((float) 10000); + pojoRoot.setDoubleValue(20000.0); + pojoRoot.setBool(true); + + pojoRoot.setObjInt32(10000); + pojoRoot.setObjInt64(20000L); + pojoRoot.setObjUint32(30000); + pojoRoot.setObjUint64(40000L); + pojoRoot.setObjSint32(50000); + pojoRoot.setObjSint64(60000L); + pojoRoot.setObjFixed32(70000); + pojoRoot.setObjFixed64(80000L); + pojoRoot.setObjSfixed32(90000); + pojoRoot.setObjSfixed64(100000L); + pojoRoot.setObjFloatValue((float) 10000); + pojoRoot.setObjDoubleValue(20000.0); + pojoRoot.setObjBool(true); + pojoRoot.setString("string value"); pojoRoot.setColor(Color.BLUE); - pojoRoot.setsList(Arrays.asList("string value1", "string value2")); - pojoRoot.setpList(Arrays.asList( - new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name1"), - new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name2"))); - pojoRoot.setSsMap(new HashMap<>()); + pojoRoot.setUser(new org.apache.servicecomb.foundation.protobuf.internal.model.User("name1")); + + pojoRoot.setSsMap(new LinkedHashMap<>()); pojoRoot.getSsMap().put("k1", "v1"); pojoRoot.getSsMap().put("k2", "v2"); - pojoRoot.setSpMap(new HashMap<>()); + pojoRoot.setSpMap(new LinkedHashMap<>()); pojoRoot.getSpMap().put("u1", new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name1")); pojoRoot.getSpMap().put("u2", new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name2")); - builder.setInt32(1) - .setInt64(1L) + pojoRoot.setInt32sPacked(Arrays.asList(10000, 20000, 30000)); + pojoRoot.setInt64sPacked(Arrays.asList(10000L, 20000L, 30000L)); + pojoRoot.setUint32sPacked(Arrays.asList(10000, 20000, 30000)); + pojoRoot.setUint64sPacked(Arrays.asList(10000L, 20000L, 30000L)); + pojoRoot.setSint32sPacked(Arrays.asList(10000, 20000, 30000)); + pojoRoot.setSint64sPacked(Arrays.asList(10000L, 20000L, 30000L)); + pojoRoot.setFixed32sPacked(Arrays.asList(10000, 20000, 30000)); + pojoRoot.setFixed64sPacked(Arrays.asList(10000L, 20000L, 30000L)); + pojoRoot.setSfixed32sPacked(Arrays.asList(10000, 20000, 30000)); + pojoRoot.setSfixed64sPacked(Arrays.asList(10000L, 20000L, 30000L)); + pojoRoot.setFloatsPacked(Arrays.asList((float) 10000, (float) 20000, (float) 30000)); + pojoRoot.setDoublesPacked(Arrays.asList(10000.0, 20000.0, 30000.0)); + pojoRoot.setBoolsPacked(Arrays.asList(true, false)); + pojoRoot.setColorsPacked(Arrays.asList(Color.RED, Color.BLUE)); + + pojoRoot.setStrings(Arrays.asList("string value1", "string value2")); + pojoRoot.setUsers(Arrays.asList( + new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name1"), + new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name2"), + new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name3"), + new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name4"))); + + builder.setInt32(10000) + .setInt64(20000L) + .setUint32(30000) + .setUint64(40000L) + .setSint32(50000) + .setSint64(60000L) + .setFixed32(70000) + .setFixed64(80000L) + .setSfixed32(90000) + .setSfixed64(100000L) + .setFloatValue((float) 10000) + .setDoubleValue(20000.0) + .setBool(true) + + .setObjInt32(10000) + .setObjInt64(20000L) + .setObjUint32(30000) + .setObjUint64(40000L) + .setObjSint32(50000) + .setObjSint64(60000L) + .setObjFixed32(70000) + .setObjFixed64(80000L) + .setObjSfixed32(90000) + .setObjSfixed64(100000L) + .setObjFloatValue((float) 10000) + .setObjDoubleValue(20000.0) + .setObjBool(true) + .setString("string value") .setColorValue(2) - .addSList("string value1") - .addSList("string value2") - .addPList(User.newBuilder().setName("name1").build()) - .addPList(User.newBuilder().setName("name2").build()) + .setUser(User.newBuilder().setName("name1").build()) + .putSsMap("k1", "v1") .putSsMap("k2", "v2") .putSpMap("u1", User.newBuilder().setName("name1").build()) - .putSpMap("u2", User.newBuilder().setName("name2").build()); + .putSpMap("u2", User.newBuilder().setName("name2").build()) + + .addAllInt32SPacked(Arrays.asList(10000, 20000, 30000)) + .addAllInt64SPacked(Arrays.asList(10000L, 20000L, 30000L)) + .addAllUint32SPacked(Arrays.asList(10000, 20000, 30000)) + .addAllUint64SPacked(Arrays.asList(10000L, 20000L, 30000L)) + .addAllSint32SPacked(Arrays.asList(10000, 20000, 30000)) + .addAllSint64SPacked(Arrays.asList(10000L, 20000L, 30000L)) + .addAllFixed32SPacked(Arrays.asList(10000, 20000, 30000)) + .addAllFixed64SPacked(Arrays.asList(10000L, 20000L, 30000L)) + .addAllSfixed32SPacked(Arrays.asList(10000, 20000, 30000)) + .addAllSfixed64SPacked(Arrays.asList(10000L, 20000L, 30000L)) + .addAllFloatsPacked(Arrays.asList((float) 10000, (float) 20000, (float) 30000)) + .addAllDoublesPacked(Arrays.asList(10000.0, 20000.0, 30000.0)) + .addAllBoolsPacked(Arrays.asList(true, false)) + .addAllColorsPacked(Arrays.asList(ProtobufRoot.Color.RED, ProtobufRoot.Color.BLUE)) + + .addStrings("string value1") + .addStrings("string value2") + .addUsers(User.newBuilder().setName("name1").build()) + .addUsers(User.newBuilder().setName("name2").build()) + .addUsers(User.newBuilder().setName("name3").build()) + .addUsers(User.newBuilder().setName("name4").build()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Pojo.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Pojo.java new file mode 100644 index 00000000000..d435ed392a7 --- /dev/null +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Pojo.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.protobuf.performance.cases; + +import org.apache.servicecomb.foundation.protobuf.internal.model.ProtobufRoot.User; +import org.apache.servicecomb.foundation.protobuf.performance.TestBase; + +public class Pojo extends TestBase { + public Pojo() { + pojoRoot.setUser(new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name1")); + + builder.setUser(User.newBuilder().setName("name1").build()); + } +} diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/PojoList.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/PojoList.java index eb51199dd7b..929d62666e9 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/PojoList.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/PojoList.java @@ -23,11 +23,11 @@ public class PojoList extends TestBase { public PojoList() { - pojoRoot.setpList(Arrays.asList( + pojoRoot.setUsers(Arrays.asList( new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name1"), new org.apache.servicecomb.foundation.protobuf.internal.model.User().name("name2"))); - builder.addPList(User.newBuilder().setName("name1").build()) - .addPList(User.newBuilder().setName("name2").build()); + builder.addUsers(User.newBuilder().setName("name1").build()) + .addUsers(User.newBuilder().setName("name2").build()); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Scalars.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Scalars.java index 9e457af876c..bf272164523 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Scalars.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/Scalars.java @@ -21,13 +21,13 @@ public class Scalars extends TestBase { public Scalars() { - pojoRoot.setInt32(1); - pojoRoot.setInt64(1L); + pojoRoot.setInt32(10000); + pojoRoot.setInt64(10000L); pojoRoot.setString("string value"); pojoRoot.setColor(Color.BLUE); - builder.setInt32(1) - .setInt64(1L) + builder.setInt32(10000) + .setInt64(10000L) .setString("string value") .setColorValue(2); } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/SimpleList.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/SimpleList.java index 054bc2a5900..2e30d28bc7e 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/SimpleList.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/cases/SimpleList.java @@ -22,9 +22,9 @@ public class SimpleList extends TestBase { public SimpleList() { - pojoRoot.setsList(Arrays.asList("string value1", "string value2")); + pojoRoot.setStrings(Arrays.asList("string value1", "string value2")); - builder.addSList("string value1") - .addSList("string value2"); + builder.addStrings("string value1") + .addStrings("string value2"); } } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Jackson.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Jackson.java index 74186fa4040..10d11d699bd 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Jackson.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Jackson.java @@ -32,7 +32,7 @@ import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader; public class Jackson implements ProtubufCodecEngine { - @JsonIgnoreProperties({"ssMap", "spMap", "any", "anys", "typeRecursive"}) + @JsonIgnoreProperties({"ssMap", "spMap", "sint32Map", "any", "anys", "typeRecursive"}) interface RootMixin { } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Protostuff.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Protostuff.java index 5377f6f8dbe..c58f85d2a85 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Protostuff.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/Protostuff.java @@ -35,7 +35,9 @@ public class Protostuff implements ProtubufCodecEngine { public byte[] serialize(Object model) throws IOException { LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); ProtobufOutput output = new ProtobufOutput(linkedBuffer); - rootSchema.writeTo(output, (Root) model); + if (model != null) { + rootSchema.writeTo(output, (Root) model); + } return output.toByteArray(); } diff --git a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/SCB.java b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/SCB.java index 945112fdc29..dba5dd9bcde 100644 --- a/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/SCB.java +++ b/foundations/foundation-protobuf/src/test/java/org/apache/servicecomb/foundation/protobuf/performance/engine/SCB.java @@ -29,9 +29,9 @@ public class SCB { static ProtoMapper protoMapper = factory.createFromName("protobufRoot.proto"); - static RootSerializer serializer = protoMapper.findRootSerializer("Root"); + static RootSerializer serializer = protoMapper.createRootSerializer("Root", Root.class); - static RootDeserializer deserializer = protoMapper.createRootDeserializer(Root.class, "Root"); + static RootDeserializer deserializer = protoMapper.createRootDeserializer("Root", Root.class); - static RootDeserializer mapDeserializer = protoMapper.createRootDeserializer(Map.class, "Root"); + static RootDeserializer> mapDeserializer = protoMapper.createRootDeserializer("Root", Map.class); } diff --git a/foundations/foundation-protobuf/src/test/resources/jacksonRoot.proto b/foundations/foundation-protobuf/src/test/resources/jacksonRoot.proto index 590402fdb2b..b1804922666 100644 --- a/foundations/foundation-protobuf/src/test/resources/jacksonRoot.proto +++ b/foundations/foundation-protobuf/src/test/resources/jacksonRoot.proto @@ -5,9 +5,9 @@ The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,15 +32,61 @@ message Root { optional float floatValue = 11; optional double doubleValue = 12; optional bool bool = 13; - optional string string = 14; - optional bytes bytes = 15; - optional Color color = 16; - optional User user = 17; + optional int32 objInt32 = 20; + optional int64 objInt64 = 21; + optional uint32 objUint32 = 22; + optional uint64 objUint64 = 23; + optional sint32 objSint32 = 24; + optional sint64 objSint64 = 25; + optional fixed32 objFixed32 = 26; + optional fixed64 objFixed64 = 27; + optional sfixed32 objSfixed32 = 28; + optional sfixed64 objSfixed64 = 29; + optional float objFloatValue = 30; + optional double objDoubleValue = 31; + optional bool objBool = 32; + + optional string string = 40; + optional bytes bytes = 41; + optional Color color = 42; + optional User user = 43; + + repeated int32 int32sPacked = 70; + repeated int64 int64sPacked = 71; + repeated uint32 uint32sPacked = 72; + repeated uint64 uint64sPacked = 73; + repeated sint32 sint32sPacked = 74; + repeated sint64 sint64sPacked = 75; + repeated fixed32 fixed32sPacked = 76; + repeated fixed64 fixed64sPacked = 77; + repeated sfixed32 sfixed32sPacked = 78; + repeated sfixed64 sfixed64sPacked = 79; + repeated float floatsPacked = 80; + repeated double doublesPacked = 81; + repeated bool boolsPacked = 82; + repeated Color colorsPacked = 83; - repeated string sList = 20; - repeated User pList = 21; + repeated int32 int32sNotPacked = 90 [packed = false]; + repeated int64 int64sNotPacked = 91 [packed = false]; + repeated uint32 uint32sNotPacked = 92 [packed = false]; + repeated uint64 uint64sNotPacked = 93 [packed = false]; + repeated sint32 sint32sNotPacked = 94 [packed = false]; + repeated sint64 sint64sNotPacked = 95 [packed = false]; + repeated fixed32 fixed32sNotPacked = 96 [packed = false]; + repeated fixed64 fixed64sNotPacked = 97 [packed = false]; + repeated sfixed32 sfixed32sNotPacked = 98 [packed = false]; + repeated sfixed64 sfixed64sNotPacked = 99 [packed = false]; + repeated float floatsNotPacked = 100 [packed = false]; + repeated double doublesNotPacked = 101 [packed = false]; + repeated bool boolsNotPacked = 102 [packed = false]; + repeated Color colorsNotPacked = 103 [packed = false]; + + repeated string strings = 110; + repeated bytes bytess = 111; + repeated User users = 112; } + enum Color { RED = 0; YELLOW = 1; @@ -49,4 +95,4 @@ enum Color { message User { optional string name = 1; -} \ No newline at end of file +} diff --git a/foundations/foundation-protobuf/src/test/resources/method.proto b/foundations/foundation-protobuf/src/test/resources/method.proto new file mode 100644 index 00000000000..414b7643880 --- /dev/null +++ b/foundations/foundation-protobuf/src/test/resources/method.proto @@ -0,0 +1,45 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; + +//@WrapArguments +message RequestWrap { + bool boolValue = 1; + repeated int32 iArr = 2; + repeated User user = 3; +} + +message Request { + bool boolValue = 1; + repeated int32 iArr = 2; + repeated User user = 3; +} + +//@WrapProperty +message ResponseWrap { + repeated int32 value = 1; +} + +message Response { + repeated int32 value = 1; +} + +message User { + string name = 1; + repeated User friends = 2; +} diff --git a/foundations/foundation-protobuf/src/test/resources/protobufRoot.proto b/foundations/foundation-protobuf/src/test/resources/protobufRoot.proto index 3cc85706303..1e9f7f41076 100644 --- a/foundations/foundation-protobuf/src/test/resources/protobufRoot.proto +++ b/foundations/foundation-protobuf/src/test/resources/protobufRoot.proto @@ -5,9 +5,9 @@ The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +19,9 @@ syntax = "proto3"; import "google/protobuf/any.proto"; package org.apache.servicecomb.foundation.protobuf.internal.model; +option java_package = "org.apache.servicecomb.foundation.protobuf.internal.model"; +option java_outer_classname = "ProtobufRoot"; + message Root { int32 int32 = 1; int64 int64 = 2; @@ -33,23 +36,69 @@ message Root { float floatValue = 11; double doubleValue = 12; bool bool = 13; - string string = 14; - bytes bytes = 15; - Color color = 16; - User user = 17; + int32 objInt32 = 20; + int64 objInt64 = 21; + uint32 objUint32 = 22; + uint64 objUint64 = 23; + sint32 objSint32 = 24; + sint64 objSint64 = 25; + fixed32 objFixed32 = 26; + fixed64 objFixed64 = 27; + sfixed32 objSfixed32 = 28; + sfixed64 objSfixed64 = 29; + float objFloatValue = 30; + double objDoubleValue = 31; + bool objBool = 32; + + string string = 40; + bytes bytes = 41; + Color color = 42; + User user = 43; + Root typeRecursive = 44; - map ssMap = 18; - map spMap = 19; + google.protobuf.Any any = 50; + repeated google.protobuf.Any anys = 51; - repeated string sList = 20; - repeated User pList = 21; + map ssMap = 60; + map sint32Map = 61; + map spMap = 62; - google.protobuf.Any any = 22; - repeated google.protobuf.Any anys = 23; + repeated int32 int32sPacked = 70; + repeated int64 int64sPacked = 71; + repeated uint32 uint32sPacked = 72; + repeated uint64 uint64sPacked = 73; + repeated sint32 sint32sPacked = 74; + repeated sint64 sint64sPacked = 75; + repeated fixed32 fixed32sPacked = 76; + repeated fixed64 fixed64sPacked = 77; + repeated sfixed32 sfixed32sPacked = 78; + repeated sfixed64 sfixed64sPacked = 79; + repeated float floatsPacked = 80; + repeated double doublesPacked = 81; + repeated bool boolsPacked = 82; + repeated Color colorsPacked = 83; - Root typeRecursive = 24; + repeated int32 int32sNotPacked = 90 [packed = false]; + repeated int64 int64sNotPacked = 91 [packed = false]; + repeated uint32 uint32sNotPacked = 92 [packed = false]; + repeated uint64 uint64sNotPacked = 93 [packed = false]; + repeated sint32 sint32sNotPacked = 94 [packed = false]; + repeated sint64 sint64sNotPacked = 95 [packed = false]; + repeated fixed32 fixed32sNotPacked = 96 [packed = false]; + repeated fixed64 fixed64sNotPacked = 97 [packed = false]; + repeated sfixed32 sfixed32sNotPacked = 98 [packed = false]; + repeated sfixed64 sfixed64sNotPacked = 99 [packed = false]; + repeated float floatsNotPacked = 100 [packed = false]; + repeated double doublesNotPacked = 101 [packed = false]; + repeated bool boolsNotPacked = 102 [packed = false]; + repeated Color colorsNotPacked = 103 [packed = false]; + + repeated string strings = 110; + repeated bytes bytess = 111; + repeated User users = 112; } + enum Color { RED = 0; YELLOW = 1; @@ -60,4 +109,4 @@ message User { string name = 1; Root typeRecursive = 2; -} \ No newline at end of file +} diff --git a/foundations/foundation-registry/pom.xml b/foundations/foundation-registry/pom.xml new file mode 100644 index 00000000000..d4cca8111c4 --- /dev/null +++ b/foundations/foundation-registry/pom.xml @@ -0,0 +1,56 @@ + + + + + + foundations + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + + + + foundation-registry + Java Chassis::Foundations::Registry + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-vertx + + + org.apache.servicecomb + swagger-invocation-core + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.mockito + mockito-inline + test + + + diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/DiscoveryManager.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/DiscoveryManager.java new file mode 100644 index 00000000000..edcd3b3caef --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/DiscoveryManager.java @@ -0,0 +1,337 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.foundation.common.NamedThreadFactory; +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.LambdaUtils; +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.api.LifeCycle; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.discovery.InstancePing; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.HistoryStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.IsolationStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.PingStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +public class DiscoveryManager implements LifeCycle { + public interface InstanceChangeListener { + void onInstancesChanged(String registryName, String application, String serviceName, + List instances); + } + + private static final Logger LOGGER = LoggerFactory.getLogger(DiscoveryManager.class); + + private final ScheduledExecutorService task; + + private final List> discoveryList; + + private final InstancePing ping; + + private final HealthCheckTask healthCheckTask = new HealthCheckTask(); + + // application:serviceName:instanceId + private final Map>> + allInstances = new ConcurrentHashMapEx<>(); + + // application:serviceName + private final Map> + versionedCache = new ConcurrentHashMapEx<>(); + + private final Object cacheLock = new Object(); + + private final List instanceChangeListeners = new ArrayList<>(); + + public DiscoveryManager(List> discoveryList, + List pings) { + this.discoveryList = discoveryList; + for (Discovery discovery : this.discoveryList) { + discovery.setInstanceChangedListener(this::onInstancesChanged); + } + this.ping = pings.get(0); + task = Executors.newScheduledThreadPool(1, new NamedThreadFactory("discovery-manager-task")); + } + + public Discovery getPrimaryDiscovery() { + return this.discoveryList.get(0); + } + + private void onInstancesChanged(String application, String serviceName, + List instances) { + onInstancesChanged(null, application, serviceName, instances); + } + + private void onInstancesChanged(String registryName, String application, String serviceName, + List instances) { + Map statefulInstances = allInstances.computeIfAbsent(application, key -> + new ConcurrentHashMapEx<>()).computeIfAbsent(serviceName, key -> new ConcurrentHashMapEx<>()); + + for (StatefulDiscoveryInstance statefulInstance : statefulInstances.values()) { + if (registryName == null || registryName.equals(statefulInstance.getRegistryName())) { + if (!instances.contains(statefulInstance)) { + statefulInstance.setPingTime(0); + statefulInstance.setHistoryStatus(HistoryStatus.HISTORY); + } + } + } + + for (DiscoveryInstance instance : instances) { + StatefulDiscoveryInstance target = new StatefulDiscoveryInstance(instance); + StatefulDiscoveryInstance origin = statefulInstances.get(instance.getInstanceId()); + if (origin == null) { + statefulInstances.put(instance.getInstanceId(), target); + continue; + } + target.setPingTime(origin.getPingTime()); + target.setPingStatus(origin.getPingStatus()); + target.setIsolateDuration(origin.getIsolateDuration()); + target.setIsolationStatus(origin.getIsolationStatus()); + statefulInstances.put(instance.getInstanceId(), target); + } + + StringBuilder instanceInfo = new StringBuilder(); + for (DiscoveryInstance instance : instances) { + instanceInfo.append("{") + .append(instance.getInstanceId()).append(",") + .append(instance.getStatus()).append(",") + .append(instance.getEndpoints()).append(",") + .append(instance.getRegistryName()) + .append("}"); + } + LOGGER.info("Applying new instance list for {}/{}/{}. Endpoints {}", + application, serviceName, instances.size(), instanceInfo); + + rebuildVersionCache(application, serviceName); + + for (InstanceChangeListener listener : this.instanceChangeListeners) { + listener.onInstancesChanged(registryName, application, serviceName, instances); + } + } + + public void addInstanceChangeListener(InstanceChangeListener instanceChangeListener) { + this.instanceChangeListeners.add(instanceChangeListener); + } + + public void onInstanceIsolated(DiscoveryInstance instance, long isolateDuration) { + Map statefulInstances = allInstances.computeIfAbsent( + instance.getApplication(), key -> + new ConcurrentHashMapEx<>()).computeIfAbsent(instance.getServiceName(), key + -> new ConcurrentHashMapEx<>()); + StatefulDiscoveryInstance target = statefulInstances.get(instance.getInstanceId()); + if (target == null) { + return; + } + + target.setIsolatedTime(System.currentTimeMillis()); + target.setIsolateDuration(isolateDuration); + + if (target.getIsolationStatus() != IsolationStatus.ISOLATED) { + target.setIsolationStatus(IsolationStatus.ISOLATED); + rebuildVersionCache(instance.getApplication(), instance.getServiceName()); + } + + LOGGER.warn("Isolated instance {}/{}/{}, time {}/{}", + instance.getApplication(), instance.getServiceName(), instance.getInstanceId(), + target.getIsolatedTime(), target.getIsolateDuration()); + } + + private void rebuildVersionCache(String application, String serviceName) { + Map caches = versionedCache.computeIfAbsent(application, key -> + new ConcurrentHashMapEx<>()); + caches.put(serviceName, calcAvailableInstance(application, serviceName)); + } + + private VersionedCache calcAvailableInstance(String application, String serviceName) { + Map statefulInstances = allInstances.computeIfAbsent( + application, key -> + new ConcurrentHashMapEx<>()).computeIfAbsent(serviceName, key + -> new ConcurrentHashMapEx<>()); + List result = new ArrayList<>(); + for (StatefulDiscoveryInstance instance : statefulInstances.values()) { + if (instance.getHistoryStatus() == HistoryStatus.CURRENT) { + result.add(instance); + continue; + } + if (instance.getHistoryStatus() == HistoryStatus.HISTORY + && instance.getStatus() == MicroserviceInstanceStatus.UP + && instance.getPingStatus() == PingStatus.OK + && instance.getIsolationStatus() == IsolationStatus.NORMAL) { + result.add(instance); + } + } + StringBuilder instanceInfo = new StringBuilder(); + for (StatefulDiscoveryInstance instance : result) { + instanceInfo.append("{") + .append(instance.getInstanceId()).append(",") + .append(instance.getHistoryStatus()).append(",") + .append(instance.getStatus()).append(",") + .append(instance.getPingStatus()).append(",") + .append(instance.getIsolationStatus()).append(",") + .append(instance.getEndpoints()).append(",") + .append(instance.getRegistryName()) + .append("}"); + } + LOGGER.info("Rebuild cached instance list for {}/{}/{}. Endpoints {}", + application, serviceName, result.size(), instanceInfo); + return new VersionedCache() + .name(application + ":" + serviceName) + .autoCacheVersion() + .data(result); + } + + public VersionedCache getOrCreateVersionedCache(String application, String serviceName) { + Map caches = versionedCache.computeIfAbsent(application, key -> + new ConcurrentHashMapEx<>()); + VersionedCache cache = caches.get(serviceName); + if (cache == null) { + synchronized (cacheLock) { + cache = caches.get(serviceName); + if (cache != null) { + return cache; + } + List instances = findServiceInstances(application, serviceName); + onInstancesChanged(application, serviceName, instances); + return versionedCache.get(application).get(serviceName); + } + } + return cache; + } + + public List findServiceInstances(String application, String serviceName) { + List result = new ArrayList<>(); + for (Discovery discovery : discoveryList) { + if (!discovery.enabled() || !discovery.enabled(application, serviceName)) { + continue; + } + List temp = discovery.findServiceInstances(application, serviceName); + if (CollectionUtils.isEmpty(temp)) { + continue; + } + result.addAll(temp); + } + return result; + } + + @Override + public void destroy() { + discoveryList.forEach(LambdaUtils.ignoreException(LifeCycle::destroy)); + task.shutdownNow(); + } + + @Override + public void run() { + discoveryList.forEach(LifeCycle::run); + task.schedule(healthCheckTask, 3, TimeUnit.SECONDS); + } + + @Override + public void init() { + discoveryList.forEach(LifeCycle::init); + } + + public String info() { + StringBuilder result = new StringBuilder(); + AtomicBoolean first = new AtomicBoolean(true); + discoveryList.forEach(discovery -> { + if (first.getAndSet(false)) { + result.append("Discovery implementations:\n"); + } + result.append(" name:").append(discovery.name()).append("\n"); + }); + return result.toString(); + } + + class HealthCheckTask implements Runnable { + + @Override + public void run() { + try { + Map>> removed = new HashMap<>(); + for (Entry>> apps : DiscoveryManager.this.allInstances.entrySet()) { + for (Entry> services : apps.getValue().entrySet()) { + boolean changed = false; + for (StatefulDiscoveryInstance instance : services.getValue().values()) { + // check isolated time + if (instance.getIsolationStatus() == IsolationStatus.ISOLATED && + instance.getIsolatedTime() + instance.getIsolateDuration() < System.currentTimeMillis()) { + instance.setIsolationStatus(IsolationStatus.NORMAL); + changed = true; + } + // check ping status + if (System.currentTimeMillis() - instance.getPingTime() > 60_000L) { + boolean pingResult = DiscoveryManager.this.ping.ping(instance); + if (pingResult && instance.getPingStatus() != PingStatus.OK) { + instance.setPingStatus(PingStatus.OK); + changed = true; + } else if (!pingResult && instance.getPingStatus() != PingStatus.FAIL) { + instance.setPingStatus(PingStatus.FAIL); + changed = true; + } + instance.setPingTime(System.currentTimeMillis()); + } + // check unused + if (instance.getHistoryStatus() == HistoryStatus.HISTORY) { + if (instance.getStatus() != MicroserviceInstanceStatus.UP || + instance.getPingStatus() == PingStatus.FAIL || + instance.getIsolationStatus() == IsolationStatus.ISOLATED) { + removed.computeIfAbsent(apps.getKey(), k -> new HashMap<>()) + .computeIfAbsent(services.getKey(), k -> new ArrayList<>()).add(instance.getInstanceId()); + LOGGER.info("Remove instance {}/{}/{}/{}/{}/{}/{}/{}", + apps.getKey(), services.getKey(), instance.getRegistryName(), + instance.getInstanceId(), instance.getHistoryStatus(), + instance.getStatus(), instance.getPingStatus(), instance.getIsolationStatus()); + changed = true; + } + } + } + if (changed) { + rebuildVersionCache(apps.getKey(), services.getKey()); + } + } + } + // remove unused + for (Entry>> apps : removed.entrySet()) { + for (Entry> services : apps.getValue().entrySet()) { + for (String instance : services.getValue()) { + DiscoveryManager.this.allInstances.get(apps.getKey()).get(services.getKey()).remove(instance); + } + } + } + } catch (Throwable e) { + LOGGER.error("discovery manager task error. ", e); + } finally { + DiscoveryManager.this.task.schedule(this, 3, TimeUnit.SECONDS); + } + } + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationId.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationId.java new file mode 100644 index 00000000000..9932f5fdfc9 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationId.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry; + +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RegistrationId { + private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationId.class); + + private final String instanceId; + + public RegistrationId() { + this.instanceId = buildInstanceId(); + LOGGER.info("initialized global registration id {}", this.instanceId); + } + + public String getInstanceId() { + return instanceId; + } + + private static String buildInstanceId() { + return UUID.randomUUID().toString(); + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationManager.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationManager.java new file mode 100644 index 00000000000..9c135d380c8 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistrationManager.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.utils.LambdaUtils; +import org.apache.servicecomb.foundation.common.utils.SPIEnabled; +import org.apache.servicecomb.registry.api.LifeCycle; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.springframework.util.CollectionUtils; + +import io.vertx.core.json.jackson.JacksonFactory; + +public class RegistrationManager { + private final List> registrationList; + + public RegistrationManager(List> registrationList) { + if (registrationList == null) { + this.registrationList = Collections.emptyList(); + return; + } + this.registrationList = registrationList.stream().filter(SPIEnabled::enabled).collect(Collectors.toList()); + } + + /** + * For internal use. Get instance id from registry name. If not exists, return empty. + */ + public String getInstanceId(String registryName) { + if (CollectionUtils.isEmpty(registrationList)) { + return ""; + } + Optional> registration = + registrationList.stream().filter(r -> registryName.equals(r.name())).collect(Collectors.toList()) + .stream().findFirst(); + if (!registration.isPresent()) { + return ""; + } + return registration.get().getMicroserviceInstance().getInstanceId(); + } + + /** + * For internal use. Get service id from registry name. If not exists, return empty. + */ + public String getServiceId(String registryName) { + if (CollectionUtils.isEmpty(registrationList)) { + return ""; + } + Optional> registration = + registrationList.stream().filter(r -> registryName.equals(r.name())).collect(Collectors.toList()) + .stream().findFirst(); + if (!registration.isPresent()) { + return ""; + } + return registration.get().getMicroserviceInstance().getServiceId(); + } + + public Registration getPrimaryRegistration() { + return registrationList.get(0); + } + + public void updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + registrationList + .forEach(registration -> registration.updateMicroserviceInstanceStatus(status)); + } + + public void addProperty(String key, String value) { + registrationList + .forEach(registration -> registration.addProperty(key, value)); + } + + public void addSchema(String schemaId, String content) { + registrationList + .forEach(registration -> registration.addSchema(schemaId, content)); + } + + public void addEndpoint(String endpoint) { + registrationList + .forEach(registration -> registration.addEndpoint(endpoint)); + } + + public void destroy() { + registrationList.forEach(LambdaUtils.ignoreException(LifeCycle::destroy)); + } + + public void run() { + registrationList.forEach(LifeCycle::run); + } + + public void init() { + registrationList.forEach(LifeCycle::init); + } + + public String info() { + StringBuilder result = new StringBuilder(); + AtomicBoolean first = new AtomicBoolean(true); + registrationList.forEach(registration -> { + if (first.getAndSet(false)) { + result.append("App ID: ").append(registration.getMicroserviceInstance().getApplication()).append("\n"); + result.append("Service Name: ").append(registration.getMicroserviceInstance().getServiceName()).append("\n"); + result.append("Version: ").append(registration.getMicroserviceInstance().getVersion()).append("\n"); + result.append("Environment: ").append(registration.getMicroserviceInstance().getEnvironment()).append("\n"); + result.append("Endpoints: ").append(getEndpoints(registration.getMicroserviceInstance().getEndpoints())) + .append("\n"); + result.append("Registration implementations:\n"); + } + + result.append(" name:").append(registration.name()).append("\n"); + result.append(" Instance ID: ").append(registration.getMicroserviceInstance().getInstanceId()).append("\n"); + }); + return result.toString(); + } + + private String getEndpoints(List endpoints) { + return JacksonFactory.CODEC.toString(endpoints); + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistryConfiguration.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistryConfiguration.java new file mode 100644 index 00000000000..7a1d72460cc --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/RegistryConfiguration.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry; + +import java.util.List; + +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.registry.discovery.InstancePing; +import org.apache.servicecomb.registry.discovery.InstanceStatusDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.MicroserviceInstanceCache; +import org.apache.servicecomb.registry.discovery.TelnetInstancePing; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@SuppressWarnings("unused") +public class RegistryConfiguration { + @Bean + public RegistrationManager scbRegistrationManager( + List> registrationList) { + return new RegistrationManager(registrationList); + } + + @Bean + public TelnetInstancePing scbTelnetInstancePing() { + return new TelnetInstancePing(); + } + + @Bean + public DiscoveryManager scbDiscoveryManager( + List> discoveryList, + List pingList) { + return new DiscoveryManager(discoveryList, pingList); + } + + @Bean + public DiscoveryTree scbDiscoveryTree(DiscoveryManager discoveryManager) { + return new DiscoveryTree(discoveryManager); + } + + @Bean + public InstanceStatusDiscoveryFilter scbInstanceStatusDiscoveryFilter() { + return new InstanceStatusDiscoveryFilter(); + } + + @Bean + public MicroserviceInstanceCache scbMicroserviceInstanceCache(DiscoveryManager discoveryManager) { + return new MicroserviceInstanceCache(discoveryManager); + } + + @Bean + public RegistrationId scbRegistrationId() { + return new RegistrationId(); + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/AbstractDiscoveryInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/AbstractDiscoveryInstance.java new file mode 100644 index 00000000000..08bcd6c02de --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/AbstractDiscoveryInstance.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.api; + +public abstract class AbstractDiscoveryInstance implements DiscoveryInstance { + @Override + public int hashCode() { + return getInstanceId().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DiscoveryInstance) { + return getInstanceId().equals(((DiscoveryInstance) obj).getInstanceId()); + } + return false; + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DataCenterInfo.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DataCenterInfo.java new file mode 100644 index 00000000000..7c6496e4b91 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DataCenterInfo.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.api; + +public class DataCenterInfo { + private String name; + + private String region; + + private String availableZone; + + public DataCenterInfo() { + + } + + public DataCenterInfo(String name, String region, String availableZone) { + this.name = name; + this.region = region; + this.availableZone = availableZone; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getAvailableZone() { + return availableZone; + } + + public void setAvailableZone(String availableZone) { + this.availableZone = availableZone; + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Discovery.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Discovery.java new file mode 100644 index 00000000000..0c57ed6b605 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Discovery.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.api; + +import java.util.List; + +import org.apache.servicecomb.foundation.common.utils.SPIEnabled; +import org.apache.servicecomb.foundation.common.utils.SPIOrder; + +/** + * This is the core service discovery interface.
+ */ +public interface Discovery extends SPIEnabled, SPIOrder, LifeCycle { + interface InstanceChangedListener { + /** + * Called by Discovery Implementations when instance list changed. + * @param registryName Name of the calling discovery implementation + * @param application Microservice application + * @param serviceName Microservice name + * @param updatedInstances The latest updated instances. + */ + void onInstanceChanged(String registryName, String application, String serviceName, List updatedInstances); + } + + String name(); + + /** + * If this implementation enabled for this microservice. + */ + boolean enabled(String application, String serviceName); + + /** + * Find all instances. + * + * Life Cycle:This method is called anytime after run. + * + * @param application application + * @param serviceName microservice name + * @return all instances match the criteria. + */ + List findServiceInstances(String application, String serviceName); + + /** + * Find all services of this application. + * + * @param application application + * @return all services match the criteria. + */ + List findServices(String application); + + /** + * Discovery can call InstanceChangedListener when instance get changed. + */ + void setInstanceChangedListener(InstanceChangedListener instanceChangedListener); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DiscoveryInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DiscoveryInstance.java new file mode 100644 index 00000000000..f981aa349e6 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/DiscoveryInstance.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.api; + +/** + * Microserivce instance discovery object. + */ +public interface DiscoveryInstance extends MicroserviceInstance { + /** + * Microservice instance status. + */ + MicroserviceInstanceStatus getStatus(); + + /** + * This name of Discovery Implementation. + */ + String getRegistryName(); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/LifeCycle.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/LifeCycle.java new file mode 100644 index 00000000000..64647d9a29b --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/LifeCycle.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.api; + +public interface LifeCycle { + void init(); + + void run(); + + void destroy(); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstance.java new file mode 100644 index 00000000000..c5c872beefd --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstance.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.api; + +import java.util.List; +import java.util.Map; + +/** + * Standard information used for microservice instance registration and discovery. + */ +public interface MicroserviceInstance { + /** + * Environment(Required): Used for logic separation of microservice instance. Only + * microservice instance with same environment can discovery each other. + */ + String getEnvironment(); + + /** + * Application(Required): Used for logic separation of microservice instance. Only + * microservice instance with same application can discovery each other. + */ + String getApplication(); + + /** + * Service Name(Required): Unique identifier for microservice. + */ + String getServiceName(); + + /** + * Service Name Alias(Optional): Unique identifier for microservice. + * This alias is used by registry implementation to support rename + * of a microservice, e.g. old consumers use old service name can + * find a renamed microservice service. + */ + String getAlias(); + + /** + * Service Version(Required): version of this microservice. + */ + String getVersion(); + + /** + * Data center info(Optional). + */ + DataCenterInfo getDataCenterInfo(); + + /** + * Service Description(Optional) + */ + String getDescription(); + + /** + * Service Properties(Optional) + */ + Map getProperties(); + + /** + * Service Schemas(Optional): Open API information. + */ + Map getSchemas(); + + /** + * Service endpoints(Optional). + */ + List getEndpoints(); + + /** + * Microservice instance id(Required). This id can be generated when microservice instance is starting + * or assigned by registry implementation. + * + * When microservice instance is restarted, this id should be changed. + */ + String getInstanceId(); + + /** + * Microservice service id(Optional). This is used for service center, other implementations may not + * support service id. + */ + default String getServiceId() { + return ""; + } + + /** + * Service status(Required): status of this microservice. + * + */ + MicroserviceInstanceStatus getStatus(); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstanceStatus.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstanceStatus.java new file mode 100644 index 00000000000..4bde42dee91 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceInstanceStatus.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.api; + +public enum MicroserviceInstanceStatus { + STARTING, + TESTING, + UP, + DOWN, + UNKNOWN +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/MicroserviceKey.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceKey.java similarity index 97% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/MicroserviceKey.java rename to foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceKey.java index ea920c24320..4f56d723354 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/MicroserviceKey.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/MicroserviceKey.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.api; +package org.apache.servicecomb.registry.api; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/PropertyExtended.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/PropertyExtended.java similarity index 94% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/PropertyExtended.java rename to foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/PropertyExtended.java index 5f19146a383..e0d3cb8e50c 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/PropertyExtended.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/PropertyExtended.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.api; +package org.apache.servicecomb.registry.api; import java.util.Map; diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Registration.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Registration.java new file mode 100644 index 00000000000..014da5f147b --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/Registration.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.api; + +import org.apache.servicecomb.foundation.common.utils.SPIEnabled; +import org.apache.servicecomb.foundation.common.utils.SPIOrder; + + +/** + * This is the core service registration interface. + */ +public interface Registration extends SPIEnabled, SPIOrder, LifeCycle { + String name(); + + /** + * get MicroserviceInstance + *

+ * Life Cycle:This method is called anytime after run. + */ + R getMicroserviceInstance(); + + /** + * update MicroserviceInstance status + *

+ * Life Cycle:This method is called anytime after run. + */ + boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status); + + /** + * adding schemas to Microservice + *

+ * Life Cycle:This method is called after init and before run. + */ + void addSchema(String schemaId, String content); + + /** + * adding endpoints to MicroserviceInstance + *

+ * Life Cycle:This method is called after init and before run. + */ + void addEndpoint(String endpoint); + + /** + * adding property to MicroserviceInstance + *

+ * Life Cycle:This method is called after init and before run. + */ + void addProperty(String key, String value); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/RegistrationInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/RegistrationInstance.java new file mode 100644 index 00000000000..a7d7cafda88 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/RegistrationInstance.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.api; + +/** + * Microserivce instance registration object. + */ +public interface RegistrationInstance extends MicroserviceInstance { +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/DefinitionConst.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/DefinitionConst.java new file mode 100644 index 00000000000..528caaafde9 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/DefinitionConst.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.definition; + +public interface DefinitionConst { + // Whether to allow cross-app calls to me + String CONFIG_ALLOW_CROSS_APP_KEY = "allowCrossApp"; + + String DEFAULT_STAGE = "prod"; + + String VERSION_RULE_LATEST = "latest"; + + String VERSION_RULE_ALL = "0.0.0.0+"; + + String APP_SERVICE_SEPARATOR = ":"; + + String URL_PREFIX = "urlPrefix"; + + String INSTANCE_PUBKEY_PRO = "publickey"; + + String REGISTER_URL_PREFIX = "servicecomb.registry.registerUrlPrefix"; +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/MicroserviceNameParser.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/MicroserviceNameParser.java new file mode 100644 index 00000000000..e99afdbf8be --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/definition/MicroserviceNameParser.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.definition; + +/** + * Parse application and microservice from join name. + * + * 1. microserviceName + * 2. application:microserviceName + */ +public class MicroserviceNameParser { + private String appId; + + private String microserviceName; + + public MicroserviceNameParser(String defaultAppId, String microserviceName) { + parseMicroserviceName(defaultAppId, microserviceName); + } + + private void parseMicroserviceName(String defaultAppId, String microserviceName) { + int idxAt = microserviceName.indexOf(DefinitionConst.APP_SERVICE_SEPARATOR); + if (idxAt == -1) { + this.appId = defaultAppId; + this.microserviceName = microserviceName; + return; + } + + this.appId = microserviceName.substring(0, idxAt); + this.microserviceName = microserviceName.substring(idxAt + 1); + } + + public String getAppId() { + return appId; + } + + public String getMicroserviceName() { + return microserviceName; + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractDiscoveryFilter.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractDiscoveryFilter.java new file mode 100644 index 00000000000..f274799c30e --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractDiscoveryFilter.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.ArrayList; + +import org.apache.servicecomb.config.DynamicProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class AbstractDiscoveryFilter implements DiscoveryFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDiscoveryFilter.class); + + protected Boolean enabled; + + protected DynamicProperties dynamicProperties; + + @Autowired + public void setDynamicProperties(DynamicProperties dynamicProperties) { + this.dynamicProperties = dynamicProperties; + } + + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + if (!parent.childrenInited()) { + synchronized (parent) { + if (!parent.childrenInited()) { + init(context, parent); + parent.childrenInited(true); + } + } + } + + String childName = findChildName(context, parent); + DiscoveryTreeNode node = parent.child(childName); + if (node == null) { + LOGGER.warn("discovery filter {}/{} return null.", this.getClass().getSimpleName(), childName); + return new DiscoveryTreeNode().subName(parent, "empty").data(new ArrayList<>()); + } + return node; + } + + protected abstract void init(DiscoveryContext context, DiscoveryTreeNode parent); + + protected abstract String findChildName(DiscoveryContext context, DiscoveryTreeNode parent); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractEndpointDiscoveryFilter.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractEndpointDiscoveryFilter.java new file mode 100644 index 00000000000..f4b464f0097 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractEndpointDiscoveryFilter.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractEndpointDiscoveryFilter implements DiscoveryFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractEndpointDiscoveryFilter.class); + + private static final String ALL_TRANSPORT = ""; + + private static final String WEBSOCKET_TRANSPORT = "websocket"; + + private static final String REST_TRANSPORT = "rest"; + + @Override + public boolean isGroupingFilter() { + return true; + } + + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + String expectTransportName = findTransportName(context, parent); + return parent.children() + .computeIfAbsent(expectTransportName, etn -> createDiscoveryTreeNode(expectTransportName, context, parent)); + } + + protected DiscoveryTreeNode createDiscoveryTreeNode(String expectTransportName, DiscoveryContext context, + DiscoveryTreeNode parent) { + List endpoints = new ArrayList<>(); + List instances = parent.data(); + for (StatefulDiscoveryInstance instance : instances) { + for (String endpoint : instance.getEndpoints()) { + try { + URIEndpointObject endpointObject = new URIEndpointObject(endpoint); + String transPortName = endpointObject.getSchema(); + if (endpointObject.isWebsocketEnabled() && WEBSOCKET_TRANSPORT.equals(expectTransportName)) { + transPortName = WEBSOCKET_TRANSPORT; + } + if (!isTransportNameMatch(transPortName, expectTransportName)) { + continue; + } + + Object objEndpoint = createEndpoint(context, transPortName, endpoint, instance); + if (objEndpoint == null) { + continue; + } + + endpoints.add(objEndpoint); + } catch (Exception e) { + LOGGER.warn("unrecognized address find, ignore {}.", endpoint); + } + } + } + + return new DiscoveryTreeNode() + .subName(parent, expectTransportName) + .data(endpoints); + } + + protected boolean isTransportNameMatch(String transportName, String expectTransportName) { + if (ALL_TRANSPORT.equals(expectTransportName)) { + return true; + } + return transportName.equals(expectTransportName); + } + + protected abstract String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent); + + protected abstract Object createEndpoint(DiscoveryContext context, String transportName, String endpoint, + StatefulDiscoveryInstance instance); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractGroupDiscoveryFilter.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractGroupDiscoveryFilter.java new file mode 100644 index 00000000000..b76d860903d --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/AbstractGroupDiscoveryFilter.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +public abstract class AbstractGroupDiscoveryFilter extends AbstractDiscoveryFilter { + @Override + public boolean isGroupingFilter() { + return true; + } + + protected abstract String groupsSizeParameter(); + + protected abstract String contextParameter(); + + protected abstract String groupPrefix(); + + @Override + protected String findChildName(DiscoveryContext context, DiscoveryTreeNode parent) { + Integer level = context.getContextParameter(contextParameter()); + Integer groups = parent.attribute(groupsSizeParameter()); + + String group; + if (level == null) { + group = groupPrefix() + 1; + if (groups > 1) { + context.pushRerunFilter(); + context.putContextParameter(contextParameter(), 1); + } + return group; + } + + level = level + 1; + group = groupPrefix() + level; + + if (level < groups) { + context.pushRerunFilter(); + context.putContextParameter(contextParameter(), level); + } + return group; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryContext.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryContext.java similarity index 91% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryContext.java rename to foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryContext.java index a22fd46de69..7340c7dbf65 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryContext.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryContext.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.discovery; +package org.apache.servicecomb.registry.discovery; import java.util.HashMap; import java.util.Map; @@ -24,13 +24,13 @@ public class DiscoveryContext { private Object inputParameters; - private Map contextParameters = new HashMap<>(); + private final Map contextParameters = new HashMap<>(); // some filter support rerun logic, eg:ZoneAware // instances grouping to self zone, other zone, and so on // first try self zone, after other filter(Isolation Filter), no instances are available // then try other zone - private Stack rerunStack = new Stack<>(); + private final Stack rerunStack = new Stack<>(); private DiscoveryTreeNode currentNode; diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryFilter.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryFilter.java new file mode 100644 index 00000000000..14b0cc44681 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryFilter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import org.springframework.core.Ordered; + +/** + * Server list filters for DiscoveryTree. + * + * Implementation Notice: DiscoveryFilter is initialized using bean and instance shared for all + * microservices. If implementation has states, can put the states to DiscoveryContext or parent DiscoveryTreeNode. + */ +public interface DiscoveryFilter extends Ordered { + default boolean enabled() { + return true; + } + + /** + * grouping filter, means grouping instances to some groups + * eg: operation/ZoneAware/transport + */ + default boolean isGroupingFilter() { + return false; + } + + DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTree.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTree.java new file mode 100644 index 00000000000..c7b70f606b9 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTree.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +/** + *
+ * DiscoveryTree is used to:
+ * 1.get all instances by app/microserviceName
+ * 2.filter all instances set, and output another set, the output set is instance or something else, this depend on filter set
+ *
+ * DiscoveryFilter have different types:
+ * 1.normal filter: just filter input set
+ * 2.grouping filter: will split input set to groups
+ * 3.convert filter: eg: convert from instance to endpoint
+ * different types can composite in one filter
+ *
+ * features:
+ * 1.if some filter output set is empty, DiscoveryTree can support try refilter logic
+ *   eg: if there is no available instances in self AZ, can refilter in other AZ
+ * 2.every filter must try to cache result, avoid calculate every time.
+ *
+ * usage:
+ * 1.declare a field: DiscoveryTree discoveryTree = new DiscoveryTree();
+ * 2.initialize:
+ *     discoveryTree.loadFromSPI(DiscoveryFilter.class);
+ *     // add filters by your requirement
+ *     discoveryTree.addFilter(new EndpointDiscoveryFilter());
+ *     discoveryTree.sort();
+ * 3.filter for a invocation:
+ *     DiscoveryContext context = new DiscoveryContext();
+ *     context.setInputParameters(invocation);
+ *     VersionedCache endpointsVersionedCache = discoveryTree.discovery(context,
+ *         invocation.getAppId(),
+ *         invocation.getMicroserviceName(),
+ *         invocation.getMicroserviceVersionRule());
+ *     if (endpointsVersionedCache.isEmpty()) {
+ *       // 404 not found logic
+ *       ......
+ *       return;
+ *     }
+ *
+ *     // result is endpoints or something else, which is depends on your filter set
+ *     List<Endpoint> endpoints = endpointsVersionedCache.data();
+ *
+ */ +public class DiscoveryTree { + private static final Logger LOGGER = LoggerFactory.getLogger(DiscoveryTree.class); + + private final Map> root = new ConcurrentHashMapEx<>(); + + private final Object lock = new Object(); + + private List filters = Collections.emptyList(); + + private final DiscoveryManager discoveryManager; + + public DiscoveryTree(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Autowired + public void setDiscoveryFilters(List filters) { + this.filters = filters; + log(); + } + + private void log() { + StringBuilder sb = new StringBuilder(); + sb.append("DiscoveryFilters(name, enabled, order, group):"); + for (DiscoveryFilter filter : filters) { + sb.append("(").append(filter.getClass().getName()).append(",") + .append(filter.enabled()).append(",").append(filter.getOrder()).append(",") + .append(filter.isGroupingFilter()).append(")"); + } + LOGGER.info(sb.toString()); + } + + boolean isMatch(VersionedCache existing, VersionedCache inputCache) { + return existing != null && existing.isSameVersion(inputCache); + } + + boolean isExpired(VersionedCache existing, VersionedCache inputCache) { + return existing == null || existing.isExpired(inputCache); + } + + public DiscoveryTreeNode discovery(DiscoveryContext context, String appId, String microserviceName) { + VersionedCache instanceVersionedCache = this.discoveryManager.getOrCreateVersionedCache(appId, microserviceName); + + return discovery(appId, microserviceName, context, instanceVersionedCache); + } + + DiscoveryTreeNode discovery(String appId, String microserviceName, DiscoveryContext context, + VersionedCache inputCache) { + DiscoveryTreeNode tmpRoot = getOrCreateRoot(appId, microserviceName, inputCache); + DiscoveryTreeNode parent = tmpRoot.children() + .computeIfAbsent(inputCache.name(), name -> new DiscoveryTreeNode().fromCache(inputCache)); + return doDiscovery(context, parent); + } + + protected DiscoveryTreeNode getOrCreateRoot(String appId, String microserviceName, VersionedCache inputCache) { + DiscoveryTreeNode tmpRoot = root.computeIfAbsent(appId, k -> new ConcurrentHashMapEx<>()).get(microserviceName); + if (isMatch(tmpRoot, inputCache)) { + return tmpRoot; + } + + synchronized (lock) { + if (isExpired(tmpRoot, inputCache)) { + // not initialized or inputCache newer than root, create new root + tmpRoot = new DiscoveryTreeNode().cacheVersion(inputCache.cacheVersion()); + root.get(appId).put(microserviceName, tmpRoot); + return tmpRoot; + } + + if (tmpRoot.isSameVersion(inputCache)) { + // reuse root directly + return tmpRoot; + } + } + + // root newer than inputCache, it's a minimal probability event: + // 1) thread 1, use v1 inputCache, run into getOrCreateRoot, but did not run any code yet, suspend and switch to thread 2 + // 2) thread 2, use v2 inputCache, v2 > v1, create new root + // 3) thread 1 go on, then root is newer than inputCache + // but if create old children in new version root, it's a wrong logic + // so just create a temporary root for the inputCache, DO NOT assign to root + tmpRoot = new DiscoveryTreeNode().cacheVersion(inputCache.cacheVersion()); + root.get(appId).put(microserviceName, tmpRoot); + return tmpRoot; + } + + protected DiscoveryTreeNode doDiscovery(DiscoveryContext context, DiscoveryTreeNode parent) { + for (int idx = 0; idx < filters.size(); ) { + DiscoveryFilter filter = filters.get(idx); + if (!filter.enabled()) { + idx++; + continue; + } + context.setCurrentNode(parent); + + DiscoveryTreeNode child = filter.discovery(context, parent); + if (child == null) { + // impossible, throw exception to help fix bug + throw new ServiceCombException(filter.getClass().getName() + " discovery return null."); + } + + child.level(idx + 1); + if (!filter.isGroupingFilter()) { + child.name(parent.name()); + } + + if (child.isEmpty()) { + // maybe need to rerun some filter + DiscoveryTreeNode rerunNode = context.popRerunFilter(); + if (rerunNode != null) { + parent = rerunNode; + idx = parent.level(); + continue; + } + + // no rerun support, go on even result is empty + // because maybe some filter use other mechanism to create an instance(eg:domain name) + } + + parent = child; + idx++; + } + + return parent; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTreeNode.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTreeNode.java similarity index 96% rename from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTreeNode.java rename to foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTreeNode.java index b764937baff..e0f7c828c10 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTreeNode.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/DiscoveryTreeNode.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.discovery; +package org.apache.servicecomb.registry.discovery; import java.util.Map; @@ -25,7 +25,7 @@ public class DiscoveryTreeNode extends VersionedCache { private volatile boolean childrenInited; - private int level; + private volatile int level; protected Map attributes = new ConcurrentHashMapEx<>(); diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstancePing.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstancePing.java new file mode 100644 index 00000000000..2aa45718194 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstancePing.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.discovery; + +import org.springframework.core.Ordered; + +public interface InstancePing extends Ordered { + boolean ping(StatefulDiscoveryInstance instance); +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstanceStatusDiscoveryFilter.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstanceStatusDiscoveryFilter.java new file mode 100644 index 00000000000..e7a4029bdeb --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/InstanceStatusDiscoveryFilter.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.HistoryStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.IsolationStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.PingStatus; + +public class InstanceStatusDiscoveryFilter extends AbstractGroupDiscoveryFilter { + public static final String PARAMETER = "status_level"; + + public static final String GROUP_PREFIX = "status_group_"; + + public static final String GROUP_SIZE = "status_group_size"; + + public static final String SERVICECOMB_LOADBALANCE_FILTER_STATUS_ENABLED = "servicecomb.loadbalance.filter.status.enabled"; + + @Override + public int getOrder() { + return -10000; + } + + @Override + public boolean enabled() { + + if (enabled == null) { + enabled = dynamicProperties.getBooleanProperty(SERVICECOMB_LOADBALANCE_FILTER_STATUS_ENABLED, + value -> enabled = value, + true); + } + return enabled; + } + + @Override + protected String groupsSizeParameter() { + return GROUP_SIZE; + } + + @Override + protected String contextParameter() { + return PARAMETER; + } + + @Override + protected String groupPrefix() { + return GROUP_PREFIX; + } + + @Override + public void init(DiscoveryContext context, DiscoveryTreeNode parent) { + List instances = parent.data(); + List level0 = new ArrayList<>(); + List level1 = new ArrayList<>(); + List level2 = new ArrayList<>(); + List level3 = new ArrayList<>(); + + int groups = 1; + + for (StatefulDiscoveryInstance instance : instances) { + if (HistoryStatus.CURRENT == instance.getHistoryStatus() && + MicroserviceInstanceStatus.UP == instance.getStatus() && + PingStatus.OK == instance.getPingStatus() && + IsolationStatus.NORMAL == instance.getIsolationStatus()) { + level0.add(instance); + continue; + } + if (HistoryStatus.CURRENT == instance.getHistoryStatus() && + MicroserviceInstanceStatus.UP == instance.getStatus() && + PingStatus.UNKNOWN == instance.getPingStatus() && + IsolationStatus.NORMAL == instance.getIsolationStatus()) { + level1.add(instance); + continue; + } + if (HistoryStatus.HISTORY == instance.getHistoryStatus() && + MicroserviceInstanceStatus.UP == instance.getStatus() && + PingStatus.OK == instance.getPingStatus() && + IsolationStatus.NORMAL == instance.getIsolationStatus()) { + level2.add(instance); + continue; + } + level3.add(instance); + } + + if (!level0.isEmpty()) { + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(level0)); + groups++; + } + if (!level1.isEmpty()) { + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(level1)); + groups++; + } + if (!level2.isEmpty()) { + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(level2)); + groups++; + } + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(level3)); + + parent.attribute(GROUP_SIZE, groups); + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/MicroserviceInstanceCache.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/MicroserviceInstanceCache.java new file mode 100644 index 00000000000..4990b3d8f90 --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/MicroserviceInstanceCache.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.util.concurrent.UncheckedExecutionException; + +/** + * 在公钥认证场景,需要查询对端的实例信息。 + * + * 微服务实例缓存 key 为:serviceId@instanceId 缓存limit:1000 缓存老化策略:30分钟没有访问就过期。 + * + */ +public class MicroserviceInstanceCache { + + private static final Logger logger = LoggerFactory.getLogger(MicroserviceInstanceCache.class); + + private static final Cache instances = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterAccess(30, TimeUnit.MINUTES) + .build(); + + private final DiscoveryManager discoveryManager; + + public MicroserviceInstanceCache(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + public DiscoveryInstance getOrCreate(String application, String serviceName) { + try { + String key = String.format("%s@%s", application, serviceName); + return instances.get(key, () -> { + VersionedCache instances = discoveryManager.getOrCreateVersionedCache(application, serviceName); + List statefulDiscoveryInstances = instances.data(); + if (CollectionUtils.isEmpty(statefulDiscoveryInstances)) { + throw new IllegalArgumentException("instance id not exists."); + } + return statefulDiscoveryInstances.get(0); + }); + } catch (ExecutionException | UncheckedExecutionException e) { + logger.error("get microservice instance from cache failed, {}, {}", + String.format("%s@%s", application, serviceName), + e.getMessage()); + return null; + } + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/StatefulDiscoveryInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/StatefulDiscoveryInstance.java new file mode 100644 index 00000000000..394b2b03ccc --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/StatefulDiscoveryInstance.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.discovery; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; + +/** + * Wrapper class for DiscoveryInstance with states like: isolation, health, metrics and so on. + */ +public class StatefulDiscoveryInstance extends AbstractDiscoveryInstance { + public enum IsolationStatus { + NORMAL, + ISOLATED + } + + public enum PingStatus { + UNKNOWN, + OK, + FAIL + } + + public enum HistoryStatus { + CURRENT, + HISTORY + } + + private final DiscoveryInstance discoveryInstance; + + private IsolationStatus isolationStatus = IsolationStatus.NORMAL; + + private long isolatedTime; + + private long isolateDuration; + + private PingStatus pingStatus = PingStatus.UNKNOWN; + + private long pingTime = System.currentTimeMillis(); + + private HistoryStatus historyStatus = HistoryStatus.CURRENT; + + public StatefulDiscoveryInstance(DiscoveryInstance discoveryInstance) { + this.discoveryInstance = discoveryInstance; + } + + public IsolationStatus getIsolationStatus() { + return isolationStatus; + } + + public void setIsolationStatus( + IsolationStatus isolationStatus) { + this.isolationStatus = isolationStatus; + } + + public PingStatus getPingStatus() { + return pingStatus; + } + + public void setPingStatus(PingStatus pingStatus) { + this.pingStatus = pingStatus; + } + + public HistoryStatus getHistoryStatus() { + return historyStatus; + } + + public void setHistoryStatus(HistoryStatus historyStatus) { + this.historyStatus = historyStatus; + } + + public long getIsolatedTime() { + return isolatedTime; + } + + public void setIsolatedTime(long isolatedTime) { + this.isolatedTime = isolatedTime; + } + + public long getIsolateDuration() { + return isolateDuration; + } + + public void setIsolateDuration(long isolateDuration) { + this.isolateDuration = isolateDuration; + } + + public long getPingTime() { + return pingTime; + } + + public void setPingTime(long pingTime) { + this.pingTime = pingTime; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return this.discoveryInstance.getStatus(); + } + + @Override + public String getRegistryName() { + return this.discoveryInstance.getRegistryName(); + } + + @Override + public String getEnvironment() { + return this.discoveryInstance.getEnvironment(); + } + + @Override + public String getApplication() { + return this.discoveryInstance.getApplication(); + } + + @Override + public String getServiceName() { + return this.discoveryInstance.getServiceName(); + } + + @Override + public String getAlias() { + return this.discoveryInstance.getAlias(); + } + + @Override + public String getVersion() { + return this.discoveryInstance.getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return this.discoveryInstance.getDataCenterInfo(); + } + + @Override + public String getDescription() { + return this.discoveryInstance.getDescription(); + } + + @Override + public Map getProperties() { + return this.discoveryInstance.getProperties(); + } + + @Override + public Map getSchemas() { + return this.discoveryInstance.getSchemas(); + } + + @Override + public List getEndpoints() { + return this.discoveryInstance.getEndpoints(); + } + + @Override + public String getInstanceId() { + return this.discoveryInstance.getInstanceId(); + } + + @Override + public String getServiceId() { + return this.discoveryInstance.getServiceId(); + } +} diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/TelnetInstancePing.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/TelnetInstancePing.java new file mode 100644 index 00000000000..07967579a3b --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/discovery/TelnetInstancePing.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.discovery; + +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.apache.servicecomb.foundation.common.net.IpPort; +import org.apache.servicecomb.foundation.common.net.NetUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +public class TelnetInstancePing implements InstancePing { + private static final Logger LOGGER = LoggerFactory.getLogger(TelnetInstancePing.class); + + @Override + public boolean ping(StatefulDiscoveryInstance instance) { + if (CollectionUtils.isEmpty(instance.getEndpoints())) { + return false; + } + + for (String endpoint : instance.getEndpoints()) { + IpPort ipPort = NetUtils.parseIpPortFromURI(endpoint); + try (Socket s = new Socket()) { + s.connect(new InetSocketAddress(ipPort.getHostOrIp(), ipPort.getPort()), 3000); + return true; + } catch (Exception e) { + LOGGER.warn("ping instance {}/{}/{}/{} endpoint {} failed", + instance.getApplication(), + instance.getServiceName(), + instance.getRegistryName(), + instance.getInstanceId(), endpoint); + } + } + + return false; + } + + @Override + public int getOrder() { + return 10000; + } +} diff --git a/foundations/foundation-registry/src/main/resources/META-INF/services/org.apache.servicecomb.registry.consumer.MicroserviceInstancePing b/foundations/foundation-registry/src/main/resources/META-INF/services/org.apache.servicecomb.registry.consumer.MicroserviceInstancePing new file mode 100644 index 00000000000..56169c4507c --- /dev/null +++ b/foundations/foundation-registry/src/main/resources/META-INF/services/org.apache.servicecomb.registry.consumer.MicroserviceInstancePing @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.registry.consumer.SimpleMicroserviceInstancePing diff --git a/foundations/foundation-registry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/foundations/foundation-registry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..8296569485a --- /dev/null +++ b/foundations/foundation-registry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.RegistryConfiguration diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/TestDiscoveryManager.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/TestDiscoveryManager.java new file mode 100644 index 00000000000..bd50cc85748 --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/TestDiscoveryManager.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.HistoryStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.IsolationStatus; +import org.apache.servicecomb.registry.discovery.TelnetInstancePing; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestDiscoveryManager { + + @Test + public void test_initial_service_list_correct() { + MyDiscovery discovery1 = Mockito.spy(new MyDiscovery()); + MyDiscoveryInstance instance1 = Mockito.mock(MyDiscoveryInstance.class); + DiscoveryManager discoveryManager = new DiscoveryManager(List.of(discovery1), List.of(new TelnetInstancePing())); + Mockito.when(discovery1.findServiceInstances("app", "service")) + .thenReturn(List.of(instance1)); + Mockito.when(instance1.getInstanceId()).thenReturn("instance1"); + //first read + VersionedCache versionedCache = discoveryManager.getOrCreateVersionedCache("app", "service"); + List result = versionedCache.data(); + Assertions.assertEquals(1, result.size()); + Assertions.assertEquals("instance1", result.get(0).getInstanceId()); + Assertions.assertEquals(HistoryStatus.CURRENT, result.get(0).getHistoryStatus()); + // second read + versionedCache = discoveryManager.getOrCreateVersionedCache("app", "service"); + result = versionedCache.data(); + Assertions.assertEquals(1, result.size()); + Assertions.assertEquals("instance1", result.get(0).getInstanceId()); + Assertions.assertEquals(HistoryStatus.CURRENT, result.get(0).getHistoryStatus()); + } + + @Test + public void test_initial_empty_service_list_correct() { + MyDiscovery discovery1 = Mockito.spy(new MyDiscovery()); + DiscoveryManager discoveryManager = new DiscoveryManager(List.of(discovery1), List.of(new TelnetInstancePing())); + Mockito.when(discovery1.findServiceInstances("app", "service")) + .thenReturn(Collections.emptyList()); + //first read + VersionedCache versionedCache = discoveryManager.getOrCreateVersionedCache("app", "service"); + List result = versionedCache.data(); + Assertions.assertEquals(0, result.size()); + // second read + discoveryManager.getOrCreateVersionedCache("app", "service"); + result = versionedCache.data(); + Assertions.assertEquals(0, result.size()); + } + + @Test + public void test_isolate_service_instance_correct() { + MyDiscovery discovery1 = Mockito.spy(new MyDiscovery()); + MyDiscoveryInstance instance1 = Mockito.mock(MyDiscoveryInstance.class); + DiscoveryManager discoveryManager = new DiscoveryManager(List.of(discovery1), List.of(new TelnetInstancePing())); + Mockito.when(discovery1.findServiceInstances("app", "service")) + .thenReturn(List.of(instance1)); + Mockito.when(instance1.getInstanceId()).thenReturn("instance1"); + Mockito.when(instance1.getApplication()).thenReturn("app"); + Mockito.when(instance1.getServiceName()).thenReturn("service"); + + VersionedCache versionedCache = discoveryManager.getOrCreateVersionedCache("app", "service"); + List result = versionedCache.data(); + discoveryManager.onInstanceIsolated(result.get(0), 10000L); + versionedCache = discoveryManager.getOrCreateVersionedCache("app", "service"); + result = versionedCache.data(); + Assertions.assertEquals(1, result.size()); + Assertions.assertEquals("instance1", result.get(0).getInstanceId()); + Assertions.assertEquals(HistoryStatus.CURRENT, result.get(0).getHistoryStatus()); + Assertions.assertEquals(IsolationStatus.ISOLATED, result.get(0).getIsolationStatus()); + } + + static class MyDiscovery implements Discovery { + + @Override + public String name() { + return "my"; + } + + @Override + public boolean enabled(String application, String serviceName) { + return true; + } + + @Override + public List findServiceInstances(String application, String serviceName) { + return null; + } + + @Override + public List findServices(String application) { + return null; + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + + } + + @Override + public void init() { + + } + + @Override + public void run() { + + } + + @Override + public void destroy() { + + } + + @Override + public boolean enabled() { + return true; + } + } + + static class MyDiscoveryInstance extends AbstractDiscoveryInstance { + @Override + public MicroserviceInstanceStatus getStatus() { + return null; + } + + @Override + public String getRegistryName() { + return null; + } + + @Override + public String getEnvironment() { + return null; + } + + @Override + public String getApplication() { + return null; + } + + @Override + public String getServiceName() { + return null; + } + + @Override + public String getAlias() { + return null; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return null; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public Map getProperties() { + return null; + } + + @Override + public Map getSchemas() { + return null; + } + + @Override + public List getEndpoints() { + return null; + } + + @Override + public String getInstanceId() { + return null; + } + } +} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractDiscoveryFilter.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractDiscoveryFilter.java similarity index 79% rename from service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractDiscoveryFilter.java rename to foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractDiscoveryFilter.java index cc0a2d91caa..987ec0a0be1 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractDiscoveryFilter.java +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractDiscoveryFilter.java @@ -15,10 +15,10 @@ * limitations under the License. */ -package org.apache.servicecomb.serviceregistry.discovery; +package org.apache.servicecomb.registry.discovery; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestAbstractDiscoveryFilter { int initCallCount; @@ -68,20 +68,19 @@ private void doDiscovery() { public void discoveryInited() { doDiscovery(); - Assert.assertEquals(1, childrenInitedCallCount); - Assert.assertEquals(0, initCallCount); - Assert.assertSame(child, result); + Assertions.assertEquals(1, childrenInitedCallCount); + Assertions.assertEquals(0, initCallCount); + Assertions.assertSame(child, result); } - @Test public void discoveryNotInitedOnce() { inited[0] = false; doDiscovery(); - Assert.assertEquals(2, childrenInitedCallCount); - Assert.assertEquals(0, initCallCount); - Assert.assertSame(child, result); + Assertions.assertEquals(2, childrenInitedCallCount); + Assertions.assertEquals(0, initCallCount); + Assertions.assertSame(child, result); } @Test @@ -90,8 +89,8 @@ public void discoveryNotInitedTwice() { inited[1] = false; doDiscovery(); - Assert.assertEquals(2, childrenInitedCallCount); - Assert.assertEquals(1, initCallCount); - Assert.assertSame(child, result); + Assertions.assertEquals(2, childrenInitedCallCount); + Assertions.assertEquals(1, initCallCount); + Assertions.assertSame(child, result); } } diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractTransportDiscoveryFilter.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractTransportDiscoveryFilter.java new file mode 100644 index 00000000000..4a0c04140e4 --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestAbstractTransportDiscoveryFilter.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestAbstractTransportDiscoveryFilter { + class AbstractEndpointDiscoveryFilterForTest extends AbstractEndpointDiscoveryFilter { + @Override + public int getOrder() { + return 0; + } + + @Override + protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { + return transportName; + } + + @Override + protected Object createEndpoint(DiscoveryContext context, String transportName, String endpoint, + StatefulDiscoveryInstance instance) { + if (disableCreate) { + return null; + } + + return endpoint; + } + } + + boolean disableCreate; + + String transportName; + + AbstractEndpointDiscoveryFilterForTest filter = new AbstractEndpointDiscoveryFilterForTest(); + + DiscoveryContext context = new DiscoveryContext(); + + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent"); + + DiscoveryTreeNode result; + + @Test + public void isGroupingFilter() { + Assertions.assertTrue(filter.isGroupingFilter()); + } + + @Test + public void isTransportNameMatch_expectAll() { + Assertions.assertTrue(filter.isTransportNameMatch("any", "")); + } + + @Test + public void isTransportNameMatch_equals() { + Assertions.assertTrue(filter.isTransportNameMatch("rest", "rest")); + } + + @Test + public void isTransportNameMatch_notEquals() { + Assertions.assertFalse(filter.isTransportNameMatch("rest", "highway")); + } + + @Test + public void discoveryNotExist() { + transportName = "notExist"; + parent.data(Collections.emptyList()); + result = filter.discovery(context, parent); + + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void discoveryExist() { + transportName = "rest"; + DiscoveryTreeNode child = new DiscoveryTreeNode(); + parent.child(transportName, child); + result = filter.discovery(context, parent); + + Assertions.assertSame(child, result); + } + + private StatefulDiscoveryInstance createInstance(String... schemas) { + String id = UUID.randomUUID().toString(); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance = new StatefulDiscoveryInstance(discoveryInstance); + List endpoints = new ArrayList<>(); + for (int idx = 0; idx < schemas.length; idx++) { + String schema = schemas[idx]; + endpoints.add(String.format("%s://%s:%d", schema, id, 8080 + idx)); + } + Mockito.when(discoveryInstance.getInstanceId()).thenReturn(id); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(endpoints); + return instance; + } + + private List createMicroserviceInstances(StatefulDiscoveryInstance... instances) { + List result = new ArrayList<>(); + for (StatefulDiscoveryInstance instance : instances) { + result.add(instance); + } + return result; + } + + @Test + public void createDiscoveryTree_oneTransport() { + StatefulDiscoveryInstance instance1 = createInstance("a", "b"); + StatefulDiscoveryInstance instance2 = createInstance("b"); + List instances = createMicroserviceInstances(instance1, instance2); + parent.data(instances); + + result = filter.createDiscoveryTreeNode("a", context, parent); + + Assertions.assertEquals("parent/a", result.name()); + MatcherAssert.assertThat(result.collectionData(), + Matchers.contains(instance1.getEndpoints().get(0))); + } + + @Test + public void createDiscoveryTree_allTransport() { + StatefulDiscoveryInstance instance1 = createInstance("a", "b"); + StatefulDiscoveryInstance instance2 = createInstance("b"); + List instances = createMicroserviceInstances(instance1, instance2); + parent.data(instances); + + result = filter.createDiscoveryTreeNode("", context, parent); + + Assertions.assertEquals("parent/", result.name()); + + List expect = new ArrayList<>(); + expect.addAll(instance1.getEndpoints()); + expect.addAll(instance2.getEndpoints()); + MatcherAssert.assertThat(result.collectionData(), Matchers.contains(expect.toArray())); + } + + @Test + public void createDiscoveryTree_ignoreInvalid() { + StatefulDiscoveryInstance instance1 = createInstance("a", "b"); + StatefulDiscoveryInstance instance2 = createInstance(""); + List instances = createMicroserviceInstances(instance1, instance2); + parent.data(instances); + + result = filter.createDiscoveryTreeNode("", context, parent); + + Assertions.assertEquals("parent/", result.name()); + MatcherAssert.assertThat(result.collectionData(), + Matchers.contains(instance1.getEndpoints().toArray())); + } + + @Test + public void createEndpointNull() { + disableCreate = true; + StatefulDiscoveryInstance instance1 = createInstance("a", "b"); + List instances = createMicroserviceInstances(instance1); + parent.data(instances); + + result = filter.createDiscoveryTreeNode("", context, parent); + + Assertions.assertEquals("parent/", result.name()); + MatcherAssert.assertThat(result.collectionData(), Matchers.empty()); + } +} diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryContext.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryContext.java new file mode 100644 index 00000000000..53c9d026c6f --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryContext.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestDiscoveryContext { + DiscoveryContext context = new DiscoveryContext(); + + @Test + public void inputParameters() { + Object inputParameters = new Object(); + context.setInputParameters(inputParameters); + + Assertions.assertSame(inputParameters, context.getInputParameters()); + } + + @Test + public void contextParameters() { + String name = "name"; + Object value = new Object(); + context.putContextParameter(name, value); + + Assertions.assertSame(value, context.getContextParameter(name)); + Assertions.assertNull(context.getContextParameter("notExist")); + } + + @Test + public void rerun() { + Assertions.assertNull(context.popRerunFilter()); + + DiscoveryTreeNode node = new DiscoveryTreeNode(); + context.setCurrentNode(node); + context.pushRerunFilter(); + + Assertions.assertSame(node, context.popRerunFilter()); + Assertions.assertNull(context.popRerunFilter()); + } +} diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTree.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTree.java new file mode 100644 index 00000000000..d726d1b59c0 --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTree.java @@ -0,0 +1,279 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.config.DynamicProperties; +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestDiscoveryTree { + DiscoveryContext context = new DiscoveryContext(); + + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent"); + + DiscoveryTreeNode result; + + @BeforeEach + public void before() { + + } + + @AfterEach + public void tearDown() { + } + + @Test + public void isMatch_existingNull() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + Assertions.assertFalse(discoveryTree.isMatch(null, null)); + } + + @Test + public void isMatch_yes() { + DiscoveryTree discoveryTree = new DiscoveryTree(new DiscoveryManager(Collections.emptyList(), + List.of(new TelnetInstancePing()))); + parent.cacheVersion(1); + Assertions.assertTrue(discoveryTree.isMatch(new DiscoveryTreeNode().cacheVersion(1), parent)); + } + + @Test + public void isMatch_no() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + parent.cacheVersion(0); + Assertions.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(1), parent)); + } + + @Test + public void isExpired_existingNull() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + Assertions.assertTrue(discoveryTree.isExpired(null, null)); + } + + @Test + public void isExpired_yes() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + parent.cacheVersion(1); + Assertions.assertTrue(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent)); + } + + @Test + public void isExpired_no() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + parent.cacheVersion(0); + Assertions.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent)); + } + + static class DiscoveryFilterForTest implements DiscoveryFilter { + protected String groupName; + + public DiscoveryFilterForTest(String groupName) { + this.groupName = groupName; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isGroupingFilter() { + return groupName != null; + } + + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + DiscoveryTreeNode child = new DiscoveryTreeNode(); + if (groupName != null) { + child.subName(parent, groupName); + } + return child; + } + } + + @Test + public void filterNormal() { + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + parent.name("1.0.0-2.0.0"); + + discoveryTree.setDiscoveryFilters(Arrays.asList(new DiscoveryFilterForTest("g1"), + new DiscoveryFilterForTest(null), new DiscoveryFilterForTest("g2"), + new DiscoveryFilterForTest(null))); + result = discoveryTree.discovery("app", "service", context, parent); + + Assertions.assertEquals("1.0.0-2.0.0/g1/g2", result.name()); + } + + @Test + public void easyDiscovery() { + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + Mockito.when(discoveryManager.getOrCreateVersionedCache("app", "svc")).thenReturn(parent); + + result = discoveryTree.discovery(context, "app", "svc"); + Assertions.assertEquals(parent.name(), result.name()); + Assertions.assertEquals(parent.cacheVersion(), result.cacheVersion()); + } + + @Test + public void discovery_filterReturnNull() { + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("app", "service")).thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + DiscoveryFilter filter = new DiscoveryFilter() { + @Override + public int getOrder() { + return 0; + } + + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + return null; + } + }; + discoveryTree.setDiscoveryFilters(Arrays.asList(filter)); + + ServiceCombException exception = Assertions.assertThrows(ServiceCombException.class, + () -> result = discoveryTree.discovery(context, "app", "service")); + Assertions.assertEquals(filter.getClass().getName() + " discovery return null.", exception.getMessage()); + } + + @Test + public void filterRerun() { + parent.name("1.0.0-2.0.0"); + + DiscoveryFilterForTest f1 = new DiscoveryFilterForTest("g1") { + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + if (context.getContextParameter("step") == null) { + context.pushRerunFilter(); + context.putContextParameter("step", 1); + return new DiscoveryTreeNode().name(groupName).data("first"); + } + + return new DiscoveryTreeNode().name(groupName).data("second"); + } + }; + DiscoveryFilterForTest f2 = new DiscoveryFilterForTest(null) { + @Override + public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { + if ("first".equals(parent.data())) { + return new DiscoveryTreeNode(); + } + + return new DiscoveryTreeNode().data(parent.data()); + } + }; + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + discoveryTree.setDiscoveryFilters(Arrays.asList(f1, f2)); + result = discoveryTree.discovery("app", "service", context, parent); + + Assertions.assertEquals("second", result.data()); + } + + @Test + @SuppressWarnings("unchecked") + public void test_multi_service_discovery_correct() { + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + DiscoveryContext discoveryContext = new DiscoveryContext(); + + List service1 = Arrays.asList("s11", "s12"); + Mockito.when(discoveryManager.getOrCreateVersionedCache("app", "service1")) + .thenReturn(new VersionedCache().name("0+").data(service1)); + DiscoveryTreeNode result = discoveryTree.discovery(discoveryContext, "app", "service1"); + Assertions.assertArrayEquals(service1.toArray(new String[0]), + ((List) result.data()).toArray(new String[0])); + + List service2 = Arrays.asList("s21", "s22"); + Mockito.when(discoveryManager.getOrCreateVersionedCache("app", "service2")) + .thenReturn(new VersionedCache().name("0+").data(service2)); + result = discoveryTree.discovery(discoveryContext, "app", "service2"); + Assertions.assertArrayEquals(service2.toArray(new String[0]), + ((List) result.data()).toArray(new String[0])); + + result = discoveryTree.discovery(discoveryContext, "app", "service1"); + Assertions.assertArrayEquals(service1.toArray(new String[0]), + ((List) result.data()).toArray(new String[0])); + } + + @Test + @SuppressWarnings("unchecked") + public void test_one_service_concurrent_correct() throws Exception { + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + DiscoveryContext discoveryContext = new DiscoveryContext(); + InstanceStatusDiscoveryFilter filter = new InstanceStatusDiscoveryFilter(); + DynamicProperties dynamicProperties = Mockito.mock(DynamicProperties.class); + Mockito.when(dynamicProperties.getBooleanProperty(Mockito.eq("servicecomb.loadbalance.filter.status.enabled"), + Mockito.any(), + Mockito.eq(true))) + .thenReturn(true); + filter.setDynamicProperties(dynamicProperties); + discoveryTree.setDiscoveryFilters(List.of(filter)); + + StatefulDiscoveryInstance instance1 = Mockito.mock(StatefulDiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = Mockito.mock(StatefulDiscoveryInstance.class); + + VersionedCache expects0 = new VersionedCache().autoCacheVersion().name("0+") + .data(Arrays.asList(instance1, instance2)); + VersionedCache[] expects999 = new VersionedCache[999]; + for (int i = 0; i < 999; i++) { + expects999[i] = new VersionedCache().name("0+") + .data(Arrays.asList(instance1, instance2)).cacheVersion(i + 1); + } + Mockito.when(discoveryManager.getOrCreateVersionedCache("app", "service1")) + .thenReturn(expects0, expects999); + + CountDownLatch countDownLatch = new CountDownLatch(1000); + AtomicInteger success = new AtomicInteger(0); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + for (int j = 0; j < 100; j++) { + DiscoveryTreeNode result = discoveryTree.discovery(discoveryContext, "app", "service1"); + if (((List) result.data()).size() == 2) { + success.getAndIncrement(); + } + countDownLatch.countDown(); + } + }).start(); + } + + countDownLatch.await(3000, TimeUnit.MILLISECONDS); + Assertions.assertEquals(1000, success.get()); + } +} diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTreeNode.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTreeNode.java new file mode 100644 index 00000000000..0dcd4ff99ac --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestDiscoveryTreeNode.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.discovery; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestDiscoveryTreeNode { + DiscoveryTreeNode node = new DiscoveryTreeNode(); + + @Test + public void childrenInited() { + Assertions.assertFalse(node.childrenInited()); + + node.childrenInited(true); + Assertions.assertTrue(node.childrenInited()); + } + + @Test + public void level() { + node.level(1); + + Assertions.assertEquals(1, node.level()); + } + + @Test + public void attribute() { + node.attribute("k1", "v1"); + + Assertions.assertEquals("v1", node.attribute("k1")); + } + + @Test + public void children() { + Map children = new HashMap<>(); + node.children(children); + + Assertions.assertSame(children, node.children()); + } + + @Test + public void child() { + DiscoveryTreeNode child = new DiscoveryTreeNode().name("child"); + node.child(child.name(), child); + + Assertions.assertSame(child, node.child(child.name())); + } + + @Test + public void fromCache() { + Object data = new Object(); + VersionedCache other = new VersionedCache().cacheVersion(1).name("cache").data(data); + node.fromCache(other); + + Assertions.assertEquals(1, node.cacheVersion()); + Assertions.assertEquals("cache", node.name()); + Assertions.assertSame(data, node.data()); + } +} diff --git a/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestInstanceStatusDiscoveryFilter.java b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestInstanceStatusDiscoveryFilter.java new file mode 100644 index 00000000000..8e7307098b9 --- /dev/null +++ b/foundations/foundation-registry/src/test/java/org/apache/servicecomb/registry/discovery/TestInstanceStatusDiscoveryFilter.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.discovery; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.HistoryStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.IsolationStatus; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance.PingStatus; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestInstanceStatusDiscoveryFilter { + @Test + public void test_all_group_correct_init() { + InstanceStatusDiscoveryFilter filter = new InstanceStatusDiscoveryFilter(); + DiscoveryTreeNode parent = new DiscoveryTreeNode(); + List instances = new ArrayList<>(); + StatefulDiscoveryInstance instance1 = Mockito.mock(StatefulDiscoveryInstance.class); + Mockito.when(instance1.getHistoryStatus()).thenReturn(HistoryStatus.CURRENT); + Mockito.when(instance1.getStatus()).thenReturn(MicroserviceInstanceStatus.UP); + Mockito.when(instance1.getPingStatus()).thenReturn(PingStatus.OK); + Mockito.when(instance1.getIsolationStatus()).thenReturn(IsolationStatus.NORMAL); + StatefulDiscoveryInstance instance2 = Mockito.mock(StatefulDiscoveryInstance.class); + Mockito.when(instance2.getHistoryStatus()).thenReturn(HistoryStatus.CURRENT); + Mockito.when(instance2.getStatus()).thenReturn(MicroserviceInstanceStatus.UP); + Mockito.when(instance2.getPingStatus()).thenReturn(PingStatus.UNKNOWN); + Mockito.when(instance2.getIsolationStatus()).thenReturn(IsolationStatus.NORMAL); + StatefulDiscoveryInstance instance3 = Mockito.mock(StatefulDiscoveryInstance.class); + Mockito.when(instance3.getHistoryStatus()).thenReturn(HistoryStatus.HISTORY); + Mockito.when(instance3.getStatus()).thenReturn(MicroserviceInstanceStatus.UP); + Mockito.when(instance3.getPingStatus()).thenReturn(PingStatus.OK); + Mockito.when(instance3.getIsolationStatus()).thenReturn(IsolationStatus.NORMAL); + StatefulDiscoveryInstance instance4 = Mockito.mock(StatefulDiscoveryInstance.class); + Mockito.when(instance4.getHistoryStatus()).thenReturn(HistoryStatus.CURRENT); + Mockito.when(instance4.getStatus()).thenReturn(MicroserviceInstanceStatus.UP); + Mockito.when(instance4.getPingStatus()).thenReturn(PingStatus.FAIL); + Mockito.when(instance4.getIsolationStatus()).thenReturn(IsolationStatus.NORMAL); + instances.addAll(Arrays.asList(instance1, instance2, instance3, instance4)); + + parent.name("parent"); + parent.data(instances); + filter.init(new DiscoveryContext(), parent); + + List level0 = parent + .child(InstanceStatusDiscoveryFilter.GROUP_PREFIX + 1) + .data(); + Assertions.assertEquals(1, level0.size()); + List level1 = parent + .child(InstanceStatusDiscoveryFilter.GROUP_PREFIX + 2) + .data(); + Assertions.assertEquals(1, level1.size()); + Assertions.assertEquals(1, level1.size()); + List level2 = parent + .child(InstanceStatusDiscoveryFilter.GROUP_PREFIX + 3) + .data(); + Assertions.assertEquals(1, level2.size()); + List level3 = parent + .child(InstanceStatusDiscoveryFilter.GROUP_PREFIX + 4) + .data(); + Assertions.assertEquals(1, level3.size()); + + Assertions.assertEquals(null, parent + .child(InstanceStatusDiscoveryFilter.GROUP_PREFIX + 5)); + } +} diff --git a/foundations/foundation-registry/src/test/resources/log4j2.xml b/foundations/foundation-registry/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..3125ebd11e4 --- /dev/null +++ b/foundations/foundation-registry/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/foundations/foundation-spi/pom.xml b/foundations/foundation-spi/pom.xml new file mode 100644 index 00000000000..aa38214b3ee --- /dev/null +++ b/foundations/foundation-spi/pom.xml @@ -0,0 +1,44 @@ + + + + 4.0.0 + + org.apache.servicecomb + foundations + 3.4.0-SNAPSHOT + + foundation-spi + Java Chassis::Foundations::SSL + + + + org.slf4j + slf4j-api + + + org.springframework + spring-core + + + org.jmockit + jmockit + test + + + diff --git a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderLoader.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderLoader.java new file mode 100644 index 00000000000..668e77faa38 --- /dev/null +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderLoader.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.auth; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; + +public class AuthHeaderLoader { + private final List authHeaderProviders = + SPIServiceUtils.getSortedService(AuthHeaderProvider.class); + + private static final AuthHeaderLoader INSTANCE = new AuthHeaderLoader(); + + private AuthHeaderLoader() { + + } + + public static AuthHeaderLoader getInstance() { + return INSTANCE; + } + + public Map loadAuthHeaders(SignRequest signRequest) { + Map result = new HashMap<>(); + authHeaderProviders.forEach(provider -> result.putAll(provider.getSignAuthHeaders(signRequest))); + return result; + } +} diff --git a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java new file mode 100644 index 00000000000..0e036e21a58 --- /dev/null +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/AuthHeaderProvider.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.auth; + +import java.util.HashMap; +import java.util.Map; + +public interface AuthHeaderProvider { + /** + * Obtain RBAC authentication request header, host is the key of cache + * + * @param host engine address ip + * @return auth headers + */ + default Map authHeaders(String host) { + return new HashMap<>(0); + } + + default Map getSignAuthHeaders(SignRequest request) { + String host = ""; + if (request != null && request.getEndpoint() != null) { + host = request.getEndpoint().getHost(); + } + return authHeaders(host); + } +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java similarity index 96% rename from foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java rename to foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java index 116d5570f58..a41aaf571b5 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/auth/SignRequest.java @@ -37,7 +37,7 @@ public class SignRequest { /** * Map of the headers included in this request */ - private Map headers = new HashMap<>(); + private final Map headers = new HashMap<>(); /** * The service endpoint to which this request should be sent @@ -58,7 +58,7 @@ public class SignRequest { * The datetime in milliseconds for which the signature needs to be * computed. */ - private long signingDateTimeMilli = System.currentTimeMillis(); + private final long signingDateTimeMilli = System.currentTimeMillis(); /** * The scope of the signature. diff --git a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/bootstrap/BootStrapService.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/bootstrap/BootStrapService.java new file mode 100644 index 00000000000..505dac988cb --- /dev/null +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/bootstrap/BootStrapService.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.bootstrap; + +import org.apache.servicecomb.foundation.common.utils.SPIOrder; +import org.springframework.core.env.Environment; + +/** + * A boot strap service is loaded after Spring Environment is created. + * + * In boot strap service, user's can only read configurations from Environment. Dynamic configurations + * + * from config center is not available. + * + * e.g. an authentication service must be connected before connecting to config center. + * e.g. an config center configurations must be read before connecting to config center. + */ +public interface BootStrapService extends SPIOrder { + void startup(Environment environment); +} diff --git a/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIEnabled.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIEnabled.java new file mode 100644 index 00000000000..adab60adf99 --- /dev/null +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIEnabled.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +public interface SPIEnabled { + boolean enabled(); +} diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java similarity index 91% rename from foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java rename to foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java index b9fc016ee17..adaf18de073 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIOrder.java @@ -17,7 +17,9 @@ package org.apache.servicecomb.foundation.common.utils; -public interface SPIOrder { +import org.springframework.core.Ordered; + +public interface SPIOrder extends Ordered { default int getOrder() { return 0; } diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java similarity index 95% rename from foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java rename to foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java index ea8a0bc12ea..abd2dcab32e 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java +++ b/foundations/foundation-spi/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java @@ -76,11 +76,12 @@ public static List loadSortedService(Class serviceType) { .map(Entry::getValue) .collect(Collectors.toList()); - LOGGER.info("Found SPI service {}, count={}.", serviceType.getName(), services.size()); + StringBuilder info = new StringBuilder(); for (int idx = 0; idx < services.size(); idx++) { T service = services.get(idx); - LOGGER.info(" {}. {}.", idx, service.getClass().getName()); + info.append("{").append(idx).append(",").append(service.getClass().getSimpleName()).append("}"); } + LOGGER.info("Found SPI service {}, services={}.", serviceType.getSimpleName(), info); return services; } diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef.java b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef.java similarity index 100% rename from foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef.java rename to foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef.java diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0.java b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0.java similarity index 100% rename from foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0.java rename to foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0.java diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java similarity index 100% rename from foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java rename to foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDefImpl.java b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDefImpl.java similarity index 100% rename from foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDefImpl.java rename to foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDefImpl.java diff --git a/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java new file mode 100644 index 00000000000..040c840718f --- /dev/null +++ b/foundations/foundation-spi/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.common.utils; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnJre; +import org.junit.jupiter.api.condition.JRE; +import org.mockito.Mockito; +import org.springframework.core.Ordered; + +import mockit.Deencapsulation; +import mockit.Expectations; + +/** + * Test SPIServiceUtils + * + * + */ +public class TestSPIServiceUtils { + @Test + public void testGetTargetServiceNull() { + SPIServiceDef0 service = SPIServiceUtils.getTargetService(SPIServiceDef0.class); + Assertions.assertNull(service); + } + + @Test + public void testGetTargetServiceNotNull() { + SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class); + Assertions.assertNotNull(service); + + Assertions.assertSame(service, SPIServiceUtils.getTargetService(SPIServiceDef.class)); + } + + @Test + public void testGetTargetService_special_null() { + Assertions.assertNull(SPIServiceUtils.getTargetService(SPIServiceDef0.class, SPIServiceDef0Impl.class)); + } + + @Test + public void testGetTargetService_special_notNull() { + SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class, SPIServiceDefImpl.class); + Assertions.assertNotNull(service); + } + + @Test + @EnabledOnJre(JRE.JAVA_8) + public void testSort() { + Ordered o1 = Mockito.mock(Ordered.class); + Ordered o2 = Mockito.mock(Ordered.class); + Map map = new LinkedHashMap<>(); + map.put("a", o1); + map.put("b", o2); + + ServiceLoader serviceLoader = ServiceLoader.load(Ordered.class); + Deencapsulation.setField(serviceLoader, "providers", map); + new Expectations(ServiceLoader.class) { + { + o1.getOrder(); + result = -1; + o2.getOrder(); + result = Integer.MAX_VALUE; + ServiceLoader.load(Ordered.class); + result = serviceLoader; + } + }; + + MatcherAssert.assertThat(SPIServiceUtils.getSortedService(Ordered.class), Matchers.contains(o1, o2)); + MatcherAssert.assertThat(SPIServiceUtils.getAllService(Ordered.class), Matchers.contains(o1, o2)); + MatcherAssert.assertThat(SPIServiceUtils.getPriorityHighestService(Ordered.class), Matchers.is(o1)); + + Map, List> cache = Deencapsulation.getField(SPIServiceUtils.class, "cache"); + cache.clear(); + } + + @Test + public void getPriorityHighestService_null() { + Assertions.assertNull(SPIServiceUtils.getPriorityHighestService(SPIServiceDef0.class)); + } + + interface PriorityIntf { + String getName(); + + int getOrder(); + } + + public static class PriorityImpl implements PriorityIntf { + private final String name; + + private final int order; + + public PriorityImpl(String name, int order) { + this.name = name; + this.order = order; + } + + @Override + public String getName() { + return name; + } + + @Override + public int getOrder() { + return order; + } + + @Override + public String toString() { + return "PriorityImpl{" + + "name='" + name + '\'' + + ", order=" + order + + '}'; + } + } + + @Test + @EnabledOnJre(JRE.JAVA_8) + public void getPriorityHighestServices() { + Map instances = new LinkedHashMap<>(); + instances.putIfAbsent("1", new PriorityImpl("n1", 0)); + instances.putIfAbsent("2", new PriorityImpl("n1", -1)); + instances.putIfAbsent("3", new PriorityImpl("n1", 1)); + instances.putIfAbsent("4", new PriorityImpl("n2", 0)); + instances.putIfAbsent("5", new PriorityImpl("n2", -1)); + instances.putIfAbsent("6", new PriorityImpl("n2", 1)); + + ServiceLoader serviceLoader = ServiceLoader.load(PriorityIntf.class); + Deencapsulation.setField(serviceLoader, "providers", instances); + new Expectations(ServiceLoader.class) { + { + ServiceLoader.load(PriorityIntf.class); + result = serviceLoader; + } + }; + + MatcherAssert.assertThat(SPIServiceUtils.getPriorityHighestServices(PriorityIntf::getName, PriorityIntf.class), + Matchers.containsInAnyOrder(instances.get("2"), instances.get("5"))); + + Map, List> cache = Deencapsulation.getField(SPIServiceUtils.class, "cache"); + cache.clear(); + } +} diff --git a/foundations/foundation-common/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef b/foundations/foundation-spi/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef similarity index 99% rename from foundations/foundation-common/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef rename to foundations/foundation-spi/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef index eebf462d01b..7d8b6d492a4 100644 --- a/foundations/foundation-common/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef +++ b/foundations/foundation-spi/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.common.utils.SPIServiceDef @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.foundation.common.utils.SPIServiceDefImpl \ No newline at end of file +org.apache.servicecomb.foundation.common.utils.SPIServiceDefImpl diff --git a/foundations/foundation-ssl/pom.xml b/foundations/foundation-ssl/pom.xml index 5e2f10088df..3cf7cdcb485 100644 --- a/foundations/foundation-ssl/pom.xml +++ b/foundations/foundation-ssl/pom.xml @@ -21,19 +21,19 @@ org.apache.servicecomb foundations - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT foundation-ssl Java Chassis::Foundations::SSL - com.netflix.archaius - archaius-core + org.springframework + spring-context - commons-configuration - commons-configuration + org.apache.commons + commons-lang3 org.slf4j @@ -44,8 +44,13 @@ netty-tcnative-boringssl-static - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core test @@ -53,5 +58,10 @@ foundation-config test + + org.jmockit + jmockit + test + diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/CertificateUtil.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/CertificateUtil.java index 2091adba8c5..8fcf41af10a 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/CertificateUtil.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/CertificateUtil.java @@ -126,7 +126,7 @@ public static Set getCN(X509Certificate cert) { Object key = list.get(0); Object value = list.get(1); if (key instanceof Integer && value instanceof String) { - int intKey = ((Integer) key).intValue(); + int intKey = (Integer) key; String strValue = (String) value; if (intKey == SUBALTNAME_DNSNAME || intKey == SUBALTNAME_IPADDRESS) { names.add(strValue); diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/ClientAuth.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/ClientAuth.java new file mode 100644 index 00000000000..b80d0033ec9 --- /dev/null +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/ClientAuth.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.ssl; + +public final class ClientAuth { + public static final String REQUIRED = "REQUIRED"; + + public static final String REQUEST = "REQUEST"; + + public static final String NONE = "NONE"; +} diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtil.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtil.java index 63aa00ef79c..0666365a2f0 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtil.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtil.java @@ -17,10 +17,12 @@ package org.apache.servicecomb.foundation.ssl; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.security.KeyStore; import java.security.cert.CRL; import java.security.cert.CRLException; @@ -38,25 +40,43 @@ private KeyStoreUtil() { } - public static KeyStore createKeyStore(String storename, String storetype, - char[] storevalue) { - InputStream is = null; + public static KeyStore createKeyStore(String storeName, String storeType, + char[] storeValue) { + if (storeName == null) { + return null; + } + + File storeFile = new File(storeName); + try { - KeyStore keystore = KeyStore.getInstance(storetype); - is = new FileInputStream(storename); - keystore.load(is, storevalue); + if (storeFile.isFile()) { + return createKeyStore(new FileInputStream(storeFile), storeType, storeValue); + } + + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader() == null ? KeyStoreUtil.class.getClassLoader() + : Thread.currentThread().getContextClassLoader(); + URL resource = classLoader.getResource(storeName); + if (resource != null) { + return createKeyStore(resource.openStream(), storeType, storeValue); + } + } catch (IOException e) { + throw new IllegalArgumentException("Bad key store or value." + + e.getMessage()); + } + + return null; + } + + public static KeyStore createKeyStore(InputStream store, String storeType, + char[] storeValue) { + try (InputStream is = store) { + KeyStore keystore = KeyStore.getInstance(storeType); + keystore.load(is, storeValue); return keystore; } catch (Exception e) { throw new IllegalArgumentException("Bad key store or value." + e.getMessage()); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - ignore(); - } - } } } @@ -67,8 +87,7 @@ public static CRL[] createCRL(String crlfile) { CertificateFactory cf = CertificateFactory.getInstance("X.509"); is = new FileInputStream(crlfile); Collection c = cf.generateCRLs(is); - CRL[] crls = (CRL[]) c.toArray(new CRL[c.size()]); - return crls; + return (CRL[]) c.toArray(new CRL[0]); } catch (CertificateException e) { throw new IllegalArgumentException("bad cert file."); } catch (FileNotFoundException e) { @@ -104,8 +123,7 @@ public static TrustManager[] createTrustManagers(final KeyStore keystore) { TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmfactory.init(keystore); - TrustManager[] trustmanagers = tmfactory.getTrustManagers(); - return trustmanagers; + return tmfactory.getTrustManagers(); } catch (Exception e) { throw new IllegalArgumentException("Bad trust store." + e.getMessage()); diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLCustom.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLCustom.java index bec5467927b..4c116649d84 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLCustom.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLCustom.java @@ -45,9 +45,9 @@ public String getFullPath(String filename) { public static SSLCustom createSSLCustom(String name) { try { if (name != null && !name.isEmpty()) { - return (SSLCustom) Class.forName(name).newInstance(); + return (SSLCustom) Class.forName(name).getDeclaredConstructor().newInstance(); } - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + } catch (ReflectiveOperationException e) { LOG.warn("init SSLCustom class failed, name is " + name); } return defaultSSLCustom(); diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLManager.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLManager.java index a50597342b2..b7136f7752e 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLManager.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLManager.java @@ -17,7 +17,6 @@ package org.apache.servicecomb.foundation.ssl; -import java.io.File; import java.io.IOException; import java.net.UnknownHostException; import java.security.KeyManagementException; @@ -35,6 +34,9 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509ExtendedTrustManager; +import org.apache.commons.lang3.StringUtils; + + /** * 根据传递的SSLOption构造SSL上下文。请参考JSSE获取相关API的层次参考。 * @@ -47,29 +49,29 @@ private SSLManager() { public static SSLContext createSSLContext(SSLOption option, SSLCustom custom) { try { String keyStoreName = custom.getFullPath(option.getKeyStore()); - KeyManager[] keymanager; - if (keyStoreName != null && new File(keyStoreName).exists()) { - char[] keyStoreValue = - custom.decode(option.getKeyStoreValue().toCharArray()); - KeyStore keyStore = - KeyStoreUtil.createKeyStore(keyStoreName, - option.getKeyStoreType(), - keyStoreValue); - keymanager = + char[] keyStoreValue = option.getKeyStoreValue() == null ? new char[0] : + custom.decode(option.getKeyStoreValue().toCharArray()); + KeyStore keyStore = + KeyStoreUtil.createKeyStore(keyStoreName, + option.getKeyStoreType(), + keyStoreValue); + + KeyManager[] keyManager = null; + if (keyStore != null) { + keyManager = KeyStoreUtil.createKeyManagers(keyStore, keyStoreValue); - } else { - keymanager = null; } String trustStoreName = custom.getFullPath(option.getTrustStore()); + char[] trustStoreValue = option.getTrustStoreValue() == null ? new char[0] : + custom.decode(option.getTrustStoreValue().toCharArray()); + KeyStore trustStore = + KeyStoreUtil.createKeyStore(trustStoreName, + option.getTrustStoreType(), + trustStoreValue); + TrustManager[] trustManager; - if (trustStoreName != null && new File(trustStoreName).exists()) { - char[] trustStoreValue = - custom.decode(option.getTrustStoreValue().toCharArray()); - KeyStore trustStore = - KeyStoreUtil.createKeyStore(trustStoreName, - option.getTrustStoreType(), - trustStoreValue); + if (trustStore != null) { trustManager = KeyStoreUtil.createTrustManagers(trustStore); } else { @@ -85,7 +87,7 @@ public static SSLContext createSSLContext(SSLOption option, SSLCustom custom) { // ?: ssl context version SSLContext context = SSLContext.getInstance("TLS"); - context.init(keymanager, wrapped, new SecureRandom()); + context.init(keyManager, wrapped, new SecureRandom()); return context; } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("NoSuchAlgorithmException." @@ -100,8 +102,8 @@ public static SSLSocketFactory createSSLSocketFactory(SSLOption option, SSLCusto SSLContext context = createSSLContext(option, custom); SSLSocketFactory factory = context.getSocketFactory(); String[] supported = factory.getSupportedCipherSuites(); - String[] eanbled = option.getCiphers().split(","); - return new SSLSocketFactoryExt(factory, getEnabledCiphers(supported, eanbled), + String[] enabled = option.getCiphers().split(","); + return new SSLSocketFactoryExt(factory, getEnabledCiphers(supported, enabled), option.getProtocols().split(",")); } @@ -111,9 +113,9 @@ public static SSLEngine createSSLEngine(SSLOption option, SSLCustom custom) { context.createSSLEngine(); engine.setEnabledProtocols(option.getProtocols().split(",")); String[] supported = engine.getSupportedCipherSuites(); - String[] eanbled = option.getCiphers().split(","); - engine.setEnabledCipherSuites(getEnabledCiphers(supported, eanbled)); - engine.setNeedClientAuth(option.isAuthPeer()); + String[] enabled = option.getCiphers().split(","); + engine.setEnabledCipherSuites(getEnabledCiphers(supported, enabled)); + setClientAuth(option, engine); return engine; } @@ -123,12 +125,38 @@ public static SSLEngine createSSLEngine(SSLOption option, SSLCustom custom, Stri context.createSSLEngine(peerHost, peerPort); engine.setEnabledProtocols(option.getProtocols().split(",")); String[] supported = engine.getSupportedCipherSuites(); - String[] eanbled = option.getCiphers().split(","); - engine.setEnabledCipherSuites(getEnabledCiphers(supported, eanbled)); - engine.setNeedClientAuth(option.isAuthPeer()); + String[] enabled = option.getCiphers().split(","); + engine.setEnabledCipherSuites(getEnabledCiphers(supported, enabled)); + setClientAuth(option, engine); return engine; } + private static void setClientAuth(SSLOption option, SSLEngine engine) { + if (option.isAuthPeer() || ClientAuth.REQUIRED.equals(option.getClientAuth())) { + engine.setNeedClientAuth(true); + return; + } + if (ClientAuth.NONE.equals(option.getClientAuth())) { + engine.setNeedClientAuth(false); + engine.setWantClientAuth(false); + return; + } + engine.setWantClientAuth(true); + } + + private static void setClientAuth(SSLOption option, SSLServerSocket serverSocket) { + if (option.isAuthPeer() || ClientAuth.REQUIRED.equals(option.getClientAuth())) { + serverSocket.setNeedClientAuth(true); + return; + } + if (ClientAuth.NONE.equals(option.getClientAuth())) { + serverSocket.setNeedClientAuth(false); + serverSocket.setWantClientAuth(false); + return; + } + serverSocket.setWantClientAuth(true); + } + public static SSLServerSocket createSSLServerSocket(SSLOption option, SSLCustom custom) { try { @@ -138,12 +166,12 @@ public static SSLServerSocket createSSLServerSocket(SSLOption option, (SSLServerSocket) factory.createServerSocket(); socket.setEnabledProtocols(option.getProtocols().split(",")); String[] supported = socket.getSupportedCipherSuites(); - String[] eanbled = option.getCiphers().split(","); - socket.setEnabledCipherSuites(getEnabledCiphers(supported, eanbled)); - socket.setNeedClientAuth(option.isAuthPeer()); + String[] enabled = option.getCiphers().split(","); + socket.setEnabledCipherSuites(getEnabledCiphers(supported, enabled)); + setClientAuth(option, socket); return socket; } catch (UnknownHostException e) { - throw new IllegalArgumentException("unkown host"); + throw new IllegalArgumentException("unknown host"); } catch (IOException e) { throw new IllegalArgumentException("unable create socket"); } @@ -152,16 +180,16 @@ public static SSLServerSocket createSSLServerSocket(SSLOption option, public static SSLSocket createSSLSocket(SSLOption option, SSLCustom custom) { try { SSLContext context = createSSLContext(option, custom); - SSLSocketFactory facroty = context.getSocketFactory(); + SSLSocketFactory factory = context.getSocketFactory(); SSLSocket socket = - (SSLSocket) facroty.createSocket(); + (SSLSocket) factory.createSocket(); socket.setEnabledProtocols(option.getProtocols().split(",")); String[] supported = socket.getSupportedCipherSuites(); - String[] eanbled = option.getCiphers().split(","); - socket.setEnabledCipherSuites(getEnabledCiphers(supported, eanbled)); + String[] enabled = option.getCiphers().split("\\s*,\\s*"); + socket.setEnabledCipherSuites(getEnabledCiphers(supported, enabled)); return socket; } catch (UnknownHostException e) { - throw new IllegalArgumentException("unkown host"); + throw new IllegalArgumentException("unknown host"); } catch (IOException e) { throw new IllegalArgumentException("unable create socket"); } @@ -189,10 +217,14 @@ private static String[] getEnabledCiphers(String[] supported, return r; } - public static String[] getEnalbedCiphers(String enabledCiphers) { + public static String[] getEnabledCiphers(SSLOption sslOption) { SSLOption option = new SSLOption(); - option.setProtocols("TLSv1.2"); - option.setCiphers(enabledCiphers); + if (StringUtils.isNotEmpty(sslOption.getProtocols())) { + option.setProtocols(sslOption.getProtocols()); + } else { + option.setProtocols("TLSv1.2"); + } + option.setCiphers(sslOption.getCiphers()); SSLCustom custom = SSLCustom.defaultSSLCustom(); SSLSocket socket = createSSLSocket(option, custom); return socket.getEnabledCipherSuites(); diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOption.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOption.java index b7b5034e168..19160bb3927 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOption.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOption.java @@ -24,19 +24,17 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; -import java.nio.charset.Charset; -import java.util.List; +import java.nio.charset.StandardCharsets; import java.util.Properties; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.DynamicPropertyFactory; +import org.springframework.core.env.Environment; /** * SSL配置选项。 * */ public final class SSLOption { - private static final SSLOption DEFAULT_OPTION = new SSLOption(); + public static final SSLOption DEFAULT_OPTION = new SSLOption(); public static final String DEFAULT_CIPHERS = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; @@ -49,7 +47,7 @@ public final class SSLOption { DEFAULT_OPTION.setCheckCNHost(false); DEFAULT_OPTION.setCheckCNWhite(false); DEFAULT_OPTION.setCheckCNWhiteFile("white.list"); - DEFAULT_OPTION.setAllowRenegociate(true); + DEFAULT_OPTION.setAllowRenegotiate(true); DEFAULT_OPTION.setStorePath("internal"); DEFAULT_OPTION.setTrustStore("trust.jks"); DEFAULT_OPTION.setTrustStoreType("JKS"); @@ -74,7 +72,9 @@ public final class SSLOption { private String checkCNWhiteFile; - private boolean allowRenegociate; + private boolean allowRenegotiate; + + private String clientAuth; private String storePath; @@ -126,8 +126,8 @@ public void setCheckCNWhiteFile(String checkCNWhiteFile) { this.checkCNWhiteFile = checkCNWhiteFile; } - public void setAllowRenegociate(boolean allowRenegociate) { - this.allowRenegociate = allowRenegociate; + public void setAllowRenegotiate(boolean allowRenegotiate) { + this.allowRenegotiate = allowRenegotiate; } public void setStorePath(String storePath) { @@ -186,14 +186,22 @@ public String getCheckCNWhiteFile() { return checkCNWhiteFile; } - public boolean isAllowRenegociate() { - return allowRenegociate; + public boolean isAllowRenegotiate() { + return allowRenegotiate; } public String getStorePath() { return storePath; } + public String getClientAuth() { + return this.clientAuth; + } + + public void setClientAuth(String clientAuth) { + this.clientAuth = clientAuth; + } + public String getTrustStore() { return trustStore; } @@ -243,30 +251,11 @@ public static SSLOption build(InputStream inputStream) { return option; } - private static String listToString(Object[] lists) { - StringBuilder sb = new StringBuilder(); - sb.append(lists[0]); - for (int i = 1; i < lists.length; i++) { - sb.append(","); - sb.append(lists[i]); - } - return sb.toString(); - } - - public static String getStringProperty(ConcurrentCompositeConfiguration configSource, String defaultValue, + public static String getStringProperty(Environment environment, String defaultValue, String... keys) { String property = null; for (String key : keys) { - if (configSource != null) { - Object v = configSource.getProperty(key); - if (List.class.isInstance(v)) { - property = listToString(((List) v).toArray()); - } else { - property = (String) configSource.getProperty(key); - } - } else { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); - } + property = environment.getProperty(key); if (property != null) { break; } @@ -279,17 +268,11 @@ public static String getStringProperty(ConcurrentCompositeConfiguration configSo } } - private static boolean getBooleanProperty(ConcurrentCompositeConfiguration configSource, boolean defaultValue, + private static boolean getBooleanProperty(Environment environment, boolean defaultValue, String... keys) { String property = null; for (String key : keys) { - if (configSource != null) { - if (configSource.getProperty(key) != null) { - return configSource.getBoolean(key); - } - } else { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); - } + property = environment.getProperty(key); if (property != null) { break; } @@ -302,78 +285,79 @@ private static boolean getBooleanProperty(ConcurrentCompositeConfiguration confi } } - public static SSLOption buildFromYaml(String tag, ConcurrentCompositeConfiguration configSource) { + public static SSLOption build(String tag, Environment environment) { SSLOption option = new SSLOption(); - option.engine = getStringProperty(configSource, + option.engine = getStringProperty(environment, DEFAULT_OPTION.getEngine(), "ssl." + tag + ".engine", "ssl.engine"); option.protocols = - getStringProperty(configSource, + getStringProperty(environment, DEFAULT_OPTION.getProtocols(), "ssl." + tag + ".protocols", "ssl.protocols"); option.ciphers = - getStringProperty(configSource, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".ciphers", "ssl.ciphers"); + getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".ciphers", "ssl.ciphers"); option.authPeer = - getBooleanProperty(configSource, DEFAULT_OPTION.isAuthPeer(), "ssl." + tag + ".authPeer", "ssl.authPeer"); + getBooleanProperty(environment, DEFAULT_OPTION.isAuthPeer(), "ssl." + tag + ".authPeer", "ssl.authPeer"); option.checkCNHost = - getBooleanProperty(configSource, + getBooleanProperty(environment, DEFAULT_OPTION.isCheckCNHost(), "ssl." + tag + ".checkCN.host", "ssl.checkCN.host"); option.checkCNWhite = - getBooleanProperty(configSource, + getBooleanProperty(environment, DEFAULT_OPTION.isCheckCNWhite(), "ssl." + tag + ".checkCN.white", "ssl.checkCN.white"); - option.checkCNWhiteFile = getStringProperty(configSource, + option.checkCNWhiteFile = getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".checkCN.white.file", "ssl.checkCN.white.file"); - option.allowRenegociate = getBooleanProperty(configSource, - DEFAULT_OPTION.isAllowRenegociate(), - "ssl." + tag + ".allowRenegociate", - "ssl.allowRenegociate"); + option.allowRenegotiate = getBooleanProperty(environment, + DEFAULT_OPTION.isAllowRenegotiate(), + "ssl." + tag + ".allowRenegotiate", + "ssl.allowRenegotiate"); option.storePath = - getStringProperty(configSource, + getStringProperty(environment, DEFAULT_OPTION.getStorePath(), "ssl." + tag + ".storePath", "ssl.storePath"); + option.clientAuth = + getStringProperty(environment, + DEFAULT_OPTION.getClientAuth(), + "ssl." + tag + ".storePath", + "ssl.clientAuth"); option.trustStore = - getStringProperty(configSource, + getStringProperty(environment, DEFAULT_OPTION.getTrustStore(), "ssl." + tag + ".trustStore", "ssl.trustStore"); - option.trustStoreType = getStringProperty(configSource, + option.trustStoreType = getStringProperty(environment, DEFAULT_OPTION.getTrustStoreType(), "ssl." + tag + ".trustStoreType", "ssl.trustStoreType"); - option.trustStoreValue = getStringProperty(configSource, + option.trustStoreValue = getStringProperty(environment, DEFAULT_OPTION.getTrustStoreValue(), "ssl." + tag + ".trustStoreValue", "ssl.trustStoreValue"); option.keyStore = - getStringProperty(configSource, DEFAULT_OPTION.getKeyStore(), "ssl." + tag + ".keyStore", "ssl.keyStore"); + getStringProperty(environment, DEFAULT_OPTION.getKeyStore(), "ssl." + tag + ".keyStore", "ssl.keyStore"); option.keyStoreType = - getStringProperty(configSource, + getStringProperty(environment, DEFAULT_OPTION.getKeyStoreType(), "ssl." + tag + ".keyStoreType", "ssl.keyStoreType"); - option.keyStoreValue = getStringProperty(configSource, + option.keyStoreValue = getStringProperty(environment, DEFAULT_OPTION.getKeyStoreValue(), "ssl." + tag + ".keyStoreValue", "ssl.keyStoreValue"); - option.crl = getStringProperty(configSource, DEFAULT_OPTION.getCrl(), "ssl." + tag + ".crl", "ssl.crl"); + option.crl = getStringProperty(environment, DEFAULT_OPTION.getCrl(), "ssl." + tag + ".crl", "ssl.crl"); option.sslCustomClass = - getStringProperty(configSource, null, "ssl." + tag + ".sslCustomClass", "ssl.sslCustomClass"); + getStringProperty(environment, null, "ssl." + tag + ".sslCustomClass", "ssl.sslCustomClass"); return option; } - public static SSLOption buildFromYaml(String tag) { - return buildFromYaml(tag, null); - } - private void fromProperty(Properties props) { this.protocols = propString(props, "ssl.protocols"); this.ciphers = propString(props, "ssl.ciphers"); @@ -381,8 +365,9 @@ private void fromProperty(Properties props) { this.checkCNHost = propBoolean(props, "ssl.checkCN.host"); this.checkCNWhite = propBoolean(props, "ssl.checkCN.white"); this.checkCNWhiteFile = propString(props, "ssl.checkCN.white.file"); - this.allowRenegociate = propBoolean(props, "ssl.allowRenegociate"); + this.allowRenegotiate = propBoolean(props, "ssl.allowRenegotiate"); this.storePath = propString(props, "ssl.storePath"); + this.clientAuth = propString(props, "ssl.clientAuth", false); this.trustStore = propString(props, "ssl.trustStore"); this.trustStoreType = propString(props, "ssl.trustStoreType"); this.trustStoreValue = propString(props, "ssl.trustStoreValue"); @@ -394,8 +379,12 @@ private void fromProperty(Properties props) { } private String propString(Properties props, String key) { + return propString(props, key, true); + } + + private String propString(Properties props, String key, boolean required) { String s = props.getProperty(key); - if (s == null) { + if (s == null && required) { throw new IllegalArgumentException("No key :" + key); } return s; @@ -414,7 +403,7 @@ private void load(InputStream inputStream) { Reader reader = null; try { reader = - new InputStreamReader(inputStream, Charset.forName("UTF-8")); + new InputStreamReader(inputStream, StandardCharsets.UTF_8); props.load(reader); fromProperty(props); } catch (IOException e) { @@ -439,7 +428,8 @@ private void load(InputStream inputStream) { } } - private void load(String path) { + // visible for testing + void load(String path) { try { load(new FileInputStream(path)); } catch (FileNotFoundException e) { diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOptionFactory.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOptionFactory.java index a6b55c8d96f..49cdb3ab15b 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOptionFactory.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLOptionFactory.java @@ -17,11 +17,11 @@ package org.apache.servicecomb.foundation.ssl; -import com.netflix.config.ConcurrentCompositeConfiguration; +import org.springframework.core.env.Environment; public interface SSLOptionFactory { - static SSLOptionFactory createSSLOptionFactory(String tag, ConcurrentCompositeConfiguration configSource) { - String name = SSLOption.getStringProperty(configSource, + static SSLOptionFactory createSSLOptionFactory(String tag, Environment environment) { + String name = SSLOption.getStringProperty(environment, null, "ssl." + tag + ".sslOptionFactory", "ssl.sslOptionFactory"); @@ -31,8 +31,8 @@ static SSLOptionFactory createSSLOptionFactory(String tag, ConcurrentCompositeCo static SSLOptionFactory createSSLOptionFactory(String className) { if (className != null && !className.isEmpty()) { try { - return (SSLOptionFactory) Class.forName(className).newInstance(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + return (SSLOptionFactory) Class.forName(className).getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { throw new IllegalStateException("Failed to create SSLOptionFactory.", e); } } diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLSocketFactoryExt.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLSocketFactoryExt.java index 79e2dc5011d..e0cc0f24d8d 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLSocketFactoryExt.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/SSLSocketFactoryExt.java @@ -30,11 +30,11 @@ * */ public class SSLSocketFactoryExt extends SSLSocketFactory { - private SSLSocketFactory sslSocketFactory; + private final SSLSocketFactory sslSocketFactory; - private String[] ciphers; + private final String[] ciphers; - private String[] protos; + private final String[] protos; public SSLSocketFactoryExt(SSLSocketFactory factory, String[] ciphers, String[] protos) { this.sslSocketFactory = factory; diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustAllManager.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustAllManager.java index 0a50a364032..b978ede4b9d 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustAllManager.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustAllManager.java @@ -24,6 +24,7 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedTrustManager; +/** it is not secure */ public class TrustAllManager extends X509ExtendedTrustManager { @Override diff --git a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustManagerExt.java b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustManagerExt.java index 6137b1f68b3..597894571c5 100644 --- a/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustManagerExt.java +++ b/foundations/foundation-ssl/src/main/java/org/apache/servicecomb/foundation/ssl/TrustManagerExt.java @@ -50,11 +50,11 @@ public class TrustManagerExt extends X509ExtendedTrustManager { private static final int WHITE_SIZE = 1024; - private X509ExtendedTrustManager trustManager; + private final X509ExtendedTrustManager trustManager; - private SSLOption option; + private final SSLOption option; - private SSLCustom custom; + private final SSLCustom custom; public TrustManagerExt(X509ExtendedTrustManager manager, SSLOption option, SSLCustom custom) { @@ -189,14 +189,14 @@ private void checkCNHost(X509Certificate[] chain, String ip) throws CertificateE } } } catch (SocketException e) { - throw new CertificateException("Get local adrress fail."); + throw new CertificateException("Get local address fail."); } } else if (cnValid(cns, ipTmp)) { return; } - LOG.error("CN does not match IP: e=" + cns.toString() + LOG.error("CN does not match IP: e=" + cns + ",t=" + ip); - throw new CertificateException("CN does not match IP: e=" + cns.toString() + throw new CertificateException("CN does not match IP: e=" + cns + ",t=" + ip); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/CertificateUtilTest.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/CertificateUtilTest.java index 0285b8b3183..118df056a7c 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/CertificateUtilTest.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/CertificateUtilTest.java @@ -35,15 +35,16 @@ import javax.security.auth.x500.X500Principal; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import mockit.Expectations; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class CertificateUtilTest { - class MyX509Certificate extends X509Certificate { + @SuppressWarnings("deprecation") + static class MyX509Certificate extends X509Certificate { private static final long serialVersionUID = -3585440601605666278L; public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { @@ -199,7 +200,7 @@ public void testGetCN(@Mocked X500Principal aX500Principal, @Mocked MyX509Certif MyX509Certificate xxmyX509Certificate = new MyX509Certificate(); Set strExpect = CertificateUtil.getCN(xxmyX509Certificate); - Assert.assertEquals(true, strExpect.contains("Test1234")); + Assertions.assertTrue(strExpect.contains("Test1234")); } @Test @@ -218,9 +219,9 @@ public void testGetCNException(@Mocked X500Principal aX500Principal, try { Set strExpect = CertificateUtil.getCN(xxmyX509Certificate); - Assert.assertEquals(strExpect.size(), 0); + Assertions.assertEquals(strExpect.size(), 0); } catch (IllegalArgumentException e) { - Assert.assertNotNull(null); + Assertions.assertNotNull(null); } } @@ -255,7 +256,7 @@ public void testFindOwner(@Mocked X500Principal aX500Principal1, @Mocked X500Pri xxmyX509Certificate[1] = myX509Certificate2; X509Certificate aX509Certificate = CertificateUtil.findOwner(xxmyX509Certificate); - Assert.assertNull(aX509Certificate); + Assertions.assertNull(aX509Certificate); } @Test @@ -290,9 +291,9 @@ public void testFindRootCAException(@Mocked X500Principal aX500Principal1, @Mock try { X509Certificate aX509Certificate = CertificateUtil.findOwner(xxmyX509Certificate); - Assert.assertNull(aX509Certificate); + Assertions.assertNull(aX509Certificate); } catch (IllegalArgumentException e) { - Assert.assertEquals("bad certificate chain: no root CA.", e.getMessage()); + Assertions.assertEquals("bad certificate chain: no root CA.", e.getMessage()); } } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtilTest.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtilTest.java index a4531ac6ab1..54955139087 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtilTest.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/KeyStoreUtilTest.java @@ -26,12 +26,12 @@ import java.security.cert.CertificateFactory; import java.util.Collection; -import org.junit.Assert; import org.junit.Test; -import org.mockito.Mockito; +import org.junit.jupiter.api.Assertions; import mockit.Mock; import mockit.MockUp; +import org.mockito.Mockito; public class KeyStoreUtilTest { final String strFilePath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); @@ -45,7 +45,7 @@ public void testCreateKeyStoreException() { try { KeyStoreUtil.createKeyStore(storename, storetype, storevalue); } catch (IllegalArgumentException e) { - Assert.assertEquals("Bad key store or value.testType not found", e.getMessage()); + Assertions.assertEquals("Bad key store or value.testType not found", e.getMessage()); } } @@ -58,16 +58,14 @@ public void testCreateKeyStoreException2() { try { KeyStoreUtil.createKeyStore(storename, storetype, storevalue); } catch (IllegalArgumentException e) { - Assert.assertEquals("Bad key store or value.DerInputStream.getLength(): lengthTag=109, too big.", + Assertions.assertEquals("Bad key store or value.DerInputStream.getLength(): lengthTag=109, too big.", e.getMessage()); } } - @SuppressWarnings("unused") @Test public void testCreateKeyManagersException() { KeyStore keystore; - char[] keyvalue; String storename = strFilePath + "/ssl/server.p12"; String storetype = "PKCS12"; @@ -79,8 +77,9 @@ public void testCreateKeyManagersException() { try { KeyStoreUtil.createKeyManagers(keystore, storeKeyValue); } catch (IllegalArgumentException e) { - Assert.assertEquals("Bad key store.Get Key failed: null", - e.getMessage()); + Assertions.assertEquals("Bad key store.Get Key failed:" + + " Cannot read the array length because \"password\" is null", + e.getMessage()); } } @@ -91,11 +90,11 @@ public void testCreateCRL() { boolean validAssert = true; try { CRL[] crl = KeyStoreUtil.createCRL(crlfile); - Assert.assertNull(crl); + Assertions.assertNull(crl); } catch (Exception e) { validAssert = false; } - Assert.assertTrue(validAssert); + Assertions.assertTrue(validAssert); } @Test @@ -105,7 +104,7 @@ public void testCreateCRLException() { try { new MockUp() { @Mock - public final CertificateFactory getInstance(String type) throws CertificateException { + public CertificateFactory getInstance(String type) throws CertificateException { throw new CertificateException(); } }; @@ -114,7 +113,7 @@ public final CertificateFactory getInstance(String type) throws CertificateExcep } catch (Exception e) { validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } @Test @@ -124,7 +123,7 @@ public void testExceptionFileNotFound() { try { new MockUp() { @Mock - public final CertificateFactory getInstance( + public CertificateFactory getInstance( String type) throws CertificateException, FileNotFoundException { throw new FileNotFoundException(); } @@ -132,9 +131,9 @@ public final CertificateFactory getInstance( KeyStoreUtil.createCRL(crlfile); } catch (Exception e) { validAssert = false; - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } @Test @@ -144,23 +143,23 @@ public void testExceptionCRLException() { try { new MockUp() { @Mock - public final CertificateFactory getInstance(String type) throws CertificateException, CRLException { + public CertificateFactory getInstance(String type) throws CertificateException, CRLException { throw new CRLException(); } }; KeyStoreUtil.createCRL(crlfile); } catch (Exception e) { validAssert = false; - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } private void mockGenerateCRLs() { new MockUp() { @SuppressWarnings("unchecked") @Mock - public final Collection generateCRLs(InputStream inStream) throws CRLException { + public Collection generateCRLs(InputStream inStream) throws CRLException { return Mockito.mock(Collection.class); } }; diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLManagerTest.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLManagerTest.java index d1b1476d692..71758fa3cff 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLManagerTest.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLManagerTest.java @@ -27,16 +27,14 @@ import java.security.NoSuchAlgorithmException; import java.util.Enumeration; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import mockit.Expectations; import mockit.Mock; @@ -50,7 +48,7 @@ public class SSLManagerTest { public void testSSLManagerServerAndClient(final @Mocked NetworkInterface nif) throws Exception { final InetAddress ia = Inet4Address.getByName("10.57.65.225"); final Enumeration interfaces = new Enumeration() { - int count = 1; + final int count = 1; int cur = 0; @@ -70,7 +68,7 @@ public NetworkInterface nextElement() { }; final Enumeration ias = new Enumeration() { - int count = 1; + final int count = 1; int cur = 0; @@ -120,56 +118,50 @@ public char[] decode(char[] encrypted) { } }; final SSLServerSocket serverSocket = SSLManager.createSSLServerSocket(option, custom); + Assertions.assertTrue(serverSocket.getNeedClientAuth()); serverSocket.bind(new InetSocketAddress("127.0.0.1", 8886)); String[] protos = serverSocket.getEnabledCipherSuites(); String[] protosExpected = - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" + "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" .split(","); - Assert.assertArrayEquals(protos, protosExpected); + Assertions.assertArrayEquals(protos, protosExpected); String[] ciphers = serverSocket.getEnabledCipherSuites(); String[] ciphersExpected = - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" + "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" .split(","); - Assert.assertArrayEquals(ciphers, ciphersExpected); - Assert.assertEquals(serverSocket.getNeedClientAuth(), true); + Assertions.assertArrayEquals(ciphers, ciphersExpected); + Assertions.assertTrue(serverSocket.getNeedClientAuth()); SSLOption clientoption = SSLOption.build(DIR + "/client.ssl.properties"); SSLSocket clientsocket = SSLManager.createSSLSocket(clientoption, custom); String[] clientprotos = clientsocket.getEnabledCipherSuites(); String[] clientprotosExpected = - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" + "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" .split(","); - Assert.assertArrayEquals(clientprotos, clientprotosExpected); + Assertions.assertArrayEquals(clientprotos, clientprotosExpected); String[] clientciphers = clientsocket.getEnabledCipherSuites(); String[] clientciphersExpected = - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" + "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA" .split(","); - Assert.assertArrayEquals(clientciphers, clientciphersExpected); - Assert.assertEquals(clientsocket.getNeedClientAuth(), false); + Assertions.assertArrayEquals(clientciphers, clientciphersExpected); + Assertions.assertFalse(clientsocket.getNeedClientAuth()); boolean validAssert = true; try { clientsocket.connect(new InetSocketAddress("127.0.0.1", 8886)); - new Thread() { - public void run() { + new Thread(() -> { - try { - SSLSocket s = (SSLSocket) serverSocket.accept(); - s.addHandshakeCompletedListener(new HandshakeCompletedListener() { + try { + SSLSocket s = (SSLSocket) serverSocket.accept(); + s.addHandshakeCompletedListener(arg0 -> { - @Override - public void handshakeCompleted(HandshakeCompletedEvent arg0) { - - } - }); - s.getOutputStream().write(new byte[] {0, 1}); - } catch (IOException e) { - e.printStackTrace(); - // this should not happen, do a false assert - Assert.assertEquals(false, true); - } + }); + s.getOutputStream().write(new byte[] {0, 1}); + } catch (IOException e) { + e.printStackTrace(); + Assertions.fail("this should not happen"); } - }.start(); + }).start(); clientsocket.startHandshake(); clientsocket.close(); @@ -180,7 +172,7 @@ public void handshakeCompleted(HandshakeCompletedEvent arg0) { e.printStackTrace(); validAssert = false; } - Assert.assertTrue(validAssert); + Assertions.assertTrue(validAssert); } @Test @@ -199,8 +191,33 @@ public char[] decode(char[] encrypted) { }; SSLEngine aSSLEngine = SSLManager.createSSLEngine(option, custom); - Assert.assertEquals(false, aSSLEngine.getUseClientMode()); - Assert.assertNotNull(aSSLEngine); + // if client mode may not decided at initialization. Different JDK is different, do not check it. + // Assertions.assertEquals(false, aSSLEngine.getUseClientMode()); + Assertions.assertTrue(aSSLEngine.getNeedClientAuth()); + } + + @Test + public void testCreateSSLEngineClientAuthNone() { + SSLOption option = SSLOption.build(DIR + "/server.ssl.properties"); + option.setClientAuth("NONE"); + option.setAuthPeer(false); + SSLCustom custom = new SSLCustom() { + @Override + public String getFullPath(String filename) { + return DIR + "/ssl/" + filename; + } + + @Override + public char[] decode(char[] encrypted) { + return encrypted; + } + }; + + SSLEngine aSSLEngine = SSLManager.createSSLEngine(option, custom); + // if client mode may not decided at initialization. Different JDK is different, do not check it. + // Assertions.assertEquals(false, aSSLEngine.getUseClientMode()); + Assertions.assertFalse(aSSLEngine.getNeedClientAuth()); + Assertions.assertFalse(aSSLEngine.getWantClientAuth()); } @Test @@ -221,8 +238,18 @@ public char[] decode(char[] encrypted) { int port = 39093; String peerHost = "host1"; SSLEngine aSSLEngine = SSLManager.createSSLEngine(option, custom, peerHost, port); - Assert.assertNotNull(aSSLEngine); - Assert.assertEquals("host1", aSSLEngine.getPeerHost().toString()); + Assertions.assertNotNull(aSSLEngine); + Assertions.assertEquals("host1", aSSLEngine.getPeerHost()); + } + + @Test + public void testCreateSSLContextResource() { + SSLOption option = SSLOption.build(DIR + "/server.ssl.resource.properties"); + + SSLCustom custom = SSLCustom.defaultSSLCustom(); + + SSLContext context = SSLManager.createSSLContext(option, custom); + Assertions.assertNotNull(context); } @Test @@ -243,16 +270,16 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws NoSuchAlgorithmException { + public SSLContext getInstance(String type) throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException(); } }; try { - SSLContext context = SSLManager.createSSLContext(option, custom); - Assert.assertNotNull(context); + SSLManager.createSSLContext(option, custom); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -274,16 +301,16 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws KeyManagementException { + public SSLContext getInstance(String type) throws KeyManagementException { throw new KeyManagementException(); } }; try { - SSLContext context = SSLManager.createSSLContext(option, custom); - Assert.assertNotNull(context); + SSLManager.createSSLContext(option, custom); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -305,17 +332,17 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws UnknownHostException { + public SSLContext getInstance(String type) throws UnknownHostException { throw new UnknownHostException(); } }; try { - SSLServerSocket context = SSLManager.createSSLServerSocket(option, custom); + SSLManager.createSSLServerSocket(option, custom); - Assert.assertNotNull(context); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -337,16 +364,16 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws IOException { + public SSLContext getInstance(String type) throws IOException { throw new IOException(); } }; try { - SSLServerSocket context = SSLManager.createSSLServerSocket(option, custom); - Assert.assertNotNull(context); + SSLManager.createSSLServerSocket(option, custom); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -368,16 +395,16 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws UnknownHostException { + public SSLContext getInstance(String type) throws UnknownHostException { throw new UnknownHostException(); } }; try { - SSLSocket context = SSLManager.createSSLSocket(option, custom); - Assert.assertNotNull(context); + SSLManager.createSSLSocket(option, custom); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -399,16 +426,16 @@ public char[] decode(char[] encrypted) { new MockUp() { @Mock - public final SSLContext getInstance(String type) throws IOException { + public SSLContext getInstance(String type) throws IOException { throw new IOException(); } }; try { - SSLSocket context = SSLManager.createSSLSocket(option, custom); - Assert.assertNotNull(context); + SSLManager.createSSLSocket(option, custom); + Assertions.assertNotNull(null); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -428,11 +455,15 @@ public char[] decode(char[] encrypted) { }; SSLSocketFactory aSSLSocketFactory = SSLManager.createSSLSocketFactory(option, custom); - Assert.assertNotNull(aSSLSocketFactory.getDefaultCipherSuites()[0]); + Assertions.assertNotNull(aSSLSocketFactory.getDefaultCipherSuites()[0]); } + @Test public void testGetSupportedCiphers() { - String[] ciphers = SSLManager.getEnalbedCiphers("TLS_RSA_WITH_AES_128_GCM_SHA256"); - Assert.assertEquals(ciphers[0], "TLS_RSA_WITH_AES_128_GCM_SHA256"); + SSLOption option = new SSLOption(); + option.setCiphers("TLS_RSA_WITH_AES_128_GCM_SHA256"); + option.setProtocols("TLSv1.2"); + String[] ciphers = SSLManager.getEnabledCiphers(option); + Assertions.assertEquals(ciphers[0], "TLS_RSA_WITH_AES_128_GCM_SHA256"); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLOptionTest.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLOptionTest.java index 70726a12794..ae91fcbb697 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLOptionTest.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/SSLOptionTest.java @@ -17,8 +17,6 @@ package org.apache.servicecomb.foundation.ssl; -import static org.apache.servicecomb.config.archaius.sources.ConfigSourceMaker.yamlConfigSource; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -26,31 +24,38 @@ import java.net.URL; import java.util.Properties; -import org.apache.commons.configuration.SystemConfiguration; -import org.apache.servicecomb.config.ConfigUtil; -import org.junit.AfterClass; -import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConcurrentMapConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicConfiguration; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.FixedDelayPollingScheduler; - -import mockit.Deencapsulation; import mockit.Mock; import mockit.MockUp; public class SSLOptionTest { private static final String DIR = Thread.currentThread().getContextClassLoader().getResource("").getPath(); - @AfterClass - public static void tearDown() throws Exception { - Deencapsulation.setField(ConfigurationManager.class, "instance", null); - Deencapsulation.setField(ConfigurationManager.class, "customConfigurationInstalled", false); - Deencapsulation.setField(DynamicPropertyFactory.class, "config", null); + Environment environment = Mockito.mock(Environment.class); + + @Before + public void setUp() throws Exception { + Mockito.when(environment.getProperty("ssl.protocols")).thenReturn("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello"); + Mockito.when(environment.getProperty("ssl.ciphers")).thenReturn( + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"); + Mockito.when(environment.getProperty("ssl.authPeer")).thenReturn("true"); + Mockito.when(environment.getProperty("ssl.checkCN.host")).thenReturn("true"); + Mockito.when(environment.getProperty("ssl.checkCN.white")).thenReturn("true"); + Mockito.when(environment.getProperty("ssl.checkCN.white.file")).thenReturn("white.list"); + Mockito.when(environment.getProperty("ssl.allowRenegotiate")).thenReturn("false"); + Mockito.when(environment.getProperty("ssl.storePath")).thenReturn("internal"); + Mockito.when(environment.getProperty("ssl.trustStore")).thenReturn("trust.jks"); + Mockito.when(environment.getProperty("ssl.trustStoreType")).thenReturn("JKS"); + Mockito.when(environment.getProperty("ssl.trustStoreValue")).thenReturn("Changeme_123"); + Mockito.when(environment.getProperty("ssl.keyStore")).thenReturn("server.p12"); + Mockito.when(environment.getProperty("ssl.keyStoreType")).thenReturn("PKCS12"); + Mockito.when(environment.getProperty("ssl.keyStoreValue")).thenReturn("Changeme_123"); + Mockito.when(environment.getProperty("ssl.crl")).thenReturn("revoke.crl"); } @Test @@ -60,270 +65,245 @@ public void testSSLOption() { String protocols = option.getProtocols(); option.setProtocols(protocols); - Assert.assertEquals("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); + Assertions.assertEquals("TLSv1.3,TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); String ciphers = option.getCiphers(); option.setCiphers(ciphers); - Assert.assertEquals( - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SH" + Assertions.assertEquals( + "TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SH" + "A,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA", ciphers); boolean authPeer = option.isAuthPeer(); option.setAuthPeer(authPeer); - Assert.assertEquals(true, authPeer); + Assertions.assertTrue(authPeer); boolean checkCNHost = option.isCheckCNHost(); option.setCheckCNHost(checkCNHost); - Assert.assertEquals(true, checkCNHost); + Assertions.assertTrue(checkCNHost); boolean checkCNWhite = option.isCheckCNWhite(); option.setCheckCNWhite(checkCNWhite); - Assert.assertEquals(true, checkCNWhite); + Assertions.assertTrue(checkCNWhite); String checkCNWhiteFile = option.getCheckCNWhiteFile(); option.setCheckCNWhiteFile(checkCNWhiteFile); - Assert.assertEquals("white.list", checkCNWhiteFile); + Assertions.assertEquals("white.list", checkCNWhiteFile); - boolean allowRenegociate = option.isAllowRenegociate(); - option.setAllowRenegociate(allowRenegociate); - Assert.assertEquals(false, allowRenegociate); + boolean allowRenegotiate = option.isAllowRenegotiate(); + option.setAllowRenegotiate(allowRenegotiate); + Assertions.assertFalse(allowRenegotiate); String storePath = option.getStorePath(); option.setStorePath(storePath); - Assert.assertEquals("internal", storePath); + Assertions.assertEquals("internal", storePath); String trustStore = option.getTrustStore(); option.setTrustStore(trustStore); - Assert.assertEquals("trust.jks", trustStore); + Assertions.assertEquals("trust.jks", trustStore); String trustStoreType = option.getTrustStoreType(); option.setTrustStoreType(trustStoreType); - Assert.assertEquals("JKS", trustStoreType); + Assertions.assertEquals("JKS", trustStoreType); String trustStoreValue = option.getTrustStoreValue(); option.setTrustStoreValue(trustStoreValue); - Assert.assertEquals("Changeme_123", trustStoreValue); + Assertions.assertEquals("Changeme_123", trustStoreValue); String keyStore = option.getKeyStore(); option.setKeyStore(keyStore); - Assert.assertEquals("server.p12", keyStore); + Assertions.assertEquals("server.p12", keyStore); String keyStoreType = option.getKeyStoreType(); option.setKeyStoreType(keyStoreType); - Assert.assertEquals("PKCS12", keyStoreType); + Assertions.assertEquals("PKCS12", keyStoreType); String keyStoreValue = option.getKeyStoreValue(); option.setKeyStoreValue(keyStoreValue); - Assert.assertEquals("Changeme_123", keyStoreValue); + Assertions.assertEquals("Changeme_123", keyStoreValue); String crl = option.getCrl(); option.setCrl(crl); - Assert.assertEquals("revoke.crl", crl); + Assertions.assertEquals("revoke.crl", crl); } @Test public void testSSLOptionYaml() { - // configuration from yaml files: default microservice.yaml - DynamicConfiguration configFromYamlFile = - new DynamicConfiguration(yamlConfigSource(), new FixedDelayPollingScheduler()); - // configuration from system properties - ConcurrentMapConfiguration configFromSystemProperties = - new ConcurrentMapConfiguration(new SystemConfiguration()); - - // create a hierarchy of configuration that makes - // 1) dynamic configuration source override system properties - ConcurrentCompositeConfiguration finalConfig = new ConcurrentCompositeConfiguration(); - finalConfig.addConfiguration(configFromSystemProperties, "systemEnvConfig"); - finalConfig.addConfiguration(configFromYamlFile, "configFromYamlFile"); - ConfigurationManager.install(finalConfig); - - SSLOption option = SSLOption.buildFromYaml("server"); + Mockito.when(environment.getProperty("ssl.server.sslCustomClass")).thenReturn("wwrong"); + SSLOption option = SSLOption.build("server", environment); String protocols = option.getProtocols(); option.setProtocols(protocols); - Assert.assertEquals("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); + Assertions.assertEquals("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); String ciphers = option.getCiphers(); option.setCiphers(ciphers); - Assert.assertEquals( - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SH" - + - "A,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA", + Assertions.assertEquals("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", ciphers); boolean authPeer = option.isAuthPeer(); option.setAuthPeer(authPeer); - Assert.assertEquals(true, authPeer); + Assertions.assertTrue(authPeer); boolean checkCNHost = option.isCheckCNHost(); option.setCheckCNHost(checkCNHost); - Assert.assertEquals(true, checkCNHost); + Assertions.assertTrue(checkCNHost); boolean checkCNWhite = option.isCheckCNWhite(); option.setCheckCNWhite(checkCNWhite); - Assert.assertEquals(true, checkCNWhite); + Assertions.assertTrue(checkCNWhite); String checkCNWhiteFile = option.getCheckCNWhiteFile(); option.setCheckCNWhiteFile(checkCNWhiteFile); - Assert.assertEquals("white.list", checkCNWhiteFile); + Assertions.assertEquals("white.list", checkCNWhiteFile); - boolean allowRenegociate = option.isAllowRenegociate(); - option.setAllowRenegociate(allowRenegociate); - Assert.assertEquals(false, allowRenegociate); + boolean allowRenegotiate = option.isAllowRenegotiate(); + option.setAllowRenegotiate(allowRenegotiate); + Assertions.assertFalse(allowRenegotiate); String storePath = option.getStorePath(); option.setStorePath(storePath); - Assert.assertEquals("internal", storePath); + Assertions.assertEquals("internal", storePath); String trustStore = option.getTrustStore(); option.setTrustStore(trustStore); - Assert.assertEquals("trust.jks", trustStore); + Assertions.assertEquals("trust.jks", trustStore); String trustStoreType = option.getTrustStoreType(); option.setTrustStoreType(trustStoreType); - Assert.assertEquals("JKS", trustStoreType); + Assertions.assertEquals("JKS", trustStoreType); String trustStoreValue = option.getTrustStoreValue(); option.setTrustStoreValue(trustStoreValue); - Assert.assertEquals("Changeme_123", trustStoreValue); + Assertions.assertEquals("Changeme_123", trustStoreValue); String keyStore = option.getKeyStore(); option.setKeyStore(keyStore); - Assert.assertEquals("server.p12", keyStore); + Assertions.assertEquals("server.p12", keyStore); String keyStoreType = option.getKeyStoreType(); option.setKeyStoreType(keyStoreType); - Assert.assertEquals("PKCS12", keyStoreType); + Assertions.assertEquals("PKCS12", keyStoreType); String keyStoreValue = option.getKeyStoreValue(); option.setKeyStoreValue(keyStoreValue); - Assert.assertEquals("Changeme_123", keyStoreValue); + Assertions.assertEquals("Changeme_123", keyStoreValue); String crl = option.getCrl(); option.setCrl(crl); - Assert.assertEquals("revoke.crl", crl); + Assertions.assertEquals("revoke.crl", crl); option.setSslCustomClass("123"); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); - Assert.assertArrayEquals(custom.decode("123".toCharArray()), "123".toCharArray()); + Assertions.assertArrayEquals(custom.decode("123".toCharArray()), "123".toCharArray()); } @Test public void testSSLOptionYamlOption2() throws Exception { - System.setProperty("ssl.protocols", "TLSv1.2"); - ConcurrentCompositeConfiguration finalConfig = ConfigUtil.createLocalConfig(); + Mockito.when(environment.getProperty("ssl.protocols")).thenReturn("TLSv1.2"); - SSLOption option = SSLOption.buildFromYaml("server", finalConfig); + SSLOption option = SSLOption.build("server", environment); String protocols = option.getProtocols(); option.setProtocols(protocols); - Assert.assertEquals("TLSv1.2", protocols); + Assertions.assertEquals("TLSv1.2", protocols); System.clearProperty("ssl.protocols"); } @Test - public void testSSLOptionYamlOptionWithProperyFalse() throws Exception { - System.setProperty("ssl.authPeer", "false"); - ConcurrentCompositeConfiguration finalConfig = ConfigUtil.createLocalConfig(); + public void testSSLOptionYamlOptionWithPropertyFalse() throws Exception { + Mockito.when(environment.getProperty("ssl.authPeer")).thenReturn("false"); - SSLOption option = SSLOption.buildFromYaml("server", finalConfig); + SSLOption option = SSLOption.build("server", environment); boolean authPeer = option.isAuthPeer(); option.setAuthPeer(authPeer); - Assert.assertEquals(false, authPeer); + Assertions.assertFalse(authPeer); System.getProperties().remove("ssl.authPeer"); } @Test - public void testSSLOptionYamlOptionWithProperyTrue() throws Exception { - System.setProperty("ssl.authPeer", "true"); - ConcurrentCompositeConfiguration finalConfig = ConfigUtil.createLocalConfig(); - - SSLOption option = SSLOption.buildFromYaml("server", finalConfig); + public void testSSLOptionYamlOptionWithPropertyTrue() throws Exception { + SSLOption option = SSLOption.build("server", environment); boolean authPeer = option.isAuthPeer(); option.setAuthPeer(authPeer); - Assert.assertEquals(true, authPeer); + Assertions.assertTrue(authPeer); System.getProperties().remove("ssl.authPeer"); } @Test public void testSSLOptionYamlOption() throws Exception { - ConcurrentCompositeConfiguration finalConfig = ConfigUtil.createLocalConfig(); - - SSLOption option = SSLOption.buildFromYaml("server", finalConfig); + SSLOption option = SSLOption.build("server", environment); String protocols = option.getProtocols(); option.setProtocols(protocols); - Assert.assertEquals("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); + Assertions.assertEquals("TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello", protocols); String ciphers = option.getCiphers(); option.setCiphers(ciphers); - Assert.assertEquals( - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SH" - + - "A,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA", + Assertions.assertEquals( + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", ciphers); boolean authPeer = option.isAuthPeer(); option.setAuthPeer(authPeer); - Assert.assertEquals(true, authPeer); + Assertions.assertTrue(authPeer); boolean checkCNHost = option.isCheckCNHost(); option.setCheckCNHost(checkCNHost); - Assert.assertEquals(true, checkCNHost); + Assertions.assertTrue(checkCNHost); boolean checkCNWhite = option.isCheckCNWhite(); option.setCheckCNWhite(checkCNWhite); - Assert.assertEquals(true, checkCNWhite); + Assertions.assertTrue(checkCNWhite); String checkCNWhiteFile = option.getCheckCNWhiteFile(); option.setCheckCNWhiteFile(checkCNWhiteFile); - Assert.assertEquals("white.list", checkCNWhiteFile); + Assertions.assertEquals("white.list", checkCNWhiteFile); - boolean allowRenegociate = option.isAllowRenegociate(); - option.setAllowRenegociate(allowRenegociate); - Assert.assertEquals(false, allowRenegociate); + boolean allowRenegotiate = option.isAllowRenegotiate(); + option.setAllowRenegotiate(allowRenegotiate); + Assertions.assertFalse(allowRenegotiate); String storePath = option.getStorePath(); option.setStorePath(storePath); - Assert.assertEquals("internal", storePath); + Assertions.assertEquals("internal", storePath); String trustStore = option.getTrustStore(); option.setTrustStore(trustStore); - Assert.assertEquals("trust.jks", trustStore); + Assertions.assertEquals("trust.jks", trustStore); String trustStoreType = option.getTrustStoreType(); option.setTrustStoreType(trustStoreType); - Assert.assertEquals("JKS", trustStoreType); + Assertions.assertEquals("JKS", trustStoreType); String trustStoreValue = option.getTrustStoreValue(); option.setTrustStoreValue(trustStoreValue); - Assert.assertEquals("Changeme_123", trustStoreValue); + Assertions.assertEquals("Changeme_123", trustStoreValue); String keyStore = option.getKeyStore(); option.setKeyStore(keyStore); - Assert.assertEquals("server.p12", keyStore); + Assertions.assertEquals("server.p12", keyStore); String keyStoreType = option.getKeyStoreType(); option.setKeyStoreType(keyStoreType); - Assert.assertEquals("PKCS12", keyStoreType); + Assertions.assertEquals("PKCS12", keyStoreType); String keyStoreValue = option.getKeyStoreValue(); option.setKeyStoreValue(keyStoreValue); - Assert.assertEquals("Changeme_123", keyStoreValue); + Assertions.assertEquals("Changeme_123", keyStoreValue); String crl = option.getCrl(); option.setCrl(crl); - Assert.assertEquals("revoke.crl", crl); + Assertions.assertEquals("revoke.crl", crl); option.setSslCustomClass("123"); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); - Assert.assertArrayEquals(custom.decode("123".toCharArray()), "123".toCharArray()); + Assertions.assertArrayEquals(custom.decode("123".toCharArray()), "123".toCharArray()); } @SuppressWarnings("unused") @@ -332,7 +312,7 @@ public void testSSLOptionNull() { try { SSLOption option = SSLOption.build(DIR + "/servers.ssl.properties"); } catch (IllegalArgumentException e) { - Assert.assertEquals("Bad file name.", e.getMessage()); + Assertions.assertEquals("Bad file name.", e.getMessage()); } } @@ -347,9 +327,9 @@ public String getCanonicalPath() throws IOException { try { SSLOption option = SSLOption.build(DIR + "/server.ssl.properties"); - Assert.assertNotNull(option); + Assertions.assertNotNull(option); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -364,12 +344,12 @@ public synchronized void load(Reader reader) throws IOException { boolean validAssert = true; try { SSLOption option = SSLOption.build(DIR + "/server.ssl.properties"); - Assert.assertEquals("revoke.crl", option.getCrl()); + Assertions.assertEquals("revoke.crl", option.getCrl()); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } @Test @@ -380,9 +360,9 @@ public void testBuildInputStream() { InputStream inputStream = url.openStream(); SSLOption option = SSLOption.build(inputStream); - Assert.assertNotNull(option); + Assertions.assertNotNull(option); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); } } @@ -391,11 +371,11 @@ public void testPrivateMethodException() { SSLOption option = new SSLOption(); boolean validAssert = true; try { - Deencapsulation.invoke(option, "load", "test"); + option.load("test"); } catch (Exception e) { - Assert.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); + Assertions.assertEquals("java.lang.IllegalArgumentException", e.getClass().getName()); validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLOptionFactory.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLOptionFactory.java index c18c4dad3ce..1d3b1b8b229 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLOptionFactory.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLOptionFactory.java @@ -17,13 +17,10 @@ package org.apache.servicecomb.foundation.ssl; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.netflix.config.ConcurrentCompositeConfiguration; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import mockit.Expectations; import mockit.Mock; @@ -31,39 +28,38 @@ import mockit.Mocked; public class TestSSLOptionFactory { - @Rule - public ExpectedException expectedException = ExpectedException.none(); + Environment environment = Mockito.mock(Environment.class); @Test public void testSSLOptionFactory() { - SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory("cc", null); - Assert.assertEquals(factory, null); + SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory("cc", environment); + Assertions.assertNull(factory); } @Test public void testSSLOptionFactoryWrong(@Mocked SSLOption option) { new Expectations() { { - SSLOption.getStringProperty((ConcurrentCompositeConfiguration) any, anyString, (String[]) any); + SSLOption.getStringProperty((Environment) any, anyString, (String[]) any); result = "wrong"; } }; - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Failed to create SSLOptionFactory.")); - SSLOptionFactory.createSSLOptionFactory("cc", null); + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, + () -> SSLOptionFactory.createSSLOptionFactory("cc", null)); + Assertions.assertEquals("Failed to create SSLOptionFactory.", exception.getMessage()); } @Test - public void testSSLOptionFactoryCorrent() { + public void testSSLOptionFactoryCurrent() { new MockUp() { @Mock - public String getStringProperty(ConcurrentCompositeConfiguration configSource, String defaultValue, + public String getStringProperty(Environment environment, String defaultValue, String... keys) { return "org.apache.servicecomb.foundation.ssl.MyOptionFactory"; } }; - SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory("cc", null); - Assert.assertEquals(factory.createSSLOption().getProtocols(), "TLSv1.2"); + SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory("cc", environment); + Assertions.assertEquals(factory.createSSLOption().getProtocols(), "TLSv1.2"); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLSocketFactoryExt.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLSocketFactoryExt.java index 001600bd004..7c1e8c87724 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLSocketFactoryExt.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestSSLSocketFactoryExt.java @@ -20,9 +20,9 @@ import javax.net.ssl.SSLSocketFactory; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; public class TestSSLSocketFactoryExt { @@ -51,6 +51,6 @@ public void testCreateSocketException() { } catch (Exception e) { validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestTrustAllManager.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestTrustAllManager.java index 8690a79abf6..7a5256925c9 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestTrustAllManager.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TestTrustAllManager.java @@ -17,14 +17,14 @@ package org.apache.servicecomb.foundation.ssl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + import java.net.Socket; import java.security.cert.X509Certificate; import javax.net.ssl.SSLEngine; -import org.junit.Assert; -import org.junit.Test; - public class TestTrustAllManager { @Test public void testTrustAllManager() throws Exception { @@ -45,6 +45,6 @@ public void testTrustAllManager() throws Exception { manager.checkServerTrusted((X509Certificate[]) null, (String) null, (SSLEngine) null); - Assert.assertEquals(manager.getAcceptedIssuers() == null, true); + Assertions.assertNull(manager.getAcceptedIssuers()); } } diff --git a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TrustManagerExtTest.java b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TrustManagerExtTest.java index 22f8cb74051..d9f65d56aae 100644 --- a/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TrustManagerExtTest.java +++ b/foundations/foundation-ssl/src/test/java/org/apache/servicecomb/foundation/ssl/TrustManagerExtTest.java @@ -41,7 +41,6 @@ import javax.net.ssl.X509ExtendedTrustManager; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -49,11 +48,12 @@ import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TrustManagerExtTest { final String strFilePath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); - class MyX509ExtendedTrustManager extends X509ExtendedTrustManager { + static class MyX509ExtendedTrustManager extends X509ExtendedTrustManager { public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString, Socket paramSocket) throws CertificateException { } @@ -83,7 +83,8 @@ public X509Certificate[] getAcceptedIssuers() { } } - class MyX509Certificate extends X509Certificate { + @SuppressWarnings("deprecation") + static class MyX509Certificate extends X509Certificate { private static final long serialVersionUID = -3585440601605666276L; public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { @@ -260,8 +261,8 @@ public void testConstructor() { TrustManagerExt trustManagerExt = new TrustManagerExt((X509ExtendedTrustManager) trustManager[0], option, custom); - Assert.assertEquals(3, trustManagerExt.getAcceptedIssuers()[0].getVersion()); - Assert.assertNotNull(trustManagerExt); + Assertions.assertEquals(3, trustManagerExt.getAcceptedIssuers()[0].getVersion()); + Assertions.assertNotNull(trustManagerExt); } @Test @@ -269,9 +270,9 @@ public void testConstructorWithParam() { MyX509Certificate myX509Certificate1 = new MyX509Certificate(); MyX509Certificate myX509Certificate2 = new MyX509Certificate(); - MyX509Certificate[] MyX509CertificateArray = new MyX509Certificate[2]; - MyX509CertificateArray[0] = myX509Certificate1; - MyX509CertificateArray[1] = myX509Certificate2; + MyX509Certificate[] myX509CertificateArray = new MyX509Certificate[2]; + myX509CertificateArray[0] = myX509Certificate1; + myX509CertificateArray[1] = myX509Certificate2; new Expectations(CertificateUtil.class) { { @@ -286,16 +287,16 @@ public void testConstructorWithParam() { MyX509ExtendedTrustManager myX509ExtendedTrustManager = new MyX509ExtendedTrustManager(); TrustManagerExt trustManagerExt = new TrustManagerExt(myX509ExtendedTrustManager, option, custom); - Assert.assertNotNull(trustManagerExt); + Assertions.assertNotNull(trustManagerExt); boolean validAssert = true; try { - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks"); - trustManagerExt.checkServerTrusted(MyX509CertificateArray, "pks"); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks"); + trustManagerExt.checkServerTrusted(myX509CertificateArray, "pks"); trustManagerExt.getAcceptedIssuers(); } catch (Exception e) { validAssert = false; } - Assert.assertTrue(validAssert); + Assertions.assertTrue(validAssert); } @Test @@ -303,9 +304,9 @@ public void testCheckClientTrusted(@Mocked CertificateUtil certificateUtil) { MyX509Certificate myX509Certificate1 = new MyX509Certificate(); MyX509Certificate myX509Certificate2 = new MyX509Certificate(); - MyX509Certificate[] MyX509CertificateArray = new MyX509Certificate[2]; - MyX509CertificateArray[0] = myX509Certificate1; - MyX509CertificateArray[1] = myX509Certificate2; + MyX509Certificate[] myX509CertificateArray = new MyX509Certificate[2]; + myX509CertificateArray[0] = myX509Certificate1; + myX509CertificateArray[1] = myX509Certificate2; new Expectations() { { @@ -324,14 +325,14 @@ public void testCheckClientTrusted(@Mocked CertificateUtil certificateUtil) { SSLEngine sslengine = null; boolean validAssert = true; try { - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks", socket); - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks", sslengine); - trustManagerExt.checkServerTrusted(MyX509CertificateArray, "pks", socket); - trustManagerExt.checkServerTrusted(MyX509CertificateArray, "pks", sslengine); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks", socket); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks", sslengine); + trustManagerExt.checkServerTrusted(myX509CertificateArray, "pks", socket); + trustManagerExt.checkServerTrusted(myX509CertificateArray, "pks", sslengine); } catch (Exception e) { validAssert = false; } - Assert.assertTrue(validAssert); + Assertions.assertTrue(validAssert); } @Test @@ -339,9 +340,9 @@ public void testCatchException(@Mocked CertificateUtil certificateUtil) { MyX509Certificate myX509Certificate1 = new MyX509Certificate(); MyX509Certificate myX509Certificate2 = new MyX509Certificate(); - MyX509Certificate[] MyX509CertificateArray = new MyX509Certificate[2]; - MyX509CertificateArray[0] = myX509Certificate1; - MyX509CertificateArray[1] = myX509Certificate2; + MyX509Certificate[] myX509CertificateArray = new MyX509Certificate[2]; + myX509CertificateArray[0] = myX509Certificate1; + myX509CertificateArray[1] = myX509Certificate2; new Expectations() { { @@ -357,22 +358,22 @@ public void testCatchException(@Mocked CertificateUtil certificateUtil) { TrustManagerExt trustManagerExt = new TrustManagerExt(myX509ExtendedTrustManager, option, custom); boolean validAssert = true; try { - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks"); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks"); } catch (CertificateException e) { - Assert.assertEquals("CN does not match IP: e=[10.67.147.114],t=null", e.getMessage()); + Assertions.assertEquals("CN does not match IP: e=[10.67.147.114],t=null", e.getMessage()); validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } @Test - public void testCheckClientTrustedExecption(@Mocked CertificateUtil certificateUtil) { + public void testCheckClientTrustedException(@Mocked CertificateUtil certificateUtil) { MyX509Certificate myX509Certificate1 = new MyX509Certificate(); MyX509Certificate myX509Certificate2 = new MyX509Certificate(); - MyX509Certificate[] MyX509CertificateArray = new MyX509Certificate[2]; - MyX509CertificateArray[0] = myX509Certificate1; - MyX509CertificateArray[1] = myX509Certificate2; + MyX509Certificate[] myX509CertificateArray = new MyX509Certificate[2]; + myX509CertificateArray[0] = myX509Certificate1; + myX509CertificateArray[1] = myX509Certificate2; new Expectations() { { @@ -392,20 +393,20 @@ public void testCheckClientTrustedExecption(@Mocked CertificateUtil certificateU new MockUp() { @Mock - public int read(char cbuf[]) throws IOException { + public int read(char[] cbuf) throws IOException { throw new IOException(); } }; boolean validAssert = true; try { - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks", socket); - trustManagerExt.checkClientTrusted(MyX509CertificateArray, "pks", sslengine); - trustManagerExt.checkServerTrusted(MyX509CertificateArray, "pks", socket); - trustManagerExt.checkServerTrusted(MyX509CertificateArray, "pks", sslengine); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks", socket); + trustManagerExt.checkClientTrusted(myX509CertificateArray, "pks", sslengine); + trustManagerExt.checkServerTrusted(myX509CertificateArray, "pks", socket); + trustManagerExt.checkServerTrusted(myX509CertificateArray, "pks", sslengine); } catch (Exception e) { - Assert.assertEquals("java.security.cert.CertificateException", e.getClass().getName()); + Assertions.assertEquals("java.security.cert.CertificateException", e.getClass().getName()); validAssert = false; } - Assert.assertFalse(validAssert); + Assertions.assertFalse(validAssert); } } diff --git a/foundations/foundation-ssl/src/test/resources/client.ssl.properties b/foundations/foundation-ssl/src/test/resources/client.ssl.properties index 82209e75c81..87808468196 100644 --- a/foundations/foundation-ssl/src/test/resources/client.ssl.properties +++ b/foundations/foundation-ssl/src/test/resources/client.ssl.properties @@ -16,13 +16,14 @@ # #########SSL options -ssl.protocols=TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello -ssl.ciphers=TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA +ssl.protocols=TLSv1.3,TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello +## test with extra blank +ssl.ciphers=TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA ssl.authPeer=true ssl.checkCN.host=false ssl.checkCN.white=true ssl.checkCN.white.file=white.list -ssl.allowRenegociate=false +ssl.allowRenegotiate=false #########certificates config ssl.storePath=internal diff --git a/foundations/foundation-ssl/src/test/resources/log4j.properties b/foundations/foundation-ssl/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/foundations/foundation-ssl/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/foundations/foundation-ssl/src/test/resources/microservice.yaml b/foundations/foundation-ssl/src/test/resources/microservice.yaml index 41ca3326e51..482c8e48ea7 100644 --- a/foundations/foundation-ssl/src/test/resources/microservice.yaml +++ b/foundations/foundation-ssl/src/test/resources/microservice.yaml @@ -23,7 +23,7 @@ ssl: checkCN.host: true checkCN.white: true checkCN.white.file: white.list - allowRenegociate: false + allowRenegotiate: false storePath: internal trustStore: trust.jks trustStoreType: JKS diff --git a/foundations/foundation-ssl/src/test/resources/server.ssl.properties b/foundations/foundation-ssl/src/test/resources/server.ssl.properties index 7adfb36bd4f..d2a8180ab51 100644 --- a/foundations/foundation-ssl/src/test/resources/server.ssl.properties +++ b/foundations/foundation-ssl/src/test/resources/server.ssl.properties @@ -16,13 +16,13 @@ # #########SSL options -ssl.protocols=TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello -ssl.ciphers=TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA +ssl.protocols=TLSv1.3,TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello +ssl.ciphers=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA ssl.authPeer=true ssl.checkCN.host=true ssl.checkCN.white=true ssl.checkCN.white.file=white.list -ssl.allowRenegociate=false +ssl.allowRenegotiate=false #########certificates config ssl.storePath=internal diff --git a/foundations/foundation-ssl/src/test/resources/server.ssl.resource.properties b/foundations/foundation-ssl/src/test/resources/server.ssl.resource.properties new file mode 100644 index 00000000000..01f7380ba71 --- /dev/null +++ b/foundations/foundation-ssl/src/test/resources/server.ssl.resource.properties @@ -0,0 +1,35 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#########SSL options +ssl.protocols=TLSv1.2,TLSv1.1,TLSv1,SSLv2Hello +ssl.ciphers=TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA +ssl.authPeer=true +ssl.checkCN.host=true +ssl.checkCN.white=true +ssl.checkCN.white.file=white.list +ssl.allowRenegotiate=false + +#########certificates config +ssl.storePath=internal +ssl.trustStore=ssl/trust.jks +ssl.trustStoreType=JKS +ssl.trustStoreValue=Changeme_123 +ssl.keyStore=ssl/server.p12 +ssl.keyStoreType=PKCS12 +ssl.keyStoreValue=Changeme_123 +ssl.crl=revoke.crl diff --git a/foundations/foundation-ssl/src/test/resources/ssl/server.cer b/foundations/foundation-ssl/src/test/resources/ssl/server.cer index 79a62b21dea..fa0810bf80f 100644 --- a/foundations/foundation-ssl/src/test/resources/ssl/server.cer +++ b/foundations/foundation-ssl/src/test/resources/ssl/server.cer @@ -50,18 +50,18 @@ Certificate: 53:08:33 Exponent: 65537 (0x10001) X509v3 extensions: - X509v3 Basic Constraints: + X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: critical Digital Signature, Non Repudiation, Key Encipherment - X509v3 Subject Key Identifier: + X509v3 Subject Key Identifier: 27:15:69:5B:D5:13:60:C4:5C:62:54:75:55:A1:1D:4D:57:27:03:1F - X509v3 Authority Key Identifier: + X509v3 Authority Key Identifier: keyid:D5:4E:82:08:70:16:63:3D:DF:87:25:0B:7D:2E:EB:83:21:6A:BA:5B DirName:/C=CN/ST=GuangDong/L=ShenZhen/O=Huawei Technologies Co., Ltd/OU=OSS & Service Tools Dept/CN=OSS3.0 CA serial:7D:FD:C5:D8:70:DA:6E:0F:00:00:00:00:00:00:00:00 - X509v3 Subject Alternative Name: + X509v3 Subject Alternative Name: DNS:10.57.65.225, IP Address:10.57.65.225 Signature Algorithm: sha256WithRSAEncryption 38:1b:40:c9:3c:7f:63:a0:2d:64:59:2b:d9:4a:4b:db:c4:70: diff --git a/foundations/foundation-ssl/src/test/resources/ssl/trust.cer b/foundations/foundation-ssl/src/test/resources/ssl/trust.cer index a41bd779130..f010f4bf058 100644 --- a/foundations/foundation-ssl/src/test/resources/ssl/trust.cer +++ b/foundations/foundation-ssl/src/test/resources/ssl/trust.cer @@ -50,18 +50,18 @@ Certificate: 05:60:4b Exponent: 65537 (0x10001) X509v3 extensions: - X509v3 Basic Constraints: + X509v3 Basic Constraints: CA:TRUE X509v3 Key Usage: critical Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: + X509v3 Subject Key Identifier: D5:4E:82:08:70:16:63:3D:DF:87:25:0B:7D:2E:EB:83:21:6A:BA:5B - X509v3 Authority Key Identifier: + X509v3 Authority Key Identifier: keyid:D5:4E:82:08:70:16:63:3D:DF:87:25:0B:7D:2E:EB:83:21:6A:BA:5B DirName:/C=CN/ST=GuangDong/L=ShenZhen/O=Huawei Technologies Co., Ltd/OU=OSS & Service Tools Dept/CN=OSS3.0 CA serial:7D:FD:C5:D8:70:DA:6E:0F:00:00:00:00:00:00:00:00 - X509v3 Subject Alternative Name: + X509v3 Subject Alternative Name: email:oss3ca@huawei.com Signature Algorithm: sha256WithRSAEncryption 8a:52:5f:99:d0:7b:a0:8c:2d:e8:6c:ff:7a:bc:89:64:03:d4: diff --git a/foundations/foundation-ssl/src/test/resources/ssl/white.list b/foundations/foundation-ssl/src/test/resources/ssl/white.list index fe1d44d8e85..5719754cff9 100644 --- a/foundations/foundation-ssl/src/test/resources/ssl/white.list +++ b/foundations/foundation-ssl/src/test/resources/ssl/white.list @@ -1,4 +1,4 @@ 127.0.0.1 10.67.190.60 10.67.147.115 -10.57.65.225 \ No newline at end of file +10.57.65.225 diff --git a/foundations/foundation-test-scaffolding/pom.xml b/foundations/foundation-test-scaffolding/pom.xml index 95eeaa0a1c4..f3feba62148 100644 --- a/foundations/foundation-test-scaffolding/pom.xml +++ b/foundations/foundation-test-scaffolding/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb foundations - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT foundation-test-scaffolding Java Chassis::Foundations::Test Scaffolding @@ -31,15 +31,6 @@ org.springframework spring-context - - com.netflix.archaius - archaius-core - - - commons-configuration - commons-configuration - compile - io.vertx vertx-web @@ -49,14 +40,43 @@ vertx-codegen provided - - com.netflix.spectator - spectator-reg-servo + com.google.guava + guava + + + org.apache.logging.log4j + log4j-core + provided + true + + + org.apache.logging.log4j + log4j-api + provided + true - log4j - log4j + com.fasterxml.jackson.core + jackson-annotations + + + javax.inject + javax.inject + + + org.springframework + spring-aspects + + + io.swagger.core.v3 + swagger-core-jakarta + provided + + + org.assertj + assertj-core + compile diff --git a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncContext.java b/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncContext.java deleted file mode 100644 index eb039afd66b..00000000000 --- a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncContext.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.vertx.core.impl; - -import java.util.concurrent.Executor; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.spi.metrics.PoolMetrics; - -public class SyncContext extends EventLoopContext { - public SyncContext() { - this(null); - } - - public SyncContext(VertxInternal vertx) { - super(vertx, null, null, null, null, null, null); - if (SyncVertx.class.isInstance(vertx)) { - ((SyncVertx) vertx).setContext(this); - } - } - - @Override - public void runOnContext(Handler task) { - task.handle(null); - } - - public static void syncExecuteBlocking(Handler> blockingCodeHandler, - Handler> asyncResultHandler) { - Future res = Future.future(); - - try { - blockingCodeHandler.handle(res); - } catch (Throwable e) { - res.fail(e); - return; - } - - res.setHandler(asyncResultHandler); - } - - @Override - public void executeBlocking(Action action, Handler> resultHandler) { - syncExecuteBlocking((future) -> { - try { - future.complete(action.perform()); - } catch (Throwable e) { - future.fail(e); - } - }, resultHandler); - } - - @Override - public void executeBlocking(Handler> blockingCodeHandler, boolean ordered, - Handler> asyncResultHandler) { - syncExecuteBlocking(blockingCodeHandler, asyncResultHandler); - } - - @Override - void executeBlocking(Action action, Handler> blockingCodeHandler, - Handler> resultHandler, - Executor exec, TaskQueue queue, @SuppressWarnings("rawtypes") PoolMetrics metrics) { - syncExecuteBlocking(blockingCodeHandler, resultHandler); - } -} diff --git a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncVertx.java b/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncVertx.java deleted file mode 100644 index 5fada598c84..00000000000 --- a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/core/impl/SyncVertx.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.vertx.core.impl; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; - -/** - * after test finished, need to invoke vertx.close - */ -public class SyncVertx extends VertxImpl { - private ContextImpl context = new SyncContext(this); - - public SyncVertx() { - this(null, null); - } - - protected SyncVertx(VertxOptions options, Handler> resultHandler) { - } - - @Override - public ContextImpl getContext() { - return context; - } - - public void setContext(ContextImpl context) { - this.context = context; - } - - @Override - public ContextImpl getOrCreateContext() { - return context; - } -} diff --git a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/ext/web/impl/HttpServerRequestWrapperForTest.java b/foundations/foundation-test-scaffolding/src/main/java/io/vertx/ext/web/impl/HttpServerRequestWrapperForTest.java deleted file mode 100644 index 19364eb8df5..00000000000 --- a/foundations/foundation-test-scaffolding/src/main/java/io/vertx/ext/web/impl/HttpServerRequestWrapperForTest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.ext.web.impl; - -import io.vertx.core.http.HttpServerRequest; - -public class HttpServerRequestWrapperForTest extends HttpServerRequestWrapper { - HttpServerRequestWrapperForTest(HttpServerRequest request) { - super(request); - } -} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/AssertUtils.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/AssertUtils.java new file mode 100644 index 00000000000..ef310a9da51 --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/AssertUtils.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.assertj.core.api.AbstractStringAssert; + +import io.netty.handler.codec.string.LineSeparator; +import io.vertx.core.json.Json; + +public interface AssertUtils { + static AbstractStringAssert assertPrettyJson(Object value) { + String json = Json.encodePrettily(value) + .replace(LineSeparator.WINDOWS.value(), LineSeparator.UNIX.value()); + return assertThat(json); + } +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/config/ArchaiusUtils.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/config/ArchaiusUtils.java deleted file mode 100644 index ca91ef6179a..00000000000 --- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/config/ArchaiusUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.test.scaffolding.config; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.util.ReflectionUtils; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicProperty; -import com.netflix.config.DynamicPropertyFactory; - -public final class ArchaiusUtils { - private static final Field FIELD_INSTANCE = ReflectionUtils.findField(ConfigurationManager.class, "instance"); - - private static final Field FIELD_CUSTOM_CONFIGURATION_INSTALLED = - ReflectionUtils.findField(ConfigurationManager.class, "customConfigurationInstalled"); - - private static final Field FIELD_CONFIG = ReflectionUtils.findField(DynamicPropertyFactory.class, "config"); - - private static final Field FIELD_INITIALIZED_WITH_DEFAULT_CONFIG = - ReflectionUtils.findField(DynamicPropertyFactory.class, "initializedWithDefaultConfig"); - - private static final Field FIELD_DYNAMIC_PROPERTY_SUPPORTIMPL = - ReflectionUtils.findField(DynamicProperty.class, "dynamicPropertySupportImpl"); - - private static final Field FIELD_DYNAMIC_PROPERTY_ALL_PROPS = ReflectionUtils - .findField(DynamicProperty.class, "ALL_PROPS"); - - private static Method updatePropertyMethod = - ReflectionUtils.findMethod(DynamicProperty.class, "updateProperty", String.class, Object.class); - - static { - FIELD_INSTANCE.setAccessible(true); - FIELD_CUSTOM_CONFIGURATION_INSTALLED.setAccessible(true); - FIELD_CONFIG.setAccessible(true); - FIELD_INITIALIZED_WITH_DEFAULT_CONFIG.setAccessible(true); - FIELD_DYNAMIC_PROPERTY_SUPPORTIMPL.setAccessible(true); - FIELD_DYNAMIC_PROPERTY_ALL_PROPS.setAccessible(true); - updatePropertyMethod.setAccessible(true); - } - - private ArchaiusUtils() { - } - - @SuppressWarnings("unchecked") - public static void resetConfig() { - ReflectionUtils.setField(FIELD_INSTANCE, null, null); - ReflectionUtils.setField(FIELD_CUSTOM_CONFIGURATION_INSTALLED, null, false); - ReflectionUtils.setField(FIELD_CONFIG, null, null); - ReflectionUtils.setField(FIELD_INITIALIZED_WITH_DEFAULT_CONFIG, null, false); - ReflectionUtils.setField(FIELD_DYNAMIC_PROPERTY_SUPPORTIMPL, null, null); - ((ConcurrentHashMap) ReflectionUtils.getField(FIELD_DYNAMIC_PROPERTY_ALL_PROPS, null)) - .clear(); - } - - public static void setProperty(String key, Object value) { - // ensure have instance - DynamicPropertyFactory.getInstance(); - - ConcurrentCompositeConfiguration config = (ConcurrentCompositeConfiguration) DynamicPropertyFactory - .getBackingConfigurationSource(); - config.getConfiguration(0).addProperty(key, value); - } - - /** - * difference with setProperty is that, updateProperty value can be null - * @param key - * @param value - */ - public static void updateProperty(String key, Object value) { - ReflectionUtils.invokeMethod(updatePropertyMethod, null, key, value); - } -} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/exception/RuntimeExceptionWithoutStackTrace.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/exception/RuntimeExceptionWithoutStackTrace.java new file mode 100644 index 00000000000..65f17678548 --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/exception/RuntimeExceptionWithoutStackTrace.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.test.scaffolding.exception; + +public class RuntimeExceptionWithoutStackTrace extends RuntimeException { + private static final long serialVersionUID = -1L; + + public RuntimeExceptionWithoutStackTrace() { + } + + public RuntimeExceptionWithoutStackTrace(String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java index 026408a91a2..5b435b89829 100644 --- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java @@ -16,53 +16,93 @@ */ package org.apache.servicecomb.foundation.test.scaffolding.log; +import java.io.Closeable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; -import org.apache.log4j.Appender; -import org.apache.log4j.AppenderSkeleton; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.log4j.spi.LoggingEvent; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.layout.PatternLayout; -public class LogCollector { - List events = new ArrayList<>(); +public class LogCollector implements Closeable { + List events = new ArrayList<>(); - Appender appender = new AppenderSkeleton() { - @Override - public void append(LoggingEvent event) { - events.add(event); - } + Appender appender; - @Override - public void close() { - - } - - @Override - public boolean requiresLayout() { - return false; - } - }; + String appenderName; public LogCollector() { - Logger.getRootLogger().addAppender(appender); + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + appenderName = "LogCollector" + System.nanoTime(); + appender = new AbstractAppender(appenderName, null, PatternLayout.createDefaultLayout(), + true, + Property.EMPTY_ARRAY) { + @Override + public void append(LogEvent event) { + events.add(event); + } + }; + appender.start(); + config.getRootLogger().addAppender(appender, Level.ALL, null); + ctx.updateLoggers(config); } public LogCollector setLogLevel(String logName, Level level) { - Logger.getLogger(logName).setLevel(level); + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + config.getLoggerConfig(logName).setLevel(level); return this; } - public List getEvents() { + public List getEvents() { return events; } - public void teardown() { - Logger.getRootLogger().removeAppender(appender); + public LogEvent getEvent(int index) { + return events.get(index); + } + + public LogEvent getLastEvents() { + return events.get(events.size() - 1); + } + + public List getThrowables() { + return events.stream() + .map(LogEvent::getThrown) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + public List getThrowableMessages() { + return events.stream() + .filter(e -> e.getThrown() != null) + .map(e -> e.getThrown().getMessage()) + .collect(Collectors.toList()); + } + + public void tearDown() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + appender.stop(); + config.getRootLogger().removeAppender(appenderName); + ctx.updateLoggers(config); } public void clear() { events = new ArrayList<>(); } + + @Override + public void close() { + tearDown(); + } } diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/Media.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/Media.java new file mode 100644 index 00000000000..f16acc4bacc --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/Media.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * To test the situation that enum values are specified by {@link JsonProperty}. + */ +public enum Media { + @JsonProperty("AAC") + AAC, + @JsonProperty + FLAC, + @JsonProperty("H.264") + H_264, + @JsonProperty("MPEG-2") + MPEG_2, + WMV +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java new file mode 100644 index 00000000000..e5600ce9024 --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/People.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding.model; + +import java.util.List; + +public class People { + public String name; + + public List friends; +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/User.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/User.java index 0508a67864a..630d48b0ca1 100644 --- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/User.java +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/model/User.java @@ -19,8 +19,14 @@ import java.util.List; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; + public class User { public String name; + // An issue not fixed by open api + // see: https://github.com/swagger-api/swagger-core/issues/3484 + @ArraySchema(schema = @Schema(implementation = User.class)) public List friends; } diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java new file mode 100644 index 00000000000..ba0f3c625e5 --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockClock.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding.time; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +public class MockClock extends Clock { + private MockValues values; + + public MockClock() { + this(0L); + } + + public MockClock(Long... values) { + this.setValues(values); + } + + public MockClock setValues(Long... values) { + this.values = new MockValues() + .setDefaultValue(0L) + .setValues(values); + return this; + } + + @Override + public ZoneId getZone() { + return null; + } + + @Override + public Clock withZone(ZoneId zone) { + return null; + } + + @Override + public Instant instant() { + return null; + } + + @Override + public long millis() { + return values.read(); + } +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java new file mode 100644 index 00000000000..9bd666d00ed --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockTicker.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding.time; + +import com.google.common.base.Ticker; + +public class MockTicker extends Ticker { + private MockValues values; + + public MockTicker() { + this(0L); + } + + public MockTicker(Long... values) { + this.setValues(values); + } + + public MockTicker setValues(Long... values) { + this.values = new MockValues() + .setDefaultValue(0L) + .setValues(values); + return this; + } + + @Override + public long read() { + return values.read(); + } +} diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java new file mode 100644 index 00000000000..457a8f0c072 --- /dev/null +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/time/MockValues.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.test.scaffolding.time; + +public class MockValues { + private T defaultValue; + + private T[] values; + + private int index; + + public MockValues setDefaultValue(T defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public MockValues setValues(T[] values) { + this.values = values; + this.index = 0; + return this; + } + + public T read() { + if (values == null || values.length == 0) { + return defaultValue; + } + + if (index >= values.length) { + return values[values.length - 1]; + } + + T value = values[index]; + index++; + return value; + } +} diff --git a/foundations/foundation-test-scaffolding/src/main/resources/config/log4j.properties b/foundations/foundation-test-scaffolding/src/main/resources/config/log4j.properties deleted file mode 100644 index a6911b4f6b3..00000000000 --- a/foundations/foundation-test-scaffolding/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -paas.logs.dir=target/ \ No newline at end of file diff --git a/foundations/foundation-vertx/pom.xml b/foundations/foundation-vertx/pom.xml index 652068a7e39..24556f590f7 100644 --- a/foundations/foundation-vertx/pom.xml +++ b/foundations/foundation-vertx/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb foundations - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT foundation-vertx Java Chassis::Foundations::Vertx @@ -49,10 +49,20 @@ vertx-codegen provided - + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + - org.slf4j - slf4j-log4j12 + org.jmockit + jmockit test diff --git a/foundations/foundation-vertx/src/main/java/io/vertx/core/impl/VertxImplEx.java b/foundations/foundation-vertx/src/main/java/io/vertx/core/impl/VertxImplEx.java deleted file mode 100644 index 2020ff3b41d..00000000000 --- a/foundations/foundation-vertx/src/main/java/io/vertx/core/impl/VertxImplEx.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.core.impl; - -import java.lang.reflect.Field; -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -import io.vertx.core.VertxOptions; -import io.vertx.core.json.JsonObject; - -public class VertxImplEx extends VertxImpl { - private AtomicLong eventLoopContextCreated = new AtomicLong(); - - public VertxImplEx(String name, VertxOptions vertxOptions) { - super(vertxOptions); - - if (StringUtils.isEmpty(name)) { - return; - } - - Field field = ReflectionUtils.findField(VertxImpl.class, "eventLoopThreadFactory"); - field.setAccessible(true); - VertxThreadFactory eventLoopThreadFactory = (VertxThreadFactory) ReflectionUtils.getField(field, this); - - field = ReflectionUtils.findField(eventLoopThreadFactory.getClass(), "prefix"); - field.setAccessible(true); - - String prefix = (String) ReflectionUtils.getField(field, eventLoopThreadFactory); - ReflectionUtils.setField(field, eventLoopThreadFactory, name + "-" + prefix); - } - - @Override - public EventLoopContext createEventLoopContext(String deploymentID, WorkerPool workerPool, JsonObject config, - ClassLoader tccl) { - eventLoopContextCreated.incrementAndGet(); - return super.createEventLoopContext(deploymentID, workerPool, config, tccl); - } - - public long getEventLoopContextCreatedCount() { - return eventLoopContextCreated.get(); - } -} diff --git a/foundations/foundation-vertx/src/main/java/io/vertx/core/net/impl/VertxHelper.java b/foundations/foundation-vertx/src/main/java/io/vertx/core/net/impl/VertxHelper.java deleted file mode 100644 index 31873d1256a..00000000000 --- a/foundations/foundation-vertx/src/main/java/io/vertx/core/net/impl/VertxHelper.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.core.net.impl; - -import io.vertx.core.Context; - -public final class VertxHelper { - private VertxHelper() { - } - - public static Context getConnectionContext(ConnectionBase connection) { - return connection.getContext(); - } -} diff --git a/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/HttpServerRequestUtils.java b/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/HttpServerRequestUtils.java deleted file mode 100644 index 257770eb10b..00000000000 --- a/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/HttpServerRequestUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.ext.web.impl; - -import io.vertx.core.http.HttpServerRequest; - -public interface HttpServerRequestUtils { - static void setPath(HttpServerRequest request, String path) { - ((HttpServerRequestWrapper) request).setPath(path); - } -} diff --git a/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/MimeTypesUtils.java b/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/MimeTypesUtils.java deleted file mode 100644 index c184726a990..00000000000 --- a/foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/MimeTypesUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 Red Hat, Inc. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Apache License v2.0 which accompanies this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * The Apache License v2.0 is available at - * http://www.opensource.org/licenses/apache2.0.php - * - * You may elect to redistribute this code under either of these licenses. - * - */ - -/* - * Forked from https://github.com/vert-x3/vertx-web/blob/927ed057ddc028eb09a168db621de3d72fd85ed4/vertx-web/src/main/java/io/vertx/ext/web/impl/Utils.java - * Because we uses getSortedAcceptableMimeTypes method which is removed by vertx. - */ - -package io.vertx.ext.web.impl; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.regex.Pattern; - -public class MimeTypesUtils { - private static final Pattern COMMA_SPLITTER = Pattern.compile(" *, *"); - - private static final Pattern SEMICOLON_SPLITTER = Pattern.compile(" *; *"); - - private static final Pattern EQUAL_SPLITTER = Pattern.compile(" *= *"); - - private static final Comparator ACCEPT_X_COMPARATOR = new Comparator() { - float getQuality(String s) { - if (s == null) { - return 0; - } - - String[] params = SEMICOLON_SPLITTER.split(s); - for (int i = 1; i < params.length; i++) { - String[] q = EQUAL_SPLITTER.split(params[1]); - if ("q".equals(q[0])) { - return Float.parseFloat(q[1]); - } - } - return 1; - } - - @Override - public int compare(String o1, String o2) { - float f1 = getQuality(o1); - float f2 = getQuality(o2); - return Float.compare(f2, f1); - } - }; - - public static List getSortedAcceptableMimeTypes(String acceptHeader) { - // accept anything when accept is not present - if (acceptHeader == null) { - return Collections.emptyList(); - } - - // parse - String[] items = COMMA_SPLITTER.split(acceptHeader); - // sort on quality - Arrays.sort(items, ACCEPT_X_COMPARATOR); - - List list = new ArrayList<>(items.length); - - for (String item : items) { - // find any ; e.g.: "application/json;q=0.8" - int space = item.indexOf(';'); - - if (space != -1) { - list.add(item.substring(0, space)); - } else { - list.add(item); - } - } - - return list; - } -} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/AddressResolverConfig.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/AddressResolverConfig.java index 90f3865da94..2d4ee389642 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/AddressResolverConfig.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/AddressResolverConfig.java @@ -20,12 +20,10 @@ import java.util.Arrays; import java.util.List; -import org.apache.commons.configuration.Configuration; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.netflix.config.DynamicPropertyFactory; - import io.vertx.core.dns.AddressResolverOptions; public class AddressResolverConfig { @@ -37,84 +35,69 @@ public class AddressResolverConfig { * @param tag config tag, such as sc.consumer or cc.consumer * @return AddressResolverOptions */ - public static AddressResolverOptions getAddressResover(String tag) { - return getAddressResover(tag, null); - } - - /** - * get the target endpoints with custom address resolve config - * @param tag config tag, such as sc.consumer or cc.consumer - * @param configSource get config from special config source - * @return AddressResolverOptions - */ - public static AddressResolverOptions getAddressResover(String tag, Configuration configSource) { + public static AddressResolverOptions getAddressResolverOptions(String tag) { AddressResolverOptions addressResolverOptions = new AddressResolverOptions(); addressResolverOptions - .setServers(getStringListProperty(configSource, - AddressResolverOptions.DEFAULT_SEACH_DOMAINS, + .setServers(getStringListProperty( + AddressResolverOptions.DEFAULT_SERVERS, "addressResolver." + tag + ".servers", "addressResolver.servers")); addressResolverOptions - .setOptResourceEnabled(getBooleanProperty(configSource, + .setOptResourceEnabled(getBooleanProperty( AddressResolverOptions.DEFAULT_OPT_RESOURCE_ENABLED, "addressResolver." + tag + ".optResourceEnabled", "addressResolver.optResourceEnabled")); addressResolverOptions - .setCacheMinTimeToLive(getPositiveIntProperty(configSource, + .setCacheMinTimeToLive(getPositiveIntProperty( AddressResolverOptions.DEFAULT_CACHE_MIN_TIME_TO_LIVE, "addressResolver." + tag + ".cacheMinTimeToLive", "addressResolver.cacheMinTimeToLive")); addressResolverOptions - .setCacheMaxTimeToLive(getPositiveIntProperty(configSource, + .setCacheMaxTimeToLive(getPositiveIntProperty( AddressResolverOptions.DEFAULT_CACHE_MAX_TIME_TO_LIVE, "addressResolver." + tag + ".cacheMaxTimeToLive", "addressResolver.cacheMaxTimeToLive")); addressResolverOptions - .setCacheNegativeTimeToLive(getPositiveIntProperty(configSource, + .setCacheNegativeTimeToLive(getPositiveIntProperty( AddressResolverOptions.DEFAULT_CACHE_NEGATIVE_TIME_TO_LIVE, "addressResolver." + tag + ".cacheNegativeTimeToLive", "addressResolver.cacheNegativeTimeToLive")); addressResolverOptions - .setQueryTimeout(getPositiveIntProperty(configSource, + .setQueryTimeout(getPositiveIntProperty( AddressResolverOptions.DEFAULT_QUERY_TIMEOUT, "addressResolver." + tag + ".queryTimeout", "addressResolver.queryTimeout")); addressResolverOptions - .setMaxQueries(getPositiveIntProperty(configSource, + .setMaxQueries(getPositiveIntProperty( AddressResolverOptions.DEFAULT_MAX_QUERIES, "addressResolver." + tag + ".maxQueries", "addressResolver.maxQueries")); addressResolverOptions - .setRdFlag(getBooleanProperty(configSource, + .setRdFlag(getBooleanProperty( AddressResolverOptions.DEFAULT_RD_FLAG, "addressResolver." + tag + ".rdFlag", "addressResolver.rdFlag")); addressResolverOptions - .setSearchDomains(getStringListProperty(configSource, - AddressResolverOptions.DEFAULT_SEACH_DOMAINS, + .setSearchDomains(getStringListProperty( + AddressResolverOptions.DEFAULT_SEARCH_DOMAINS, "addressResolver." + tag + ".searchDomains", "addressResolver.searchDomains")); addressResolverOptions - .setNdots(getPositiveIntProperty(configSource, - AddressResolverOptions.DEFAULT_CACHE_MIN_TIME_TO_LIVE, + .setNdots(getPositiveIntProperty( + AddressResolverOptions.DEFAULT_NDOTS, "addressResolver." + tag + ".ndots", "addressResolver.ndots")); addressResolverOptions - .setRotateServers(getBooleanProperty(configSource, + .setRotateServers(getBooleanProperty( AddressResolverOptions.DEFAULT_ROTATE_SERVERS, "addressResolver." + tag + ".rotateServers", "addressResolver.rotateServers")); return addressResolverOptions; } - private static List getStringListProperty(Configuration configSource, - List defaultValue, String... keys) { - configSource = guardConfigSource(configSource); - if (configSource == null) { - return defaultValue; - } + private static List getStringListProperty(List defaultValue, String... keys) { for (String key : keys) { - String[] vals = configSource.getStringArray(key); + String[] vals = LegacyPropertyFactory.getProperty(key, String[].class); if (vals != null && vals.length > 0) { return Arrays.asList(vals); } @@ -122,15 +105,11 @@ private static List getStringListProperty(Configuration configSource, return defaultValue; } - private static int getPositiveIntProperty(Configuration configSource, int defaultValue, String... keys) { - configSource = guardConfigSource(configSource); - if (configSource == null) { - return defaultValue; - } + private static int getPositiveIntProperty(int defaultValue, String... keys) { for (String key : keys) { - Integer val = configSource.getInteger(key, null); + Integer val = LegacyPropertyFactory.getProperty(key, Integer.class); if (val != null && val <= 0) { - LOGGER.warn("Address resover key:{}'s value:{} is not positive, please check!", key, val); + LOGGER.warn("Address resolver key:{}'s value:{} is not positive, please check!", key, val); continue; } if (val != null) { @@ -140,25 +119,14 @@ private static int getPositiveIntProperty(Configuration configSource, int defaul return defaultValue; } - private static boolean getBooleanProperty(Configuration configSource, boolean defaultValue, + private static boolean getBooleanProperty(boolean defaultValue, String... keys) { - configSource = guardConfigSource(configSource); - if (configSource == null) { - return defaultValue; - } for (String key : keys) { - Boolean val = configSource.getBoolean(key, null); + Boolean val = LegacyPropertyFactory.getProperty(key, Boolean.class); if (val != null) { return val; } } return defaultValue; } - - private static Configuration guardConfigSource(Configuration configSource) { - if (configSource == null && DynamicPropertyFactory.getBackingConfigurationSource() != null) { - configSource = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - } - return configSource; - } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SharedVertxFactory.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SharedVertxFactory.java new file mode 100644 index 00000000000..9f2d3af797b --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SharedVertxFactory.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.vertx; + +import org.apache.servicecomb.foundation.vertx.metrics.DefaultVertxMetricsFactory; +import org.apache.servicecomb.foundation.vertx.metrics.MetricsOptionsEx; +import org.springframework.core.env.Environment; + +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.core.shareddata.Shareable; + +public class SharedVertxFactory { + static class SharedVertxInfo implements Shareable { + public VertxOptions vertxOptions = new VertxOptions(); + + public DefaultVertxMetricsFactory metricsFactory = new DefaultVertxMetricsFactory(); + + public MetricsOptionsEx metricsOptionsEx = (MetricsOptionsEx) metricsFactory.newOptions(); + + public SharedVertxInfo(Environment environment) { + vertxOptions.setMetricsOptions(metricsOptionsEx); + vertxOptions.setEventLoopPoolSize(readEventLoopPoolSize(environment, "servicecomb.transport.eventloop.size")); + } + + private static int readEventLoopPoolSize(Environment environment, String key) { + int count = environment.getProperty(key, int.class, -1); + if (count > 0) { + return count; + } + return VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE; + } + } + + private static final String LOCAL_MAP_NAME = "scb"; + + private static final String INFO = "transport-vertx-info"; + + public static DefaultVertxMetricsFactory getMetricsFactory(Environment environment) { + SharedVertxInfo info = (SharedVertxInfo) getSharedVertx(environment).sharedData().getLocalMap(LOCAL_MAP_NAME) + .get(INFO); + return info.metricsFactory; + } + + public static Vertx getSharedVertx(Environment environment) { + return VertxUtils.getVertxMap().computeIfAbsent("transport", + key -> createSharedVertx(environment, key)); + } + + private static Vertx createSharedVertx(Environment environment, String name) { + SharedVertxInfo info = new SharedVertxInfo(environment); + + Vertx vertx = VertxUtils.init(name, info.vertxOptions, info.metricsFactory); + info.metricsFactory.setVertx(vertx, info.vertxOptions); + vertx.sharedData().getLocalMap(LOCAL_MAP_NAME).put(INFO, info); + + return vertx; + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SimpleBodyHandler.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SimpleBodyHandler.java index afced60db00..7f089ead415 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SimpleBodyHandler.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/SimpleBodyHandler.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.foundation.vertx; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status; import org.apache.http.HttpHeaders; diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxConst.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxConst.java new file mode 100644 index 00000000000..1ee2afa27d2 --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxConst.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx; + +public final class VertxConst { + public static final String PROXY_PRE_NAME = "servicecomb.proxy."; + + public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable"; + + public static final String PROXY_HOST = PROXY_PRE_NAME + "host"; + + public static final String PROXY_PORT = PROXY_PRE_NAME + "port"; + + public static final String PROXY_USERNAME = PROXY_PRE_NAME + "username"; + + public static final String PROXY_PASSWD = PROXY_PRE_NAME + "passwd"; +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxTLSBuilder.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxTLSBuilder.java index 790c7640bea..ba2203338e6 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxTLSBuilder.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxTLSBuilder.java @@ -18,9 +18,12 @@ package org.apache.servicecomb.foundation.vertx; import java.io.File; +import java.net.URL; import java.util.Arrays; import java.util.HashSet; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.ssl.SSLCustom; import org.apache.servicecomb.foundation.ssl.SSLManager; import org.apache.servicecomb.foundation.ssl.SSLOption; @@ -30,6 +33,7 @@ import io.vertx.core.http.ClientAuth; import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.WebSocketClientOptions; import io.vertx.core.net.ClientOptionsBase; import io.vertx.core.net.JksOptions; import io.vertx.core.net.NetServerOptions; @@ -51,19 +55,32 @@ private VertxTLSBuilder() { public static NetServerOptions buildNetServerOptions(SSLOption sslOption, SSLCustom sslCustom, NetServerOptions netServerOptions) { buildTCPSSLOptions(sslOption, sslCustom, netServerOptions); - if (sslOption.isAuthPeer()) { + setClientAuth(sslOption, netServerOptions); + return netServerOptions; + } + + private static void setClientAuth(SSLOption sslOption, NetServerOptions netServerOptions) { + if (sslOption.isAuthPeer() || org.apache.servicecomb.foundation.ssl.ClientAuth.REQUIRED + .equals(sslOption.getClientAuth())) { netServerOptions.setClientAuth(ClientAuth.REQUIRED); - } else { - netServerOptions.setClientAuth(ClientAuth.REQUEST); + return; } - return netServerOptions; + + if (org.apache.servicecomb.foundation.ssl.ClientAuth.NONE + .equals(sslOption.getClientAuth())) { + netServerOptions.setClientAuth(ClientAuth.NONE); + return; + } + + netServerOptions.setClientAuth(ClientAuth.REQUEST); + return; } public static void buildHttpClientOptions(String sslKey, HttpClientOptions httpClientOptions) { - SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory(sslKey, null); + SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory(sslKey, LegacyPropertyFactory.getEnvironment()); SSLOption sslOption; if (factory == null) { - sslOption = SSLOption.buildFromYaml(sslKey); + sslOption = SSLOption.build(sslKey, LegacyPropertyFactory.getEnvironment()); } else { sslOption = factory.createSSLOption(); } @@ -71,6 +88,18 @@ public static void buildHttpClientOptions(String sslKey, HttpClientOptions httpC buildHttpClientOptions(sslOption, sslCustom, httpClientOptions); } + public static void buildWebSocketClientOptions(String sslKey, WebSocketClientOptions webSocketClientOptions) { + SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory(sslKey, LegacyPropertyFactory.getEnvironment()); + SSLOption sslOption; + if (factory == null) { + sslOption = SSLOption.build(sslKey, LegacyPropertyFactory.getEnvironment()); + } else { + sslOption = factory.createSSLOption(); + } + SSLCustom sslCustom = SSLCustom.createSSLCustom(sslOption.getSslCustomClass()); + buildWebSocketClientOptions(sslOption, sslCustom, webSocketClientOptions); + } + public static HttpClientOptions buildHttpClientOptions(SSLOption sslOption, SSLCustom sslCustom, HttpClientOptions httpClientOptions) { buildClientOptionsBase(sslOption, sslCustom, httpClientOptions); @@ -78,6 +107,13 @@ public static HttpClientOptions buildHttpClientOptions(SSLOption sslOption, SSLC return httpClientOptions; } + public static WebSocketClientOptions buildWebSocketClientOptions(SSLOption sslOption, SSLCustom sslCustom, + WebSocketClientOptions webSocketClientOptions) { + buildClientOptionsBase(sslOption, sslCustom, webSocketClientOptions); + webSocketClientOptions.setVerifyHost(sslOption.isCheckCNHost()); + return webSocketClientOptions; + } + public static ClientOptionsBase buildClientOptionsBase(SSLOption sslOption, SSLCustom sslCustom, ClientOptionsBase clientOptionsBase) { buildTCPSSLOptions(sslOption, sslCustom, clientOptionsBase); @@ -95,22 +131,20 @@ private static TCPSSLOptions buildTCPSSLOptions(SSLOption sslOption, SSLCustom s tcpClientOptions.setSsl(true); if (sslOption.getEngine().equalsIgnoreCase("openssl")) { - OpenSSLEngineOptions options = new OpenSSLEngineOptions(); - options.setSessionCacheEnabled(true); - tcpClientOptions.setOpenSslEngineOptions(new OpenSSLEngineOptions()); + tcpClientOptions.setSslEngineOptions(new OpenSSLEngineOptions()); } String fullKeyStore = sslCustom.getFullPath(sslOption.getKeyStore()); if (isFileExists(fullKeyStore)) { if (STORE_PKCS12.equalsIgnoreCase(sslOption.getKeyStoreType())) { PfxOptions keyPfxOptions = new PfxOptions(); - keyPfxOptions.setPath(sslCustom.getFullPath(sslOption.getKeyStore())); + keyPfxOptions.setPath(fullKeyStore); keyPfxOptions.setPassword(new String(sslCustom.decode(sslOption.getKeyStoreValue().toCharArray()))); - tcpClientOptions.setPfxKeyCertOptions(keyPfxOptions); + tcpClientOptions.setKeyCertOptions(keyPfxOptions); } else if (STORE_JKS.equalsIgnoreCase(sslOption.getKeyStoreType())) { JksOptions keyJksOptions = new JksOptions(); - keyJksOptions.setPath(sslCustom.getFullPath(sslOption.getKeyStore())); + keyJksOptions.setPath(fullKeyStore); keyJksOptions.setPassword(new String(sslCustom.decode(sslOption.getKeyStoreValue().toCharArray()))); - tcpClientOptions.setKeyStoreOptions(keyJksOptions); + tcpClientOptions.setKeyCertOptions(keyJksOptions); } else { throw new IllegalArgumentException("invalid key store type."); } @@ -121,16 +155,16 @@ private static TCPSSLOptions buildTCPSSLOptions(SSLOption sslOption, SSLCustom s if (isFileExists(fullTrustStore)) { if (STORE_PKCS12.equalsIgnoreCase(sslOption.getTrustStoreType())) { PfxOptions trustPfxOptions = new PfxOptions(); - trustPfxOptions.setPath(sslCustom.getFullPath(sslOption.getTrustStore())); + trustPfxOptions.setPath(fullTrustStore); trustPfxOptions .setPassword(new String(sslCustom.decode(sslOption.getTrustStoreValue().toCharArray()))); - tcpClientOptions.setPfxTrustOptions(trustPfxOptions); + tcpClientOptions.setTrustOptions(trustPfxOptions); } else if (STORE_JKS.equalsIgnoreCase(sslOption.getTrustStoreType())) { JksOptions trustJksOptions = new JksOptions(); - trustJksOptions.setPath(sslCustom.getFullPath(sslOption.getTrustStore())); + trustJksOptions.setPath(fullTrustStore); trustJksOptions .setPassword(new String(sslCustom.decode(sslOption.getTrustStoreValue().toCharArray()))); - tcpClientOptions.setTrustStoreOptions(trustJksOptions); + tcpClientOptions.setTrustOptions(trustJksOptions); } else { throw new IllegalArgumentException("invalid trust store type."); } @@ -139,9 +173,9 @@ private static TCPSSLOptions buildTCPSSLOptions(SSLOption sslOption, SSLCustom s } tcpClientOptions - .setEnabledSecureTransportProtocols(new HashSet(Arrays.asList(sslOption.getProtocols().split(",")))); + .setEnabledSecureTransportProtocols(new HashSet<>(Arrays.asList(sslOption.getProtocols().split(",")))); - for (String cipher : SSLManager.getEnalbedCiphers(sslOption.getCiphers())) { + for (String cipher : SSLManager.getEnabledCiphers(sslOption)) { tcpClientOptions.addEnabledCipherSuite(cipher); } @@ -152,10 +186,22 @@ private static TCPSSLOptions buildTCPSSLOptions(SSLOption sslOption, SSLCustom s } private static boolean isFileExists(String name) { - if (name == null || name.isEmpty()) { + if (StringUtils.isEmpty(name)) { return false; } File f = new File(name); - return f.exists(); + if (f.isFile()) { + return true; + } + + try { + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader() == null ? VertxTLSBuilder.class.getClassLoader() + : Thread.currentThread().getContextClassLoader(); + URL resource = classLoader.getResource(name); + return resource != null; + } catch (Exception e) { + return false; + } } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxUtils.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxUtils.java index a3aabd69452..5eceac0b24d 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxUtils.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/VertxUtils.java @@ -20,13 +20,14 @@ import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; - -import javax.xml.ws.Holder; +import java.util.concurrent.TimeUnit; import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; @@ -37,13 +38,17 @@ import io.netty.buffer.ByteBuf; import io.vertx.core.AbstractVerticle; import io.vertx.core.DeploymentOptions; +import io.vertx.core.Future; import io.vertx.core.Verticle; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; -import io.vertx.core.impl.FileResolver; -import io.vertx.core.impl.VertxImplEx; -import io.vertx.core.logging.SLF4JLogDelegateFactory; +import io.vertx.core.impl.SysProps; +import io.vertx.core.impl.VertxThread; +import io.vertx.core.internal.VertxBootstrap; +import io.vertx.core.spi.VertxMetricsFactory; +import io.vertx.core.spi.VertxThreadFactory; +import io.vertx.core.transport.Transport; /** * VertxUtils @@ -51,29 +56,22 @@ * */ public final class VertxUtils { - static { - // initialize vertx logger, this can be done multiple times - System.setProperty("vertx.logger-delegate-factory-class-name", SLF4JLogDelegateFactory.class.getName()); - io.vertx.core.logging.LoggerFactory.initialise(); - } - private static final Logger LOGGER = LoggerFactory.getLogger(VertxUtils.class); private static final long BLOCKED_THREAD_CHECK_INTERVAL = Long.MAX_VALUE / 2; // key为vertx实例名称,以支撑vertx功能分组 - private static Map vertxMap = new ConcurrentHashMapEx<>(); + private static final Map vertxMap = new ConcurrentHashMapEx<>(); private VertxUtils() { } - public static Map getVertxMap() { + public static Map getVertxMap() { return vertxMap; } public static void deployVerticle(Vertx vertx, Class cls, int instanceCount) { DeploymentOptions options = new DeploymentOptions().setInstances(instanceCount); - vertx.deployVerticle(cls.getName(), options); } @@ -89,17 +87,19 @@ public static DeploymentOptions createClientDeployOptions( } // deploy Verticle and wait for its success. do not call this method in event-loop thread - public static boolean blockDeploy(Vertx vertx, + public static Map blockDeploy(Vertx vertx, Class cls, DeploymentOptions options) throws InterruptedException { - Holder result = new Holder<>(); + Map result = new HashMap<>(); CountDownLatch latch = new CountDownLatch(1); - vertx.deployVerticle(cls.getName(), options, ar -> { - result.value = ar.succeeded(); + Future future = vertx.deployVerticle(cls.getName(), options); + future.onComplete((success, failure) -> { + result.put("code", failure == null); - if (ar.failed()) { - LOGGER.error("deploy vertx failed, cause ", ar.cause()); + if (failure != null) { + result.put("message", failure.getMessage()); + LOGGER.error("deploy vertx failed, cause ", failure); } latch.countDown(); @@ -107,18 +107,15 @@ public static boolean blockDeploy(Vertx vertx, latch.await(); - return result.value; + return result; } - public static Vertx getOrCreateVertxByName(String name, VertxOptions vertxOptions) { - return vertxMap.computeIfAbsent(name, vertxName -> (VertxImplEx) init(vertxName, vertxOptions)); + public static Vertx getOrCreateVertxByName(String name, VertxOptions vertxOptions, + VertxMetricsFactory metricsFactory) { + return vertxMap.computeIfAbsent(name, vertxName -> init(name, vertxOptions, metricsFactory)); } - public static Vertx init(VertxOptions vertxOptions) { - return init(null, vertxOptions); - } - - public static Vertx init(String name, VertxOptions vertxOptions) { + public static Vertx init(String name, VertxOptions vertxOptions, VertxMetricsFactory metricsFactory) { if (vertxOptions == null) { vertxOptions = new VertxOptions(); } @@ -129,23 +126,48 @@ public static Vertx init(String name, VertxOptions vertxOptions) { LOGGER.info("in debug mode, disable blocked thread check."); } - configureVertxFileCaching(); - return new VertxImplEx(name, vertxOptions); + configureVertxFileCaching(vertxOptions); + + VertxBootstrap bootstrap = bootstrap(vertxOptions, metricsFactory) + .threadFactory(new VertxThreadFactory() { + @Override + public VertxThread newVertxThread(Runnable target, String threadName, boolean worker, long maxExecTime, + TimeUnit maxExecTimeUnit) { + return VertxThreadFactory.super + .newVertxThread(target, name + "-" + threadName, worker, maxExecTime, maxExecTimeUnit); + } + }); + + return bootstrap.init().vertx(); + } + + private static VertxBootstrap bootstrap(VertxOptions options, VertxMetricsFactory metricsFactory) { + VertxBootstrap bootstrap = VertxBootstrap.create(); + bootstrap.options(options); + bootstrap.metricsFactory(metricsFactory); + Transport tr; + if (options.getPreferNativeTransport()) { + tr = Transport.nativeTransport(); + } else { + tr = Transport.NIO; + } + bootstrap.transport(tr.implementation()); + return bootstrap; } /** * 配置vertx的文件缓存功能,默认关闭 */ - protected static void configureVertxFileCaching() { - if (System.getProperty(FileResolver.DISABLE_CP_RESOLVING_PROP_NAME) == null) { - System.setProperty(FileResolver.DISABLE_CP_RESOLVING_PROP_NAME, "true"); - } + private static void configureVertxFileCaching(VertxOptions vertxOptions) { + boolean disableFileCPResolving = LegacyPropertyFactory + .getBooleanProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, true); + vertxOptions.getFileSystemOptions().setClassPathResolvingEnabled(!disableFileCPResolving); } // try to reference byte[] // otherwise copy byte[] public static byte[] getBytesFast(InputStream inputStream) throws IOException { - if (BufferInputStream.class.isInstance(inputStream)) { + if (inputStream instanceof BufferInputStream) { return getBytesFast(((BufferInputStream) inputStream).getByteBuf()); } @@ -153,8 +175,9 @@ public static byte[] getBytesFast(InputStream inputStream) throws IOException { } public static byte[] getBytesFast(Buffer buffer) { - ByteBuf byteBuf = buffer.getByteBuf(); - return getBytesFast(byteBuf); + byte[] arr = new byte[buffer.length()]; + buffer.getBytes(arr, 0); + return arr; } public static byte[] getBytesFast(ByteBuf byteBuf) { @@ -177,24 +200,46 @@ public static CompletableFuture closeVertxByName(String name) { return future; } - vertx.close(ar -> { - if (ar.succeeded()) { + Future closeFuture = vertx.close(); + closeFuture.onComplete((succ, fail) -> { + if (fail == null) { LOGGER.info("Success to close vertx {}.", name); future.complete(null); return; } - future.completeExceptionally(ar.cause()); + future.completeExceptionally(fail); }); + return future; } public static void blockCloseVertxByName(String name) { CompletableFuture future = closeVertxByName(name); try { - future.get(); + future.get(30, TimeUnit.SECONDS); + } catch (Throwable e) { + LOGGER.error("Failed to wait close vertx {}.", name, e); + } + } + + public static void blockCloseVertx(Vertx vertx) { + CountDownLatch latch = new CountDownLatch(1); + Future closeFuture = vertx.close(); + closeFuture.onComplete((succ, fail) -> { + if (fail == null) { + LOGGER.info("Success to close vertx {}.", vertx); + } else { + LOGGER.info("Failed to close vertx {}.", vertx); + } + + latch.countDown(); + }); + + try { + latch.await(30, TimeUnit.SECONDS); } catch (Throwable e) { - LOGGER.error("Failed to close vertx {}.", name, e); + LOGGER.info("Failed to wait close vertx {}.", vertx); } } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/ClientPoolManager.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/ClientPoolManager.java index 68568323982..900f994c161 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/ClientPoolManager.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/ClientPoolManager.java @@ -39,17 +39,17 @@ * sync/async is not about net operation, just about consumer invoke mode. */ public class ClientPoolManager { - private Vertx vertx; + private final Vertx vertx; - private String id = UUID.randomUUID().toString(); + private final String id = UUID.randomUUID().toString(); - private ClientPoolFactory factory; + private final ClientPoolFactory factory; - private List pools = new CopyOnWriteArrayList<>(); + private final List pools = new CopyOnWriteArrayList<>(); // reactive mode, when call from other thread, must select a context for it // if we use threadId to hash a context, will always select the same context from one thread - private AtomicInteger reactiveNextIndex = new AtomicInteger(); + private final AtomicInteger reactiveNextIndex = new AtomicInteger(); public ClientPoolManager(Vertx vertx, ClientPoolFactory factory) { this.vertx = vertx; @@ -95,9 +95,9 @@ protected CLIENT_POOL findByContext(Context targetContext) { return clientPool; } - // this will make "client.thread-count" bigger than which in microservice.yaml - // maybe it's better to remove "client.thread-count", just use "rest/highway.thread-count" - return createClientPool(currentContext); + // Maybe executed in a call back of a reactive call. + // The Context is created in a non-event thread and passed to the event loop + // thread by vert.x. } // not in correct context: @@ -105,6 +105,7 @@ protected CLIENT_POOL findByContext(Context targetContext) { // 2.vertx worker thread // 3.other vertx thread // select a existing context + assertPoolsInitialized(); int idx = reactiveNextIndex.getAndIncrement() % pools.size(); if (idx < 0) { idx = -idx; @@ -113,7 +114,15 @@ protected CLIENT_POOL findByContext(Context targetContext) { } public CLIENT_POOL findThreadBindClientPool() { + assertPoolsInitialized(); int idx = (int) (Thread.currentThread().getId() % pools.size()); return pools.get(idx); } + + private void assertPoolsInitialized() { + if (pools.isEmpty()) { + throw new IllegalStateException("client pool not initialized successfully when making calls." + + "Please check if system boot up is ready or some errors happened when startup."); + } + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientOptionsSPI.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientOptionsSPI.java new file mode 100644 index 00000000000..83bf28db9ca --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientOptionsSPI.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.client.http; + +import org.apache.servicecomb.foundation.common.encrypt.Encryptions; +import org.apache.servicecomb.foundation.vertx.VertxTLSBuilder; + +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpVersion; +import io.vertx.core.http.WebSocketClientOptions; +import io.vertx.core.net.ClientOptionsBase; +import io.vertx.core.net.ProxyOptions; + +/** + * common Http Client Options must be set by implementations + */ +public interface HttpClientOptionsSPI { + /* unique name in this service */ + String clientName(); + + /* loading order */ + int getOrder(); + + /* can turn off the client */ + boolean enabled(); + + /* config tag is used for group configurations, like ssl, address resolver, etc. set config tag to distinguish + * other clients configuration or read the common configuration. */ + String getConfigTag(); + + /***************** vert.x common settings ***************************/ + int getEventLoopPoolSize(); + + boolean useSharedVertx(); + + /***************** vert.x vertical common settings ***************************/ + int getInstanceCount(); + + boolean isWorker(); + + String getWorkerPoolName(); + + int getWorkerPoolSize(); + + /***************** http common settings ***************************/ + HttpVersion getHttpVersion(); + + int getConnectTimeoutInMillis(); + + int getIdleTimeoutInSeconds(); + + boolean isTryUseCompression(); + + int getMaxWaitQueueSize(); + + int getMaxPoolSize(); + + boolean isKeepAlive(); + + int getMaxHeaderSize(); + + int getKeepAliveTimeout(); + + boolean enableLogActivity(); + + /***************** http 2 settings ****************************/ + int getHttp2MultiplexingLimit(); + + int getHttp2MaxPoolSize(); + + boolean isUseAlpn(); + + /***************** proxy settings ***************************/ + boolean isProxyEnable(); + + String getProxyHost(); + + int getProxyPort(); + + String getProxyUsername(); + + String getProxyPassword(); + + /***************** ssl settings ***************************/ + boolean isSsl(); + + static void buildClientOptionsBase(HttpClientOptionsSPI spi, ClientOptionsBase httpClientOptions) { + httpClientOptions.setConnectTimeout(spi.getConnectTimeoutInMillis()); + httpClientOptions.setIdleTimeout(spi.getIdleTimeoutInSeconds()); + httpClientOptions.setLogActivity(spi.enableLogActivity()); + + if (spi.isProxyEnable()) { + ProxyOptions proxy = new ProxyOptions(); + proxy.setHost(spi.getProxyHost()); + proxy.setPort(spi.getProxyPort()); + proxy.setUsername(spi.getProxyUsername()); + proxy.setPassword( + Encryptions.decode(spi.getProxyPassword(), spi.getConfigTag())); + httpClientOptions.setProxyOptions(proxy); + } + + if (spi.getHttpVersion() == HttpVersion.HTTP_2) { + httpClientOptions.setUseAlpn(spi.isUseAlpn()); + } + } + + static HttpClientOptions createHttpClientOptions(HttpClientOptionsSPI spi) { + HttpClientOptions httpClientOptions = new HttpClientOptions(); + buildClientOptionsBase(spi, httpClientOptions); + + httpClientOptions.setProtocolVersion(spi.getHttpVersion()); + httpClientOptions.setDecompressionSupported(spi.isTryUseCompression()); + httpClientOptions.setKeepAlive(spi.isKeepAlive()); + httpClientOptions.setMaxHeaderSize(spi.getMaxHeaderSize()); + + if (spi.getHttpVersion() == HttpVersion.HTTP_2) { + httpClientOptions.setHttp2ClearTextUpgrade(false); + httpClientOptions.setHttp2MultiplexingLimit(spi.getHttp2MultiplexingLimit()); + httpClientOptions.setHttp2KeepAliveTimeout(spi.getKeepAliveTimeout()); + } else { + httpClientOptions.setKeepAliveTimeout(spi.getKeepAliveTimeout()); + } + + if (spi.isSsl()) { + VertxTLSBuilder.buildHttpClientOptions(spi.getConfigTag(), httpClientOptions); + } + + return httpClientOptions; + } + + static WebSocketClientOptions createWebSocketClientOptions(HttpClientOptionsSPI spi, boolean sslEnabled) { + WebSocketClientOptions webSocketClientOptions = new WebSocketClientOptions(); + buildClientOptionsBase(spi, webSocketClientOptions); + + if (sslEnabled) { + VertxTLSBuilder.buildWebSocketClientOptions(spi.getConfigTag(), webSocketClientOptions); + } + + return webSocketClientOptions; + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientPoolFactory.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientPoolFactory.java index a6b1f60b3e3..69f15e6e397 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientPoolFactory.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientPoolFactory.java @@ -5,9 +5,7 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * * http://www.apache.org/licenses/LICENSE-2.0 - * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,23 +16,44 @@ package org.apache.servicecomb.foundation.vertx.client.http; import org.apache.servicecomb.foundation.vertx.client.ClientPoolFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import io.vertx.core.Context; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.PoolOptions; // execute in vertx context public class HttpClientPoolFactory implements ClientPoolFactory { - private HttpClientOptions httpClientOptions; + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPoolFactory.class); - public HttpClientPoolFactory(HttpClientOptions httpClientOptions) { + private final HttpClientOptions httpClientOptions; + + private final PoolOptions poolOptions; + + public HttpClientPoolFactory(HttpClientOptions httpClientOptions, PoolOptions poolOptions) { this.httpClientOptions = httpClientOptions; + this.poolOptions = poolOptions; } @Override public HttpClientWithContext createClientPool(Context context) { - HttpClient httpClient = context.owner().createHttpClient(httpClientOptions); - + HttpClient httpClient = context.owner().httpClientBuilder() + .with(httpClientOptions) + .with(poolOptions) + .withConnectHandler(connection -> { + LOGGER.debug("http connection connected, local:{}, remote:{}.", + connection.localAddress(), connection.remoteAddress()); + connection.closeHandler(v -> + LOGGER.debug("http connection closed, local:{}, remote:{}.", + connection.localAddress(), connection.remoteAddress()) + ); + connection.exceptionHandler(e -> + LOGGER.error("http connection exception, local:{}, remote:{}.", + connection.localAddress(), connection.remoteAddress(), e) + ); + }).build(); return new HttpClientWithContext(httpClient, context); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientWithContext.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientWithContext.java index 9b85ac3ad6a..f9dab51e83a 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientWithContext.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClientWithContext.java @@ -25,9 +25,9 @@ public interface RunHandler { void run(HttpClient httpClient); } - private HttpClient httpClient; + private final HttpClient httpClient; - private Context context; + private final Context context; public HttpClientWithContext(HttpClient httpClient, Context context) { this.httpClient = httpClient; @@ -39,9 +39,7 @@ public HttpClient getHttpClient() { } public void runOnContext(RunHandler handler) { - context.runOnContext((v) -> { - handler.run(httpClient); - }); + context.runOnContext((v) -> handler.run(httpClient)); } public Context context() { diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClients.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClients.java new file mode 100644 index 00000000000..b1ef46436ec --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/http/HttpClients.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.client.http; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.foundation.vertx.AddressResolverConfig; +import org.apache.servicecomb.foundation.vertx.SharedVertxFactory; +import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; +import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.Context; +import io.vertx.core.DeploymentOptions; +import io.vertx.core.ThreadingModel; +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.core.dns.AddressResolverOptions; +import io.vertx.core.http.PoolOptions; +import io.vertx.core.http.WebSocketClient; + +/** + * load and manages a set of HttpClient at boot up. + */ +public class HttpClients { + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClients.class); + + private static final Map> httpClients = new HashMap<>(); + + /* load at boot up, call this method once and only once. */ + public static void load() { + List clientOptionsList = SPIServiceUtils.getOrLoadSortedService(HttpClientOptionsSPI.class); + clientOptionsList.forEach(option -> { + if (option.enabled()) { + ClientPoolManager clientPoolManager = httpClients.get(option.clientName()); + if (clientPoolManager != null) { + LOGGER.warn("client pool {} initialized again.", option.clientName()); + } + httpClients.put(option.clientName(), createClientPoolManager(option)); + } + }); + } + + /* destroy at shutdown. */ + public static void destroy() { + httpClients.clear(); + List clientOptionsList = SPIServiceUtils.getOrLoadSortedService(HttpClientOptionsSPI.class); + clientOptionsList.forEach(option -> VertxUtils.blockCloseVertxByName(option.clientName())); + } + + private static ClientPoolManager createClientPoolManager(HttpClientOptionsSPI option) { + Vertx vertx = getOrCreateVertx(option); + PoolOptions poolOptions = new PoolOptions(); + poolOptions.setMaxWaitQueueSize(option.getMaxWaitQueueSize()); + poolOptions.setHttp1MaxSize(option.getMaxPoolSize()); + poolOptions.setHttp2MaxSize(option.getHttp2MaxPoolSize()); + ClientPoolManager clientPoolManager = new ClientPoolManager<>(vertx, + new HttpClientPoolFactory(HttpClientOptionsSPI.createHttpClientOptions(option), poolOptions)); + + DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(clientPoolManager, + option.getInstanceCount()) + .setThreadingModel(option.isWorker() ? ThreadingModel.WORKER : ThreadingModel.EVENT_LOOP) + .setWorkerPoolName(option.getWorkerPoolName()) + .setWorkerPoolSize(option.getWorkerPoolSize()); + try { + VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); + return clientPoolManager; + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } + } + + public static WebSocketClient createWebSocketClient(HttpClientOptionsSPI option, boolean sslEnabled) { + Vertx vertx = getOrCreateVertx(option); + return vertx.createWebSocketClient(HttpClientOptionsSPI.createWebSocketClientOptions(option, sslEnabled)); + } + + private static Vertx getOrCreateVertx(HttpClientOptionsSPI option) { + if (option.useSharedVertx()) { + return SharedVertxFactory.getSharedVertx(LegacyPropertyFactory.getEnvironment()); + } + + AddressResolverOptions resolverOptions = AddressResolverConfig + .getAddressResolverOptions(option.getConfigTag()); + VertxOptions vertxOptions = new VertxOptions() + .setAddressResolverOptions(resolverOptions) + .setEventLoopPoolSize(option.getEventLoopPoolSize()); + + // Maybe we can deploy only one vert.x for the application. However this has did it like this. + return VertxUtils.getOrCreateVertxByName(option.clientName(), vertxOptions, null); + } + + /** + * get client instance by name + * @param clientName instance name + * @return the deployed instance name + */ + public static HttpClientWithContext getClient(String clientName) { + return getClient(clientName, true); + } + + /** + * get client instance by name + * @param clientName instance name + * @param sync reactive or not. false for reactive. + * @return the deployed instance name + */ + public static HttpClientWithContext getClient(String clientName, boolean sync) { + return getClient(clientName, sync, null); + } + + /** + * get client instance by name + * @param clientName instance name + * @param sync reactive or not. false for reactive. + * @param targetContext running context + * @return the deployed instance name + */ + public static HttpClientWithContext getClient(String clientName, boolean sync, Context targetContext) { + ClientPoolManager poolManager = httpClients.get(clientName); + if (poolManager == null) { + LOGGER.error("client name [{}] not exists, should only happen in tests.", clientName); + return null; + } + return poolManager.findClientPool(sync, targetContext); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/AbstractTcpClientPackage.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/AbstractTcpClientPackage.java index d979f1fd657..ef6717f8968 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/AbstractTcpClientPackage.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/AbstractTcpClientPackage.java @@ -21,13 +21,15 @@ import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; public abstract class AbstractTcpClientPackage { - private static AtomicLong reqId = new AtomicLong(); + private static final AtomicLong reqId = new AtomicLong(); public static long getAndIncRequestId() { return reqId.getAndIncrement(); } - private long finishWriteToBuffer; + private volatile long msRequestTimeout; + + private volatile long finishWriteToBuffer; protected long msgId = getAndIncRequestId(); @@ -35,6 +37,14 @@ public long getMsgId() { return msgId; } + public long getMsRequestTimeout() { + return msRequestTimeout; + } + + public void setMsRequestTimeout(long msRequestTimeout) { + this.msRequestTimeout = msRequestTimeout; + } + public long getFinishWriteToBuffer() { return finishWriteToBuffer; } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/NetClientWrapper.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/NetClientWrapper.java index b0c2542286d..ce47126ee47 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/NetClientWrapper.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/NetClientWrapper.java @@ -16,8 +16,7 @@ */ package org.apache.servicecomb.foundation.vertx.client.tcp; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.net.NetClient; import io.vertx.core.net.NetSocket; @@ -26,13 +25,13 @@ // can not support normal and ssl by the same instance // so we do this wrap public class NetClientWrapper { - private TcpClientConfig normalClientConfig; + private final TcpClientConfig normalClientConfig; - private NetClient normalNetClient; + private final NetClient normalNetClient; - private TcpClientConfig sslClientConfig; + private final TcpClientConfig sslClientConfig; - private NetClient sslNetClient; + private final NetClient sslNetClient; public NetClientWrapper(Vertx vertx, TcpClientConfig normalClientConfig, TcpClientConfig sslClientConfig) { this.normalClientConfig = normalClientConfig; @@ -50,12 +49,11 @@ public TcpClientConfig getClientConfig(boolean ssl) { return normalClientConfig; } - public void connect(boolean ssl, int port, String host, Handler> connectHandler) { + public Future connect(boolean ssl, int port, String host) { if (ssl) { - sslNetClient.connect(port, host, connectHandler); - return; + return sslNetClient.connect(port, host); } - normalNetClient.connect(port, host, connectHandler); + return normalNetClient.connect(port, host); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConfig.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConfig.java index 3dd71632180..dcdca0e4e90 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConfig.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConfig.java @@ -20,20 +20,19 @@ import io.vertx.core.net.NetClientOptions; public class TcpClientConfig extends NetClientOptions { - private static final int DEFAULT_TIMEOUT = 30000; + public static final int DEFAULT_LOGIN_TIMEOUT = 30000; - private long msRequestTimeout; + private long msLoginTimeout; public TcpClientConfig() { - // 30 second - msRequestTimeout = DEFAULT_TIMEOUT; + msLoginTimeout = DEFAULT_LOGIN_TIMEOUT; } - public long getRequestTimeoutMillis() { - return msRequestTimeout; + public long getMsLoginTimeout() { + return msLoginTimeout; } - public void setRequestTimeoutMillis(long msTimeout) { - this.msRequestTimeout = msTimeout; + public void setMsLoginTimeout(long msLoginTimeout) { + this.msLoginTimeout = msLoginTimeout; } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConnection.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConnection.java index 4efb8eb91ae..db071e3c34f 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConnection.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientConnection.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Queue; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeoutException; @@ -38,6 +39,7 @@ import io.vertx.core.AsyncResult; import io.vertx.core.Context; +import io.vertx.core.Future; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetSocket; import io.vertx.core.net.impl.NetSocketImpl; @@ -52,24 +54,24 @@ enum Status { WORKING } - private NetClientWrapper netClientWrapper; + private final NetClientWrapper netClientWrapper; - private TcpClientConfig clientConfig; + private final TcpClientConfig clientConfig; - private URIEndpointObject endpoint; + private final URIEndpointObject endpoint; - private InetSocketAddress socketAddress; + private final InetSocketAddress socketAddress; - private boolean localSupportLogin = false; + private volatile boolean localSupportLogin = false; - private boolean remoteSupportLogin; + private final boolean remoteSupportLogin; private volatile Status status = Status.DISCONNECTED; // save msg before login success. // before login, we can not know parameters, like: zip/codec compatible, and so on // so can only save package, can not save byteBuf - private Queue packageQueue = new ConcurrentLinkedQueue<>(); + private final Queue packageQueue = new ConcurrentLinkedQueue<>(); private volatile Map requestMap = new ConcurrentHashMap<>(); @@ -103,8 +105,20 @@ protected boolean onLoginResponse(Buffer bodyBuffer) { return true; } + public CompletableFuture send(AbstractTcpClientPackage tcpClientPackage) { + CompletableFuture future = new CompletableFuture<>(); + send(tcpClientPackage, ar -> { + if (ar.failed()) { + future.completeExceptionally(ar.cause()); + return; + } + future.complete(ar.result()); + }); + return future; + } + public void send(AbstractTcpClientPackage tcpClientPackage, TcpResponseCallback callback) { - requestMap.put(tcpClientPackage.getMsgId(), new TcpRequest(clientConfig.getRequestTimeoutMillis(), callback)); + requestMap.put(tcpClientPackage.getMsgId(), new TcpRequest(tcpClientPackage.getMsRequestTimeout(), callback)); if (writeToBufferQueue(tcpClientPackage)) { return; @@ -131,7 +145,7 @@ private boolean writeToBufferQueue(AbstractTcpClientPackage tcpClientPackage) { if (Status.WORKING.equals(status)) { // encode in sender thread try (TcpOutputStream os = tcpClientPackage.createStream()) { - write(os.getByteBuf()); + write(os.getBuffer()); tcpClientPackage.finishWriteToBuffer(); } return true; @@ -167,17 +181,17 @@ protected void connect() { this.status = Status.CONNECTING; LOGGER.info("connecting to address {}", socketAddress.toString()); - netClientWrapper.connect(endpoint.isSslEnabled(), + Future result = netClientWrapper.connect(endpoint.isSslEnabled(), socketAddress.getPort(), - socketAddress.getHostString(), - ar -> { - if (ar.succeeded()) { - onConnectSuccess(ar.result()); - return; - } - - onConnectFailed(ar.cause()); - }); + socketAddress.getHostString()); + result.onComplete((socket, fail) -> { + if (fail == null) { + onConnectSuccess(socket); + return; + } + + onConnectFailed(fail); + }); } private void onConnectSuccess(NetSocket socket) { @@ -195,7 +209,8 @@ private void onConnectSuccess(NetSocket socket) { tryLogin(); } - private void onClosed(Void v) { + @VisibleForTesting + void onClosed(Void v) { onDisconnected(new IOException("socket closed")); } @@ -236,7 +251,7 @@ protected void tryLogin() { try (TcpOutputStream os = createLogin()) { requestMap.put(os.getMsgId(), - new TcpRequest(clientConfig.getRequestTimeoutMillis(), this::onLoginResponse)); + new TcpRequest(clientConfig.getMsLoginTimeout(), this::onLoginResponse)); netSocket.write(os.getBuffer()); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientPackage.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientPackage.java index f63173cd405..ceee9357f9e 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientPackage.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpClientPackage.java @@ -19,7 +19,7 @@ import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; public class TcpClientPackage extends AbstractTcpClientPackage { - private TcpOutputStream os; + private final TcpOutputStream os; public TcpClientPackage(TcpOutputStream os) { this.os = os; diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpRequest.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpRequest.java index d1a44e0da90..6ca90adbcf1 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpRequest.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/client/tcp/TcpRequest.java @@ -24,15 +24,15 @@ import io.vertx.core.buffer.Buffer; public class TcpRequest { - private long begin; + private final long begin; - private long msTimeout; + private final long msTimeout; - private Context callContext; + private final Context callContext; - private long threadId; + private final long threadId; - private TcpResponseCallback responseCallback; + private final TcpResponseCallback responseCallback; public TcpRequest(long msTimeout, TcpResponseCallback responseCallback) { callContext = Vertx.currentContext(); @@ -50,9 +50,7 @@ public void onReply(Buffer headerBuffer, Buffer bodyBuffer) { return; } - callContext.runOnContext(Void -> { - responseCallback.success(tcpData); - }); + callContext.runOnContext(Void -> responseCallback.success(tcpData)); } public void onSendError(Throwable e) { diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/SinglePoolBlockingExecutor.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/SinglePoolBlockingExecutor.java new file mode 100644 index 00000000000..176e66aa50f --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/SinglePoolBlockingExecutor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.executor; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SinglePoolBlockingExecutor implements Executor { + private static final Logger LOGGER = LoggerFactory.getLogger(SinglePoolBlockingExecutor.class); + + private static final Executor SINGLE_POOL = Executors.newSingleThreadExecutor((r) -> { + Thread thread = new Thread(r); + thread.setName("single-pool-blocking-executor"); + return thread; + }); + + public static SinglePoolBlockingExecutor create() { + return new SinglePoolBlockingExecutor(); + } + + private SinglePoolBlockingExecutor() { + + } + + @Override + public void execute(Runnable command) { + SINGLE_POOL.execute(() -> { + try { + command.run(); + } catch (Throwable e) { + LOGGER.error("Logic should not throw exception, please fix it", e); + } + }); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxContextExecutor.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxContextExecutor.java new file mode 100644 index 00000000000..49febb1b3d4 --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxContextExecutor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.executor; + +import java.util.concurrent.Executor; + +import io.vertx.core.Context; +import io.vertx.core.Vertx; + +public class VertxContextExecutor implements Executor { + public static VertxContextExecutor create(Vertx vertx) { + return new VertxContextExecutor(vertx.getOrCreateContext()); + } + + public static VertxContextExecutor create(Context context) { + return new VertxContextExecutor(context); + } + + private final Context context; + + private VertxContextExecutor(Context context) { + this.context = context; + } + + @Override + public void execute(Runnable command) { + if (context == Vertx.currentContext()) { + command.run(); + return; + } + + context.runOnContext(v -> command.run()); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxWorkerExecutor.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxWorkerExecutor.java index 6fcbe683d19..e3334a79f1b 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxWorkerExecutor.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/executor/VertxWorkerExecutor.java @@ -25,10 +25,9 @@ public class VertxWorkerExecutor implements Executor { @Override public void execute(Runnable command) { - Vertx.currentContext().owner().executeBlocking(future -> { - command.run(); - }, - false, - null); + Vertx.currentContext().owner().executeBlocking(() -> { + command.run(); + return null; + }, false); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletRequest.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletRequest.java index b4bea0e9dac..058a9390464 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletRequest.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletRequest.java @@ -28,22 +28,23 @@ import java.util.Locale; import java.util.Map; -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.Part; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletConnection; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpUpgradeHandler; +import jakarta.servlet.http.Part; public abstract class AbstractHttpServletRequest extends BodyBufferSupportImpl implements HttpServletRequestEx { - private Map attributeMap = new HashMap<>(); + private final Map attributeMap = new HashMap<>(); @Override public Object getAttribute(String name) { @@ -65,6 +66,21 @@ public void setCharacterEncoding(String env) throws UnsupportedEncodingException throw new Error("not supported method"); } + @Override + public String getRequestId() { + throw new Error("not supported method"); + } + + @Override + public String getProtocolRequestId() { + throw new Error("not supported method"); + } + + @Override + public ServletConnection getServletConnection() { + throw new Error("not supported method"); + } + @Override public int getContentLength() { throw new Error("not supported method"); @@ -170,12 +186,6 @@ public RequestDispatcher getRequestDispatcher(String path) { throw new Error("not supported method"); } - @Override - @Deprecated - public String getRealPath(String path) { - throw new Error("not supported method"); - } - @Override public int getRemotePort() { throw new Error("not supported method"); @@ -357,12 +367,6 @@ public boolean isRequestedSessionIdFromURL() { throw new Error("not supported method"); } - @Override - @Deprecated - public boolean isRequestedSessionIdFromUrl() { - throw new Error("not supported method"); - } - @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { throw new Error("not supported method"); diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletResponse.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletResponse.java index 8b1a9a6a421..bd7899b471c 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletResponse.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/AbstractHttpServletResponse.java @@ -25,13 +25,14 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.Part; -import javax.ws.rs.core.Response.StatusType; +import io.vertx.core.buffer.Buffer; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.Response.StatusType; public abstract class AbstractHttpServletResponse extends BodyBufferSupportImpl implements HttpServletResponseEx { - private Map attributes = new HashMap<>(); + private final Map attributes = new HashMap<>(); @Override public String getCharacterEncoding() { @@ -85,6 +86,11 @@ public int getBufferSize() { @Override public void flushBuffer() throws IOException { + // for vert.x do noting + } + + @Override + public void endResponse() throws IOException { throw new Error("not supported method"); } @@ -133,18 +139,6 @@ public String encodeRedirectURL(String url) { throw new Error("not supported method"); } - @Override - @Deprecated - public String encodeUrl(String url) { - throw new Error("not supported method"); - } - - @Override - @Deprecated - public String encodeRedirectUrl(String url) { - throw new Error("not supported method"); - } - @Override public void sendError(int sc, String msg) throws IOException { throw new Error("not supported method"); @@ -195,12 +189,6 @@ public void setStatus(int sc) { throw new Error("not supported method"); } - @Override - @Deprecated - public void setStatus(int sc, String sm) { - throw new Error("not supported method"); - } - @Override public int getStatus() { throw new Error("not supported method"); @@ -240,4 +228,9 @@ public Object getAttribute(String key) { public CompletableFuture sendPart(Part body) { throw new Error("not supported method"); } + + @Override + public CompletableFuture sendBuffer(Buffer buffer) { + throw new Error("not supported method"); + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/BodyBufferSupportImpl.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/BodyBufferSupportImpl.java index 2bab47b3606..eceedf64cc9 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/BodyBufferSupportImpl.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/BodyBufferSupportImpl.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.foundation.vertx.http; +import com.google.common.annotations.VisibleForTesting; import org.apache.servicecomb.foundation.vertx.VertxUtils; import io.vertx.core.buffer.Buffer; @@ -48,12 +49,22 @@ public Buffer getBodyBuffer() { return bodyBuffer; } + @VisibleForTesting + void setBodyBytes(byte[] bodyBytes) { + this.bodyBytes = bodyBytes; + } + @Override public byte[] getBodyBytes() { prepare(); return bodyBytes; } + @VisibleForTesting + void setBodyLength(int bodyLength) { + this.bodyLength = bodyLength; + } + @Override public int getBodyBytesLength() { prepare(); diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/DownloadUtils.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/DownloadUtils.java index 8f5bffc254b..7c9c0fffbfc 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/DownloadUtils.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/DownloadUtils.java @@ -18,7 +18,7 @@ import java.io.IOException; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.servicecomb.foundation.common.http.HttpUtils; import org.apache.servicecomb.foundation.common.part.FilePartForSend; @@ -40,22 +40,31 @@ public static void prepareDownloadHeader(HttpServletResponseEx responseEx, Part if (responseEx.getHeader(HttpHeaders.CONTENT_LENGTH.toString()) == null) { responseEx.setChunked(true); } - + if (part == null) { + return; + } if (responseEx.getHeader(HttpHeaders.CONTENT_TYPE.toString()) == null) { - responseEx.setHeader(HttpHeaders.CONTENT_TYPE.toString(), part.getContentType()); + if (responseEx.getContentType() != null) { + responseEx.setHeader(HttpHeaders.CONTENT_TYPE.toString(), responseEx.getContentType()); + } else { + responseEx.setHeader(HttpHeaders.CONTENT_TYPE.toString(), part.getContentType()); + } } - if (responseEx.getHeader(javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION) == null) { + if (responseEx.getHeader(jakarta.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION) == null) { // to support chinese and space filename in firefox // must use "filename*", (https://tools.ietf.org/html/rtf6266) String encodedFileName = HttpUtils.uriEncodePath(part.getSubmittedFileName()); - responseEx.setHeader(javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION, + responseEx.setHeader(jakarta.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + encodedFileName + ";filename*=utf-8''" + encodedFileName); } } public static void clearPartResource(Part part) { - if (FilePartForSend.class.isInstance(part) && ((FilePartForSend) part).isDeleteAfterFinished()) { + if (part == null) { + return; + } + if (part instanceof FilePartForSend && ((FilePartForSend) part).isDeleteAfterFinished()) { try { part.delete(); } catch (IOException e) { diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/EmptyAsyncContext.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/EmptyAsyncContext.java index dd9f6acf0f2..142435ead3e 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/EmptyAsyncContext.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/EmptyAsyncContext.java @@ -17,12 +17,12 @@ package org.apache.servicecomb.foundation.vertx.http; -import javax.servlet.AsyncContext; -import javax.servlet.AsyncListener; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.AsyncListener; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; public class EmptyAsyncContext implements AsyncContext { @Override diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java index b80ac450d02..9e72d64d289 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java @@ -18,9 +18,9 @@ package org.apache.servicecomb.foundation.vertx.http; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import org.apache.commons.io.FileUtils; import org.apache.servicecomb.foundation.common.part.AbstractPart; @@ -28,7 +28,7 @@ import io.vertx.ext.web.FileUpload; public class FileUploadPart extends AbstractPart { - private FileUpload fileUpload; + private final FileUpload fileUpload; public FileUploadPart(FileUpload fileUpload) { this.fileUpload = fileUpload; @@ -36,7 +36,7 @@ public FileUploadPart(FileUpload fileUpload) { @Override public InputStream getInputStream() throws IOException { - return new FileInputStream(fileUpload.uploadedFileName()); + return Files.newInputStream(new File(fileUpload.uploadedFileName()).toPath()); } @Override diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletRequestEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletRequestEx.java index d2f62f2b0fe..701b117ab6c 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletRequestEx.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletRequestEx.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.foundation.vertx.http; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; public interface HttpServletRequestEx extends HttpServletRequest, BodyBufferSupport { default void setHeader(String name, String value) { diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletResponseEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletResponseEx.java index e1c2158d743..a565ed7791e 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletResponseEx.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/HttpServletResponseEx.java @@ -17,13 +17,16 @@ package org.apache.servicecomb.foundation.vertx.http; +import java.io.IOException; +import java.io.PrintWriter; import java.util.concurrent.CompletableFuture; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Part; -import javax.ws.rs.core.Response.StatusType; - +import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpHeaders; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.Response.StatusType; public interface HttpServletResponseEx extends HttpServletResponse, BodyBufferSupport { StatusType getStatusType(); @@ -34,7 +37,21 @@ public interface HttpServletResponseEx extends HttpServletResponse, BodyBufferSu CompletableFuture sendPart(Part body); + CompletableFuture sendBuffer(Buffer buffer); + default void setChunked(boolean chunked) { setHeader(HttpHeaders.TRANSFER_ENCODING.toString(), HttpHeaders.CHUNKED.toString()); } + + void endResponse() throws IOException; + + @Override + default ServletOutputStream getOutputStream() throws IOException { + throw new IOException("Not allowed"); + } + + @Override + default PrintWriter getWriter() throws IOException { + throw new IOException("Not allowed"); + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/ReadStreamPart.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/ReadStreamPart.java index caf2887314b..acd2fc1978a 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/ReadStreamPart.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/ReadStreamPart.java @@ -20,18 +20,15 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; - -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.common.http.HttpUtils; import org.apache.servicecomb.foundation.common.part.AbstractPart; import org.apache.servicecomb.foundation.vertx.stream.PumpCommon; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.vertx.core.AsyncResult; import io.vertx.core.Context; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.AsyncFile; @@ -39,21 +36,23 @@ import io.vertx.core.http.HttpClientResponse; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.WriteStream; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; /** * this is not a really part type, all method extend from AbstractPart is undefined except:
* 1.getContentType
* 2.getSubmittedFileName
* extend from AbstractPart just because want to make it be Part type, - * so that can be sent by + * so that can be sent by * {@link org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse#sendPart(Part) VertxServerResponseToHttpServletResponse.sendPart} */ public class ReadStreamPart extends AbstractPart { private static final Logger LOGGER = LoggerFactory.getLogger(ReadStreamPart.class); - private Context context; + private final Context context; - private ReadStream readStream; + private final ReadStream readStream; public ReadStreamPart(Context context, HttpClientResponse httpClientResponse) { this(context, (ReadStream) httpClientResponse); @@ -83,23 +82,21 @@ public ReadStream getReadStream() { } /** - * - * @param writeStream * @return future of save action
* * important: WriteStream did not provide endHandler, so we can not know when will really finished write. * so the return future only means finished read from readStream. */ public CompletableFuture saveToWriteStream(WriteStream writeStream) { - return new PumpCommon().pump(context, readStream, writeStream); + return new PumpCommon().pump(readStream, writeStream, null); } public CompletableFuture saveAsBytes() { - return saveAs(buf -> buf.getBytes()); + return saveAs(Buffer::getBytes); } public CompletableFuture saveAsString() { - return saveAs(buf -> buf.toString()); + return saveAs(Buffer::toString); } public CompletableFuture saveAs(Function converter) { @@ -121,8 +118,6 @@ public CompletableFuture saveAs(Function converter) { } /** - * - * @param fileName * @return future of save to file, future complete means write to file finished */ public CompletableFuture saveToFile(String fileName) { @@ -133,9 +128,6 @@ public CompletableFuture saveToFile(String fileName) { } /** - * - * @param file - * @param openOptions * @return future of save to file, future complete means write to file finished */ public CompletableFuture saveToFile(File file, OpenOptions openOptions) { @@ -143,25 +135,24 @@ public CompletableFuture saveToFile(File file, OpenOptions openOptions) { context.runOnContext((v) -> { Vertx vertx = context.owner(); - vertx.fileSystem().open(file.getAbsolutePath(), openOptions, ar -> { - onFileOpened(file, ar, future); - }); + Future openFuture = vertx.fileSystem().open(file.getAbsolutePath(), openOptions); + openFuture.onComplete((s, f) -> onFileOpened(file, s, f, future)); }); return future; } - protected void onFileOpened(File file, AsyncResult ar, CompletableFuture future) { - if (ar.failed()) { - future.completeExceptionally(ar.cause()); + protected void onFileOpened(File file, AsyncFile asyncFile, Throwable failure, CompletableFuture future) { + if (failure != null) { + future.completeExceptionally(failure); return; } - AsyncFile asyncFile = ar.result(); CompletableFuture saveFuture = saveToWriteStream(asyncFile); saveFuture.whenComplete((v, saveException) -> { - asyncFile.close(closeAr -> { - if (closeAr.failed()) { + Future result = asyncFile.close(); + result.onComplete((s, f) -> { + if (f != null) { LOGGER.error("Failed to close file {}.", file); } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java index 359bfae3df6..82b46b47597 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -29,24 +30,23 @@ import java.util.Map; import java.util.Map.Entry; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.MediaType; - import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; +import com.google.common.annotations.VisibleForTesting; + import io.vertx.core.buffer.Buffer; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.core.MediaType; public class StandardHttpServletRequestEx extends HttpServletRequestWrapper implements HttpServletRequestEx { - private BodyBufferSupport bodyBuffer = new BodyBufferSupportImpl(); + private final BodyBufferSupport bodyBuffer = new BodyBufferSupportImpl(); private boolean cacheRequest; @@ -65,14 +65,19 @@ public void setCacheRequest(boolean cacheRequest) { this.cacheRequest = cacheRequest; } + @VisibleForTesting + public boolean isCacheRequest() { + return cacheRequest; + } + @Override public ServletInputStream getInputStream() throws IOException { if (this.inputStream == null) { if (cacheRequest) { - byte inputBytes[] = IOUtils.toByteArray(getRequest().getInputStream()); - ByteBuf byteBuf = Unpooled.wrappedBuffer(inputBytes); + byte[] inputBytes = IOUtils.toByteArray(getRequest().getInputStream()); + Buffer byteBuf = Buffer.buffer(inputBytes); this.inputStream = new BufferInputStream(byteBuf); - setBodyBuffer(Buffer.buffer(Unpooled.wrappedBuffer(byteBuf))); + setBodyBuffer(byteBuf); } else { this.inputStream = getRequest().getInputStream(); } @@ -116,7 +121,7 @@ private Map parseParameterMap() { private Map convertListMapToArrayMap(Map> listMap) { Map arrayMap = new HashMap<>(); for (Entry> entry : listMap.entrySet()) { - arrayMap.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()])); + arrayMap.put(entry.getKey(), entry.getValue().toArray(new String[0])); } return arrayMap; } @@ -132,7 +137,7 @@ private void mergeParameterMaptoListMap(Map> listMap) { private Map> parseUrlEncodedBody() { try (InputStream inputStream = getInputStream()) { Map> listMap = new HashMap<>(); - String body = IOUtils.toString(inputStream); + String body = IOUtils.toString(inputStream, StandardCharsets.UTF_8); List pairs = URLEncodedUtils .parse(body, getCharacterEncoding() == null ? null : Charset.forName(getCharacterEncoding())); for (NameValuePair pair : pairs) { diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletResponseEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletResponseEx.java index 2050601bb52..38db248efdb 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletResponseEx.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletResponseEx.java @@ -23,22 +23,21 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.servlet.http.Part; -import javax.ws.rs.core.Response.StatusType; - -import org.apache.servicecomb.foundation.common.http.HttpStatus; import org.apache.servicecomb.foundation.vertx.stream.PumpFromPart; import io.vertx.core.Context; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; public class StandardHttpServletResponseEx extends HttpServletResponseWrapper implements HttpServletResponseEx { - private BodyBufferSupport bodyBuffer = new BodyBufferSupportImpl(); + private final BodyBufferSupport bodyBuffer = new BodyBufferSupportImpl(); - private Map attributes = new HashMap<>(); + private final Map attributes = new HashMap<>(); private StatusType statusType; @@ -66,11 +65,10 @@ public int getBodyBytesLength() { return bodyBuffer.getBodyBytesLength(); } - @SuppressWarnings("deprecation") @Override - public void setStatus(int sc, String sm) { - super.setStatus(sc, sm); - statusType = new HttpStatus(sc, sm); + public void setStatus(int sc) { + super.setStatus(sc); + statusType = Status.fromStatusCode(sc); } @Override @@ -84,11 +82,7 @@ public StatusType getStatusType() { } @Override - public void flushBuffer() throws IOException { - byte[] bytes = getBodyBytes(); - if (bytes != null) { - getOutputStream().write(bytes, 0, getBodyBytesLength()); - } + public void endResponse() throws IOException { super.flushBuffer(); } @@ -104,6 +98,10 @@ public Object getAttribute(String key) { @Override public CompletableFuture sendPart(Part part) { + if (part == null) { + return CompletableFuture.completedFuture(null); + } + DownloadUtils.prepareDownloadHeader(this, part); OutputStream outputStream; @@ -119,4 +117,16 @@ public CompletableFuture sendPart(Part part) { Context context = Vertx.currentContext(); return new PumpFromPart(context, part).toOutputStream(outputStream, false); } + + @Override + public CompletableFuture sendBuffer(Buffer buffer) { + CompletableFuture future = new CompletableFuture<>(); + try { + getOutputStream().write(buffer.getBytes(), 0, buffer.length()); + future.complete(null); + } catch (IOException e) { + future.completeExceptionally(e); + } + return future; + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientRequestToHttpServletRequest.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientRequestToHttpServletRequest.java index 72fd366cbae..8a54b8d835f 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientRequestToHttpServletRequest.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientRequestToHttpServletRequest.java @@ -20,15 +20,14 @@ import java.util.Collections; import java.util.Enumeration; -import javax.ws.rs.core.HttpHeaders; - import org.apache.servicecomb.foundation.common.http.HttpUtils; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientRequest; +import jakarta.ws.rs.core.HttpHeaders; public class VertxClientRequestToHttpServletRequest extends AbstractHttpServletRequest { - private HttpClientRequest clientRequest; + private final HttpClientRequest clientRequest; private String characterEncoding; @@ -42,6 +41,11 @@ public String getRequestURI() { return clientRequest.path(); } + @Override + public StringBuffer getRequestURL() { + return new StringBuffer(clientRequest.path()); + } + @Override public String getQueryString() { return clientRequest.query(); @@ -79,7 +83,7 @@ public String getContextPath() { @Override public String getMethod() { - return clientRequest.method().name(); + return clientRequest.getMethod().name(); } @Override diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientResponseToHttpServletResponse.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientResponseToHttpServletResponse.java index 82b84c045e3..da7e532174b 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientResponseToHttpServletResponse.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxClientResponseToHttpServletResponse.java @@ -19,8 +19,8 @@ import java.util.Collection; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.foundation.common.http.HttpStatus; @@ -28,7 +28,7 @@ import io.vertx.core.http.HttpClientResponse; public class VertxClientResponseToHttpServletResponse extends AbstractHttpServletResponse { - private HttpClientResponse clientResponse; + private final HttpClientResponse clientResponse; private StatusType statusType; diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerRequestToHttpServletRequest.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerRequestToHttpServletRequest.java index 9274bc2707a..da55f5ff613 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerRequestToHttpServletRequest.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerRequestToHttpServletRequest.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.foundation.vertx.http; +import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -24,12 +25,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; - -import javax.servlet.AsyncContext; -import javax.servlet.ServletInputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; +import java.util.stream.Collectors; import org.apache.servicecomb.foundation.common.http.HttpUtils; import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; @@ -42,6 +38,12 @@ import io.vertx.core.net.SocketAddress; import io.vertx.ext.web.FileUpload; import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.impl.RoutingContextInternal; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; // wrap vertx http request to Servlet http request public class VertxServerRequestToHttpServletRequest extends AbstractHttpServletRequest { @@ -49,9 +51,9 @@ public class VertxServerRequestToHttpServletRequest extends AbstractHttpServletR private static final EmptyAsyncContext EMPTY_ASYNC_CONTEXT = new EmptyAsyncContext(); - private RoutingContext context; + private final RoutingContext context; - private HttpServerRequest vertxRequest; + private final HttpServerRequest vertxRequest; private Cookie[] cookies; @@ -59,7 +61,7 @@ public class VertxServerRequestToHttpServletRequest extends AbstractHttpServletR private String path; - private SocketAddress socketAddress; + private final SocketAddress socketAddress; // cache from convert vertx parameters to servlet parameters private Map parameterMap; @@ -75,13 +77,17 @@ public VertxServerRequestToHttpServletRequest(RoutingContext context) { this.context = context; this.vertxRequest = context.request(); this.socketAddress = this.vertxRequest.remoteAddress(); - super.setBodyBuffer(context.getBody()); + super.setBodyBuffer(context.body().buffer()); } @Override public void setBodyBuffer(Buffer bodyBuffer) { super.setBodyBuffer(bodyBuffer); - context.setBody(bodyBuffer); + if (context instanceof RoutingContextInternal) { + RoutingContextInternal contextInternal = (RoutingContextInternal) context; + contextInternal.setBody(bodyBuffer); + } + this.inputStream = null; } @Override @@ -92,11 +98,11 @@ public String getContentType() { @Override public Cookie[] getCookies() { if (cookies == null) { - Set vertxCookies = context.cookies(); - Cookie tmpCookies[] = new Cookie[vertxCookies.size()]; + Set cookieSet = context.request().cookies(); + Cookie[] tmpCookies = new Cookie[cookieSet.size()]; int idx = 0; - for (io.vertx.ext.web.Cookie oneVertxCookie : vertxCookies) { - Cookie cookie = new Cookie(oneVertxCookie.getName(), oneVertxCookie.getValue()); + for (io.vertx.core.http.Cookie vertxCookie : cookieSet) { + Cookie cookie = new Cookie(vertxCookie.getName(), vertxCookie.getValue()); tmpCookies[idx] = cookie; idx++; } @@ -131,7 +137,7 @@ public String[] getParameterValues(String name) { } List paramList = this.vertxRequest.params().getAll(name); - return paramList.toArray(new String[paramList.size()]); + return paramList.toArray(new String[0]); } @Override @@ -140,8 +146,7 @@ public Map getParameterMap() { Map paramMap = new HashMap<>(); MultiMap map = this.vertxRequest.params(); for (String name : map.names()) { - List valueList = map.getAll(name); - paramMap.put(name, map.getAll(name).toArray(new String[valueList.size()])); + paramMap.put(name, map.getAll(name).toArray(new String[0])); } parameterMap = paramMap; } @@ -237,6 +242,14 @@ public String getRequestURI() { return this.path; } + @Override + public StringBuffer getRequestURL() { + if (this.path == null) { + this.path = vertxRequest.path(); + } + return new StringBuffer(this.path); + } + @Override public String getServletPath() { return this.getPathInfo(); @@ -249,9 +262,13 @@ public String getContextPath() { @Override public ServletInputStream getInputStream() { - if (inputStream == null) { - inputStream = new BufferInputStream(context.getBody().getByteBuf()); + if (inputStream != null) { + return inputStream; + } + if (context.body().buffer() == null) { + return null; } + inputStream = new BufferInputStream(context.body().buffer()); return inputStream; } @@ -275,6 +292,11 @@ public Part getPart(String name) { return new FileUploadPart(fileUpload); } + @Override + public Collection getParts() { + return context.fileUploads().stream().map(FileUploadPart::new).collect(Collectors.toList()); + } + public RoutingContext getContext() { return context; } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerResponseToHttpServletResponse.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerResponseToHttpServletResponse.java index 0d12c65225b..81785e9698c 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerResponseToHttpServletResponse.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/VertxServerResponseToHttpServletResponse.java @@ -17,25 +17,26 @@ package org.apache.servicecomb.foundation.vertx.http; +import java.io.IOException; import java.util.Collection; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.StatusType; - import org.apache.servicecomb.foundation.common.http.HttpStatus; import org.apache.servicecomb.foundation.vertx.stream.PumpFromPart; import io.vertx.core.Context; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpServerResponse; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response.StatusType; public class VertxServerResponseToHttpServletResponse extends AbstractHttpServletResponse { - private Context context; + private final Context context; - private HttpServerResponse serverResponse; + private final HttpServerResponse serverResponse; private StatusType statusType; @@ -52,10 +53,14 @@ public void setContentType(String type) { } @Override - @Deprecated - public void setStatus(int sc, String sm) { + public void setContentLength(int len) { + serverResponse.headers().set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len)); + } + + + @Override + public void setStatus(int sc) { serverResponse.setStatusCode(sc); - serverResponse.setStatusMessage(sm); } @Override @@ -102,31 +107,46 @@ public Collection getHeaderNames() { } @Override - public void flushBuffer() { + public void endResponse() { if (context == Vertx.currentContext()) { internalFlushBuffer(); return; } - context.runOnContext(V -> { - internalFlushBuffer(); - }); + context.runOnContext(V -> internalFlushBuffer()); } public void internalFlushBuffer() { - if (bodyBuffer == null) { - serverResponse.end(); + if (serverResponse.closed()) { return; } - - serverResponse.end(bodyBuffer); + serverResponse.end(); } @Override public CompletableFuture sendPart(Part part) { DownloadUtils.prepareDownloadHeader(this, part); + if (part == null) { + return CompletableFuture.completedFuture(null); + } + return new PumpFromPart(context, part).toWriteStream(serverResponse, null); + } - return new PumpFromPart(context, part).toWriteStream(serverResponse); + @Override + public CompletableFuture sendBuffer(Buffer buffer) { + if (serverResponse.closed()) { + return CompletableFuture.failedFuture(new IOException("Response is closed before sending any data. " + + "Maybe client is timeout or check idle connection timeout for provider is properly configured.")); + } + CompletableFuture future = new CompletableFuture<>(); + serverResponse.write(buffer).onComplete(result -> { + if (result.failed()) { + future.completeExceptionally(result.cause()); + } else { + future.complete(null); + } + }); + return future; } @Override diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultClientMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultClientMetrics.java new file mode 100644 index 00000000000..2bc9288857b --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultClientMetrics.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.metrics; + +import io.vertx.core.spi.metrics.ClientMetrics; +import io.vertx.core.spi.observability.HttpRequest; +import io.vertx.core.spi.observability.HttpResponse; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultRequestMetric; + +public class DefaultClientMetrics implements + ClientMetrics { + private final DefaultClientEndpointMetric clientEndpointMetric; + + public DefaultClientMetrics(DefaultClientEndpointMetric clientEndpointMetric) { + this.clientEndpointMetric = clientEndpointMetric; + } + + public DefaultClientEndpointMetric getClientEndpointMetric() { + return this.clientEndpointMetric; + } + + @Override + public DefaultRequestMetric requestBegin(String uri, HttpRequest request) { + DefaultRequestMetric requestMetric = new DefaultRequestMetric(this.clientEndpointMetric); + requestMetric.requestBegin(); + return requestMetric; + } + + @Override + public void requestEnd(DefaultRequestMetric requestMetric, long bytesWritten) { + requestMetric.requestEnd(); + } + + @Override + public void responseBegin(DefaultRequestMetric requestMetric, HttpResponse response) { + requestMetric.responseBegin(); + } + + @Override + public void responseEnd(DefaultRequestMetric requestMetric, long bytesRead) { + requestMetric.responseEnd(); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpClientMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpClientMetrics.java index f2f2b75f3f2..1279a4f8566 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpClientMetrics.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpClientMetrics.java @@ -18,19 +18,16 @@ import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetric; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetricManager; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultRequestMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.WebSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.spi.metrics.HttpClientMetrics; -/** - * important: not singleton, every HttpClient instance relate to a HttpClientMetrics instance - */ public class DefaultHttpClientMetrics implements - HttpClientMetrics { + HttpClientMetrics { + private static final String PROTOCOL = "http://"; + private final DefaultClientEndpointMetricManager clientEndpointMetricManager; public DefaultHttpClientMetrics(DefaultClientEndpointMetricManager clientEndpointMetricManager) { @@ -38,109 +35,37 @@ public DefaultHttpClientMetrics(DefaultClientEndpointMetricManager clientEndpoin } @Override - public Object createEndpoint(String host, int port, int maxPoolSize) { - return null; - } - - @Override - public void closeEndpoint(String host, int port, Object endpointMetric) { - } - - @Override - public Object enqueueRequest(Object endpointMetric) { - return null; - } - - @Override - public void dequeueRequest(Object endpointMetric, Object taskMetric) { - } - - @Override - public void endpointConnected(Object endpointMetric, DefaultHttpSocketMetric socketMetric) { + public DefaultClientMetrics createEndpointMetrics( + SocketAddress remoteAddress, int maxPoolSize) { + return new DefaultClientMetrics( + getOrCreateEndpointMetric(remoteAddress)); } - @Override - public void endpointDisconnected(Object endpointMetric, DefaultHttpSocketMetric socketMetric) { + private DefaultClientEndpointMetric getOrCreateEndpointMetric(SocketAddress remoteAddress) { + return this.clientEndpointMetricManager + .getOrCreateEndpointMetric(PROTOCOL + remoteAddress.host() + ":" + remoteAddress.port()); } @Override - public DefaultHttpSocketMetric requestBegin(Object endpointMetric, - DefaultHttpSocketMetric socketMetric, SocketAddress localAddress, SocketAddress remoteAddress, - HttpClientRequest request) { - socketMetric.requestBegin(); + public DefaultTcpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { + DefaultTcpSocketMetric socketMetric = new DefaultTcpSocketMetric( + getOrCreateEndpointMetric(remoteAddress)); + socketMetric.onConnect(); return socketMetric; } @Override - public void requestEnd(DefaultHttpSocketMetric requestMetric) { - requestMetric.requestEnd(); - } - - @Override - public void responseBegin(DefaultHttpSocketMetric requestMetric, HttpClientResponse response) { - } - - @Override - public DefaultHttpSocketMetric responsePushed(Object endpointMetric, - DefaultHttpSocketMetric socketMetric, - SocketAddress localAddress, - SocketAddress remoteAddress, HttpClientRequest request) { - return null; - } - - @Override - public void requestReset(DefaultHttpSocketMetric requestMetric) { - } - - @Override - public void responseEnd(DefaultHttpSocketMetric requestMetric, HttpClientResponse response) { - } - - @Override - public Object connected(Object endpointMetric, DefaultHttpSocketMetric socketMetric, - WebSocket webSocket) { - return null; - } - - @Override - public void disconnected(Object webSocketMetric) { - - } - - @Override - public DefaultHttpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { - DefaultClientEndpointMetric endpointMetric = this.clientEndpointMetricManager.onConnect(remoteAddress); - return new DefaultHttpSocketMetric(endpointMetric); - } - - @Override - public void disconnected(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress) { + public void disconnected(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress) { socketMetric.onDisconnect(); } @Override - public void bytesRead(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { + public void bytesRead(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { socketMetric.getEndpointMetric().addBytesRead(numberOfBytes); } @Override - public void bytesWritten(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { + public void bytesWritten(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { socketMetric.getEndpointMetric().addBytesWritten(numberOfBytes); } - - @Override - public void exceptionOccurred(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, Throwable t) { - - } - - @Override - @Deprecated - public boolean isEnabled() { - return true; - } - - @Override - public void close() { - - } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java index b99e8f9246d..011deb980a3 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultHttpServerMetrics.java @@ -16,20 +16,20 @@ */ package org.apache.servicecomb.foundation.vertx.metrics; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultRequestMetric; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.http.ServerWebSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.spi.metrics.HttpServerMetrics; +import io.vertx.core.spi.observability.HttpRequest; +import io.vertx.core.spi.observability.HttpResponse; /** - * important: not singleton, every HttpServer instance relate to a HttpServerMetrics instance + * important: not singleton, every HttpServer instance relate to an HttpServerMetrics instance */ -public class DefaultHttpServerMetrics implements HttpServerMetrics { +public class DefaultHttpServerMetrics implements + HttpServerMetrics { private final DefaultServerEndpointMetric endpointMetric; public DefaultHttpServerMetrics(DefaultServerEndpointMetric endpointMetric) { @@ -41,75 +41,46 @@ public DefaultServerEndpointMetric getEndpointMetric() { } @Override - public Object requestBegin(DefaultHttpSocketMetric socketMetric, HttpServerRequest request) { - return null; + public DefaultRequestMetric requestBegin(DefaultTcpSocketMetric socketMetric, HttpRequest request) { + DefaultRequestMetric requestMetric = new DefaultRequestMetric(socketMetric.getEndpointMetric()); + requestMetric.requestBegin(); + return requestMetric; } @Override - public void requestReset(Object requestMetric) { - - } - - @Override - public Object responsePushed(DefaultHttpSocketMetric socketMetric, HttpMethod method, String uri, - HttpServerResponse response) { - return null; - } - - @Override - public void responseEnd(Object requestMetric, HttpServerResponse response) { - - } - - @Override - public Object upgrade(Object requestMetric, ServerWebSocket serverWebSocket) { - return null; + public void requestEnd(DefaultRequestMetric requestMetric, HttpRequest request, long bytesRead) { + requestMetric.requestEnd(); } @Override - public Object connected(DefaultHttpSocketMetric socketMetric, ServerWebSocket serverWebSocket) { - return null; + public void responseBegin(DefaultRequestMetric requestMetric, HttpResponse response) { + requestMetric.responseBegin(); } @Override - public void disconnected(Object serverWebSocketMetric) { - + public void responseEnd(DefaultRequestMetric requestMetric, HttpResponse response, long bytesWritten) { + requestMetric.responseEnd(); } @Override - public DefaultHttpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { - endpointMetric.onConnect(); - return new DefaultHttpSocketMetric(endpointMetric); + public DefaultTcpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { + DefaultTcpSocketMetric socketMetric = new DefaultTcpSocketMetric(endpointMetric); + socketMetric.onConnect(); + return socketMetric; } @Override - public void disconnected(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress) { + public void disconnected(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress) { socketMetric.onDisconnect(); } @Override - public void bytesRead(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { - endpointMetric.addBytesRead(numberOfBytes); + public void bytesRead(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { + socketMetric.getEndpointMetric().addBytesRead(numberOfBytes); } @Override - public void bytesWritten(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { - endpointMetric.addBytesWritten(numberOfBytes); - } - - @Override - public void exceptionOccurred(DefaultHttpSocketMetric socketMetric, SocketAddress remoteAddress, Throwable t) { - - } - - @Override - @Deprecated - public boolean isEnabled() { - return true; - } - - @Override - public void close() { - + public void bytesWritten(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { + socketMetric.getEndpointMetric().addBytesWritten(numberOfBytes); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpClientMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpClientMetrics.java index 7233be28903..1bc6f706cb6 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpClientMetrics.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpClientMetrics.java @@ -27,6 +27,8 @@ * important: not singleton, every NetClient instance relate to a TCPMetrics instance */ public class DefaultTcpClientMetrics implements TCPMetrics { + private static final String PROTOCOL = "tcp://"; + private final DefaultClientEndpointMetricManager clientEndpointMetricManager; public DefaultTcpClientMetrics(DefaultClientEndpointMetricManager clientEndpointMetricManager) { @@ -35,8 +37,11 @@ public DefaultTcpClientMetrics(DefaultClientEndpointMetricManager clientEndpoint @Override public DefaultTcpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { - DefaultClientEndpointMetric endpointMetric = this.clientEndpointMetricManager.onConnect(remoteAddress); - return new DefaultTcpSocketMetric(endpointMetric); + DefaultClientEndpointMetric endpointMetric = this.clientEndpointMetricManager + .getOrCreateEndpointMetric(PROTOCOL + remoteAddress.toString()); + DefaultTcpSocketMetric socketMetric = new DefaultTcpSocketMetric(endpointMetric); + socketMetric.onConnect(); + return socketMetric; } @Override @@ -53,20 +58,4 @@ public void bytesRead(DefaultTcpSocketMetric socketMetric, SocketAddress remoteA public void bytesWritten(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { socketMetric.getEndpointMetric().addBytesWritten(numberOfBytes); } - - @Override - public void exceptionOccurred(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, Throwable t) { - - } - - @Override - @Deprecated - public boolean isEnabled() { - return true; - } - - @Override - public void close() { - - } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpServerMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpServerMetrics.java index a68c56f74b5..633d6a817d2 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpServerMetrics.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultTcpServerMetrics.java @@ -38,8 +38,9 @@ public DefaultServerEndpointMetric getEndpointMetric() { @Override public DefaultTcpSocketMetric connected(SocketAddress remoteAddress, String remoteName) { - endpointMetric.onConnect(); - return new DefaultTcpSocketMetric(endpointMetric); + DefaultTcpSocketMetric socketMetric = new DefaultTcpSocketMetric(endpointMetric); + socketMetric.onConnect(); + return socketMetric; } @Override @@ -49,27 +50,11 @@ public void disconnected(DefaultTcpSocketMetric socketMetric, SocketAddress remo @Override public void bytesRead(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { - endpointMetric.addBytesRead(numberOfBytes); + socketMetric.getEndpointMetric().addBytesRead(numberOfBytes); } @Override public void bytesWritten(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, long numberOfBytes) { - endpointMetric.addBytesWritten(numberOfBytes); - } - - @Override - public void exceptionOccurred(DefaultTcpSocketMetric socketMetric, SocketAddress remoteAddress, Throwable t) { - - } - - @Override - @Deprecated - public boolean isEnabled() { - return true; - } - - @Override - public void close() { - + socketMetric.getEndpointMetric().addBytesWritten(numberOfBytes); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetrics.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetrics.java index 4d59a296f99..c0b89a42eea 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetrics.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetrics.java @@ -18,75 +18,61 @@ import java.util.Map; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetricManager; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; - import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; -import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; -import io.vertx.core.metrics.impl.DummyVertxMetrics; import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.NetServerOptions; import io.vertx.core.net.SocketAddress; import io.vertx.core.spi.metrics.HttpClientMetrics; import io.vertx.core.spi.metrics.HttpServerMetrics; import io.vertx.core.spi.metrics.TCPMetrics; +import io.vertx.core.spi.metrics.VertxMetrics; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetricManager; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; -public class DefaultVertxMetrics extends DummyVertxMetrics { - private final Vertx vertx; - - private VertxOptions vertxOptions; - +public class DefaultVertxMetrics implements VertxMetrics { // to support listen multiple addresses, must use a map to manage the metric - private Map serverEndpointMetricMap = new ConcurrentHashMapEx<>(); + private final Map serverEndpointMetricMap = new ConcurrentHashMapEx<>(); - private volatile DefaultClientEndpointMetricManager clientEndpointMetricManager; + private final DefaultClientEndpointMetricManager clientEndpointMetricManager; - public DefaultVertxMetrics(Vertx vertx, VertxOptions vertxOptions) { - this.vertx = vertx; - this.vertxOptions = vertxOptions; - this.clientEndpointMetricManager = new DefaultClientEndpointMetricManager(vertx, + public DefaultVertxMetrics(VertxOptions vertxOptions) { + this.clientEndpointMetricManager = new DefaultClientEndpointMetricManager( (MetricsOptionsEx) vertxOptions.getMetricsOptions()); } - public Vertx getVertx() { - return vertx; - } - public DefaultClientEndpointMetricManager getClientEndpointMetricManager() { return clientEndpointMetricManager; } - public Map getServerEndpointMetricMap() { + public Map getServerEndpointMetricMap() { return serverEndpointMetricMap; } @Override - public HttpServerMetrics createMetrics(HttpServer server, SocketAddress localAddress, - HttpServerOptions options) { + public HttpServerMetrics createHttpServerMetrics(HttpServerOptions options, SocketAddress localAddress) { DefaultServerEndpointMetric endpointMetric = serverEndpointMetricMap - .computeIfAbsent(localAddress, DefaultServerEndpointMetric::new); + .computeIfAbsent(localAddress.toString(), DefaultServerEndpointMetric::new); return new DefaultHttpServerMetrics(endpointMetric); } @Override - public HttpClientMetrics createMetrics(HttpClient client, HttpClientOptions options) { + public HttpClientMetrics createHttpClientMetrics(HttpClientOptions options) { return new DefaultHttpClientMetrics(clientEndpointMetricManager); } @Override - public TCPMetrics createMetrics(SocketAddress localAddress, NetServerOptions options) { + public TCPMetrics createNetServerMetrics(NetServerOptions options, SocketAddress localAddress) { DefaultServerEndpointMetric endpointMetric = serverEndpointMetricMap - .computeIfAbsent(localAddress, DefaultServerEndpointMetric::new); + .computeIfAbsent(localAddress.toString(), DefaultServerEndpointMetric::new); return new DefaultTcpServerMetrics(endpointMetric); } @Override - public TCPMetrics createMetrics(NetClientOptions options) { + public TCPMetrics createNetClientMetrics(NetClientOptions options) { return new DefaultTcpClientMetrics(clientEndpointMetricManager); } @@ -95,9 +81,7 @@ public boolean isMetricsEnabled() { return true; } - @Deprecated - @Override - public boolean isEnabled() { - return true; + public void setVertx(Vertx vertx) { + clientEndpointMetricManager.setVertx(vertx); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetricsFactory.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetricsFactory.java index 1ceb91684bd..540a644b1e1 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetricsFactory.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/DefaultVertxMetricsFactory.java @@ -18,6 +18,7 @@ import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.json.JsonObject; import io.vertx.core.metrics.MetricsOptions; import io.vertx.core.spi.VertxMetricsFactory; import io.vertx.core.spi.metrics.VertxMetrics; @@ -44,9 +45,9 @@ public DefaultVertxMetrics getVertxMetrics() { } @Override - public synchronized VertxMetrics metrics(Vertx vertx, VertxOptions options) { + public synchronized VertxMetrics metrics(VertxOptions options) { if (vertxMetrics == null) { - vertxMetrics = new DefaultVertxMetrics(vertx, options); + vertxMetrics = new DefaultVertxMetrics(options); } return vertxMetrics; } @@ -54,8 +55,24 @@ public synchronized VertxMetrics metrics(Vertx vertx, VertxOptions options) { @Override public MetricsOptions newOptions() { MetricsOptionsEx metricsOptions = new MetricsOptionsEx(); - metricsOptions.setFactory(this); metricsOptions.setEnabled(true); return metricsOptions; } + + @Override + public MetricsOptions newOptions(JsonObject jsonObject) { + return new MetricsOptionsEx(jsonObject); + } + + @Override + public MetricsOptions newOptions(MetricsOptions options) { + return newOptions(options.toJson()); + } + + public void setVertx(Vertx vertx, VertxOptions options) { + if (vertxMetrics == null) { + vertxMetrics = new DefaultVertxMetrics(options); + } + vertxMetrics.setVertx(vertx); + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/MetricsOptionsEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/MetricsOptionsEx.java index 90da2c14033..0ae1de13cd4 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/MetricsOptionsEx.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/MetricsOptionsEx.java @@ -18,6 +18,7 @@ import java.util.concurrent.TimeUnit; +import io.vertx.core.json.JsonObject; import io.vertx.core.metrics.MetricsOptions; public class MetricsOptionsEx extends MetricsOptions { @@ -25,6 +26,14 @@ public class MetricsOptionsEx extends MetricsOptions { private long checkClientEndpointMetricExpiredInNano = TimeUnit.MINUTES.toNanos(15); + public MetricsOptionsEx() { + super(); + } + + public MetricsOptionsEx(JsonObject json) { + super(json); + } + public long getCheckClientEndpointMetricIntervalInMilliseconds() { return checkClientEndpointMetricIntervalInMilliseconds; } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetric.java index 41a995a02d3..ce618078957 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetric.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetric.java @@ -16,22 +16,26 @@ */ package org.apache.servicecomb.foundation.vertx.metrics.metric; -import io.vertx.core.net.SocketAddress; +import java.util.concurrent.atomic.LongAdder; +import com.google.common.annotations.VisibleForTesting; /** * for one listen address, include multiple httpClient or httpServer */ public class DefaultClientEndpointMetric extends DefaultEndpointMetric { + private final LongAdder queue = new LongAdder(); + // control if the metric instance will be expired // all invoker about incRefCount/isExpired, must lock: DefaultClientEndpointMetricManager // decRefCount no need to lock, because that only cause to be expired later. - private long lastNanoTime; + private volatile long lastNanoTime = System.nanoTime(); - public DefaultClientEndpointMetric(SocketAddress address) { + public DefaultClientEndpointMetric(String address) { super(address); } + @VisibleForTesting public long getLastNanoTime() { return lastNanoTime; } @@ -42,6 +46,18 @@ public void onDisconnect() { lastNanoTime = System.nanoTime(); } + public long getQueueCount() { + return queue.longValue(); + } + + public void enqueueRequest() { + queue.increment(); + } + + public void dequeueRequest() { + queue.decrement(); + } + public boolean isExpired(long nsTimeout) { return getCurrentConnectionCount() == 0 && (System.nanoTime() - lastNanoTime) > nsTimeout; diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetricManager.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetricManager.java index aa25d132fb9..17977a468ca 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetricManager.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientEndpointMetricManager.java @@ -17,7 +17,6 @@ package org.apache.servicecomb.foundation.vertx.metrics.metric; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -27,52 +26,48 @@ import com.google.common.annotations.VisibleForTesting; import io.vertx.core.Vertx; -import io.vertx.core.net.SocketAddress; public class DefaultClientEndpointMetricManager { - private final Vertx vertx; - private final MetricsOptionsEx metricsOptionsEx; // to avoid save too many endpoint that not exist any more // must check expired periodically - private Map clientEndpointMetricMap = new ConcurrentHashMapEx<>(); + private final Map clientEndpointMetricMap = new ConcurrentHashMapEx<>(); + // clientEndpointMetricMap is thread safe + // but get/isExpired/remove is not safe + // 1.isExpired + // 2.get + // 3.remove + // will get a removed instance + // so must lock the logic private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); - private AtomicBoolean inited = new AtomicBoolean(false); - - public DefaultClientEndpointMetricManager(Vertx vertx, MetricsOptionsEx metricsOptionsEx) { - this.vertx = vertx; + public DefaultClientEndpointMetricManager(MetricsOptionsEx metricsOptionsEx) { this.metricsOptionsEx = metricsOptionsEx; } - @VisibleForTesting - public DefaultClientEndpointMetric getClientEndpointMetric(SocketAddress serverAddress) { - return clientEndpointMetricMap.get(serverAddress); - } - - public Map getClientEndpointMetricMap() { - return clientEndpointMetricMap; - } - - public DefaultClientEndpointMetric onConnect(SocketAddress serverAddress) { - if (inited.compareAndSet(false, true)) { - vertx.setPeriodic(metricsOptionsEx.getCheckClientEndpointMetricIntervalInMilliseconds(), - this::onCheckClientEndpointMetricExpired); - } - + public DefaultClientEndpointMetric getOrCreateEndpointMetric(String address) { rwlock.readLock().lock(); try { - DefaultClientEndpointMetric clientEndpointMetric = clientEndpointMetricMap - .computeIfAbsent(serverAddress, DefaultClientEndpointMetric::new); - clientEndpointMetric.onConnect(); - return clientEndpointMetric; + if (clientEndpointMetricMap.get(address) == null) { + clientEndpointMetricMap.put(address, new DefaultClientEndpointMetric(address)); + } + return clientEndpointMetricMap.get(address); } finally { rwlock.readLock().unlock(); } } + @VisibleForTesting + public DefaultClientEndpointMetric getClientEndpointMetric(String serverAddress) { + return clientEndpointMetricMap.get(serverAddress); + } + + public Map getClientEndpointMetricMap() { + return clientEndpointMetricMap; + } + @VisibleForTesting public void onCheckClientEndpointMetricExpired(long periodic) { for (DefaultClientEndpointMetric metric : clientEndpointMetricMap.values()) { @@ -88,4 +83,9 @@ public void onCheckClientEndpointMetricExpired(long periodic) { } } } + + public void setVertx(Vertx vertx) { + vertx.setPeriodic(metricsOptionsEx.getCheckClientEndpointMetricIntervalInMilliseconds(), + this::onCheckClientEndpointMetricExpired); + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientTaskMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientTaskMetric.java new file mode 100644 index 00000000000..0b032c5e672 --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultClientTaskMetric.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.metrics.metric; + +public class DefaultClientTaskMetric { + private final DefaultClientEndpointMetric endpointMetric; + + public DefaultClientTaskMetric(DefaultClientEndpointMetric endpointMetric) { + this.endpointMetric = endpointMetric; + } + + public void enqueueRequest() { + endpointMetric.enqueueRequest(); + } + + public void dequeueRequest() { + endpointMetric.dequeueRequest(); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java index 86590ce89bb..f26f33b58de 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultEndpointMetric.java @@ -18,31 +18,33 @@ import java.util.concurrent.atomic.LongAdder; -import io.vertx.core.net.SocketAddress; - /** * for one listen address, include multiple httpClient or httpServer */ public class DefaultEndpointMetric { - private SocketAddress address; + private final String address; // summary of connect times from boot // by this, we can know how many new connections connected recently - private LongAdder connectCount = new LongAdder(); + private final LongAdder connectCount = new LongAdder(); // summary of disconnect times from boot // by this, we can know how many connections disconnected recently - private LongAdder disconnectCount = new LongAdder(); + private final LongAdder disconnectCount = new LongAdder(); + + private final LongAdder bytesRead = new LongAdder(); + + private final LongAdder bytesWritten = new LongAdder(); - private LongAdder bytesRead = new LongAdder(); + private final LongAdder requests = new LongAdder(); - private LongAdder bytesWritten = new LongAdder(); + private final LongAdder latency = new LongAdder(); - public DefaultEndpointMetric(SocketAddress address) { + public DefaultEndpointMetric(String address) { this.address = address; } - public SocketAddress getAddress() { + public String getAddress() { return address; } @@ -81,4 +83,20 @@ public long getBytesWritten() { public void addBytesWritten(long bytes) { bytesWritten.add(bytes); } + + public void incrementRequests() { + requests.increment(); + } + + public long getRequests() { + return requests.longValue(); + } + + public void addLatency(long delta) { + latency.add(delta); + } + + public long getLatency() { + return latency.longValue(); + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java deleted file mode 100644 index 307658e9337..00000000000 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultHttpSocketMetric.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.metrics.metric; - -public class DefaultHttpSocketMetric extends DefaultTcpSocketMetric { - private long requestBeginTime; - - private long requestEndTime; - - public DefaultHttpSocketMetric(DefaultEndpointMetric endpointMetric) { - super(endpointMetric); - } - - public long getRequestBeginTime() { - return requestBeginTime; - } - - public void requestBegin() { - this.requestBeginTime = System.nanoTime(); - } - - public long getRequestEndTime() { - return requestEndTime; - } - - public void requestEnd() { - this.requestEndTime = System.nanoTime(); - } -} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultRequestMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultRequestMetric.java new file mode 100644 index 00000000000..224d416c2e5 --- /dev/null +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultRequestMetric.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.foundation.vertx.metrics.metric; + +public class DefaultRequestMetric { + private long requestBeginTime; + + private long requestEndTime; + + private long responseBeginTime; + + private long responseEndTime; + + private final DefaultEndpointMetric endpointMetric; + + public DefaultRequestMetric(DefaultEndpointMetric endpointMetric) { + this.endpointMetric = endpointMetric; + } + + public long getRequestBeginTime() { + return requestBeginTime != 0 ? requestBeginTime : System.nanoTime(); + } + + public long getRequestEndTime() { + return requestEndTime != 0 ? requestEndTime : System.nanoTime(); + } + + public long getResponseBeginTime() { + return responseBeginTime != 0 ? responseBeginTime : System.nanoTime(); + } + + public long getResponseEndTime() { + return responseEndTime != 0 ? responseEndTime : System.nanoTime(); + } + + public void requestBegin() { + this.requestBeginTime = System.nanoTime(); + } + + public void requestEnd() { + this.requestEndTime = System.nanoTime(); + } + + public void responseBegin() { + this.responseBeginTime = System.nanoTime(); + } + + public void responseEnd() { + this.responseEndTime = System.nanoTime(); + this.endpointMetric.incrementRequests(); + this.endpointMetric.addLatency(System.nanoTime() - this.requestBeginTime); + } +} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultServerEndpointMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultServerEndpointMetric.java index b2d48c2d8c8..c01af512ee7 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultServerEndpointMetric.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultServerEndpointMetric.java @@ -18,12 +18,10 @@ import java.util.concurrent.atomic.LongAdder; -import io.vertx.core.net.SocketAddress; - public class DefaultServerEndpointMetric extends DefaultEndpointMetric { - private LongAdder rejectByConnectionLimitCount = new LongAdder(); + private final LongAdder rejectByConnectionLimitCount = new LongAdder(); - public DefaultServerEndpointMetric(SocketAddress address) { + public DefaultServerEndpointMetric(String address) { super(address); } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultTcpSocketMetric.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultTcpSocketMetric.java index 16adccf2ec3..32651d93f64 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultTcpSocketMetric.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/metrics/metric/DefaultTcpSocketMetric.java @@ -16,6 +16,8 @@ */ package org.apache.servicecomb.foundation.vertx.metrics.metric; +import com.google.common.annotations.VisibleForTesting; + public class DefaultTcpSocketMetric { protected DefaultEndpointMetric endpointMetric; @@ -27,20 +29,26 @@ public DefaultTcpSocketMetric(DefaultEndpointMetric endpointMetric) { this.endpointMetric = endpointMetric; } - @SuppressWarnings("unchecked") - public T getEndpointMetric() { - return (T) endpointMetric; + public DefaultEndpointMetric getEndpointMetric() { + return endpointMetric; } + @VisibleForTesting public boolean isConnected() { return connected; } + public void onConnect() { + endpointMetric.onConnect(); + this.connected = true; + } + public void onDisconnect() { endpointMetric.onDisconnect(); this.connected = false; } + @VisibleForTesting public long getConnectedTime() { return connectedTime; } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpParser.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpParser.java index c186381bbf2..4e79f69fca3 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpParser.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpParser.java @@ -17,29 +17,19 @@ package org.apache.servicecomb.foundation.vertx.server; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; -import io.netty.buffer.ByteBuf; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.core.parsetools.RecordParser; -/** - * TcpParser - * - * - */ public class TcpParser implements Handler { public static final byte[] TCP_MAGIC; public static final int TCP_HEADER_LENGTH = 23; static { - try { - TCP_MAGIC = "CSE.TCP".getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } + TCP_MAGIC = "CSE.TCP".getBytes(StandardCharsets.UTF_8); } enum ParseStatus { @@ -47,7 +37,7 @@ enum ParseStatus { TCP_PAYLOAD } - private TcpBufferHandler outputHandler; + private final TcpBufferHandler outputHandler; private RecordParser parser; @@ -90,16 +80,20 @@ public boolean firstNEqual(byte[] a, byte[] b, int n) { protected void onParse(Buffer buffer) { switch (status) { case TCP_HEADER: - ByteBuf buf = buffer.getByteBuf(); - if (!firstNEqual(TCP_MAGIC, buf.array(), TCP_MAGIC.length)) { + if (!firstNEqual(TCP_MAGIC, buffer.getBytes(), TCP_MAGIC.length)) { reset(); return; } - buf.skipBytes(TCP_MAGIC.length); - msgId = buf.readLong(); - totalLen = buf.readInt(); - headerLen = buf.readInt(); + int index = TCP_MAGIC.length; + msgId = buffer.getLong(index); + index = index + 8; + totalLen = buffer.getInt(index); + index = index + 4; + headerLen = buffer.getInt(index); + if (headerLen > totalLen || headerLen <= 0) { + throw new IllegalStateException("possibly attack."); + } if (totalLen == 0) { onReadOnePackage(null, null); diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServer.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServer.java index 58b36c94302..8a960175ad8 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServer.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServer.java @@ -19,8 +19,8 @@ import java.net.InetSocketAddress; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; import org.apache.servicecomb.foundation.ssl.SSLCustom; import org.apache.servicecomb.foundation.ssl.SSLOption; import org.apache.servicecomb.foundation.ssl.SSLOptionFactory; @@ -31,6 +31,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.net.NetServer; import io.vertx.core.net.NetServerOptions; @@ -39,7 +40,7 @@ public class TcpServer { private static final Logger LOGGER = LoggerFactory.getLogger(TcpServer.class); - private URIEndpointObject endpointObject; + private final URIEndpointObject endpointObject; public TcpServer(URIEndpointObject endpointObject) { this.endpointObject = endpointObject; @@ -49,10 +50,10 @@ public void init(Vertx vertx, String sslKey, AsyncResultCallback { - LOGGER.error("Unexpected error in server.{}", ExceptionUtils.getExceptionMessageWithoutTrace(e)); - }); + netServer.exceptionHandler( + e -> LOGGER.error("Unexpected error in server.", e)); InetSocketAddress socketAddress = endpointObject.getSocketAddress(); - netServer.listen(socketAddress.getPort(), socketAddress.getHostString(), ar -> { - if (ar.succeeded()) { + Future result = netServer.listen(socketAddress.getPort(), socketAddress.getHostString()); + result.onComplete((s, f) -> { + if (f == null) { callback.success(socketAddress); return; } // 监听失败 - String msg = String.format("listen failed, address=%s", socketAddress.toString()); - callback.fail(new Exception(msg, ar.cause())); + String msg = String.format("listen failed, address=%s", socketAddress); + callback.fail(new Exception(msg, f)); }); } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServerConnection.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServerConnection.java index 348a3f8437a..dae3d422161 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServerConnection.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/server/TcpServerConnection.java @@ -36,17 +36,13 @@ public void init(NetSocket netSocket) { LOGGER.info("connect from {}, in thread {}", remoteAddress, Thread.currentThread().getName()); - netSocket.exceptionHandler(e -> { - LOGGER.error("disconected from {}, in thread {}, cause {}", - remoteAddress, - Thread.currentThread().getName(), - e.getMessage()); - }); - netSocket.closeHandler(Void -> { - LOGGER.error("disconected from {}, in thread {}", - remoteAddress, - Thread.currentThread().getName()); - }); + netSocket.exceptionHandler(e -> LOGGER.error("disconnected from {}, in thread {}, cause {}", + remoteAddress, + Thread.currentThread().getName(), + e.getMessage())); + netSocket.closeHandler(Void -> LOGGER.info("disconnected from {}, in thread {}", + remoteAddress, + Thread.currentThread().getName())); netSocket.handler(splitter); } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferInputStream.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferInputStream.java index 9f4123a7ade..af0d4acf185 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferInputStream.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferInputStream.java @@ -20,58 +20,69 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; - -import io.netty.buffer.ByteBuf; +import io.vertx.core.buffer.Buffer; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; public class BufferInputStream extends ServletInputStream { - private ByteBuf byteBuf; + private int readIndex = 0; + + private final Buffer byteBuf; - public BufferInputStream(ByteBuf buffer) { + public BufferInputStream(Buffer buffer) { this.byteBuf = buffer; } @Override public long skip(long len) { int skipLen = Math.min((int) len, available()); - byteBuf.skipBytes(skipLen); + this.readIndex += skipLen; return skipLen; } public byte readByte() { - return byteBuf.readByte(); + int index = readIndex; + readIndex = index + 1; + return byteBuf.getByte(index); } @Override public int read() { - return byteBuf.readByte(); + return this.readByte() & 255; } public boolean readBoolean() { - return byteBuf.readBoolean(); + return this.readByte() != 0; } public short readShort() { - return byteBuf.readShort(); + int index = readIndex; + readIndex = index + 2; + return byteBuf.getShort(index); } public int readInt() { - return byteBuf.readInt(); + int index = readIndex; + readIndex = index + 4; + return byteBuf.getInt(index); } public long readLong() { - return byteBuf.readLong(); + int index = readIndex; + readIndex = index + 8; + return byteBuf.getLong(index); } public int getIndex() { - return byteBuf.readerIndex(); + return readIndex; } public String readString() { int length = readInt(); byte[] bytes = new byte[length]; - byteBuf.readBytes(bytes); + int index = readIndex; + readIndex = index + length; + byteBuf.getBytes(index, readIndex, bytes); return new String(bytes, StandardCharsets.UTF_8); } @@ -83,40 +94,47 @@ public int read(byte[] b) { @Override public int read(byte[] b, int off, int len) { int avail = available(); - if (len > avail) { - len = avail; + if (avail <= 0) { + return -1; } if (len == 0) { - return -1; + return 0; } - byteBuf.readBytes(b, off, len); + if (len > avail) { + len = avail; + } + + int index = readIndex; + readIndex = index + len; + + byteBuf.getBytes(index, readIndex, b); return len; } @Override public int available() { - return byteBuf.readableBytes(); + return byteBuf.length() - readIndex; } @Override public void close() { - byteBuf.release(); + // nothing to do } @Override public void reset() throws IOException { - byteBuf.resetReaderIndex(); + readIndex = 0; } - public ByteBuf getByteBuf() { + public Buffer getByteBuf() { return byteBuf; } @Override public boolean isFinished() { - return !byteBuf.isReadable(); + return byteBuf.length() > readIndex; } @Override diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferOutputStream.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferOutputStream.java index 8f00e2cf8aa..42c9b31261d 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferOutputStream.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/BufferOutputStream.java @@ -20,67 +20,46 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; -import io.netty.buffer.ByteBuf; import io.vertx.core.buffer.Buffer; /** - * BufferOutputStream - * + * BufferOutputStream. * + * Notice: will not release the underlining ByteBuffer, the user is responsible to release it. */ public class BufferOutputStream extends OutputStream { private static final int DIRECT_BUFFER_SIZE = 1024; - protected ByteBuf byteBuf; - - private boolean needReleaseBuffer; + protected Buffer byteBuf; public BufferOutputStream() { - // TODO:默认大小加配置项 - // TODO:如何与pool配合起来,vertx中默认都是unpool的,我们的阻塞模式下,申请与释放也不在一个线程,估计更用不上? - // 后续通道没问题了,再来验证这个问题 - // this(PooledByteBufAllocator.DEFAULT.directBuffer()); - - // this(PooledByteBufAllocator.DEFAULT.directBuffer(DIRECT_BUFFER_SIZE)); - - // this(UnpooledByteBufAllocator.DEFAULT.directBuffer(DIRECT_BUFFER_SIZE)); - // needReleaseBuffer = false; - - // this(UnpooledByteBufAllocator.DEFAULT.heapBuffer(DIRECT_BUFFER_SIZE)); - - this(Buffer.buffer(DIRECT_BUFFER_SIZE).getByteBuf()); - needReleaseBuffer = false; + this(Buffer.buffer(DIRECT_BUFFER_SIZE)); } - - public BufferOutputStream(ByteBuf buffer) { + public BufferOutputStream(Buffer buffer) { this.byteBuf = buffer; } - public ByteBuf getByteBuf() { - return byteBuf; - } - public Buffer getBuffer() { - return Buffer.buffer(byteBuf); + return byteBuf; } public int length() { - return byteBuf.readableBytes(); + return byteBuf.length(); } public void writeByte(byte value) { - byteBuf.writeByte(value); + byteBuf.appendByte(value); } // 实际是写byte @Override public void write(int byteValue) { - byteBuf.writeByte((byte) byteValue); + byteBuf.appendByte((byte) byteValue); } public void write(boolean value) { - byteBuf.writeBoolean(value); + byteBuf.appendByte(value ? (byte) 1 : (byte) 0); } public void writeInt(int pos, int value) { @@ -88,39 +67,38 @@ public void writeInt(int pos, int value) { } public void writeShort(short value) { - byteBuf.writeShort(value); + byteBuf.appendShort(value); } public void writeInt(int value) { - byteBuf.writeInt(value); + byteBuf.appendInt(value); } public void writeLong(long value) { - byteBuf.writeLong(value); + byteBuf.appendLong(value); } public void writeString(String value) { - byteBuf.writeInt(value.length()); - byteBuf.writeCharSequence(value, StandardCharsets.UTF_8); + writeInt(value.length()); + byteBuf.appendString(value, StandardCharsets.UTF_8.toString()); } + @Override public void write(byte[] b) { write(b, 0, b.length); } @Override public void write(byte[] bytes, int offset, int len) { - byteBuf.writeBytes(bytes, offset, len); + byteBuf.appendBytes(bytes, offset, len); } @Override public void close() { - if (needReleaseBuffer && byteBuf != null) { - byteBuf.release(); - } + // Do no release byteBuf, the target BufferedInputStream will release it. } public int writerIndex() { - return byteBuf.writerIndex(); + return byteBuf.length(); } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/InputStreamToReadStream.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/InputStreamToReadStream.java index 6d66fb60f98..580d460e5c0 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/InputStreamToReadStream.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/InputStreamToReadStream.java @@ -19,15 +19,14 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.buffer.Unpooled; -import io.vertx.core.AsyncResult; import io.vertx.core.Context; -import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; import io.vertx.core.streams.ReadStream; @@ -36,11 +35,11 @@ public class InputStreamToReadStream implements ReadStream { public static final int DEFAULT_READ_BUFFER_SIZE = 1024 * 1024; - private Context context; + private final Context context; - private InputStream inputStream; + private final InputStream inputStream; - private boolean closed; + private volatile boolean closed; private boolean paused; @@ -54,7 +53,7 @@ public class InputStreamToReadStream implements ReadStream { private Handler endHandler; - private boolean autoCloseInputStream; + private final boolean autoCloseInputStream; public InputStreamToReadStream(Context context, InputStream inputStream, boolean autoCloseInputStream) { @@ -97,30 +96,33 @@ public synchronized InputStreamToReadStream handler(Handler handler) { } class ReadResult { - int readed; + int read; byte[] bytes = new byte[readBufferSize]; void doRead() throws IOException { - readed = inputStream.read(bytes); + read = inputStream.read(bytes); } Buffer toBuffer() { - return Buffer.buffer(Unpooled.wrappedBuffer(bytes).writerIndex(readed)); + return Buffer.buffer(Arrays.copyOf(bytes, read)); } } private synchronized void doRead() { if (!readInProgress) { readInProgress = true; - - context.executeBlocking(this::readInWorker, - true, - this::afterReadInEventloop); + Promise future = Promise.promise(); + context.executeBlocking(() -> { + readInWorker(future); + return null; + }, + true); + future.future().onComplete(this::afterReadInEventloop); } } - private synchronized void readInWorker(Future future) { + private synchronized void readInWorker(Promise future) { try { ReadResult readResult = new ReadResult(); readResult.doRead(); @@ -135,15 +137,14 @@ public void handleException(Throwable e) { exceptionHandler.handle(e); } - private synchronized void afterReadInEventloop(AsyncResult ar) { - if (ar.failed()) { - handleException(ar.cause()); + private synchronized void afterReadInEventloop(ReadResult readResult, Throwable failure) { + if (failure != null) { + handleException(failure); return; } readInProgress = false; - ReadResult readResult = ar.result(); - if (readResult.readed < 0) { + if (readResult.read < 0) { handleEnd(); return; } @@ -191,7 +192,7 @@ private void closeInputStream() { if (closed) { return; } - + closed = true; if (!autoCloseInputStream) { return; @@ -210,4 +211,9 @@ public ReadStream endHandler(Handler handler) { this.endHandler = handler; return this; } + + @Override + public ReadStream fetch(long amount) { + return this; + } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/OutputStreamToWriteStream.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/OutputStreamToWriteStream.java index 9e697598b89..35681a723a8 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/OutputStreamToWriteStream.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/OutputStreamToWriteStream.java @@ -21,12 +21,14 @@ import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.servicecomb.foundation.common.io.AsyncCloseable; import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; import io.vertx.core.streams.WriteStream; @@ -38,11 +40,11 @@ public class OutputStreamToWriteStream implements WriteStream, AsyncClos private static final int SMALLEST_MAX_BUFFERS = 2; - private OutputStream outputStream; + private final OutputStream outputStream; - private Context context; + private final Context context; - private boolean autoCloseOutputStream; + private final boolean autoCloseOutputStream; private Handler exceptionHandler; @@ -56,9 +58,9 @@ public class OutputStreamToWriteStream implements WriteStream, AsyncClos // buffers.size() need to loop all node, and maybe result is not correct in concurrent condition // we just need to flow control by pump, so use another size - private Queue buffers = new ConcurrentLinkedQueue<>(); + private final Queue buffers = new ConcurrentLinkedQueue<>(); - private int currentBufferCount; + private final AtomicInteger currentBufferCount = new AtomicInteger(); // just indicate if buffers is full, not control add logic // must >= SMALLEST_MAX_BUFFERS @@ -88,20 +90,25 @@ private void handleException(Throwable t) { } @Override - public synchronized WriteStream write(Buffer data) { - currentBufferCount++; + public synchronized Future write(Buffer data) { + Promise result = Promise.promise(); + write(data, result); + return result.future(); + } + + private void write(Buffer data, Promise future) { + currentBufferCount.incrementAndGet(); buffers.add(data); - context.executeBlocking(this::writeInWorker, - true, - ar -> { - if (ar.failed()) { - handleException(ar.cause()); - } - }); - return this; + context.executeBlocking( + () -> { + writeInWorker(future); + return null; + }, + true + ); } - protected void writeInWorker(Future future) { + protected void writeInWorker(Promise future) { while (true) { Buffer buffer = buffers.poll(); if (buffer == null) { @@ -113,12 +120,13 @@ protected void writeInWorker(Future future) { outputStream.write(buffer.getBytes()); synchronized (OutputStreamToWriteStream.this) { - currentBufferCount--; - Runnable action = (currentBufferCount == 0 && closedDeferred != null) ? closedDeferred : this::checkDrained; + currentBufferCount.decrementAndGet(); + Runnable action = (currentBufferCount.get() == 0 && closedDeferred != null) + ? closedDeferred : this::checkDrained; action.run(); } } catch (IOException e) { - currentBufferCount--; + currentBufferCount.decrementAndGet(); future.fail(e); return; } @@ -126,20 +134,20 @@ protected void writeInWorker(Future future) { } @Override - public void end() { - close(); + public Future end() { + return Future.fromCompletionStage(close()); } @Override public WriteStream setWriteQueueMaxSize(int maxSize) { - this.maxBuffers = maxSize < SMALLEST_MAX_BUFFERS ? SMALLEST_MAX_BUFFERS : maxSize; + this.maxBuffers = Math.max(maxSize, SMALLEST_MAX_BUFFERS); this.drainMark = maxBuffers / 2; return this; } @Override public synchronized boolean writeQueueFull() { - return currentBufferCount >= maxBuffers; + return currentBufferCount.get() >= maxBuffers; } @Override @@ -149,7 +157,7 @@ public synchronized WriteStream drainHandler(Handler handler) { } private synchronized void checkDrained() { - if (drainHandler != null && currentBufferCount <= drainMark) { + if (drainHandler != null && currentBufferCount.get() <= drainMark) { Handler handler = drainHandler; drainHandler = null; handler.handle(null); @@ -177,7 +185,7 @@ private synchronized CompletableFuture closeInternal() { closed = true; CompletableFuture future = new CompletableFuture<>(); - if (currentBufferCount == 0) { + if (currentBufferCount.get() == 0) { doClose(future); } else { closedDeferred = () -> doClose(future); diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpCommon.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpCommon.java index 090882ab10e..ae4b5bac727 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpCommon.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpCommon.java @@ -20,25 +20,24 @@ import org.apache.servicecomb.foundation.common.io.AsyncCloseable; -import io.vertx.core.Context; +import io.vertx.core.Future; +import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientResponse; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.WriteStream; +import io.vertx.core.streams.impl.PipeImpl; public class PumpCommon { /** - * - * @param context - * @param readStream - * @param writeStream * @return future of save action
*

important: *

if writeStream is AsyncCloseable, future means write complete *

if writeStream is not AsyncCloseable, future only means read complete */ @SuppressWarnings("unchecked") - public CompletableFuture pump(Context context, ReadStream readStream, WriteStream writeStream) { + public CompletableFuture pump(ReadStream readStream, WriteStream writeStream, + Handler throwableHandler) { CompletableFuture readFuture = new CompletableFuture<>(); writeStream.exceptionHandler(e -> { @@ -53,24 +52,24 @@ public CompletableFuture pump(Context context, ReadStream readStre // so can only close the connection. ((HttpClientResponse) readStream).request().connection().close(); } + if (throwableHandler != null) { + throwableHandler.handle(e); + } readFuture.completeExceptionally(e); }); readStream.exceptionHandler(readFuture::completeExceptionally); - // just means read finished, not means write finished - readStream.endHandler(readFuture::complete); - // if readStream(HttpClientResponse) and writeStream(HttpServerResponse) - // belongs to difference eventloop - // maybe will cause deadlock - // if happened, vertx will print deadlock stacks - PumpImplEx.getPumpImplEx(readStream, writeStream).start(); - try { - context.runOnContext(v -> readStream.resume()); - } catch (Throwable e) { - readFuture.completeExceptionally(e); - } + Future pipeResult = new PipeImpl<>(readStream).endOnComplete(false).to(writeStream); + + pipeResult.onComplete((s) -> readFuture.complete(null), + (f) -> { + if (throwableHandler != null) { + throwableHandler.handle(f); + } + readFuture.completeExceptionally(f); + }); - if (!AsyncCloseable.class.isInstance(writeStream)) { + if (!(writeStream instanceof AsyncCloseable)) { return readFuture; } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java index 348321c65e2..2c5284e12dc 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpFromPart.java @@ -21,21 +21,26 @@ import java.io.OutputStream; import java.util.concurrent.CompletableFuture; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.commons.io.IOUtils; import org.apache.servicecomb.foundation.vertx.http.DownloadUtils; import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import io.vertx.core.Context; +import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.WriteStream; public class PumpFromPart { - private Context context; + private static final Logger LOGGER = LoggerFactory.getLogger(PumpFromPart.class); - private Part part; + private final Context context; + + private final Part part; public PumpFromPart(Context context, Part part) { this.context = context; @@ -62,10 +67,19 @@ private CompletableFuture> prepareReadStream() { return future; } - public CompletableFuture toWriteStream(WriteStream writeStream) { + public CompletableFuture toWriteStream(WriteStream writeStream, Handler throwableHandler) { return prepareReadStream() - .thenCompose(readStream -> new PumpCommon().pump(context, readStream, writeStream)) - .whenComplete((v, e) -> DownloadUtils.clearPartResource(part)); + .thenCompose(readStream -> new PumpCommon().pump(readStream, writeStream, throwableHandler)) + .whenComplete((v, e) -> { + if (e != null) { + LOGGER.error("to write stream failed.", e); + } + DownloadUtils.clearPartResource(part); + // PumpImpl will add drainHandler to writeStream, + // in order to support write multiple files to same writeStream, + // need reset after one stream is successful. + writeStream.drainHandler(null); + }); } public CompletableFuture toOutputStream(OutputStream outputStream, boolean autoCloseOutputStream) { @@ -79,13 +93,14 @@ public CompletableFuture toOutputStream(OutputStream outputStream, boolean private CompletableFuture toOutputStreamAsync(OutputStream outputStream, boolean autoCloseOutputStream) { OutputStreamToWriteStream outputStreamToWriteStream = new OutputStreamToWriteStream(context, outputStream, autoCloseOutputStream); - return toWriteStream(outputStreamToWriteStream); + return toWriteStream(outputStreamToWriteStream, null); } // DO NOT use a mocked sync context to unify the pump logic // otherwise when pump big stream, will cause stack overflow private CompletableFuture toOutputStreamSync(OutputStream outputStream, boolean autoCloseOutputStream) { CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((v, e) -> DownloadUtils.clearPartResource(part)); try (InputStream inputStream = part.getInputStream()) { IOUtils.copyLarge(inputStream, outputStream); diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java deleted file mode 100644 index e8356298f2e..00000000000 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 - * which is available at https://www.apache.org/licenses/LICENSE-2.0. - * - * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 - */ - -/* - * Froked from https://github.com/eclipse-vertx/vert.x/blob/master/src/main/java/io/vertx/core/streams/impl/PumpImpl.java - * - */ -package org.apache.servicecomb.foundation.vertx.stream; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.streams.Pump; -import io.vertx.core.streams.ReadStream; -import io.vertx.core.streams.WriteStream; - -public class PumpImplEx implements Pump { - - private final ReadStream readStream; - - private final WriteStream writeStream; - - private final Handler dataHandler; - - private final Handler drainHandler; - - private int pumped; - - public PumpImplEx(ReadStream readStream, WriteStream writeStream, int maxWriteQueueSize) { - this(readStream, writeStream); - this.writeStream.setWriteQueueMaxSize(maxWriteQueueSize); - } - - public PumpImplEx(ReadStream readStream, WriteStream writeStream) { - this.readStream = readStream; - this.writeStream = writeStream; - drainHandler = v -> readStream.resume(); - dataHandler = data -> { - if (data instanceof Buffer) { - if (((Buffer) data).length() == 0) { - return; - } - } - writeStream.write(data); - incPumped(); - if (writeStream.writeQueueFull()) { - readStream.pause(); - writeStream.drainHandler(drainHandler); - } - }; - } - - - @Override - public PumpImplEx setWriteQueueMaxSize(int maxSize) { - writeStream.setWriteQueueMaxSize(maxSize); - return this; - } - - @Override - public PumpImplEx start() { - readStream.handler(dataHandler); - return this; - } - - @Override - public PumpImplEx stop() { - writeStream.drainHandler(null); - readStream.handler(null); - return this; - } - - - @Override - public synchronized int numberPumped() { - return pumped; - } - - - private synchronized void incPumped() { - pumped++; - } - - public Handler getDataHandler() { - return dataHandler; - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static PumpImplEx getPumpImplEx(ReadStream rs, WriteStream ws) { - return new PumpImplEx(rs, ws); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static PumpImplEx getPumpImplEx(ReadStream rs, WriteStream ws, int writeQueueMaxSize) { - return new PumpImplEx(rs, ws, writeQueueMaxSize); - } -} diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpConnection.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpConnection.java index e8428ed751e..fcc22bfd7c9 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpConnection.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpConnection.java @@ -20,14 +20,10 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.CompositeByteBuf; import io.vertx.core.Context; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetSocket; import io.vertx.core.net.impl.NetSocketImpl; -import io.vertx.core.net.impl.VertxHelper; public class TcpConnection { protected String protocol; @@ -50,9 +46,9 @@ public class TcpConnection { // so this optimization: // 1.avoid vertx's lock // 2.reduce netty's task schedule - private Queue writeQueue = new ConcurrentLinkedQueue<>(); + private final Queue writeQueue = new ConcurrentLinkedQueue<>(); - private AtomicLong writeQueueSize = new AtomicLong(); + private final AtomicLong writeQueueSize = new AtomicLong(); public String getProtocol() { return protocol; @@ -81,10 +77,10 @@ public NetSocket getNetSocket() { public void initNetSocket(NetSocketImpl netSocket) { this.netSocket = netSocket; - this.context = VertxHelper.getConnectionContext(netSocket); + this.context = netSocket.context(); } - public void write(ByteBuf buf) { + public void write(Buffer buf) { writeQueue.add(buf); long oldSize = writeQueueSize.getAndIncrement(); if (oldSize == 0) { @@ -94,29 +90,19 @@ public void write(ByteBuf buf) { // notify context thread to write protected void scheduleWrite() { - context.runOnContext(v -> { - writeInContext(); - }); + context.runOnContext(v -> writeInContext()); } protected void writeInContext() { - CompositeByteBuf cbb = ByteBufAllocator.DEFAULT.compositeBuffer(); for (; ; ) { - ByteBuf buf = writeQueue.poll(); + Buffer buf = writeQueue.poll(); if (buf == null) { break; } writeQueueSize.decrementAndGet(); - cbb.addComponent(true, buf); - if (cbb.numComponents() == cbb.maxNumComponents()) { - netSocket.write(Buffer.buffer(cbb)); - cbb = ByteBufAllocator.DEFAULT.compositeBuffer(); - } - } - if (cbb.isReadable()) { - netSocket.write(Buffer.buffer(cbb)); + netSocket.write(buf); } } } diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpOutputStream.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpOutputStream.java index 716d231aad6..8efcef3b6ce 100644 --- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpOutputStream.java +++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/tcp/TcpOutputStream.java @@ -26,7 +26,7 @@ * */ public class TcpOutputStream extends BufferOutputStream { - private long msgId; + private final long msgId; public TcpOutputStream(long msgId) { super(); diff --git a/foundations/foundation-vertx/src/main/resources/META-INF/spring/cse.bean.xml b/foundations/foundation-vertx/src/main/resources/META-INF/spring/cse.bean.xml deleted file mode 100644 index 908d9ce1944..00000000000 --- a/foundations/foundation-vertx/src/main/resources/META-INF/spring/cse.bean.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - diff --git a/foundations/foundation-vertx/src/test/java/io/vertx/core/file/impl/AsyncFileUitls.java b/foundations/foundation-vertx/src/test/java/io/vertx/core/file/impl/AsyncFileUitls.java deleted file mode 100644 index a458f9bd6d8..00000000000 --- a/foundations/foundation-vertx/src/test/java/io/vertx/core/file/impl/AsyncFileUitls.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.vertx.core.file.impl; - -import io.vertx.core.file.AsyncFile; -import io.vertx.core.file.OpenOptions; -import io.vertx.core.impl.ContextImpl; -import io.vertx.core.impl.VertxInternal; - -public class AsyncFileUitls { - public static AsyncFile createAsyncFile(VertxInternal vertx, String path, OpenOptions options, ContextImpl context) { - return new AsyncFileImpl(vertx, path, options, context); - } -} diff --git a/foundations/foundation-vertx/src/test/java/io/vertx/core/impl/TestVertxImplEx.java b/foundations/foundation-vertx/src/test/java/io/vertx/core/impl/TestVertxImplEx.java deleted file mode 100644 index 733d15047df..00000000000 --- a/foundations/foundation-vertx/src/test/java/io/vertx/core/impl/TestVertxImplEx.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.vertx.core.impl; - -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.VertxOptions; -import io.vertx.core.json.JsonObject; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestVertxImplEx { - @Test - public void testContextCreatedCount(@Mocked EventLoopContext context) { - new MockUp() { - @Mock - EventLoopContext createEventLoopContext(String deploymentID, WorkerPool workerPool, JsonObject config, - ClassLoader tccl) { - return context; - } - }; - - VertxImplEx vertx = new VertxImplEx("test", new VertxOptions()); - - vertx.createEventLoopContext(null, null, null, null); - Assert.assertEquals(1, vertx.getEventLoopContextCreatedCount()); - - vertx.createEventLoopContext(null, null, null, null); - Assert.assertEquals(2, vertx.getEventLoopContextCreatedCount()); - } -} diff --git a/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestHttpServerRequestUtils.java b/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestHttpServerRequestUtils.java deleted file mode 100644 index 7730bb68c8c..00000000000 --- a/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestHttpServerRequestUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.ext.web.impl; - -import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; -import mockit.Expectations; -import mockit.Mocked; - -public class TestHttpServerRequestUtils { - @Test - public void setPath(@Mocked HttpServerRequest request) { - HttpServerRequestWrapper wrapper = new HttpServerRequestWrapper(request); - HttpServerRequestUtils.setPath(wrapper, "abc"); - - Assert.assertEquals("abc", wrapper.path()); - } - - @Test - public void VertxServerRequestToHttpServletRequest(@Mocked RoutingContext context, - @Mocked HttpServerRequest request) { - HttpServerRequestWrapper wrapper = new HttpServerRequestWrapper(request); - new Expectations() { - { - context.request(); - result = wrapper; - } - }; - - VertxServerRequestToHttpServletRequest reqEx = new VertxServerRequestToHttpServletRequest(context, "abc"); - Assert.assertEquals("abc", reqEx.getRequestURI()); - } -} diff --git a/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestMimeTypesUtils.java b/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestMimeTypesUtils.java deleted file mode 100644 index 6c79eb9a1f4..00000000000 --- a/foundations/foundation-vertx/src/test/java/io/vertx/ext/web/impl/TestMimeTypesUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.vertx.ext.web.impl; - -import static org.junit.Assert.assertEquals; - -import java.util.Collections; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -public class TestMimeTypesUtils { - @Test - public void testSortedAcceptableMimeTypes1() { - String accept = "text/html"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(1, types.size()); - assertEquals("text/html", types.get(0)); - } - - @Test - public void testSortedAcceptableMimeTypes2() { - String accept = "text/html, application/json"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(2, types.size()); - assertEquals("text/html", types.get(0)); - assertEquals("application/json", types.get(1)); - } - - @Test - public void testSortedAcceptableMimeTypes3() { - String accept = "text/html,application/json"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(2, types.size()); - assertEquals("text/html", types.get(0)); - assertEquals("application/json", types.get(1)); - } - - @Test - public void testSortedAcceptableMimeTypes4() { - String accept = "text/html; q=0.8,application/json; q=0.9"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(2, types.size()); - assertEquals("application/json", types.get(0)); - assertEquals("text/html", types.get(1)); - } - - @Test - public void testSortedAcceptableMimeTypes5() { - String accept = "text/html;q=0.8,application/json;q=0.9"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(2, types.size()); - assertEquals("application/json", types.get(0)); - assertEquals("text/html", types.get(1)); - } - - @Test - public void testSortedAcceptableMimeTypes6() { - String accept = "text/html; q=0.8,application/json; q=0.9, text/plain"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(3, types.size()); - assertEquals("text/plain", types.get(0)); - assertEquals("application/json", types.get(1)); - assertEquals("text/html", types.get(2)); - } - - @Test - public void testSortedAcceptableMimeTypes7() { - String accept = "text/html;q=0.8,application/json;q=0.9,text/plain"; - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(accept); - assertEquals(3, types.size()); - assertEquals("text/plain", types.get(0)); - assertEquals("application/json", types.get(1)); - assertEquals("text/html", types.get(2)); - } - - @Test - public void getSortedAcceptableMimeTypesNull() { - List types = MimeTypesUtils.getSortedAcceptableMimeTypes(null); - Assert.assertSame(Collections.emptyList(), types); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestAddressResolverConfig.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestAddressResolverConfig.java deleted file mode 100644 index da4bc2ccf7c..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestAddressResolverConfig.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.vertx; - -import static org.hamcrest.CoreMatchers.is; - -import java.util.Arrays; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import io.vertx.core.dns.AddressResolverOptions; -import mockit.Expectations; -import mockit.Mocked; - -public class TestAddressResolverConfig { - - @BeforeClass - public static void classSetup() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testGetResoverFromResource(@Mocked Configuration finalConfig) { - ArchaiusUtils.resetConfig(); - ArchaiusUtils.setProperty("addressResolver.servers", "8.8.8.8,8.8.4.4"); - new Expectations() { - { - finalConfig.getStringArray("addressResolver.servers"); - result = new String[] {"6.6.6.6", "6.6.4.4"}; - finalConfig.getStringArray("addressResolver.searchDomains"); - result = new String[] {"default.svc.local.cluster"}; - finalConfig.getInteger("addressResolver.queryTimeout", null); - result = 2000; - finalConfig.getInteger("addressResolver.maxQueries", null); - result = -2; - } - }; - AddressResolverOptions aroc = AddressResolverConfig.getAddressResover("test", finalConfig); - Assert.assertThat(aroc.getServers(), is(Arrays.asList("6.6.6.6", "6.6.4.4"))); - Assert.assertThat(aroc.getSearchDomains(), - is(Arrays.asList("default.svc.local.cluster"))); - Assert.assertEquals(aroc.getQueryTimeout(), - 2000); - Assert.assertNotEquals(aroc.getMaxQueries(), - -2); - } - - @Test - public void testGetResover() { - ArchaiusUtils.resetConfig(); - ArchaiusUtils.setProperty("addressResolver.servers", "8.8.8.8,8.8.4.4"); - ArchaiusUtils.setProperty("addressResolver.optResourceEnabled", true); - ArchaiusUtils.setProperty("addressResolver.cacheMinTimeToLive", 0); - ArchaiusUtils.setProperty("addressResolver.cacheMaxTimeToLive", 10000); - ArchaiusUtils.setProperty("addressResolver.cacheNegativeTimeToLive", 0); - ArchaiusUtils.setProperty("addressResolver.queryTimeout", 1000); - ArchaiusUtils.setProperty("addressResolver.maxQueries", 3); - ArchaiusUtils.setProperty("addressResolver.test.maxQueries", 3); - ArchaiusUtils.setProperty("addressResolver.rdFlag", true); - ArchaiusUtils.setProperty("addressResolver.searchDomains", - "default.svc.local.cluster,svc.local.cluster,local.cluster"); - ArchaiusUtils.setProperty("addressResolver.test.searchDomains", - "test.svc.local.cluster,svc.local.cluster,local.cluster"); - ArchaiusUtils.setProperty("addressResolver.ndots", 3); - ArchaiusUtils.setProperty("addressResolver.rotateServers", true); - AddressResolverOptions aroc = AddressResolverConfig.getAddressResover("test"); - Assert.assertThat(aroc.getServers(), is(Arrays.asList("8.8.8.8", "8.8.4.4"))); - Assert.assertThat(aroc.getSearchDomains(), - is(Arrays.asList("test.svc.local.cluster", "svc.local.cluster", "local.cluster"))); - AddressResolverOptions aroc1 = AddressResolverConfig.getAddressResover("test1"); - Assert.assertThat(aroc1.getSearchDomains(), - is(Arrays.asList("default.svc.local.cluster", "svc.local.cluster", "local.cluster"))); - } - - @Test - public void testGetResoverDefault() { - ArchaiusUtils.resetConfig(); - ArchaiusUtils.setProperty("addressResolver.servers", "8.8.8.8,8.8.4.4"); - ArchaiusUtils.setProperty("addressResolver.maxQueries", 3); - ArchaiusUtils.setProperty("addressResolver.rdFlag", false); - AddressResolverOptions aroc = AddressResolverConfig.getAddressResover("test"); - Assert.assertThat(aroc.getServers(), is(Arrays.asList("8.8.8.8", "8.8.4.4"))); - Assert.assertEquals(3, aroc.getMaxQueries()); - Assert.assertEquals(Integer.MAX_VALUE, aroc.getCacheMaxTimeToLive()); - Assert.assertTrue(aroc.isOptResourceEnabled()); - Assert.assertNull(aroc.getSearchDomains()); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSharedVertxFactory.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSharedVertxFactory.java new file mode 100644 index 00000000000..8e77a256251 --- /dev/null +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSharedVertxFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.foundation.vertx; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import io.vertx.core.impl.SysProps; + +public class TestSharedVertxFactory { + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + } + + + @Test + public void getTransportVertx() { + Assertions.assertNotNull(SharedVertxFactory.getSharedVertx(environment)); + Assertions.assertSame(SharedVertxFactory.getSharedVertx(environment), + SharedVertxFactory.getSharedVertx(environment)); + + SharedVertxFactory.getSharedVertx(environment).close(); + } +} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleBodyHandler.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleBodyHandler.java index 7c4cee493b2..8aec460f9c0 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleBodyHandler.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleBodyHandler.java @@ -17,28 +17,28 @@ package org.apache.servicecomb.foundation.vertx; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.impl.RoutingContextInternal; public class TestSimpleBodyHandler { private SimpleBodyHandler instance; - private RoutingContext context; + private RoutingContextInternal context; @Before public void setUp() throws Exception { - context = Mockito.mock(RoutingContext.class); + context = Mockito.mock(RoutingContextInternal.class); HttpServerRequest request = Mockito.mock(HttpServerRequest.class); Mockito.when(context.request()).thenReturn(request); MultiMap multiMap = Mockito.mock(MultiMap.class); @@ -63,7 +63,7 @@ protected boolean contentTypeSupported(String contentType) { } }; instance.handle(context); - Assert.assertTrue(instance.checkContentType(context)); + Assertions.assertTrue(instance.checkContentType(context)); } @Test @@ -75,6 +75,6 @@ protected boolean contentTypeSupported(String contentType) { } }; instance.handle(context); - Assert.assertFalse(instance.checkContentType(context)); + Assertions.assertFalse(instance.checkContentType(context)); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleJsonObject.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleJsonObject.java index 8f621f7c40c..d0a51708073 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleJsonObject.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestSimpleJsonObject.java @@ -16,8 +16,8 @@ */ package org.apache.servicecomb.foundation.vertx; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestSimpleJsonObject { @Test @@ -26,12 +26,12 @@ public void testPutObject() { SimpleJsonObject json = new SimpleJsonObject(); json.put("k", value); - Assert.assertSame(value, json.getValue("k")); + Assertions.assertSame(value, json.getValue("k")); } @Test public void testCopy() { SimpleJsonObject json = new SimpleJsonObject(); - Assert.assertSame(json, json.copy()); + Assertions.assertSame(json, json.copy()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestStream.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestStream.java index 9057056149e..af3e2078c90 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestStream.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestStream.java @@ -19,10 +19,9 @@ import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import io.netty.buffer.ByteBuf; import io.vertx.core.buffer.Buffer; public class TestStream { @@ -31,17 +30,21 @@ public class TestStream { @Test public void testBufferInputStream() { - ByteBuf obuf = Buffer.buffer(DIRECT_BUFFER_SIZE).getByteBuf(); - obuf.writeBytes(("testss").getBytes()); + Buffer obuf = Buffer.buffer(DIRECT_BUFFER_SIZE); + obuf.appendBytes(("tests1").getBytes()); @SuppressWarnings("resource") BufferInputStream oBufferInputStream = new BufferInputStream(obuf); - Assert.assertNotEquals(1234, oBufferInputStream.skip(0)); - Assert.assertNotEquals(obuf.readByte(), oBufferInputStream.readByte()); - Assert.assertEquals(obuf.readByte() + 1, oBufferInputStream.read()); - Assert.assertEquals(obuf.readBoolean(), oBufferInputStream.readBoolean()); - Assert.assertEquals(obuf.readerIndex(), oBufferInputStream.getIndex()); - Assert.assertEquals(obuf.readableBytes(), oBufferInputStream.available()); - Assert.assertNotEquals(null, oBufferInputStream.read(("test").getBytes())); + + byte test = oBufferInputStream.readByte(); + Assertions.assertEquals((byte) 't', test); + Assertions.assertEquals((byte) 'e', oBufferInputStream.read()); + + Assertions.assertEquals(2, oBufferInputStream.skip(2)); + Assertions.assertEquals((byte) 's', oBufferInputStream.read()); + Assertions.assertTrue(oBufferInputStream.readBoolean()); + + Assertions.assertEquals(6, oBufferInputStream.getIndex()); + Assertions.assertEquals(0, oBufferInputStream.available()); } @Test @@ -49,9 +52,14 @@ public void testBufferOutputStream() { @SuppressWarnings({"resource"}) BufferOutputStream oBufferOutputStream = new BufferOutputStream(); oBufferOutputStream.writeString("test"); - Assert.assertNotEquals(null, oBufferOutputStream.writerIndex()); oBufferOutputStream.write(1); oBufferOutputStream.write(true); - Assert.assertEquals(true, (1 < oBufferOutputStream.length())); + Assertions.assertTrue((1 < oBufferOutputStream.length())); + + @SuppressWarnings("resource") + BufferInputStream oBufferInputStream = new BufferInputStream(oBufferOutputStream.getBuffer()); + Assertions.assertEquals("test", oBufferInputStream.readString()); + Assertions.assertEquals(1, oBufferInputStream.readByte()); + Assertions.assertTrue(oBufferInputStream.readBoolean()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxTLSBuilder.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxTLSBuilder.java index 95a2cd167c3..f99abd698df 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxTLSBuilder.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxTLSBuilder.java @@ -17,14 +17,15 @@ package org.apache.servicecomb.foundation.vertx; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.ssl.SSLCustom; import org.apache.servicecomb.foundation.ssl.SSLOption; import org.apache.servicecomb.foundation.ssl.SSLOptionFactory; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.vertx.core.http.ClientAuth; import io.vertx.core.http.HttpClientOptions; @@ -33,31 +34,28 @@ import mockit.MockUp; public class TestVertxTLSBuilder { - @BeforeClass - public static void classSetup() { - ArchaiusUtils.resetConfig(); - } + Environment environment = Mockito.mock(Environment.class); - @AfterClass - public static void classTeardown() { - ArchaiusUtils.resetConfig(); + @Before + public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); } @Test - public void testbuildHttpServerOptions() { - SSLOption option = SSLOption.buildFromYaml("rest.provider"); + public void testBuildHttpServerOptions() { + SSLOption option = SSLOption.build("rest.provider", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpServerOptions serverOptions = new HttpServerOptions(); VertxTLSBuilder.buildNetServerOptions(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.getClientAuth(), ClientAuth.REQUEST); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertEquals(serverOptions.getClientAuth(), ClientAuth.REQUEST); } @Test - public void testbuildHttpClientOptions_sslKey_noFactory() { + public void testBuildHttpClientOptions_sslKey_noFactory() { HttpClientOptions clientOptions = new HttpClientOptions(); VertxTLSBuilder.buildHttpClientOptions("notExist", clientOptions); - Assert.assertTrue(clientOptions.isSsl()); + Assertions.assertTrue(clientOptions.isSsl()); } public static class SSLOptionFactoryForTest implements SSLOptionFactory { @@ -77,50 +75,51 @@ public SSLOption createSSLOption() { } @Test - public void testbuildHttpClientOptions_ssl_withFactory() { - ArchaiusUtils.setProperty("ssl.exist.sslOptionFactory", SSLOptionFactoryForTest.class.getName()); + public void testBuildHttpClientOptions_ssl_withFactory() { + Mockito.when(environment.getProperty("ssl.exist.sslOptionFactory")) + .thenReturn(SSLOptionFactoryForTest.class.getName()); HttpClientOptions clientOptions = new HttpClientOptions(); VertxTLSBuilder.buildHttpClientOptions("exist", clientOptions); - Assert.assertTrue(clientOptions.isSsl()); - Assert.assertTrue(clientOptions.isVerifyHost()); + Assertions.assertTrue(clientOptions.isSsl()); + Assertions.assertTrue(clientOptions.isVerifyHost()); } @Test - public void testbuildHttpClientOptions() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildHttpClientOptions() { + SSLOption option = SSLOption.build("rest.consumer", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); VertxTLSBuilder.buildHttpClientOptions(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildClientOptionsBase() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildClientOptionsBase() { + SSLOption option = SSLOption.build("rest.consumer", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); VertxTLSBuilder.buildClientOptionsBase(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildClientOptionsBaseFileNull() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildClientOptionsBaseFileNull() { + SSLOption option = SSLOption.build("rest.consumer", environment); option.setKeyStore(null); option.setTrustStore(null); option.setCrl(null); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); VertxTLSBuilder.buildClientOptionsBase(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildClientOptionsBaseAuthPeerFalse() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildClientOptionsBaseAuthPeerFalse() { + SSLOption option = SSLOption.build("rest.consumer", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); new MockUp() { @@ -131,13 +130,13 @@ public boolean isAuthPeer() { } }; VertxTLSBuilder.buildClientOptionsBase(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildClientOptionsBaseSTORE_JKS() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildClientOptionsBaseSTORE_JKS() { + SSLOption option = SSLOption.build("rest.consumer", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); new MockUp() { @@ -148,13 +147,13 @@ public String getKeyStoreType() { } }; VertxTLSBuilder.buildClientOptionsBase(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildClientOptionsBaseSTORE_PKCS12() { - SSLOption option = SSLOption.buildFromYaml("rest.consumer"); + public void testBuildClientOptionsBaseSTORE_PKCS12() { + SSLOption option = SSLOption.build("rest.consumer", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpClientOptions serverOptions = new HttpClientOptions(); new MockUp() { @@ -165,13 +164,13 @@ public String getTrustStoreType() { } }; VertxTLSBuilder.buildClientOptionsBase(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.isTrustAll(), true); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertTrue(serverOptions.isTrustAll()); } @Test - public void testbuildHttpServerOptionsRequest() { - SSLOption option = SSLOption.buildFromYaml("rest.provider"); + public void testBuildHttpServerOptionsRequest() { + SSLOption option = SSLOption.build("rest.provider", environment); SSLCustom custom = SSLCustom.createSSLCustom(option.getSslCustomClass()); HttpServerOptions serverOptions = new HttpServerOptions(); @@ -183,7 +182,7 @@ public boolean isAuthPeer() { } }; VertxTLSBuilder.buildNetServerOptions(option, custom, serverOptions); - Assert.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); - Assert.assertEquals(serverOptions.getClientAuth(), ClientAuth.REQUEST); + Assertions.assertEquals(serverOptions.getEnabledSecureTransportProtocols().toArray().length, 1); + Assertions.assertEquals(serverOptions.getClientAuth(), ClientAuth.REQUEST); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxUtils.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxUtils.java index d3c1edde982..9f966cbcbde 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxUtils.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/TestVertxUtils.java @@ -18,26 +18,42 @@ package org.apache.servicecomb.foundation.vertx; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.CountDownLatch; -import javax.xml.ws.Holder; - +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; +import io.vertx.core.impl.SysProps; public class TestVertxUtils { + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + + LegacyPropertyFactory.setEnvironment(environment); + } + @Test public void testGetOrCreateVertx() throws InterruptedException { - Vertx vertx = VertxUtils.getOrCreateVertxByName("ut", null); + Vertx vertx = VertxUtils.getOrCreateVertxByName("ut", null, null); Holder name = new Holder<>(); CountDownLatch latch = new CountDownLatch(1); @@ -47,35 +63,80 @@ public void testGetOrCreateVertx() throws InterruptedException { }); latch.await(); - Assert.assertEquals(name.value, "ut-vert.x-eventloop-thread-0"); - VertxUtils.closeVertxByName("ut"); + Assertions.assertEquals(name.value, "ut-vert.x-eventloop-thread-0"); + VertxUtils.blockCloseVertxByName("ut"); + } + + @Test + public void testCreateVertxWithFileCPResolving() { + // create .vertx folder + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(false); + deleteCacheFile(); + VertxUtils.getOrCreateVertxByName("testCreateVertxWithFileCPResolvingFalse", null, null); + Assertions.assertTrue(isCacheFileExists()); + VertxUtils.blockCloseVertxByName("testCreateVertxWithFileCPResolvingFalse"); + + // don't create .vertx folder + deleteCacheFile(); + Assertions.assertFalse(isCacheFileExists()); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + VertxUtils.getOrCreateVertxByName("testCreateVertxWithFileCPResolvingTrue", null, null); + Assertions.assertFalse(isCacheFileExists()); + VertxUtils.blockCloseVertxByName("testCreateVertxWithFileCPResolvingTrue"); + } + + private void deleteCacheFile() { + String cacheDirBase = System.getProperty(SysProps.FILE_CACHE_DIR.name, + System.getProperty("java.io.tmpdir", ".")); + File folder = new File(cacheDirBase); + File[] files = folder.listFiles(); + for (File f : files) { + if (f.getName().startsWith("vertx-cache")) { + FileUtils.deleteQuietly(f); + } + } + } + + private boolean isCacheFileExists() { + String cacheDirBase = System.getProperty(SysProps.FILE_CACHE_DIR.name, + System.getProperty("java.io.tmpdir", ".")); + File folder = new File(cacheDirBase); + File[] files = folder.listFiles(); + for (File f : files) { + if (f.getName().startsWith("vertx-cache")) { + return true; + } + } + return false; } @Test public void testVertxUtilsInitNullOptions() { - Vertx vertx = VertxUtils.init(null); - Assert.assertNotEquals(null, vertx); - vertx.close(); + Vertx vertx = VertxUtils.init(null, null, null); + Assertions.assertNotEquals(null, vertx); + VertxUtils.blockCloseVertx(vertx); } @Test public void testVertxUtilsInitWithOptions() { VertxOptions oOptions = new VertxOptions(); - oOptions.setClustered(false); - Vertx vertx = VertxUtils.init(oOptions); - Assert.assertNotEquals(null, vertx); - vertx.close(); + Vertx vertx = VertxUtils.init(null, oOptions, null); + Assertions.assertNotEquals(null, vertx); + VertxUtils.blockCloseVertx(vertx); } @Test public void testgetBytesFastBufferInputStream() throws IOException { byte[] bytes = new byte[] {1}; - ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes); + Buffer byteBuf = Buffer.buffer(bytes); try (BufferInputStream inputStream = new BufferInputStream(byteBuf)) { byte[] result = VertxUtils.getBytesFast(inputStream); - Assert.assertSame(bytes, result); + Assertions.assertEquals(bytes.length, result.length); + Assertions.assertEquals(bytes[0], result[0]); } } @@ -85,7 +146,7 @@ public void testgetBytesFastNormalInputStream() throws IOException { try (InputStream inputStream = new ByteArrayInputStream(bytes)) { byte[] result = VertxUtils.getBytesFast(inputStream); - Assert.assertEquals(1, result[0]); + Assertions.assertEquals(1, result[0]); } } @@ -95,7 +156,7 @@ public void testgetBytesFastBuffer() { buffer.appendByte((byte) 1); byte[] result = VertxUtils.getBytesFast(buffer); - Assert.assertEquals(1, result[0]); + Assertions.assertEquals(1, result[0]); } @Test @@ -104,17 +165,17 @@ public void testgetBytesFastByteBufHasArray() { ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes); byte[] result = VertxUtils.getBytesFast(byteBuf); - Assert.assertSame(bytes, result); + Assertions.assertSame(bytes, result); } @Test public void testgetBytesFastByteBufCopy() { ByteBuf byteBuf = Unpooled.directBuffer(); byteBuf.writeByte(1); - Assert.assertFalse(byteBuf.hasArray()); + Assertions.assertFalse(byteBuf.hasArray()); byte[] result = VertxUtils.getBytesFast(byteBuf); - Assert.assertEquals(1, result[0]); + Assertions.assertEquals(1, result[0]); byteBuf.release(); } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientPoolManager.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientPoolManager.java index 6709ca531d9..c42c3f3360e 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientPoolManager.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientPoolManager.java @@ -22,10 +22,11 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import io.vertx.core.Context; import io.vertx.core.Vertx; @@ -49,7 +50,7 @@ public class TestClientPoolManager { List pools; - Map contextMap = new HashMap<>(); + Map contextMap = new HashMap<>(); @Mocked Context context; @@ -61,13 +62,13 @@ public void setup() { pools = Deencapsulation.getField(poolMgr, "pools"); new MockUp(context) { @Mock - void put(String key, Object value) { + void put(Object key, Object value) { contextMap.put(key, value); } @SuppressWarnings("unchecked") @Mock - T get(String key) { + T get(Object key) { return (T) contextMap.get(key); } @@ -92,9 +93,9 @@ public void createClientPool(@Mocked HttpClientWithContext pool) { } }; - Assert.assertSame(pool, poolMgr.createClientPool(context)); - Assert.assertSame(pool, context.get(id)); - Assert.assertThat(pools, Matchers.contains(pool)); + Assertions.assertSame(pool, poolMgr.createClientPool(context)); + Assertions.assertSame(pool, context.get(id)); + MatcherAssert.assertThat(pools, Matchers.contains(pool)); } @Test @@ -108,8 +109,8 @@ public void findClientPool_sync(@Mocked HttpClientWithContext pool1, @Mocked Htt } }; - Assert.assertSame(pool1, poolMgr.findClientPool(true)); - Assert.assertSame(pool2, poolMgr.findClientPool(false)); + Assertions.assertSame(pool1, poolMgr.findClientPool(true)); + Assertions.assertSame(pool2, poolMgr.findClientPool(false)); } @Test @@ -124,9 +125,9 @@ long getId() { } }; - Assert.assertSame(pool1, poolMgr.findThreadBindClientPool()); + Assertions.assertSame(pool1, poolMgr.findThreadBindClientPool()); // find again, get the same result - Assert.assertSame(pool1, poolMgr.findThreadBindClientPool()); + Assertions.assertSame(pool1, poolMgr.findThreadBindClientPool()); new MockUp() { @Mock @@ -135,29 +136,29 @@ long getId() { } }; - Assert.assertSame(pool2, poolMgr.findThreadBindClientPool()); + Assertions.assertSame(pool2, poolMgr.findThreadBindClientPool()); // find again, get the same result - Assert.assertSame(pool2, poolMgr.findThreadBindClientPool()); + Assertions.assertSame(pool2, poolMgr.findThreadBindClientPool()); } @Test public void findByContext_reactive() { - HttpClientWithContext notMatchPool = new HttpClientWithContext(null, null); - pools.add(notMatchPool); + HttpClientWithContext notMatchPool1 = new HttpClientWithContext(null, null); + HttpClientWithContext notMatchPool2 = new HttpClientWithContext(null, null); + pools.add(notMatchPool1); + pools.add(notMatchPool2); - new Expectations(VertxImpl.class) { + new Expectations() { { - factory.createClientPool(context); - result = new HttpClientWithContext(null, null); - VertxImpl.context(); + Vertx.currentContext(); result = context; } }; + context.put(id, notMatchPool2); - HttpClientWithContext result = poolMgr.findByContext(); - Assert.assertNotSame(notMatchPool, result); + Assertions.assertSame(notMatchPool2, poolMgr.findByContext()); // find again, get the same result - Assert.assertSame(result, poolMgr.findByContext()); + Assertions.assertSame(notMatchPool2, poolMgr.findByContext()); } @Test @@ -167,9 +168,9 @@ public void findByContext_wrongContext_reverse() { pools.add(pool1); pools.add(pool2); - new Expectations(VertxImpl.class) { + new Expectations() { { - VertxImpl.context(); + Vertx.currentContext(); result = null; } }; @@ -177,10 +178,10 @@ public void findByContext_wrongContext_reverse() { AtomicInteger reactiveNextIndex = Deencapsulation.getField(poolMgr, "reactiveNextIndex"); reactiveNextIndex.set(Integer.MAX_VALUE); // each time invoke find, reactiveNextIndex will inc 1 - Assert.assertSame(pool2, poolMgr.findByContext()); - Assert.assertSame(pool1, poolMgr.findByContext()); - Assert.assertSame(pool2, poolMgr.findByContext()); - Assert.assertSame(pool1, poolMgr.findByContext()); + Assertions.assertSame(pool2, poolMgr.findByContext()); + Assertions.assertSame(pool1, poolMgr.findByContext()); + Assertions.assertSame(pool2, poolMgr.findByContext()); + Assertions.assertSame(pool1, poolMgr.findByContext()); } @Test @@ -188,14 +189,14 @@ public void findByContext_normalThread() { HttpClientWithContext pool = new HttpClientWithContext(null, null); pools.add(pool); - new Expectations(VertxImpl.class) { + new Expectations() { { - VertxImpl.context(); + Vertx.currentContext(); result = null; } }; - Assert.assertSame(pool, poolMgr.findByContext()); + Assertions.assertSame(pool, poolMgr.findByContext()); } @Test @@ -203,16 +204,16 @@ public void findByContext_otherVertx(@Mocked VertxImpl otherVertx, @Mocked Conte HttpClientWithContext pool = new HttpClientWithContext(null, null); pools.add(pool); - new Expectations(VertxImpl.class) { + new Expectations() { { - VertxImpl.context(); + Vertx.currentContext(); result = otherContext; otherContext.owner(); result = otherVertx; } }; - Assert.assertSame(pool, poolMgr.findByContext()); + Assertions.assertSame(pool, poolMgr.findByContext()); } @Test @@ -220,9 +221,9 @@ public void findByContext_worker(@Mocked Context workerContext) { HttpClientWithContext pool = new HttpClientWithContext(null, null); pools.add(pool); - new Expectations(VertxImpl.class) { + new Expectations() { { - VertxImpl.context(); + Vertx.currentContext(); result = workerContext; workerContext.owner(); result = vertx; @@ -231,6 +232,6 @@ public void findByContext_worker(@Mocked Context workerContext) { } }; - Assert.assertSame(pool, poolMgr.findByContext()); + Assertions.assertSame(pool, poolMgr.findByContext()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientVerticle.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientVerticle.java index 6f76372398b..197eb9f1f34 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientVerticle.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/TestClientVerticle.java @@ -20,7 +20,6 @@ import org.apache.servicecomb.foundation.vertx.SimpleJsonObject; import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.junit.Assert; import org.junit.Test; import io.vertx.core.Context; @@ -29,6 +28,7 @@ import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestClientVerticle { ClientVerticle clientVerticle = new ClientVerticle<>(); @@ -56,6 +56,6 @@ HttpClientWithContext createClientPool(Context context) { clientVerticle.start(); - Assert.assertEquals(1, count.get()); + Assertions.assertEquals(1, count.get()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/http/TestHttpClientPoolFactory.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/http/TestHttpClientPoolFactory.java deleted file mode 100644 index 669d1da6697..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/http/TestHttpClientPoolFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.client.http; - -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.http.HttpClient; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.impl.ContextImpl; -import io.vertx.core.impl.VertxImpl; -import io.vertx.core.impl.VertxInternal; -import mockit.Expectations; -import mockit.Mocked; - -public class TestHttpClientPoolFactory { - private HttpClientOptions httpClientOptions = new HttpClientOptions(); - - HttpClientPoolFactory factory = new HttpClientPoolFactory(httpClientOptions); - - @Test - public void createClientPool(@Mocked VertxInternal vertx, @Mocked ContextImpl context, - @Mocked HttpClient httpClient) { - new Expectations(VertxImpl.class) { - { - context.owner(); - result = vertx; - vertx.createHttpClient(httpClientOptions); - result = httpClient; - } - }; - HttpClientWithContext pool = factory.createClientPool(context); - - Assert.assertSame(context, pool.context()); - Assert.assertSame(httpClient, pool.getHttpClient()); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestAbstractTcpClientPoolFactory.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestAbstractTcpClientPoolFactory.java index 9c7dc36f917..dd01fdab11f 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestAbstractTcpClientPoolFactory.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestAbstractTcpClientPoolFactory.java @@ -16,17 +16,17 @@ */ package org.apache.servicecomb.foundation.vertx.client.tcp; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; +import org.junit.jupiter.api.Assertions; import io.vertx.core.Context; import io.vertx.core.Vertx; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestAbstractTcpClientPoolFactory { - private TcpClientConfig normalClientConfig = new TcpClientConfig(); + private final TcpClientConfig normalClientConfig = new TcpClientConfig(); - private TcpClientConfig sslClientConfig = new TcpClientConfig(); + private final TcpClientConfig sslClientConfig = new TcpClientConfig(); TcpClientPoolFactory factory = new TcpClientPoolFactory(normalClientConfig, sslClientConfig); @@ -37,7 +37,7 @@ public void createClientPool() { Mockito.when(context.owner()).thenReturn(vertx); TcpClientConnectionPool pool = factory.createClientPool(context); - Assert.assertSame(normalClientConfig, pool.netClientWrapper.getClientConfig(false)); - Assert.assertSame(sslClientConfig, pool.netClientWrapper.getClientConfig(true)); + Assertions.assertSame(normalClientConfig, pool.netClientWrapper.getClientConfig(false)); + Assertions.assertSame(sslClientConfig, pool.netClientWrapper.getClientConfig(true)); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestNetClientWrapper.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestNetClientWrapper.java deleted file mode 100644 index 06a6e9ba983..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestNetClientWrapper.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.client.tcp; - - -import java.util.ArrayList; -import java.util.List; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.impl.FutureFactoryImpl; -import io.vertx.core.net.NetClient; -import io.vertx.core.net.NetSocket; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestNetClientWrapper { - @Mocked - Vertx vertx; - - @Mocked - TcpClientConfig normalClientConfig; - - @Mocked - NetClient normalNetClient; - - @Mocked - TcpClientConfig sslClientConfig; - - @Mocked - NetClient sslNetClient; - - NetClientWrapper netClientWrapper; - - @Before - public void setup() { - new Expectations() { - { - vertx.createNetClient(normalClientConfig); - result = normalNetClient; - vertx.createNetClient(sslClientConfig); - result = sslNetClient; - } - }; - netClientWrapper = new NetClientWrapper(vertx, normalClientConfig, sslClientConfig); - } - - @Test - public void getClientConfig() { - Assert.assertSame(normalClientConfig, netClientWrapper.getClientConfig(false)); - Assert.assertSame(sslClientConfig, netClientWrapper.getClientConfig(true)); - } - - @Test - public void connect(@Mocked NetSocket normalSocket, @Mocked NetSocket sslSocket) { - int port = 8000; - String host = "localhost"; - - FutureFactoryImpl futureFactory = new FutureFactoryImpl(); - new MockUp(normalNetClient) { - @Mock - NetClient connect(int port, String host, Handler> connectHandler) { - connectHandler.handle(futureFactory.succeededFuture(normalSocket)); - return null; - } - }; - new MockUp(sslNetClient) { - @Mock - NetClient connect(int port, String host, Handler> connectHandler) { - connectHandler.handle(futureFactory.succeededFuture(sslSocket)); - return null; - } - }; - - List socks = new ArrayList<>(); - netClientWrapper.connect(false, port, host, asyncSocket -> { - socks.add(asyncSocket.result()); - }); - netClientWrapper.connect(true, port, host, asyncSocket -> { - socks.add(asyncSocket.result()); - }); - - Assert.assertThat(socks, Matchers.contains(normalSocket, sslSocket)); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConfig.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConfig.java index a6b57acd325..b7a2f50d048 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConfig.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConfig.java @@ -17,16 +17,16 @@ package org.apache.servicecomb.foundation.vertx.client.tcp; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestTcpClientConfig { @Test public void testTcpClientConfig() { TcpClientConfig config = new TcpClientConfig(); - Assert.assertEquals(config.getRequestTimeoutMillis(), 30000); - Assert.assertEquals(config.isSsl(), false); - config.setRequestTimeoutMillis(500); - Assert.assertEquals(config.getRequestTimeoutMillis(), 500); + Assertions.assertEquals(config.getMsLoginTimeout(), 30000); + Assertions.assertFalse(config.isSsl()); + config.setMsLoginTimeout(500); + Assertions.assertEquals(config.getMsLoginTimeout(), 500); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnection.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnection.java index d50ecb84cdf..f072d962000 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnection.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnection.java @@ -20,18 +20,19 @@ import java.util.Queue; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConnection.Status; import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.vertx.core.AsyncResult; import io.vertx.core.Context; +import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.impl.FutureFactoryImpl; +import io.vertx.core.Promise; +import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetSocket; import io.vertx.core.net.impl.NetSocketImpl; import mockit.Deencapsulation; @@ -67,20 +68,20 @@ public void setup() { @Test public void localSupportLogin() { - Assert.assertFalse(tcpClientConnection.isLocalSupportLogin()); + Assertions.assertFalse(tcpClientConnection.isLocalSupportLogin()); tcpClientConnection.setLocalSupportLogin(true); - Assert.assertTrue(tcpClientConnection.isLocalSupportLogin()); + Assertions.assertTrue(tcpClientConnection.isLocalSupportLogin()); } @Test public void createLogin() { - Assert.assertNull(tcpClientConnection.createLogin()); + Assertions.assertNull(tcpClientConnection.createLogin()); } @Test public void onLoginResponse_buffer() { - Assert.assertTrue(tcpClientConnection.onLoginResponse(null)); + Assertions.assertTrue(tcpClientConnection.onLoginResponse(null)); } @Test @@ -89,14 +90,14 @@ public void send_inWorkingStatus(@Mocked AbstractTcpClientPackage tcpClientPacka Deencapsulation.setField(tcpClientConnection, "status", Status.WORKING); long msgId = 1; - ByteBuf byteBuf = Unpooled.buffer(); + Buffer byteBuf = Buffer.buffer(); new Expectations(tcpClientConnection) { { tcpClientPackage.getMsgId(); result = msgId; tcpClientPackage.createStream(); result = tcpOutputStream; - tcpOutputStream.getByteBuf(); + tcpOutputStream.getBuffer(); result = byteBuf; } }; @@ -109,9 +110,9 @@ void runOnContext(Handler action) { tcpClientConnection.send(tcpClientPackage, ar -> { }); - Assert.assertSame(byteBuf, writeQueue.poll()); - Assert.assertNull(writeQueue.poll()); - Assert.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertSame(byteBuf, writeQueue.poll()); + Assertions.assertNull(writeQueue.poll()); + Assertions.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); } @Test @@ -133,9 +134,9 @@ void runOnContext(Handler action) { tcpClientConnection.send(tcpClientPackage, ar -> { }); - Assert.assertSame(tcpClientPackage, packageQueue.poll()); - Assert.assertNull(packageQueue.poll()); - Assert.assertEquals(Status.CONNECTING, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertSame(tcpClientPackage, packageQueue.poll()); + Assertions.assertNull(packageQueue.poll()); + Assertions.assertEquals(Status.CONNECTING, Deencapsulation.getField(tcpClientConnection, "status")); } @Test @@ -158,9 +159,9 @@ void runOnContext(Handler action) { tcpClientConnection.send(tcpClientPackage, ar -> { }); - Assert.assertSame(tcpClientPackage, packageQueue.poll()); - Assert.assertNull(packageQueue.poll()); - Assert.assertEquals(Status.TRY_LOGIN, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertSame(tcpClientPackage, packageQueue.poll()); + Assertions.assertNull(packageQueue.poll()); + Assertions.assertEquals(Status.TRY_LOGIN, Deencapsulation.getField(tcpClientConnection, "status")); } @Test @@ -171,6 +172,7 @@ public void send_disconnectedToWorking(@Mocked AbstractTcpClientPackage tcpClien { tcpClientPackage.getMsgId(); result = msgId; + tcpClientConnection.write((Buffer) any); } }; new MockUp(context) { @@ -183,25 +185,26 @@ void runOnContext(Handler action) { tcpClientConnection.send(tcpClientPackage, ar -> { }); - Assert.assertNull(writeQueue.poll()); - Assert.assertNull(packageQueue.poll()); - Assert.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertNull(writeQueue.poll()); + Assertions.assertNull(packageQueue.poll()); + Assertions.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); } @Test public void connect_success(@Mocked NetSocketImpl netSocket) { - FutureFactoryImpl futureFactory = new FutureFactoryImpl(); + Promise promise = Promise.promise(); new MockUp(netClientWrapper) { @Mock - void connect(boolean ssl, int port, String host, Handler> connectHandler) { - connectHandler.handle(futureFactory.succeededFuture(netSocket)); + public Future connect(boolean ssl, int port, String host) { + promise.complete(netSocket); + return promise.future(); } }; tcpClientConnection.connect(); - Assert.assertSame(netSocket, tcpClientConnection.getNetSocket()); - Assert.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertSame(netSocket, tcpClientConnection.getNetSocket()); + Assertions.assertEquals(Status.WORKING, Deencapsulation.getField(tcpClientConnection, "status")); } @Test @@ -209,19 +212,20 @@ public void connect_failed() { requestMap.put(10L, new TcpRequest(10, ar -> { })); - FutureFactoryImpl futureFactory = new FutureFactoryImpl(); - Error error = new Error(); + Promise promise = Promise.promise(); + RuntimeException error = new RuntimeExceptionWithoutStackTrace(); new MockUp(netClientWrapper) { @Mock - void connect(boolean ssl, int port, String host, Handler> connectHandler) { - connectHandler.handle(futureFactory.failedFuture(error)); + public Future connect(boolean ssl, int port, String host) { + promise.fail(error); + return promise.future(); } }; tcpClientConnection.connect(); - Assert.assertEquals(Status.DISCONNECTED, Deencapsulation.getField(tcpClientConnection, "status")); - Assert.assertEquals(0, requestMap.size()); + Assertions.assertEquals(Status.DISCONNECTED, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertEquals(0, requestMap.size()); } @Test @@ -230,9 +234,9 @@ public void onClosed(@Mocked NetSocketImpl netSocket) { })); tcpClientConnection.initNetSocket(netSocket); - Deencapsulation.invoke(tcpClientConnection, "onClosed", new Class[] {Void.class}, new Object[] {null}); - Assert.assertEquals(Status.DISCONNECTED, Deencapsulation.getField(tcpClientConnection, "status")); - Assert.assertEquals(0, requestMap.size()); + tcpClientConnection.onClosed(null); + Assertions.assertEquals(Status.DISCONNECTED, Deencapsulation.getField(tcpClientConnection, "status")); + Assertions.assertEquals(0, requestMap.size()); } @Test @@ -245,11 +249,9 @@ public void onReply_notExist() { public void on_exist() { long msgId = 1L; AtomicInteger count = new AtomicInteger(); - requestMap.put(msgId, new TcpRequest(10, ar -> { - count.incrementAndGet(); - })); + requestMap.put(msgId, new TcpRequest(10, ar -> count.incrementAndGet())); tcpClientConnection.onReply(msgId, null, null); - Assert.assertEquals(1, count.get()); + Assertions.assertEquals(1, count.get()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnectionPool.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnectionPool.java deleted file mode 100644 index 2ca9736d8bc..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/client/tcp/TestTcpClientConnectionPool.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.client.tcp; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.impl.ContextImpl; -import mockit.Mocked; - -public class TestTcpClientConnectionPool { - @Mocked - ContextImpl context; - - @Mocked - NetClientWrapper netClientWrapper; - - TcpClientConnectionPool pool; - - @Before - public void setup() { - pool = new TcpClientConnectionPool(context, netClientWrapper); - } - - @Test - public void create() { - Assert.assertThat(pool.create("rest://localhost:8765"), Matchers.instanceOf(TcpClientConnection.class)); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletRequest.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletRequest.java index c25b38930a1..de7c8dfa1db 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletRequest.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletRequest.java @@ -17,18 +17,14 @@ package org.apache.servicecomb.foundation.vertx.http; -import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.util.Collections; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; + +import jakarta.servlet.http.HttpServletRequest; public class TestAbstractHttpServletRequest { HttpServletRequest request = new AbstractHttpServletRequest() { @@ -39,478 +35,395 @@ public void testAttribute() { String key = "a1"; String value = "abc"; request.setAttribute(key, value); - Assert.assertSame(value, request.getAttribute(key)); - Assert.assertThat(Collections.list(request.getAttributeNames()), Matchers.contains(key)); + Assertions.assertSame(value, request.getAttribute(key)); + MatcherAssert.assertThat(Collections.list(request.getAttributeNames()), Matchers.contains(key)); request.setAttribute("a2", "v"); - Assert.assertThat(Collections.list(request.getAttributeNames()), Matchers.contains(key, "a2")); + MatcherAssert.assertThat(Collections.list(request.getAttributeNames()), Matchers.containsInAnyOrder(key, "a2")); request.removeAttribute(key); - Assert.assertNull(request.getAttribute(key)); + Assertions.assertNull(request.getAttribute(key)); } - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private void setExceptionExpected() { - expectedException.expect(Error.class); - expectedException.expectMessage(Matchers.is("not supported method")); + private void checkError(Error error) { + Assertions.assertEquals("not supported method", error.getMessage()); } @Test public void testGetCharacterEncoding() { - setExceptionExpected(); - - request.getCharacterEncoding(); + Error error = Assertions.assertThrows(Error.class, () -> request.getCharacterEncoding()); + checkError(error); } @Test - public void testSetCharacterEncoding() throws UnsupportedEncodingException { - setExceptionExpected(); - - request.setCharacterEncoding(""); + public void testSetCharacterEncoding() { + Error error = Assertions.assertThrows(Error.class, () -> request.setCharacterEncoding("")); + checkError(error); } @Test public void testGetContentLength() { - setExceptionExpected(); - - request.getContentLength(); + Error error = Assertions.assertThrows(Error.class, () -> request.getContentLength()); + checkError(error); } @Test public void testGetContentLengthLong() { - setExceptionExpected(); - - request.getContentLengthLong(); + Error error = Assertions.assertThrows(Error.class, () -> request.getContentLengthLong()); + checkError(error); } @Test public void testGetContentType() { - setExceptionExpected(); - - request.getContentType(); + Error error = Assertions.assertThrows(Error.class, () -> request.getContentType()); + checkError(error); } @Test - public void testGetInputStream() throws IOException { - setExceptionExpected(); - - request.getInputStream(); + public void testGetInputStream() { + Error error = Assertions.assertThrows(Error.class, () -> request.getInputStream()); + checkError(error); } @Test public void testGetParameter() { - setExceptionExpected(); - - request.getParameter(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getParameter("")); + checkError(error); } @Test public void testGetParameterNames() { - setExceptionExpected(); - - request.getParameterNames(); + Error error = Assertions.assertThrows(Error.class, () -> request.getParameterNames()); + checkError(error); } @Test public void testGetParameterValues() { - setExceptionExpected(); - - request.getParameterValues(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getParameterValues("")); + checkError(error); } @Test public void testGetParameterMap() { - setExceptionExpected(); - - request.getParameterMap(); + Error error = Assertions.assertThrows(Error.class, () -> request.getParameterMap()); + checkError(error); } @Test public void testGetProtocol() { - setExceptionExpected(); - - request.getProtocol(); + Error error = Assertions.assertThrows(Error.class, () -> request.getProtocol()); + checkError(error); } @Test public void testGetScheme() { - setExceptionExpected(); - - request.getScheme(); + Error error = Assertions.assertThrows(Error.class, () -> request.getScheme()); + checkError(error); } @Test public void testGetServerName() { - setExceptionExpected(); - - request.getServerName(); + Error error = Assertions.assertThrows(Error.class, () -> request.getServerName()); + checkError(error); } @Test public void testGetServerPort() { - setExceptionExpected(); - - request.getServerPort(); + Error error = Assertions.assertThrows(Error.class, () -> request.getServerPort()); + checkError(error); } @Test - public void testGetReader() throws IOException { - setExceptionExpected(); - - request.getReader(); + public void testGetReader() { + Error error = Assertions.assertThrows(Error.class, () -> request.getReader()); + checkError(error); } @Test public void testGetRemoteAddr() { - setExceptionExpected(); - - request.getRemoteAddr(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRemoteAddr()); + checkError(error); } @Test public void testGetRemoteHost() { - setExceptionExpected(); - - request.getRemoteHost(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRemoteHost()); + checkError(error); } @Test public void testGetLocale() { - setExceptionExpected(); - - request.getLocale(); + Error error = Assertions.assertThrows(Error.class, () -> request.getLocale()); + checkError(error); } @Test public void testGetLocales() { - setExceptionExpected(); - - request.getLocales(); + Error error = Assertions.assertThrows(Error.class, () -> request.getLocales()); + checkError(error); } @Test public void testIsSecure() { - setExceptionExpected(); - - request.isSecure(); + Error error = Assertions.assertThrows(Error.class, () -> request.isSecure()); + checkError(error); } @Test public void testGetRequestDispatcher() { - setExceptionExpected(); - - request.getRequestDispatcher(""); - } - - @SuppressWarnings("deprecation") - @Test - public void testGetRealPath() { - setExceptionExpected(); - - request.getRealPath(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getRequestDispatcher("")); + checkError(error); } @Test public void testGetRemotePort() { - setExceptionExpected(); - - request.getRemotePort(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRemotePort()); + checkError(error); } @Test public void testGetLocalName() { - setExceptionExpected(); - - request.getLocalName(); + Error error = Assertions.assertThrows(Error.class, () -> request.getLocalName()); + checkError(error); } @Test public void testGetLocalAddr() { - setExceptionExpected(); - - request.getLocalAddr(); + Error error = Assertions.assertThrows(Error.class, () -> request.getLocalAddr()); + checkError(error); } @Test public void testGetLocalPort() { - setExceptionExpected(); - - request.getLocalPort(); + Error error = Assertions.assertThrows(Error.class, () -> request.getLocalPort()); + checkError(error); } @Test public void testGetServletContext() { - setExceptionExpected(); - - request.getServletContext(); + Error error = Assertions.assertThrows(Error.class, () -> request.getServletContext()); + checkError(error); } @Test public void testStartAsync() { - setExceptionExpected(); - - request.startAsync(); + Error error = Assertions.assertThrows(Error.class, () -> request.startAsync()); + checkError(error); } @Test public void testStartAsyncWithParam() { - setExceptionExpected(); - - request.startAsync(null, null); + Error error = Assertions.assertThrows(Error.class, () -> request.startAsync(null, null)); + checkError(error); } @Test public void testIsAsyncStarted() { - setExceptionExpected(); - - request.isAsyncStarted(); + Error error = Assertions.assertThrows(Error.class, () -> request.isAsyncStarted()); + checkError(error); } @Test public void testIsAsyncSupported() { - setExceptionExpected(); - - request.isAsyncSupported(); + Error error = Assertions.assertThrows(Error.class, () -> request.isAsyncSupported()); + checkError(error); } @Test public void testGetAsyncContext() { - setExceptionExpected(); - - request.getAsyncContext(); + Error error = Assertions.assertThrows(Error.class, () -> request.getAsyncContext()); + checkError(error); } @Test public void testGetDispatcherType() { - setExceptionExpected(); - - request.getDispatcherType(); + Error error = Assertions.assertThrows(Error.class, () -> request.getDispatcherType()); + checkError(error); } @Test public void testGetAuthType() { - setExceptionExpected(); - - request.getAuthType(); + Error error = Assertions.assertThrows(Error.class, () -> request.getAuthType()); + checkError(error); } @Test public void testGetCookies() { - setExceptionExpected(); - - request.getCookies(); + Error error = Assertions.assertThrows(Error.class, () -> request.getCookies()); + checkError(error); } @Test public void testGetDateHeader() { - setExceptionExpected(); - - request.getDateHeader(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getDateHeader("")); + checkError(error); } @Test public void testGetHeader() { - setExceptionExpected(); - - request.getHeader(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getHeader("")); + checkError(error); } @Test public void testGetHeaders() { - setExceptionExpected(); - - request.getHeaders(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getHeaders("")); + checkError(error); } @Test public void testGetHeaderNames() { - setExceptionExpected(); - - request.getHeaderNames(); + Error error = Assertions.assertThrows(Error.class, () -> request.getHeaderNames()); + checkError(error); } @Test public void testGetIntHeader() { - setExceptionExpected(); - - request.getIntHeader(""); + Error error = Assertions.assertThrows(Error.class, () -> request.getIntHeader("")); + checkError(error); } @Test public void testGetMethod() { - setExceptionExpected(); - - request.getMethod(); + Error error = Assertions.assertThrows(Error.class, () -> request.getMethod()); + checkError(error); } @Test public void testGetPathInfo() { - setExceptionExpected(); - - request.getPathInfo(); + Error error = Assertions.assertThrows(Error.class, () -> request.getPathInfo()); + checkError(error); } @Test public void testGetPathTranslated() { - setExceptionExpected(); - - request.getPathTranslated(); + Error error = Assertions.assertThrows(Error.class, () -> request.getPathTranslated()); + checkError(error); } @Test public void testGetContextPath() { - setExceptionExpected(); - - request.getContextPath(); + Error error = Assertions.assertThrows(Error.class, () -> request.getContextPath()); + checkError(error); } @Test public void testGetQueryString() { - setExceptionExpected(); - - request.getQueryString(); + Error error = Assertions.assertThrows(Error.class, () -> request.getQueryString()); + checkError(error); } @Test public void testGetRemoteUser() { - setExceptionExpected(); - - request.getRemoteUser(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRemoteUser()); + checkError(error); } @Test public void testIsUserInRole() { - setExceptionExpected(); - - request.isUserInRole(""); + Error error = Assertions.assertThrows(Error.class, () -> request.isUserInRole("")); + checkError(error); } @Test public void testGetUserPrincipal() { - setExceptionExpected(); - - request.getUserPrincipal(); + Error error = Assertions.assertThrows(Error.class, () -> request.getUserPrincipal()); + checkError(error); } @Test public void testGetRequestedSessionId() { - setExceptionExpected(); - - request.getRequestedSessionId(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRequestedSessionId()); + checkError(error); } @Test public void testGetRequestURI() { - setExceptionExpected(); - - request.getRequestURI(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRequestURI()); + checkError(error); } @Test public void testGetRequestURL() { - setExceptionExpected(); - - request.getRequestURL(); + Error error = Assertions.assertThrows(Error.class, () -> request.getRequestURL()); + checkError(error); } @Test public void testGetServletPath() { - setExceptionExpected(); - - request.getServletPath(); + Error error = Assertions.assertThrows(Error.class, () -> request.getServletPath()); + checkError(error); } @Test public void testGetSessionWithParam() { - setExceptionExpected(); - - request.getSession(true); + Error error = Assertions.assertThrows(Error.class, () -> request.getSession(true)); + checkError(error); } @Test public void testGetSession() { - setExceptionExpected(); - - request.getSession(); + Error error = Assertions.assertThrows(Error.class, () -> request.getSession()); + checkError(error); } @Test public void testChangeSessionId() { - setExceptionExpected(); - - request.changeSessionId(); + Error error = Assertions.assertThrows(Error.class, () -> request.changeSessionId()); + checkError(error); } @Test public void testIsRequestedSessionIdValid() { - setExceptionExpected(); - - request.isRequestedSessionIdValid(); + Error error = Assertions.assertThrows(Error.class, () -> request.isRequestedSessionIdValid()); + checkError(error); } @Test public void testIsRequestedSessionIdFromCookie() { - setExceptionExpected(); - - request.isRequestedSessionIdFromCookie(); + Error error = Assertions.assertThrows(Error.class, () -> request.isRequestedSessionIdFromCookie()); + checkError(error); } @Test public void testIsRequestedSessionIdFromURL() { - setExceptionExpected(); - - request.isRequestedSessionIdFromURL(); - } - - @SuppressWarnings("deprecation") - @Test - public void testIsRequestedSessionIdFromUrl() { - setExceptionExpected(); - - request.isRequestedSessionIdFromUrl(); + Error error = Assertions.assertThrows(Error.class, () -> request.isRequestedSessionIdFromURL()); + checkError(error); } @Test - public void testAuthenticate() throws IOException, ServletException { - setExceptionExpected(); - - request.authenticate(null); + public void testAuthenticate() { + Error error = Assertions.assertThrows(Error.class, () -> request.authenticate(null)); + checkError(error); } @Test - public void testLogin() throws ServletException { - setExceptionExpected(); - - request.login(null, null); + public void testLogin() { + Error error = Assertions.assertThrows(Error.class, () -> request.login(null, null)); + checkError(error); } @Test - public void testLogout() throws ServletException { - setExceptionExpected(); - - request.logout(); + public void testLogout() { + Error error = Assertions.assertThrows(Error.class, () -> request.logout()); + checkError(error); } @Test - public void testGetParts() throws IOException, ServletException { - setExceptionExpected(); - - request.getParts(); + public void testGetParts() { + Error error = Assertions.assertThrows(Error.class, () -> request.getParts()); + checkError(error); } @Test - public void testGetPart() throws IOException, ServletException { - setExceptionExpected(); - - request.getPart(""); + public void testGetPart() { + Error error = Assertions.assertThrows(Error.class, () -> request.getPart("")); + checkError(error); } @Test - public void testUpgrade() throws IOException, ServletException { - setExceptionExpected(); - - request.upgrade(null); + public void testUpgrade() { + Error error = Assertions.assertThrows(Error.class, () -> request.upgrade(null)); + checkError(error); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletResponse.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletResponse.java index ec884eeea8c..053cc56e7de 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletResponse.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestAbstractHttpServletResponse.java @@ -17,306 +17,236 @@ package org.apache.servicecomb.foundation.vertx.http; -import java.io.IOException; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestAbstractHttpServletResponse { - @Rule - public ExpectedException expectedException = ExpectedException.none(); HttpServletResponseEx response = new AbstractHttpServletResponse() { }; - private void setExceptionExpected() { - expectedException.expect(Error.class); - expectedException.expectMessage(Matchers.is("not supported method")); + private void checkError(Error error) { + Assertions.assertEquals("not supported method", error.getMessage()); } @Test public void testGetCharacterEncoding() { - setExceptionExpected(); - - response.getCharacterEncoding(); + Error error = Assertions.assertThrows(Error.class, () -> response.getCharacterEncoding()); + checkError(error); } @Test public void testGetContentType() { - setExceptionExpected(); - - response.getContentType(); + Error error = Assertions.assertThrows(Error.class, () -> response.getContentType()); + checkError(error); } @Test - public void testGetOutputStream() throws IOException { - setExceptionExpected(); - - response.getOutputStream(); + public void testGetOutputStream() { + Error error = Assertions.assertThrows(Error.class, () -> response.getOutputStream()); + checkError(error); } @Test - public void testGetWriter() throws IOException { - setExceptionExpected(); - - response.getWriter(); + public void testGetWriter() { + Error error = Assertions.assertThrows(Error.class, () -> response.getWriter()); + checkError(error); } @Test public void testSetCharacterEncoding() { - setExceptionExpected(); - - response.setCharacterEncoding(""); + Error error = Assertions.assertThrows(Error.class, () -> response.setCharacterEncoding("")); + checkError(error); } @Test public void testSetContentLength() { - setExceptionExpected(); - - response.setContentLength(0); + Error error = Assertions.assertThrows(Error.class, () -> response.setContentLength(0)); + checkError(error); } @Test public void testSetContentLengthLong() { - setExceptionExpected(); - - response.setContentLengthLong(0); + Error error = Assertions.assertThrows(Error.class, () -> response.setContentLengthLong(0)); + checkError(error); } @Test public void testSetContentType() { - setExceptionExpected(); - - response.setContentType(""); + Error error = Assertions.assertThrows(Error.class, () -> response.setContentType("")); + checkError(error); } @Test public void testSetBufferSize() { - setExceptionExpected(); - - response.setBufferSize(0); + Error error = Assertions.assertThrows(Error.class, () -> response.setBufferSize(0)); + checkError(error); } @Test public void testGetBufferSize() { - setExceptionExpected(); - - response.getBufferSize(); + Error error = Assertions.assertThrows(Error.class, () -> response.getBufferSize()); + checkError(error); } @Test - public void testFlushBuffer() throws IOException { - setExceptionExpected(); - - response.flushBuffer(); + public void testFlushBuffer() { + Assertions.assertDoesNotThrow(() -> response.flushBuffer()); } @Test public void testResetBuffer() { - setExceptionExpected(); - - response.resetBuffer(); + Error error = Assertions.assertThrows(Error.class, () -> response.resetBuffer()); + checkError(error); } @Test public void testIsCommitted() { - setExceptionExpected(); - - response.isCommitted(); + Error error = Assertions.assertThrows(Error.class, () -> response.isCommitted()); + checkError(error); } @Test public void testReset() { - setExceptionExpected(); - - response.reset(); + Error error = Assertions.assertThrows(Error.class, () -> response.reset()); + checkError(error); } @Test public void testSetLocale() { - setExceptionExpected(); - - response.setLocale(null); + Error error = Assertions.assertThrows(Error.class, () -> response.setLocale(null)); + checkError(error); } @Test public void testGetLocale() { - setExceptionExpected(); - - response.getLocale(); + Error error = Assertions.assertThrows(Error.class, () -> response.getLocale()); + checkError(error); } @Test public void testAddCookie() { - setExceptionExpected(); - - response.addCookie(null); + Error error = Assertions.assertThrows(Error.class, () -> response.addCookie(null)); + checkError(error); } @Test public void testContainsHeader() { - setExceptionExpected(); - - response.containsHeader(null); + Error error = Assertions.assertThrows(Error.class, () -> response.containsHeader(null)); + checkError(error); } @Test public void testEncodeURL() { - setExceptionExpected(); - - response.encodeURL(null); + Error error = Assertions.assertThrows(Error.class, () -> response.encodeURL(null)); + checkError(error); } @Test public void testEncodeRedirectURL() { - setExceptionExpected(); - - response.encodeRedirectURL(null); - } - - @SuppressWarnings("deprecation") - @Test - public void testEncodeUrl() { - setExceptionExpected(); - - response.encodeUrl(null); + Error error = Assertions.assertThrows(Error.class, () -> response.encodeRedirectURL(null)); + checkError(error); } - @SuppressWarnings("deprecation") @Test - public void testEncodeRedirectUrl() { - setExceptionExpected(); - - response.encodeRedirectUrl(null); + public void testSendErrorScAndMsg() { + Error error = Assertions.assertThrows(Error.class, () -> response.sendError(0, null)); + checkError(error); } @Test - public void testSendErrorScAndMsg() throws IOException { - setExceptionExpected(); - - response.sendError(0, null); + public void testSendErrorSc() { + Error error = Assertions.assertThrows(Error.class, () -> response.sendError(0)); + checkError(error); } @Test - public void testSendErrorSc() throws IOException { - setExceptionExpected(); - - response.sendError(0); - } - - @Test - public void testSendRedirect() throws IOException { - setExceptionExpected(); - - response.sendRedirect(null); + public void testSendRedirect() { + Error error = Assertions.assertThrows(Error.class, () -> response.sendRedirect(null)); + checkError(error); } @Test public void testSetDateHeader() { - setExceptionExpected(); - - response.setDateHeader(null, 0); + Error error = Assertions.assertThrows(Error.class, () -> response.setDateHeader(null, 0)); + checkError(error); } @Test public void testAddDateHeader() { - setExceptionExpected(); - - response.addDateHeader(null, 0); + Error error = Assertions.assertThrows(Error.class, () -> response.addDateHeader(null, 0)); + checkError(error); } @Test public void testSetHeader() { - setExceptionExpected(); - - response.setHeader(null, null); + Error error = Assertions.assertThrows(Error.class, () -> response.setHeader(null, null)); + checkError(error); } @Test public void testAddHeader() { - setExceptionExpected(); - - response.addHeader(null, null); + Error error = Assertions.assertThrows(Error.class, () -> response.addHeader(null, null)); + checkError(error); } @Test public void testSetIntHeader() { - setExceptionExpected(); - - response.setIntHeader(null, 0); + Error error = Assertions.assertThrows(Error.class, () -> response.setIntHeader(null, 0)); + checkError(error); } @Test public void testAddIntHeader() { - setExceptionExpected(); - - response.addIntHeader(null, 0); + Error error = Assertions.assertThrows(Error.class, () -> response.addIntHeader(null, 0)); + checkError(error); } @Test public void testSetStatusSc() { - setExceptionExpected(); - - response.setStatus(0); - } - - @SuppressWarnings("deprecation") - @Test - public void testSetStatusScAndSm() { - setExceptionExpected(); - - response.setStatus(0, ""); + Error error = Assertions.assertThrows(Error.class, () -> response.setStatus(0)); + checkError(error); } @Test public void testGetStatus() { - setExceptionExpected(); - - response.getStatus(); + Error error = Assertions.assertThrows(Error.class, () -> response.getStatus()); + checkError(error); } @Test public void testGetHeader() { - setExceptionExpected(); - - response.getHeader(""); + Error error = Assertions.assertThrows(Error.class, () -> response.getHeader("")); + checkError(error); } @Test public void testGetHeaders() { - setExceptionExpected(); - - response.getHeaders(""); + Error error = Assertions.assertThrows(Error.class, () -> response.getHeaders("")); + checkError(error); } @Test public void testGetHeaderNames() { - setExceptionExpected(); - - response.getHeaderNames(); + Error error = Assertions.assertThrows(Error.class, () -> response.getHeaderNames()); + checkError(error); } @Test public void testGetStatusType() { - setExceptionExpected(); - - response.getStatusType(); + Error error = Assertions.assertThrows(Error.class, () -> response.getStatusType()); + checkError(error); } @Test public void attribute() { response.setAttribute("k", "v"); - Assert.assertEquals("v", response.getAttribute("k")); + Assertions.assertEquals("v", response.getAttribute("k")); } @Test public void sendPart() { - setExceptionExpected(); - - response.sendPart(null); + Error error = Assertions.assertThrows(Error.class, () -> response.sendPart(null)); + checkError(error); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestBodyBufferSupportImpl.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestBodyBufferSupportImpl.java index 8e777f4e537..f12bec04915 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestBodyBufferSupportImpl.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestBodyBufferSupportImpl.java @@ -17,58 +17,56 @@ package org.apache.servicecomb.foundation.vertx.http; -import org.junit.Assert; -import org.junit.Test; - import io.vertx.core.buffer.Buffer; -import mockit.Deencapsulation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestBodyBufferSupportImpl { BodyBufferSupportImpl impl = new BodyBufferSupportImpl(); @Test public void testSetBodyBuffer() { - Deencapsulation.setField(impl, "bodyBytes", new byte[] {}); - Deencapsulation.setField(impl, "bodyLength", 10); + impl.setBodyBytes(new byte[] {}); + impl.setBodyLength(10); - Assert.assertNotNull(impl.getBodyBytes()); - Assert.assertEquals(10, impl.getBodyBytesLength()); + Assertions.assertNotNull(impl.getBodyBytes()); + Assertions.assertEquals(10, impl.getBodyBytesLength()); impl.setBodyBuffer(null); - Assert.assertNull(impl.getBodyBytes()); - Assert.assertEquals(0, impl.getBodyBytesLength()); + Assertions.assertNull(impl.getBodyBytes()); + Assertions.assertEquals(0, impl.getBodyBytesLength()); } @Test public void testGetBodyBuffer() { - Assert.assertNull(impl.getBodyBuffer()); + Assertions.assertNull(impl.getBodyBuffer()); Buffer bodyBuffer = Buffer.buffer(); impl.setBodyBuffer(bodyBuffer); - Assert.assertSame(bodyBuffer, impl.getBodyBuffer()); + Assertions.assertSame(bodyBuffer, impl.getBodyBuffer()); } @Test public void testGetBodyBytes() { - Assert.assertNull(impl.getBodyBytes()); + Assertions.assertNull(impl.getBodyBytes()); byte[] bytes = new byte[] {1, 2, 3}; Buffer bodyBuffer = Buffer.buffer(bytes); impl.setBodyBuffer(bodyBuffer); - Assert.assertArrayEquals(bytes, impl.getBodyBytes()); + Assertions.assertArrayEquals(bytes, impl.getBodyBytes()); } @Test public void testGetBodyBytesLength() { - Assert.assertEquals(0, impl.getBodyBytesLength()); + Assertions.assertEquals(0, impl.getBodyBytesLength()); byte[] bytes = new byte[] {1, 2, 3}; Buffer bodyBuffer = Buffer.buffer(bytes); impl.setBodyBuffer(bodyBuffer); - Assert.assertEquals(3, impl.getBodyBytesLength()); + Assertions.assertEquals(3, impl.getBodyBytesLength()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestFileUploadPart.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestFileUploadPart.java index d5ed8db8ccb..ed2e331da71 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestFileUploadPart.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestFileUploadPart.java @@ -20,21 +20,23 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.UUID; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; import io.vertx.ext.web.FileUpload; -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestFileUploadPart { - @Mocked + FileUpload fileUpload; FileUploadPart part; @@ -43,95 +45,71 @@ public class TestFileUploadPart { static String content = "fileContent"; - @BeforeClass + @BeforeAll public static void classSetup() throws IOException { - file = File.createTempFile("upload", ".txt"); + file = Files.createTempFile("upload", ".txt").toFile(); file.deleteOnExit(); - FileUtils.writeStringToFile(file, content); + FileUtils.writeStringToFile(file, content, StandardCharsets.UTF_8, false); } - @Before + @BeforeEach public void setup() { + fileUpload = Mockito.mock(FileUpload.class); part = new FileUploadPart(fileUpload); } + @AfterEach + public void after() { + Mockito.reset(fileUpload); + } + @Test public void getInputStream() throws IOException { - new Expectations() { - { - fileUpload.uploadedFileName(); - result = file.getAbsolutePath(); - } - }; + Mockito.when(fileUpload.uploadedFileName()).thenReturn(file.getAbsolutePath()); try (InputStream is = part.getInputStream()) { - Assert.assertEquals(content, IOUtils.toString(is)); + Assertions.assertEquals(content, IOUtils.toString(is, StandardCharsets.UTF_8)); } } @Test public void getContentType() { String contentType = "type"; - new Expectations() { - { - fileUpload.contentType(); - result = contentType; - } - }; - - Assert.assertEquals(contentType, part.getContentType()); + Mockito.when(fileUpload.contentType()).thenReturn(contentType); + + Assertions.assertEquals(contentType, part.getContentType()); } @Test public void getName() { String name = "pName"; - new Expectations() { - { - fileUpload.name(); - result = name; - } - }; - - Assert.assertEquals(name, part.getName()); + Mockito.when(fileUpload.name()).thenReturn(name); + + Assertions.assertEquals(name, part.getName()); } @Test public void getSubmittedFileName() { String clientName = "clientName"; - new Expectations() { - { - fileUpload.fileName(); - result = clientName; - } - }; - - Assert.assertEquals(clientName, part.getSubmittedFileName()); + Mockito.when(fileUpload.fileName()).thenReturn(clientName); + + Assertions.assertEquals(clientName, part.getSubmittedFileName()); } @Test public void getSize() { long fileSize = 10; - new Expectations() { - { - fileUpload.size(); - result = fileSize; - } - }; - - Assert.assertEquals(fileSize, part.getSize()); + Mockito.when(fileUpload.size()).thenReturn(fileSize); + + Assertions.assertEquals(fileSize, part.getSize()); } @Test public void write() throws IOException { - new Expectations() { - { - fileUpload.uploadedFileName(); - result = file.getAbsolutePath(); - } - }; + Mockito.when(fileUpload.uploadedFileName()).thenReturn(file.getAbsolutePath()); File targetFile = new File(UUID.randomUUID().toString()); targetFile.deleteOnExit(); part.write(targetFile.getAbsolutePath()); - Assert.assertEquals(content, FileUtils.readFileToString(targetFile)); + Assertions.assertEquals(content, FileUtils.readFileToString(targetFile, StandardCharsets.UTF_8)); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestReadStreamPart.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestReadStreamPart.java deleted file mode 100644 index 0e50c68ba7d..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestReadStreamPart.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.http; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; -import java.util.concurrent.ExecutionException; - -import javax.ws.rs.core.HttpHeaders; - -import org.apache.commons.io.FileUtils; -import org.apache.servicecomb.foundation.vertx.stream.InputStreamToReadStream; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.file.FileSystemException; -import io.vertx.core.file.OpenOptions; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.impl.ContextImpl; -import io.vertx.core.impl.SyncVertx; -import io.vertx.core.streams.WriteStream; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestReadStreamPart { - static SyncVertx vertx = new SyncVertx(); - - static ContextImpl context = vertx.getContext(); - - static String src = "src"; - - static InputStream inputStream = new ByteArrayInputStream(src.getBytes()); - - InputStreamToReadStream readStream = new InputStreamToReadStream(context, inputStream, true); - - ReadStreamPart part = new ReadStreamPart(context, readStream); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - - @Before - public void setup() throws IOException { - inputStream.reset(); - } - - @AfterClass - public static void teardown() { - vertx.close(); - } - - @Test - public void constructFromHttpClientResponse_noContentType(@Mocked HttpClientResponse httpClientResponse) { - new Expectations() { - { - httpClientResponse.getHeader(HttpHeaders.CONTENT_DISPOSITION); - result = "xx;filename=name.txt"; - httpClientResponse.getHeader(HttpHeaders.CONTENT_TYPE); - result = null; - } - }; - - part = new ReadStreamPart(context, httpClientResponse); - - Assert.assertEquals("name.txt", part.getSubmittedFileName()); - Assert.assertEquals("text/plain", part.getContentType()); - } - - @Test - public void constructFromHttpClientResponse_hasContentType(@Mocked HttpClientResponse httpClientResponse) { - new Expectations() { - { - httpClientResponse.getHeader(HttpHeaders.CONTENT_DISPOSITION); - result = "xx;filename=name.txt"; - httpClientResponse.getHeader(HttpHeaders.CONTENT_TYPE); - result = "type"; - } - }; - - part = new ReadStreamPart(context, httpClientResponse); - - Assert.assertEquals("name.txt", part.getSubmittedFileName()); - Assert.assertEquals("type", part.getContentType()); - } - - @Test - public void saveToWriteStream() throws InterruptedException, ExecutionException { - Buffer buf = Buffer.buffer(); - WriteStream writeStream = new MockUp>() { - @Mock - WriteStream write(Buffer data) { - buf.appendBuffer(data); - return null; - } - }.getMockInstance(); - - part.saveToWriteStream(writeStream).get(); - - Assert.assertEquals(src, buf.toString()); - } - - @Test - public void saveToWriteStream_writeException() throws InterruptedException, ExecutionException { - Error error = new Error(); - WriteStream writeStream = new MockUp>() { - Handler exceptionHandler; - - @Mock - WriteStream exceptionHandler(Handler handler) { - this.exceptionHandler = handler; - return null; - } - - @Mock - WriteStream write(Buffer data) { - exceptionHandler.handle(error); - return null; - } - }.getMockInstance(); - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.sameInstance(error)); - - part.saveToWriteStream(writeStream).get(); - } - - @Test - public void saveToWrite_readException(@Mocked WriteStream writeStream) - throws InterruptedException, ExecutionException { - Error error = new Error(); - new MockUp(inputStream) { - @Mock - int read(byte b[]) throws IOException { - throw error; - } - }; - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.sameInstance(error)); - - part.saveToWriteStream(writeStream).get(); - } - - @Test - public void saveAsBytes() throws InterruptedException, ExecutionException { - Assert.assertArrayEquals(src.getBytes(), part.saveAsBytes().get()); - } - - @Test - public void saveAsString() throws InterruptedException, ExecutionException { - Assert.assertEquals(src, part.saveAsString().get()); - } - - @Test - public void saveToFile() throws InterruptedException, ExecutionException, IOException { - File dir = new File("target/notExist-" + UUID.randomUUID().toString()); - File file = new File(dir, "a.txt"); - - Assert.assertFalse(dir.exists()); - - part.saveToFile(file.getAbsolutePath()).get(); - - Assert.assertEquals(src, FileUtils.readFileToString(file)); - - FileUtils.forceDelete(dir); - Assert.assertFalse(dir.exists()); - } - - @Test - public void saveToFile_notExist_notCreate() throws InterruptedException, ExecutionException, IOException { - File dir = new File("target/notExist-" + UUID.randomUUID().toString()); - File file = new File(dir, "a.txt"); - - Assert.assertFalse(dir.exists()); - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.instanceOf(FileSystemException.class)); - - OpenOptions openOptions = new OpenOptions().setCreateNew(false); - part.saveToFile(file, openOptions).get(); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java index cbc2a387c01..15e52aa5f71 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java @@ -18,21 +18,22 @@ package org.apache.servicecomb.foundation.vertx.http; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.MediaType; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.core.MediaType; import org.apache.commons.io.IOUtils; import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -40,6 +41,7 @@ import mockit.Deencapsulation; import mockit.Expectations; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestStandardHttpServletRequestEx { @Mocked @@ -58,15 +60,15 @@ public void setBodyBuffer() { bodyBuffer.appendString("abc"); requestEx.setBodyBuffer(bodyBuffer); - Assert.assertSame(bodyBuffer, requestEx.getBodyBuffer()); - Assert.assertArrayEquals("abc".getBytes(), Arrays.copyOf(requestEx.getBodyBytes(), requestEx.getBodyBytesLength())); + Assertions.assertSame(bodyBuffer, requestEx.getBodyBuffer()); + Assertions.assertArrayEquals("abc".getBytes(), Arrays.copyOf(requestEx.getBodyBytes(), requestEx.getBodyBytesLength())); } @Test public void getInputStreamNotCache() throws IOException { ServletInputStream inputStream = request.getInputStream(); - Assert.assertSame(inputStream, requestEx.getInputStream()); + Assertions.assertSame(inputStream, requestEx.getInputStream()); } @Test @@ -82,10 +84,10 @@ public void getInputStreamCache() throws IOException { }; ServletInputStream cachedInputStream = requestEx.getInputStream(); - Assert.assertEquals("abc", IOUtils.toString(cachedInputStream)); - Assert.assertEquals("abc", requestEx.getBodyBuffer().toString()); + Assertions.assertEquals("abc", IOUtils.toString(cachedInputStream, StandardCharsets.UTF_8)); + Assertions.assertEquals("abc", requestEx.getBodyBuffer().toString()); // do not create another one - Assert.assertSame(cachedInputStream, requestEx.getInputStream()); + Assertions.assertSame(cachedInputStream, requestEx.getInputStream()); } @Test @@ -102,10 +104,10 @@ public void parameterMap_inherited() { } }; - Assert.assertSame(inherited, requestEx.getParameterMap()); - Assert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("p1")); - Assert.assertSame(v1, requestEx.getParameterValues("p1")); - Assert.assertEquals("v1-1", requestEx.getParameter("p1")); + Assertions.assertSame(inherited, requestEx.getParameterMap()); + MatcherAssert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("p1")); + Assertions.assertSame(v1, requestEx.getParameterValues("p1")); + Assertions.assertEquals("v1-1", requestEx.getParameter("p1")); } @Test @@ -115,7 +117,7 @@ public void parameterMap_merge() throws IOException { inherited.put("p1", v1); Buffer buffer = Buffer.buffer("p1=v1-3;p2=v2"); - BufferInputStream inputStream = new BufferInputStream(buffer.getByteBuf()); + BufferInputStream inputStream = new BufferInputStream(buffer); new Expectations() { { request.getParameterMap(); @@ -129,9 +131,9 @@ public void parameterMap_merge() throws IOException { } }; - Assert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("p1", "p2")); - Assert.assertThat(requestEx.getParameterValues("p1"), Matchers.arrayContaining("v1-1", "v1-2", "v1-3")); - Assert.assertEquals("v1-1", requestEx.getParameter("p1")); + MatcherAssert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.containsInAnyOrder("p1", "p2")); + MatcherAssert.assertThat(requestEx.getParameterValues("p1"), Matchers.arrayContaining("v1-1", "v1-2", "v1-3")); + Assertions.assertEquals("v1-1", requestEx.getParameter("p1")); } @Test @@ -142,11 +144,11 @@ public void setParameter() { requestEx.setParameter("k1", "v1"); requestEx.setParameter("k2", "v2"); - Assert.assertEquals("v1", requestEx.getParameter("k1")); - Assert.assertEquals("v2", requestEx.getParameter("k2")); + Assertions.assertEquals("v1", requestEx.getParameter("k1")); + Assertions.assertEquals("v2", requestEx.getParameter("k2")); - Assert.assertSame(parameterMap, requestEx.getParameterMap()); + Assertions.assertSame(parameterMap, requestEx.getParameterMap()); - Assert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("k1", "k2")); + MatcherAssert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.containsInAnyOrder("k1", "k2")); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletResponseEx.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletResponseEx.java index 7a07853d2b6..289d5b15226 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletResponseEx.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletResponseEx.java @@ -21,48 +21,40 @@ import java.io.IOException; import java.io.InputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Part; - -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.apache.servicecomb.foundation.common.part.InputStreamPart; -import org.hamcrest.Matchers; -import org.junit.Assert; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; import io.vertx.core.buffer.Buffer; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Part; + public class TestStandardHttpServletResponseEx { - @Mocked HttpServletResponse response; StandardHttpServletResponseEx responseEx; - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Before public void setup() { + response = Mockito.mock(HttpServletResponse.class); responseEx = new StandardHttpServletResponseEx(response); } @Test public void setBodyBuffer() { - Assert.assertNull(responseEx.getBodyBuffer()); + Assertions.assertNull(responseEx.getBodyBuffer()); Buffer bodyBuffer = Buffer.buffer(); bodyBuffer.appendString("abc"); responseEx.setBodyBuffer(bodyBuffer); - Assert.assertEquals("abc", responseEx.getBodyBuffer().toString()); + Assertions.assertEquals("abc", responseEx.getBodyBuffer().toString()); } @Test @@ -70,7 +62,7 @@ public void getBodyBytes() { Buffer bodyBuffer = Buffer.buffer(); bodyBuffer.appendString("abc"); responseEx.setBodyBuffer(bodyBuffer); - Assert.assertEquals("abc", new String(responseEx.getBodyBytes(), 0, responseEx.getBodyBytesLength())); + Assertions.assertEquals("abc", new String(responseEx.getBodyBytes(), 0, responseEx.getBodyBytesLength())); } @Test @@ -78,15 +70,7 @@ public void getBodyBytesLength() { Buffer bodyBuffer = Buffer.buffer(); bodyBuffer.appendString("abc"); responseEx.setBodyBuffer(bodyBuffer); - Assert.assertEquals(3, responseEx.getBodyBytesLength()); - } - - @Test - public void setStatus() { - responseEx.setStatus(200, "ok"); - Assert.assertEquals(200, responseEx.getStatus()); - Assert.assertEquals(200, responseEx.getStatusType().getStatusCode()); - Assert.assertEquals("ok", responseEx.getStatusType().getReasonPhrase()); + Assertions.assertEquals(3, responseEx.getBodyBytesLength()); } @Test @@ -104,71 +88,66 @@ public void setWriteListener(WriteListener writeListener) { } @Override - public void write(int b) throws IOException { + public void write(int b) { buffer.appendByte((byte) b); } }; - response = new MockUp() { - @Mock - ServletOutputStream getOutputStream() { - return output; - } - }.getMockInstance(); + + Mockito.when(response.getOutputStream()).thenReturn(output); responseEx = new StandardHttpServletResponseEx(response); // no body responseEx.flushBuffer(); - Assert.assertEquals(0, buffer.length()); + Assertions.assertEquals(0, buffer.length()); Buffer body = Buffer.buffer().appendString("body"); responseEx.setBodyBuffer(body); responseEx.flushBuffer(); - Assert.assertEquals("body", buffer.toString()); + Assertions.assertEquals(0, buffer.length()); } @Test public void attribute() { responseEx.setAttribute("k", "v"); - Assert.assertEquals("v", responseEx.getAttribute("k")); + Assertions.assertEquals("v", responseEx.getAttribute("k")); } @Test public void sendPart_succ() throws Throwable { - String src = RandomStringUtils.random(100); + String src = RandomStringUtils.random(100, true, true); InputStream inputStream = new ByteArrayInputStream(src.getBytes()); Part part = new InputStreamPart("name", inputStream); Buffer buffer = Buffer.buffer(); - ServletOutputStream outputStream = new MockUp() { - @Mock - void write(int b) { - buffer.appendByte((byte) b); + + ServletOutputStream outputStream = new ServletOutputStream() { + @Override + public boolean isReady() { + return false; } - }.getMockInstance(); - new Expectations() { - { - response.getOutputStream(); - result = outputStream; + @Override + public void setWriteListener(WriteListener writeListener) { + + } + + @Override + public void write(int b) { + buffer.appendByte((byte) b); } }; + Mockito.when(response.getOutputStream()).thenReturn(outputStream); responseEx.sendPart(part).get(); - Assert.assertEquals(src, buffer.toString()); + Assertions.assertEquals(src, buffer.toString()); } @Test - public void sendPart_failed(@Mocked Part part) throws Throwable { - Error error = new Error(); - new Expectations() { - { - response.getOutputStream(); - result = error; - } - }; + public void sendPart_failed() throws Throwable { + Part part = Mockito.mock(Part.class); + RuntimeException error = new RuntimeExceptionWithoutStackTrace(); + Mockito.when(response.getOutputStream()).thenThrow(error); - expectedException.expect(Matchers.sameInstance(error)); - - responseEx.sendPart(part).get(); + Assertions.assertThrows(RuntimeException.class, () -> responseEx.sendPart(part).get()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientRequestToHttpServletRequest.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientRequestToHttpServletRequest.java index 271a0c08710..9cbe78713b3 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientRequestToHttpServletRequest.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientRequestToHttpServletRequest.java @@ -19,160 +19,122 @@ import java.util.Collections; -import javax.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.HttpHeaders; import org.apache.servicecomb.foundation.common.http.HttpUtils; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpMethod; import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestVertxClientRequestToHttpServletRequest { - @Mocked HttpClientRequest clientRequest; Buffer bodyBuffer = Buffer.buffer(); VertxClientRequestToHttpServletRequest request; - @Before + @BeforeEach public void setup() { + clientRequest = Mockito.mock(HttpClientRequest.class); request = new VertxClientRequestToHttpServletRequest(clientRequest, bodyBuffer); } + @AfterEach + public void after() { + Mockito.reset(clientRequest); + } + @Test public void testGetRequestURI() { - new Expectations() { - { - clientRequest.path(); - result = "/path"; - } - }; + Mockito.when(clientRequest.path()).thenReturn("/path"); - Assert.assertEquals("/path", request.getRequestURI()); + Assertions.assertEquals("/path", request.getRequestURI()); } @Test public void testGetQueryString() { - new Expectations() { - { - clientRequest.query(); - result = "a=1&b=2"; - } - }; + Mockito.when(clientRequest.query()).thenReturn("a=1&b=2"); - Assert.assertEquals("a=1&b=2", request.getQueryString()); + Assertions.assertEquals("a=1&b=2", request.getQueryString()); } @Test public void testGetHeader() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); headers.add("name", "value"); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); - Assert.assertEquals("value", request.getHeader("name")); + Assertions.assertEquals("value", request.getHeader("name")); } @Test public void testGetHeaders() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); headers.add("name", "value"); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); - Assert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); + MatcherAssert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); } @Test public void testGetHeaderNames() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); headers.add("name", "value"); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); - Assert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); + MatcherAssert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); } @Test public void testSetHeader() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); request.setHeader("name", "v1"); request.setHeader("name", "v2"); - Assert.assertThat(headers.getAll("name"), Matchers.contains("v2")); + MatcherAssert.assertThat(headers.getAll("name"), Matchers.contains("v2")); } @Test public void testAddHeader() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); request.addHeader("name", "v1"); request.addHeader("name", "v2"); - Assert.assertThat(headers.getAll("name"), Matchers.contains("v1", "v2")); + MatcherAssert.assertThat(headers.getAll("name"), Matchers.contains("v1", "v2")); } @Test public void testGetContextPath() { - Assert.assertEquals("", request.getContextPath()); + Assertions.assertEquals("", request.getContextPath()); } @Test public void getMethod() { - new Expectations() { - { - clientRequest.method(); - result = HttpMethod.GET; - } - }; + Mockito.when(clientRequest.getMethod()).thenReturn(HttpMethod.GET); - Assert.assertEquals("GET", request.getMethod()); + Assertions.assertEquals("GET", request.getMethod()); } @Test public void getContentType() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - new Expectations() { - { - clientRequest.headers(); - result = headers; - } - }; + Mockito.when(clientRequest.headers()).thenReturn(headers); request.addHeader(HttpHeaders.CONTENT_TYPE, "ct"); - Assert.assertEquals("ct", request.getContentType()); + Assertions.assertEquals("ct", request.getContentType()); } @Test @@ -185,13 +147,12 @@ public void getCharacterEncoding() { { HttpUtils.getCharsetFromContentType(contentType); result = characterEncoding; - clientRequest.headers(); - result = headers; } }; + Mockito.when(clientRequest.headers()).thenReturn(headers); request.addHeader(HttpHeaders.CONTENT_TYPE, contentType); - Assert.assertEquals("ce", request.getCharacterEncoding()); + Assertions.assertEquals("ce", request.getCharacterEncoding()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientResponseToHttpServletResponse.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientResponseToHttpServletResponse.java index 5d38fa3cccb..ca204c9b6fc 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientResponseToHttpServletResponse.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxClientResponseToHttpServletResponse.java @@ -17,84 +17,69 @@ package org.apache.servicecomb.foundation.vertx.http; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response.StatusType; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientResponse; -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestVertxClientResponseToHttpServletResponse { - @Mocked HttpClientResponse clientResponse; Buffer bodyBuffer = Buffer.buffer(); VertxClientResponseToHttpServletResponse response; - @Before + @BeforeEach public void setup() { + clientResponse = Mockito.mock(HttpClientResponse.class); response = new VertxClientResponseToHttpServletResponse(clientResponse, bodyBuffer); } + @AfterEach + public void after() { + Mockito.reset(clientResponse); + } + @Test public void getStatus() { - new Expectations() { - { - clientResponse.statusCode(); - result = 123; - } - }; - - Assert.assertEquals(123, response.getStatus()); + Mockito.when(clientResponse.statusCode()).thenReturn(123); + + Assertions.assertEquals(123, response.getStatus()); } @Test public void getStatusType() { - new Expectations() { - { - clientResponse.statusCode(); - result = 123; - clientResponse.statusMessage(); - result = "test"; - } - }; + Mockito.when(clientResponse.statusCode()).thenReturn(123); + Mockito.when(clientResponse.statusMessage()).thenReturn("test"); StatusType type = response.getStatusType(); - Assert.assertSame(type, response.getStatusType()); - Assert.assertEquals(123, type.getStatusCode()); - Assert.assertEquals("test", type.getReasonPhrase()); + Assertions.assertSame(type, response.getStatusType()); + Assertions.assertEquals(123, type.getStatusCode()); + Assertions.assertEquals("test", type.getReasonPhrase()); } @Test public void getContentType() { - new Expectations() { - { - clientResponse.getHeader(HttpHeaders.CONTENT_TYPE); - result = "json"; - } - }; - - Assert.assertEquals("json", response.getContentType()); + Mockito.when(clientResponse.getHeader(HttpHeaders.CONTENT_TYPE)).thenReturn("json"); + + Assertions.assertEquals("json", response.getContentType()); } @Test public void getHeader() { - new Expectations() { - { - clientResponse.getHeader("name"); - result = "value"; - } - }; - - Assert.assertEquals("value", response.getHeader("name")); + Mockito.when(clientResponse.getHeader("name")).thenReturn("value"); + + Assertions.assertEquals("value", response.getHeader("name")); } @Test @@ -102,14 +87,9 @@ public void getHeaders() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); headers.add("name", "v1"); headers.add("name", "v2"); - new Expectations() { - { - clientResponse.headers(); - result = headers; - } - }; - - Assert.assertThat(response.getHeaders("name"), Matchers.contains("v1", "v2")); + Mockito.when(clientResponse.headers()).thenReturn(headers); + + MatcherAssert.assertThat(response.getHeaders("name"), Matchers.contains("v1", "v2")); } @Test @@ -117,13 +97,8 @@ public void getHeaderNames() { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); headers.add("n1", "v1"); headers.add("n2", "v2"); - new Expectations() { - { - clientResponse.headers(); - result = headers; - } - }; - - Assert.assertThat(response.getHeaderNames(), Matchers.contains("n1", "n2")); + Mockito.when(clientResponse.headers()).thenReturn(headers); + + MatcherAssert.assertThat(response.getHeaderNames(), Matchers.contains("n1", "n2")); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerRequestToHttpServletRequest.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerRequestToHttpServletRequest.java index 2e98a837730..9d53cd649da 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerRequestToHttpServletRequest.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerRequestToHttpServletRequest.java @@ -20,19 +20,22 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.servlet.AsyncContext; -import javax.servlet.ServletInputStream; -import javax.servlet.http.Cookie; -import javax.ws.rs.core.HttpHeaders; -import javax.xml.ws.Holder; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.Cookie; +import jakarta.ws.rs.core.HttpHeaders; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.impl.RoutingContextInternal; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.foundation.common.http.HttpUtils; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -44,9 +47,9 @@ import io.vertx.ext.web.RoutingContext; import mockit.Deencapsulation; import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; public class TestVertxServerRequestToHttpServletRequest { @Mocked @@ -58,6 +61,14 @@ public class TestVertxServerRequestToHttpServletRequest { @Mocked SocketAddress socketAddress; + RequestBody mockRequestBody; + + RoutingContextInternal mockContext; + + HttpServerRequest mockHttpServerRequest; + + SocketAddress mockSocketAddress; + VertxServerRequestToHttpServletRequest request; @Before @@ -71,70 +82,79 @@ public void setup() { } }; + mockRequestBody = Mockito.mock(RequestBody.class); + mockContext = Mockito.mock(RoutingContextInternal.class); + mockHttpServerRequest = Mockito.mock(HttpServerRequest.class); + mockSocketAddress = Mockito.mock(SocketAddress.class); + // init mocks + Mockito.when(mockHttpServerRequest.remoteAddress()).thenReturn(mockSocketAddress); + Mockito.when(mockContext.body()).thenReturn(mockRequestBody); + Mockito.when(mockContext.request()).thenReturn(mockHttpServerRequest); + request = new VertxServerRequestToHttpServletRequest(context); } + @After + public void clean() { + Mockito.reset(mockRequestBody); + Mockito.reset(mockContext); + } + @Test public void constructWithPath() { request = new VertxServerRequestToHttpServletRequest(context, "/path"); - Assert.assertEquals("/path", request.getRequestURI()); + Assertions.assertEquals("/path", request.getRequestURI()); } @Test public void setBodyBuffer() { Holder bodyHolder = new Holder<>(); - context = new MockUp() { - @Mock - HttpServerRequest request() { - return vertxRequest; - } - - @Mock - void setBody(Buffer body) { - bodyHolder.value = body; - } - }.getMockInstance(); - request = new VertxServerRequestToHttpServletRequest(context); + Mockito.doAnswer(invocation -> { + bodyHolder.value = invocation.getArgument(0); + return null; + }).when(mockContext).setBody(Mockito.any()); + request = new VertxServerRequestToHttpServletRequest(mockContext); Buffer bodyBuffer = Buffer.buffer(); request.setBodyBuffer(bodyBuffer); - Assert.assertSame(bodyBuffer, bodyHolder.value); - Assert.assertSame(bodyBuffer, request.getBodyBuffer()); + Assertions.assertSame(bodyBuffer, bodyHolder.value); + Assertions.assertSame(bodyBuffer, request.getBodyBuffer()); } @Test public void testGetContentType() { - new Expectations() { - { - vertxRequest.getHeader(HttpHeaders.CONTENT_TYPE); - result = "json"; - } - }; - - Assert.assertEquals("json", request.getContentType()); + VertxServerRequestToHttpServletRequest request = new VertxServerRequestToHttpServletRequest(mockContext); + Mockito.when(mockHttpServerRequest.getHeader(HttpHeaders.CONTENT_TYPE)).thenReturn("json"); + Assertions.assertEquals("json", request.getContentType()); } @Test public void testGetCookies() { - Set vertxCookies = new LinkedHashSet<>(); - vertxCookies.add(io.vertx.ext.web.Cookie.cookie("c1", "c1v")); - vertxCookies.add(io.vertx.ext.web.Cookie.cookie("c2", "c2v")); + Set vertxCookies = new HashSet<>(); + vertxCookies.add(io.vertx.core.http.Cookie.cookie("c1", "c1v")); + vertxCookies.add(io.vertx.core.http.Cookie.cookie("c2", "c2v")); new Expectations() { { - context.cookies(); + context.request().cookies(); result = vertxCookies; } }; Cookie[] cookies = request.getCookies(); - Assert.assertEquals("c1", cookies[0].getName()); - Assert.assertEquals("c1v", cookies[0].getValue()); - Assert.assertEquals("c2", cookies[1].getName()); - Assert.assertEquals("c2v", cookies[1].getValue()); - - Assert.assertSame(cookies, request.getCookies()); + // we can't ensure the sequence when set to list + if (cookies[0].getName().equals("c1")) { + Assertions.assertEquals("c1", cookies[0].getName()); + Assertions.assertEquals("c1v", cookies[0].getValue()); + Assertions.assertEquals("c2", cookies[1].getName()); + Assertions.assertEquals("c2v", cookies[1].getValue()); + } else { + Assertions.assertEquals("c2", cookies[0].getName()); + Assertions.assertEquals("c2v", cookies[0].getValue()); + Assertions.assertEquals("c1", cookies[1].getName()); + Assertions.assertEquals("c1v", cookies[1].getValue()); + } } @Test @@ -146,12 +166,12 @@ public void testGetParameter() { } }; - Assert.assertEquals("value", request.getParameter("name")); + Assertions.assertEquals("value", request.getParameter("name")); } @Test public void testGetParameterValuesNull() { - Assert.assertEquals(0, request.getParameterValues("name").length); + Assertions.assertEquals(0, request.getParameterValues("name").length); } @Test @@ -166,7 +186,7 @@ public void testGetParameterValuesNormal() { } }; - Assert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); + MatcherAssert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); } @Test @@ -182,9 +202,9 @@ public void testGetParameterMap() { }; Map result = request.getParameterMap(); - Assert.assertThat(result.keySet(), Matchers.contains("name")); - Assert.assertThat(result.get("name"), Matchers.arrayContaining("value")); - Assert.assertSame(result, request.getParameterMap()); + MatcherAssert.assertThat(result.keySet(), Matchers.contains("name")); + MatcherAssert.assertThat(result.get("name"), Matchers.arrayContaining("value")); + Assertions.assertSame(result, request.getParameterMap()); } @Test @@ -196,7 +216,7 @@ public void testScheme() { } }; - Assert.assertEquals("abc", request.getScheme()); + Assertions.assertEquals("abc", request.getScheme()); } @Test @@ -208,7 +228,7 @@ public void testGetRemoteAddr() { } }; - Assert.assertEquals("host", request.getRemoteAddr()); + Assertions.assertEquals("host", request.getRemoteAddr()); } @Test @@ -219,7 +239,7 @@ public void testGetRemoteAddrNull() { result = null; } }; - Assert.assertEquals(null, request.getRemoteAddr()); + Assertions.assertNull(request.getRemoteAddr()); } @Test @@ -231,7 +251,7 @@ public void testGetRemoteHost() { } }; - Assert.assertEquals("host", request.getRemoteHost()); + Assertions.assertEquals("host", request.getRemoteHost()); } @Test @@ -243,7 +263,7 @@ public void testGetRemotePort() { } }; - Assert.assertEquals(1234, request.getRemotePort()); + Assertions.assertEquals(1234, request.getRemotePort()); } @Test @@ -257,7 +277,7 @@ public void testGetgetLocalAddr(@Mocked SocketAddress sa) { } }; - Assert.assertEquals("host", request.getLocalAddr()); + Assertions.assertEquals("host", request.getLocalAddr()); } @Test @@ -271,7 +291,7 @@ public void testGetLocalPort(@Mocked SocketAddress sa) { } }; - Assert.assertEquals(1234, request.getLocalPort()); + Assertions.assertEquals(1234, request.getLocalPort()); } @Test @@ -283,7 +303,7 @@ public void testGetHeader() { } }; - Assert.assertEquals("value", request.getHeader("key")); + Assertions.assertEquals("value", request.getHeader("key")); } @Test @@ -297,7 +317,7 @@ public void testGetHeaders() { } }; - Assert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); + MatcherAssert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); } @Test @@ -311,12 +331,12 @@ public void testGetHeaderNames() { } }; - Assert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); + MatcherAssert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); } @Test public void testGetIntHeaderNotExist() { - Assert.assertEquals(-1, request.getIntHeader("key")); + Assertions.assertEquals(-1, request.getIntHeader("key")); } @Test @@ -330,9 +350,9 @@ public void testGetIntHeaderNotNumber() { try { request.getIntHeader("key"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (NumberFormatException e) { - Assert.assertEquals("For input string: \"value\"", e.getMessage()); + Assertions.assertEquals("For input string: \"value\"", e.getMessage()); } } @@ -345,7 +365,7 @@ public void testGetIntHeaderNormal() { } }; - Assert.assertEquals(1, request.getIntHeader("key")); + Assertions.assertEquals(1, request.getIntHeader("key")); } @Test @@ -357,7 +377,7 @@ public void testGetMethod() { } }; - Assert.assertEquals("GET", request.getMethod()); + Assertions.assertEquals("GET", request.getMethod()); } @Test @@ -369,7 +389,7 @@ public void testGetPathInfo() { } }; - Assert.assertEquals("/path", request.getPathInfo()); + Assertions.assertEquals("/path", request.getPathInfo()); } @Test @@ -381,7 +401,7 @@ public void testGetQueryString() { } }; - Assert.assertEquals("k1=v1&k2=v2", request.getQueryString()); + Assertions.assertEquals("k1=v1&k2=v2", request.getQueryString()); } @Test @@ -393,7 +413,7 @@ public void testGetRequestURI() { } }; - Assert.assertEquals("/path", request.getRequestURI()); + Assertions.assertEquals("/path", request.getRequestURI()); } @Test @@ -405,12 +425,12 @@ public void testGetServletPath() { } }; - Assert.assertEquals("/path", request.getServletPath()); + Assertions.assertEquals("/path", request.getServletPath()); } @Test public void testGetContextPath() { - Assert.assertEquals("", request.getContextPath()); + Assertions.assertEquals("", request.getContextPath()); } @Test @@ -418,18 +438,21 @@ public void testGetInputStream() throws IOException { Buffer body = Buffer.buffer(); body.appendByte((byte) 1); - new Expectations() { - { - context.getBody(); - result = body; - } - }; + Mockito.when(mockRequestBody.buffer()).thenReturn(body); + Mockito.when(mockContext.request()).thenReturn(vertxRequest); + Mockito.when(mockContext.body()).thenReturn(mockRequestBody); + + VertxServerRequestToHttpServletRequest request = new VertxServerRequestToHttpServletRequest(mockContext); + ServletInputStream is1 = request.getInputStream(); + Assertions.assertSame(is1, request.getInputStream()); + int value = is1.read(); + is1.close(); + Assertions.assertEquals(1, value); + Assertions.assertSame(is1, request.getInputStream()); - ServletInputStream is = request.getInputStream(); - Assert.assertSame(is, request.getInputStream()); - int value = is.read(); - is.close(); - Assert.assertEquals(1, value); + request.setBodyBuffer(Buffer.buffer().appendByte((byte) 2)); + ServletInputStream is2 = request.getInputStream(); + Assertions.assertNotSame(is1, is2); } @Test @@ -437,7 +460,7 @@ public void testGetAsyncContext() { AsyncContext asyncContext = Deencapsulation.getField(VertxServerRequestToHttpServletRequest.class, "EMPTY_ASYNC_CONTEXT"); - Assert.assertSame(asyncContext, request.getAsyncContext()); + Assertions.assertSame(asyncContext, request.getAsyncContext()); } @Test @@ -451,7 +474,7 @@ public void getCharacterEncoding() { } }; - Assert.assertEquals("ce", request.getCharacterEncoding()); + Assertions.assertEquals("ce", request.getCharacterEncoding()); } @@ -463,11 +486,11 @@ public void setParameter() { request.setParameter("k1", "v1"); request.setParameter("k2", "v2"); - Assert.assertEquals("v1", request.getParameter("k1")); - Assert.assertEquals("v2", request.getParameter("k2")); + Assertions.assertEquals("v1", request.getParameter("k1")); + Assertions.assertEquals("v2", request.getParameter("k2")); - Assert.assertSame(parameterMap, request.getParameterMap()); + Assertions.assertSame(parameterMap, request.getParameterMap()); - Assert.assertThat(Collections.list(request.getParameterNames()), Matchers.contains("k1", "k2")); + MatcherAssert.assertThat(Collections.list(request.getParameterNames()), Matchers.containsInAnyOrder("k1", "k2")); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerResponseToHttpServletResponse.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerResponseToHttpServletResponse.java deleted file mode 100644 index 07de74aa747..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestVertxServerResponseToHttpServletResponse.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.vertx.http; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.StatusType; - -import org.apache.commons.io.FileUtils; -import org.apache.servicecomb.foundation.common.http.HttpStatus; -import org.apache.servicecomb.foundation.common.part.FilePart; -import org.apache.servicecomb.foundation.vertx.stream.PumpFromPart; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Context; -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.impl.SyncContext; -import io.vertx.core.impl.VertxImpl; -import io.vertx.core.streams.WriteStream; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestVertxServerResponseToHttpServletResponse { - MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - - HttpStatus httpStatus = new HttpStatus(123, "default"); - - HttpServerResponse serverResponse; - - VertxServerResponseToHttpServletResponse response; - - boolean flushWithBody; - - boolean runOnContextInvoked; - - @Mocked - Vertx vertx; - - @Mocked - Context context; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - boolean chunked; - - @Before - public void setup() { - serverResponse = new MockUp() { - @Mock - HttpServerResponse setStatusCode(int statusCode) { - Deencapsulation.setField(httpStatus, "statusCode", statusCode); - return serverResponse; - } - - @Mock - HttpServerResponse setStatusMessage(String statusMessage) { - Deencapsulation.setField(httpStatus, "reason", statusMessage); - return serverResponse; - } - - @Mock - int getStatusCode() { - return httpStatus.getStatusCode(); - } - - @Mock - String getStatusMessage() { - return httpStatus.getReasonPhrase(); - } - - @Mock - MultiMap headers() { - return headers; - } - - @Mock - HttpServerResponse putHeader(String name, String value) { - headers.set(name, value); - return serverResponse; - } - - @Mock - void end() { - flushWithBody = false; - } - - @Mock - void end(Buffer chunk) { - flushWithBody = true; - } - - @Mock - HttpServerResponse setChunked(boolean chunked) { - TestVertxServerResponseToHttpServletResponse.this.chunked = chunked; - return serverResponse; - } - - @Mock - boolean isChunked() { - return chunked; - } - }.getMockInstance(); - - new Expectations(VertxImpl.class) { - { - VertxImpl.context(); - result = context; - } - }; - - new MockUp(context) { - @Mock - void runOnContext(Handler action) { - runOnContextInvoked = true; - action.handle(null); - } - - @Mock - void executeBlocking(Handler> blockingCodeHandler, boolean ordered, - Handler> resultHandler) { - SyncContext.syncExecuteBlocking(blockingCodeHandler, resultHandler); - } - - @Mock - Vertx owner() { - return vertx; - } - }; - - response = new VertxServerResponseToHttpServletResponse(serverResponse); - } - - @Test - public void construct_invalid() throws IOException { - new Expectations(VertxImpl.class) { - { - VertxImpl.context(); - result = null; - } - }; - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage(Matchers.is("must run in vertx context.")); - - new VertxServerResponseToHttpServletResponse(serverResponse); - } - - @Test - public void setContentType() { - response.setContentType("json"); - Assert.assertEquals("json", headers.get(HttpHeaders.CONTENT_TYPE)); - } - - @SuppressWarnings("deprecation") - @Test - public void setStatus() { - response.setStatus(222, "test"); - Assert.assertEquals(222, httpStatus.getStatusCode()); - Assert.assertEquals("test", httpStatus.getReasonPhrase()); - } - - @Test - public void getStatusType() { - StatusType status = response.getStatusType(); - - Assert.assertSame(status, response.getStatusType()); - Assert.assertEquals(123, httpStatus.getStatusCode()); - Assert.assertEquals("default", httpStatus.getReasonPhrase()); - } - - @Test - public void addHeader() { - response.addHeader("n1", "v1_1"); - response.addHeader("n1", "v1_2"); - response.addHeader("n2", "v2"); - - Assert.assertEquals(2, headers.size()); - Assert.assertThat(headers.getAll("n1"), Matchers.contains("v1_1", "v1_2")); - Assert.assertThat(headers.getAll("n2"), Matchers.contains("v2")); - } - - @Test - public void setHeader() { - response.setHeader("n1", "v1_1"); - response.setHeader("n1", "v1_2"); - response.setHeader("n2", "v2"); - - Assert.assertEquals(2, headers.size()); - Assert.assertThat(headers.getAll("n1"), Matchers.contains("v1_2")); - Assert.assertThat(headers.getAll("n2"), Matchers.contains("v2")); - } - - @Test - public void getStatus() { - Assert.assertEquals(123, response.getStatus()); - } - - @Test - public void getContentType() { - headers.set(HttpHeaders.CONTENT_TYPE, "json"); - Assert.assertEquals("json", response.getContentType()); - } - - @Test - public void getHeader() { - headers.set(HttpHeaders.CONTENT_TYPE, "json"); - Assert.assertEquals("json", response.getHeader(HttpHeaders.CONTENT_TYPE)); - } - - @Test - public void getHeaders() { - headers.add("h1", "h1_1"); - headers.add("h1", "h1_2"); - - Assert.assertThat(response.getHeaders("h1"), Matchers.contains("h1_1", "h1_2")); - } - - @Test - public void getHeaderNames() { - headers.add("h1", "h1"); - headers.add("h2", "h2"); - - Assert.assertThat(response.getHeaderNames(), Matchers.contains("h1", "h2")); - } - - @Test - public void flushBuffer_sameContext() throws IOException { - response.flushBuffer(); - - Assert.assertFalse(runOnContextInvoked); - } - - @Test - public void flushBuffer_diffContext() throws IOException { - new Expectations(VertxImpl.class) { - { - VertxImpl.context(); - result = null; - } - }; - response.flushBuffer(); - - Assert.assertTrue(runOnContextInvoked); - } - - @Test - public void internalFlushBufferNoBody() throws IOException { - response.internalFlushBuffer(); - - Assert.assertFalse(flushWithBody); - } - - @Test - public void internalFlushBufferWithBody() throws IOException { - response.setBodyBuffer(Buffer.buffer()); - response.internalFlushBuffer(); - - Assert.assertTrue(flushWithBody); - } - - @Test - public void prepareSendPartHeader_update(@Mocked Part part) { - new Expectations() { - { - part.getContentType(); - result = "type"; - part.getSubmittedFileName(); - result = "测 试"; - } - }; - DownloadUtils.prepareDownloadHeader(response, part); - - Assert.assertTrue(serverResponse.isChunked()); - Assert.assertEquals("type", response.getHeader(HttpHeaders.CONTENT_TYPE)); - Assert.assertEquals( - "attachment;filename=%E6%B5%8B%20%20%20%20%20%E8%AF%95;filename*=utf-8''%E6%B5%8B%20%20%20%20%20%E8%AF%95", - response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); - } - - @Test - public void prepareSendPartHeader_notUpdate(@Mocked Part part) { - headers.add(HttpHeaders.CONTENT_LENGTH, "10"); - headers.add(HttpHeaders.CONTENT_TYPE, "type"); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "disposition"); - - DownloadUtils.prepareDownloadHeader(response, part); - - Assert.assertFalse(serverResponse.isChunked()); - Assert.assertEquals("type", response.getHeader(HttpHeaders.CONTENT_TYPE)); - Assert.assertEquals("disposition", response.getHeader(HttpHeaders.CONTENT_DISPOSITION)); - } - - @Test - public void sendPart_openInputStreamFailed(@Mocked Part part) - throws IOException, InterruptedException, ExecutionException { - IOException ioException = new IOException("forbid open stream"); - new Expectations() { - { - part.getInputStream(); - result = ioException; - } - }; - - CompletableFuture future = response.sendPart(part); - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.sameInstance(ioException)); - - future.get(); - } - - @Test - public void sendPart_inputStreamBreak(@Mocked Part part, @Mocked InputStream inputStream) - throws IOException, InterruptedException, ExecutionException { - IOException ioException = new IOException("forbid read"); - new Expectations() { - { - part.getInputStream(); - result = inputStream; - inputStream.read((byte[]) any); - result = ioException; - } - }; - - CompletableFuture future = response.sendPart(part); - - expectedException.expect(ExecutionException.class); - expectedException.expectCause(Matchers.sameInstance(ioException)); - - future.get(); - } - - @Test - public void sendPart_ReadStreamPart(@Mocked ReadStreamPart part) { - CompletableFuture future = new CompletableFuture<>(); - new MockUp() { - @Mock - CompletableFuture toWriteStream(WriteStream writeStream) { - return future; - } - }; - - Assert.assertSame(future, response.sendPart(part)); - } - - @Test - public void sendPart_succ(@Mocked Part part, @Mocked InputStream inputStream) - throws IOException, InterruptedException, ExecutionException { - new Expectations() { - { - part.getInputStream(); - result = inputStream; - inputStream.read((byte[]) any); - result = -1; - } - }; - - CompletableFuture future = response.sendPart(part); - - Assert.assertNull(future.get()); - } - - @Test - public void clearPartResource_deleteFile() throws IOException { - File file = new File("target", UUID.randomUUID().toString() + ".txt"); - FileUtils.write(file, "content"); - FilePart part = new FilePart(null, file).setDeleteAfterFinished(true); - - Assert.assertTrue(file.exists()); - DownloadUtils.clearPartResource(part); - Assert.assertFalse(file.exists()); - } - - @Test - public void clearPartResource_notDeleteFile() throws IOException { - File file = new File("target", UUID.randomUUID().toString() + ".txt"); - FileUtils.write(file, "content"); - FilePart part = new FilePart(null, file); - - Assert.assertTrue(file.exists()); - DownloadUtils.clearPartResource(part); - Assert.assertTrue(file.exists()); - - file.delete(); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpClientMetrics.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpClientMetrics.java index caeb25e1541..7049fb9aa78 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpClientMetrics.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpClientMetrics.java @@ -17,8 +17,9 @@ package org.apache.servicecomb.foundation.vertx.metrics; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetric; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; -import org.junit.Assert; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultRequestMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -27,12 +28,13 @@ import io.vertx.core.VertxOptions; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpClientRequest; import io.vertx.core.net.SocketAddress; import io.vertx.core.net.impl.SocketAddressImpl; +import io.vertx.core.spi.observability.HttpRequest; import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestDefaultHttpClientMetrics { @Mocked @@ -63,21 +65,29 @@ public class TestDefaultHttpClientMetrics { SocketAddress address2 = new SocketAddressImpl(port2, host); - DefaultClientEndpointMetric endpointMetric_a_1; + DefaultClientMetrics clientMetrics_a_1; - DefaultHttpSocketMetric socketMetric_a_1; + DefaultEndpointMetric endpointMetric_a_1; - DefaultClientEndpointMetric endpointMetric_a_2; + DefaultTcpSocketMetric socketMetric_a_1; - DefaultHttpSocketMetric socketMetric_a_2; + DefaultClientMetrics clientMetrics_a_2; - DefaultClientEndpointMetric endpointMetric_b_1; + DefaultEndpointMetric endpointMetric_a_2; - DefaultHttpSocketMetric socketMetric_b_1; + DefaultTcpSocketMetric socketMetric_a_2; - DefaultClientEndpointMetric endpointMetric_b_2; + DefaultClientMetrics clientMetrics_b_1; - DefaultHttpSocketMetric socketMetric_b_2; + DefaultEndpointMetric endpointMetric_b_1; + + DefaultTcpSocketMetric socketMetric_b_1; + + DefaultClientMetrics clientMetrics_b_2; + + DefaultEndpointMetric endpointMetric_b_2; + + DefaultTcpSocketMetric socketMetric_b_2; static long nanoTime; @@ -91,46 +101,56 @@ long nanoTime() { }; } - private static DefaultHttpSocketMetric initSocketMetric(DefaultHttpClientMetrics metrics, + private static DefaultTcpSocketMetric initSocketMetric(DefaultClientMetrics clientMetrics, + DefaultHttpClientMetrics metrics, SocketAddress address) { - return metrics.connected(address, address.toString()); + DefaultTcpSocketMetric socketMetric = metrics.connected(address, address.toString()); + metrics.endpointConnected(clientMetrics); + return socketMetric; } @Before public void setup() { vertxOptions.setMetricsOptions(metricsOptionsEx); - defaultVertxMetrics = new DefaultVertxMetrics(vertx, vertxOptions); - clientMetrics_a = (DefaultHttpClientMetrics) defaultVertxMetrics.createMetrics(anyHttpClient, options); - clientMetrics_b = (DefaultHttpClientMetrics) defaultVertxMetrics.createMetrics(anyHttpClient, options); + defaultVertxMetrics = new DefaultVertxMetrics(vertxOptions); + defaultVertxMetrics.setVertx(vertx); + clientMetrics_a = (DefaultHttpClientMetrics) defaultVertxMetrics.createHttpClientMetrics(options); + clientMetrics_b = (DefaultHttpClientMetrics) defaultVertxMetrics.createHttpClientMetrics(options); nanoTime = 1; - socketMetric_a_1 = initSocketMetric(clientMetrics_a, address1); + clientMetrics_a_1 = clientMetrics_a.createEndpointMetrics(address1, 0); + socketMetric_a_1 = initSocketMetric(clientMetrics_a_1, clientMetrics_a, address1); endpointMetric_a_1 = socketMetric_a_1.getEndpointMetric(); - socketMetric_a_2 = initSocketMetric(clientMetrics_a, address2); + + clientMetrics_a_2 = clientMetrics_a.createEndpointMetrics(address2, 0); + socketMetric_a_2 = initSocketMetric(clientMetrics_a_2, clientMetrics_a, address2); endpointMetric_a_2 = socketMetric_a_2.getEndpointMetric(); - socketMetric_b_1 = initSocketMetric(clientMetrics_b, address1); + clientMetrics_b_1 = clientMetrics_b.createEndpointMetrics(address1, 0); + socketMetric_b_1 = initSocketMetric(clientMetrics_b_1, clientMetrics_b, address1); endpointMetric_b_1 = socketMetric_b_1.getEndpointMetric(); - socketMetric_b_2 = initSocketMetric(clientMetrics_b, address2); + + clientMetrics_b_2 = clientMetrics_b.createEndpointMetrics(address2, 0); + socketMetric_b_2 = initSocketMetric(clientMetrics_b_2, clientMetrics_b, address2); endpointMetric_b_2 = socketMetric_b_2.getEndpointMetric(); } @Test public void createMetrics() { - Assert.assertNotSame(clientMetrics_a, clientMetrics_b); + Assertions.assertNotSame(clientMetrics_a, clientMetrics_b); } @Test public void createEndpoint() { - Assert.assertSame(endpointMetric_a_1, endpointMetric_b_1); - Assert.assertNotSame(endpointMetric_a_1, endpointMetric_a_2); + Assertions.assertSame(endpointMetric_a_1, endpointMetric_b_1); + Assertions.assertNotSame(endpointMetric_a_1, endpointMetric_a_2); - Assert.assertNotSame(endpointMetric_a_2, endpointMetric_b_1); - Assert.assertSame(endpointMetric_a_2, endpointMetric_b_2); + Assertions.assertNotSame(endpointMetric_a_2, endpointMetric_b_1); + Assertions.assertSame(endpointMetric_a_2, endpointMetric_b_2); - Assert.assertEquals(2, endpointMetric_a_1.getCurrentConnectionCount()); - Assert.assertEquals(2, endpointMetric_a_2.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric_a_1.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric_a_2.getCurrentConnectionCount()); } @Test @@ -143,161 +163,146 @@ public void expire() { nanoTime = 13; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("http://" + address1.toString())); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("http://" + address2.toString())); clientMetrics_b.disconnected(socketMetric_b_1, null); clientMetrics_b.disconnected(socketMetric_b_2, null); nanoTime = 23; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("http://" + address1.toString())); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("http://" + address2.toString())); nanoTime = 24; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions + .assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1.toString())); + Assertions + .assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2.toString())); } @Test public void connect() { { - Assert.assertSame(endpointMetric_a_1, socketMetric_a_1.getEndpointMetric()); - Assert.assertTrue(socketMetric_a_1.isConnected()); - Assert.assertEquals(1, socketMetric_a_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(0, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_a_1, socketMetric_a_1.getEndpointMetric()); + Assertions.assertTrue(socketMetric_a_1.isConnected()); + Assertions.assertEquals(1, socketMetric_a_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(0, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 2; clientMetrics_a.disconnected(socketMetric_a_1, null); - Assert.assertEquals(2, endpointMetric_a_1.getLastNanoTime()); - Assert.assertFalse(socketMetric_a_1.isConnected()); - Assert.assertEquals(1, socketMetric_a_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(2, ((DefaultClientEndpointMetric) endpointMetric_a_1).getLastNanoTime()); + Assertions.assertFalse(socketMetric_a_1.isConnected()); + Assertions.assertEquals(1, socketMetric_a_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_a_2, socketMetric_a_2.getEndpointMetric()); - Assert.assertTrue(socketMetric_a_2.isConnected()); - Assert.assertEquals(1, socketMetric_a_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(0, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_a_2, socketMetric_a_2.getEndpointMetric()); + Assertions.assertTrue(socketMetric_a_2.isConnected()); + Assertions.assertEquals(1, socketMetric_a_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(0, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 4; clientMetrics_a.disconnected(socketMetric_a_2, null); - Assert.assertEquals(4, endpointMetric_a_2.getLastNanoTime()); - Assert.assertFalse(socketMetric_a_2.isConnected()); - Assert.assertEquals(1, socketMetric_a_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(4, ((DefaultClientEndpointMetric) endpointMetric_a_2).getLastNanoTime()); + Assertions.assertFalse(socketMetric_a_2.isConnected()); + Assertions.assertEquals(1, socketMetric_a_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_b_1, socketMetric_b_1.getEndpointMetric()); - Assert.assertTrue(socketMetric_b_1.isConnected()); - Assert.assertEquals(1, socketMetric_b_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_b_1, socketMetric_b_1.getEndpointMetric()); + Assertions.assertTrue(socketMetric_b_1.isConnected()); + Assertions.assertEquals(1, socketMetric_b_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 6; clientMetrics_b.disconnected(socketMetric_b_1, null); - Assert.assertEquals(6, endpointMetric_b_1.getLastNanoTime()); - Assert.assertFalse(socketMetric_b_1.isConnected()); - Assert.assertEquals(1, socketMetric_b_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(0, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(6, ((DefaultClientEndpointMetric) endpointMetric_b_1).getLastNanoTime()); + Assertions.assertFalse(socketMetric_b_1.isConnected()); + Assertions.assertEquals(1, socketMetric_b_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(0, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_b_2, socketMetric_b_2.getEndpointMetric()); - Assert.assertTrue(socketMetric_b_2.isConnected()); - Assert.assertEquals(1, socketMetric_b_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_b_2, socketMetric_b_2.getEndpointMetric()); + Assertions.assertTrue(socketMetric_b_2.isConnected()); + Assertions.assertEquals(1, socketMetric_b_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 7; clientMetrics_b.disconnected(socketMetric_b_2, null); - Assert.assertEquals(7, endpointMetric_b_2.getLastNanoTime()); - Assert.assertFalse(socketMetric_b_2.isConnected()); - Assert.assertEquals(1, socketMetric_b_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(0, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(7, ((DefaultClientEndpointMetric) endpointMetric_b_2).getLastNanoTime()); + Assertions.assertFalse(socketMetric_b_2.isConnected()); + Assertions.assertEquals(1, socketMetric_b_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(0, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); } } @Test public void bytesReadAndWritten() { - DefaultHttpSocketMetric socketMetric = clientMetrics_a.connected(address1, host); - clientMetrics_a.endpointConnected(endpointMetric_a_1, socketMetric); + DefaultTcpSocketMetric socketMetric = clientMetrics_a.connected(address1, host); + clientMetrics_a.endpointConnected(clientMetrics_a_1); clientMetrics_a.bytesRead(socketMetric, address1, 1); clientMetrics_a.bytesWritten(socketMetric, address1, 1); socketMetric = clientMetrics_a.connected(address2, host); - clientMetrics_a.endpointConnected(endpointMetric_a_2, socketMetric); + clientMetrics_a.endpointConnected(clientMetrics_a_2); clientMetrics_a.bytesRead(socketMetric, address2, 1); clientMetrics_a.bytesWritten(socketMetric, address2, 1); socketMetric = clientMetrics_b.connected(address1, host); - clientMetrics_b.endpointConnected(endpointMetric_b_1, socketMetric); + clientMetrics_b.endpointConnected(clientMetrics_b_1); clientMetrics_b.bytesRead(socketMetric, address1, 1); clientMetrics_b.bytesWritten(socketMetric, address1, 1); socketMetric = clientMetrics_b.connected(address2, host); - clientMetrics_b.endpointConnected(endpointMetric_b_2, socketMetric); + clientMetrics_b.endpointConnected(clientMetrics_b_2); clientMetrics_b.bytesRead(socketMetric, address2, 1); clientMetrics_b.bytesWritten(socketMetric, address2, 1); - Assert.assertEquals(2, endpointMetric_a_1.getBytesRead()); - Assert.assertEquals(2, endpointMetric_a_2.getBytesRead()); - Assert.assertEquals(2, endpointMetric_a_1.getBytesWritten()); - Assert.assertEquals(2, endpointMetric_a_2.getBytesWritten()); + Assertions.assertEquals(2, endpointMetric_a_1.getBytesRead()); + Assertions.assertEquals(2, endpointMetric_a_2.getBytesRead()); + Assertions.assertEquals(2, endpointMetric_a_1.getBytesWritten()); + Assertions.assertEquals(2, endpointMetric_a_2.getBytesWritten()); } @Test - public void requestBegin(@Mocked HttpClientRequest request) { - DefaultHttpSocketMetric socketMetric = clientMetrics_a.connected(address1, host); + public void requestBegin(@Mocked HttpRequest request) { + DefaultTcpSocketMetric socketMetric = clientMetrics_a.connected(address1, host); nanoTime = 2; - clientMetrics_a.requestBegin(endpointMetric_a_1, socketMetric, address1, address1, request); + DefaultRequestMetric requestMetric = clientMetrics_a_1.requestBegin("/ui", request); nanoTime = 3; - clientMetrics_a.requestEnd(socketMetric); - - Assert.assertEquals(2, socketMetric.getRequestBeginTime()); - Assert.assertEquals(3, socketMetric.getRequestEndTime()); - } + clientMetrics_a_1.requestEnd(requestMetric); - @SuppressWarnings("deprecation") - @Test - public void meaningless() { - Assert.assertTrue(clientMetrics_a.isEnabled()); - - clientMetrics_a.enqueueRequest(endpointMetric_a_1); - clientMetrics_a.dequeueRequest(endpointMetric_a_1, null); - clientMetrics_a.createEndpoint(null, 0, 0); - clientMetrics_a.closeEndpoint(null, 0, null); - clientMetrics_a.endpointConnected(endpointMetric_a_1, null); - clientMetrics_a.endpointDisconnected(endpointMetric_a_1, null); - clientMetrics_a.responseBegin(null, null); - clientMetrics_a.responsePushed(null, null, null, null, null); - clientMetrics_a.requestReset(null); - clientMetrics_a.responseEnd(null, null); - clientMetrics_a.connected(null, null, null); - clientMetrics_a.disconnected(null); - clientMetrics_a.exceptionOccurred(null, null, null); - clientMetrics_a.close(); + Assertions.assertEquals(2, requestMetric.getRequestBeginTime()); + Assertions.assertEquals(3, requestMetric.getRequestEndTime()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java index b95ad5a6e3c..d8cbc40c95b 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultHttpServerMetrics.java @@ -20,21 +20,17 @@ import java.util.Map; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; -import org.junit.Assert; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; import org.junit.Before; import org.junit.Test; -import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; -import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.net.SocketAddress; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestDefaultHttpServerMetrics { - @Mocked - Vertx vertx; VertxOptions vertxOptions = new VertxOptions(); @@ -42,21 +38,9 @@ public class TestDefaultHttpServerMetrics { DefaultVertxMetrics defaultVertxMetrics; - @Mocked - HttpServer listen1_server1; - - @Mocked - HttpServer listen1_server2; - @Mocked SocketAddress listen1_addr; - @Mocked - HttpServer listen2_server1; - - @Mocked - HttpServer listen2_server2; - @Mocked SocketAddress listen2_addr; @@ -80,31 +64,31 @@ public class TestDefaultHttpServerMetrics { String remoteName = "remote"; - DefaultHttpSocketMetric socketMetric_listen1_1; + DefaultTcpSocketMetric socketMetric_listen1_1; - DefaultHttpSocketMetric socketMetric_listen1_2; + DefaultTcpSocketMetric socketMetric_listen1_2; - DefaultHttpSocketMetric socketMetric_listen2_1; + DefaultTcpSocketMetric socketMetric_listen2_1; - DefaultHttpSocketMetric socketMetric_listen2_2; + DefaultTcpSocketMetric socketMetric_listen2_2; - DefaultHttpSocketMetric socketMetric_listen2_3; + DefaultTcpSocketMetric socketMetric_listen2_3; @Before public void setup() { vertxOptions.setMetricsOptions(metricsOptionsEx); - defaultVertxMetrics = new DefaultVertxMetrics(vertx, vertxOptions); + defaultVertxMetrics = new DefaultVertxMetrics(vertxOptions); metrics_listen1_server1 = (DefaultHttpServerMetrics) defaultVertxMetrics - .createMetrics(listen1_server1, listen1_addr, options); + .createHttpServerMetrics(options, listen1_addr); metrics_listen1_server2 = (DefaultHttpServerMetrics) defaultVertxMetrics - .createMetrics(listen1_server2, listen1_addr, options); + .createHttpServerMetrics(options, listen1_addr); endpointMetric1 = metrics_listen1_server1.getEndpointMetric(); metrics_listen2_server1 = (DefaultHttpServerMetrics) defaultVertxMetrics - .createMetrics(listen2_server1, listen2_addr, options); + .createHttpServerMetrics(options, listen2_addr); metrics_listen2_server2 = (DefaultHttpServerMetrics) defaultVertxMetrics - .createMetrics(listen2_server2, listen2_addr, options); + .createHttpServerMetrics(options, listen2_addr); endpointMetric2 = metrics_listen2_server1.getEndpointMetric(); socketMetric_listen1_1 = metrics_listen1_server1.connected(anyRemoteAddr, remoteName); @@ -121,11 +105,11 @@ public void createMetrics() { instances.put(metrics_listen1_server2, null); instances.put(metrics_listen2_server1, null); instances.put(metrics_listen2_server2, null); - Assert.assertEquals(4, instances.size()); + Assertions.assertEquals(4, instances.size()); - Assert.assertSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen1_server2.getEndpointMetric()); - Assert.assertNotSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen2_server1.getEndpointMetric()); - Assert.assertSame(metrics_listen2_server1.getEndpointMetric(), metrics_listen2_server2.getEndpointMetric()); + Assertions.assertSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen1_server2.getEndpointMetric()); + Assertions.assertNotSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen2_server1.getEndpointMetric()); + Assertions.assertSame(metrics_listen2_server1.getEndpointMetric(), metrics_listen2_server2.getEndpointMetric()); } @Test @@ -136,16 +120,16 @@ public void connectionCount() { instances.put(socketMetric_listen2_1, null); instances.put(socketMetric_listen2_2, null); instances.put(socketMetric_listen2_3, null); - Assert.assertEquals(5, instances.size()); + Assertions.assertEquals(5, instances.size()); - Assert.assertTrue(socketMetric_listen1_1.isConnected()); - Assert.assertTrue(socketMetric_listen1_2.isConnected()); - Assert.assertTrue(socketMetric_listen2_1.isConnected()); - Assert.assertTrue(socketMetric_listen2_2.isConnected()); - Assert.assertTrue(socketMetric_listen2_3.isConnected()); + Assertions.assertTrue(socketMetric_listen1_1.isConnected()); + Assertions.assertTrue(socketMetric_listen1_2.isConnected()); + Assertions.assertTrue(socketMetric_listen2_1.isConnected()); + Assertions.assertTrue(socketMetric_listen2_2.isConnected()); + Assertions.assertTrue(socketMetric_listen2_3.isConnected()); - Assert.assertEquals(2, endpointMetric1.getCurrentConnectionCount()); - Assert.assertEquals(3, endpointMetric2.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric1.getCurrentConnectionCount()); + Assertions.assertEquals(3, endpointMetric2.getCurrentConnectionCount()); // disconnect metrics_listen1_server1.disconnected(socketMetric_listen1_1, anyRemoteAddr); @@ -154,14 +138,14 @@ public void connectionCount() { metrics_listen2_server2.disconnected(socketMetric_listen2_2, anyRemoteAddr); metrics_listen2_server2.disconnected(socketMetric_listen2_3, anyRemoteAddr); - Assert.assertFalse(socketMetric_listen1_1.isConnected()); - Assert.assertFalse(socketMetric_listen1_2.isConnected()); - Assert.assertFalse(socketMetric_listen2_1.isConnected()); - Assert.assertFalse(socketMetric_listen2_2.isConnected()); - Assert.assertFalse(socketMetric_listen2_3.isConnected()); + Assertions.assertFalse(socketMetric_listen1_1.isConnected()); + Assertions.assertFalse(socketMetric_listen1_2.isConnected()); + Assertions.assertFalse(socketMetric_listen2_1.isConnected()); + Assertions.assertFalse(socketMetric_listen2_2.isConnected()); + Assertions.assertFalse(socketMetric_listen2_3.isConnected()); - Assert.assertEquals(0, endpointMetric1.getCurrentConnectionCount()); - Assert.assertEquals(0, endpointMetric2.getCurrentConnectionCount()); + Assertions.assertEquals(0, endpointMetric1.getCurrentConnectionCount()); + Assertions.assertEquals(0, endpointMetric2.getCurrentConnectionCount()); } @Test @@ -172,8 +156,8 @@ public void bytesRead() { metrics_listen2_server2.bytesRead(socketMetric_listen2_2, anyRemoteAddr, 4); metrics_listen2_server2.bytesRead(socketMetric_listen2_3, anyRemoteAddr, 5); - Assert.assertEquals(3, endpointMetric1.getBytesRead()); - Assert.assertEquals(12, endpointMetric2.getBytesRead()); + Assertions.assertEquals(3, endpointMetric1.getBytesRead()); + Assertions.assertEquals(12, endpointMetric2.getBytesRead()); } @Test @@ -184,24 +168,7 @@ public void bytesWritten() { metrics_listen2_server2.bytesWritten(socketMetric_listen2_2, anyRemoteAddr, 4); metrics_listen2_server2.bytesWritten(socketMetric_listen2_3, anyRemoteAddr, 5); - Assert.assertEquals(3, endpointMetric1.getBytesWritten()); - Assert.assertEquals(12, endpointMetric2.getBytesWritten()); - } - - @SuppressWarnings("deprecation") - @Test - public void meaningless() { - Assert.assertSame(listen1_addr, metrics_listen1_server1.getEndpointMetric().getAddress()); - Assert.assertTrue(metrics_listen1_server1.isEnabled()); - - metrics_listen1_server1.requestBegin(null, null); - metrics_listen1_server1.requestReset(null); - metrics_listen1_server1.responsePushed(null, null, null, null); - metrics_listen1_server1.responseEnd(null, null); - metrics_listen1_server1.upgrade(null, null); - metrics_listen1_server1.connected((DefaultHttpSocketMetric) null, null); - metrics_listen1_server1.disconnected(null); - metrics_listen1_server1.exceptionOccurred(null, null, null); - metrics_listen1_server1.close(); + Assertions.assertEquals(3, endpointMetric1.getBytesWritten()); + Assertions.assertEquals(12, endpointMetric2.getBytesWritten()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpClientMetrics.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpClientMetrics.java index fbbe8dec921..8c893b60ca9 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpClientMetrics.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpClientMetrics.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.foundation.vertx.metrics; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; -import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -31,6 +31,7 @@ import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestDefaultTcpClientMetrics { @Mocked @@ -58,19 +59,19 @@ public class TestDefaultTcpClientMetrics { SocketAddress address2 = new SocketAddressImpl(port2, host); - DefaultClientEndpointMetric endpointMetric_a_1; + DefaultEndpointMetric endpointMetric_a_1; DefaultTcpSocketMetric socketMetric_a_1; - DefaultClientEndpointMetric endpointMetric_a_2; + DefaultEndpointMetric endpointMetric_a_2; DefaultTcpSocketMetric socketMetric_a_2; - DefaultClientEndpointMetric endpointMetric_b_1; + DefaultEndpointMetric endpointMetric_b_1; DefaultTcpSocketMetric socketMetric_b_1; - DefaultClientEndpointMetric endpointMetric_b_2; + DefaultEndpointMetric endpointMetric_b_2; DefaultTcpSocketMetric socketMetric_b_2; @@ -94,9 +95,10 @@ private static DefaultTcpSocketMetric initSocketMetric(DefaultTcpClientMetrics m @Before public void setup() { vertxOptions.setMetricsOptions(metricsOptionsEx); - defaultVertxMetrics = new DefaultVertxMetrics(vertx, vertxOptions); - clientMetrics_a = (DefaultTcpClientMetrics) defaultVertxMetrics.createMetrics(options); - clientMetrics_b = (DefaultTcpClientMetrics) defaultVertxMetrics.createMetrics(options); + defaultVertxMetrics = new DefaultVertxMetrics(vertxOptions); + defaultVertxMetrics.setVertx(vertx); + clientMetrics_a = (DefaultTcpClientMetrics) defaultVertxMetrics.createNetClientMetrics(options); + clientMetrics_b = (DefaultTcpClientMetrics) defaultVertxMetrics.createNetClientMetrics(options); nanoTime = 1; @@ -113,19 +115,19 @@ public void setup() { @Test public void createMetrics() { - Assert.assertNotSame(clientMetrics_a, clientMetrics_b); + Assertions.assertNotSame(clientMetrics_a, clientMetrics_b); } @Test public void createEndpoint() { - Assert.assertSame(endpointMetric_a_1, endpointMetric_b_1); - Assert.assertNotSame(endpointMetric_a_1, endpointMetric_a_2); + Assertions.assertSame(endpointMetric_a_1, endpointMetric_b_1); + Assertions.assertNotSame(endpointMetric_a_1, endpointMetric_a_2); - Assert.assertNotSame(endpointMetric_a_2, endpointMetric_b_1); - Assert.assertSame(endpointMetric_a_2, endpointMetric_b_2); + Assertions.assertNotSame(endpointMetric_a_2, endpointMetric_b_1); + Assertions.assertSame(endpointMetric_a_2, endpointMetric_b_2); - Assert.assertEquals(2, endpointMetric_a_1.getCurrentConnectionCount()); - Assert.assertEquals(2, endpointMetric_a_2.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric_a_1.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric_a_2.getCurrentConnectionCount()); } @Test @@ -138,99 +140,105 @@ public void expire() { nanoTime = 13; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("tcp://" + address1.toString())); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("tcp://" + address2.toString())); clientMetrics_b.disconnected(socketMetric_b_1, null); clientMetrics_b.disconnected(socketMetric_b_2, null); nanoTime = 23; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNotNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("tcp://" + address1.toString())); + Assertions.assertNotNull( + defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric("tcp://" + address2.toString())); nanoTime = 24; defaultVertxMetrics.getClientEndpointMetricManager().onCheckClientEndpointMetricExpired(0); - Assert.assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1)); - Assert.assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2)); + Assertions + .assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address1.toString())); + Assertions + .assertNull(defaultVertxMetrics.getClientEndpointMetricManager().getClientEndpointMetric(address2.toString())); } @Test public void connect() { { - Assert.assertSame(endpointMetric_a_1, socketMetric_a_1.getEndpointMetric()); - Assert.assertTrue(socketMetric_a_1.isConnected()); - Assert.assertEquals(1, socketMetric_a_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(0, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_a_1, socketMetric_a_1.getEndpointMetric()); + Assertions.assertTrue(socketMetric_a_1.isConnected()); + Assertions.assertEquals(1, socketMetric_a_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(0, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 2; clientMetrics_a.disconnected(socketMetric_a_1, null); - Assert.assertEquals(2, endpointMetric_a_1.getLastNanoTime()); - Assert.assertFalse(socketMetric_a_1.isConnected()); - Assert.assertEquals(1, socketMetric_a_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(2, ((DefaultClientEndpointMetric) endpointMetric_a_1).getLastNanoTime()); + Assertions.assertFalse(socketMetric_a_1.isConnected()); + Assertions.assertEquals(1, socketMetric_a_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_a_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_a_1.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_a_2, socketMetric_a_2.getEndpointMetric()); - Assert.assertTrue(socketMetric_a_2.isConnected()); - Assert.assertEquals(1, socketMetric_a_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(0, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_a_2, socketMetric_a_2.getEndpointMetric()); + Assertions.assertTrue(socketMetric_a_2.isConnected()); + Assertions.assertEquals(1, socketMetric_a_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(0, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 4; clientMetrics_a.disconnected(socketMetric_a_2, null); - Assert.assertEquals(4, endpointMetric_a_2.getLastNanoTime()); - Assert.assertFalse(socketMetric_a_2.isConnected()); - Assert.assertEquals(1, socketMetric_a_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(4, ((DefaultClientEndpointMetric) endpointMetric_a_2).getLastNanoTime()); + Assertions.assertFalse(socketMetric_a_2.isConnected()); + Assertions.assertEquals(1, socketMetric_a_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_a_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_a_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_a_2.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_b_1, socketMetric_b_1.getEndpointMetric()); - Assert.assertTrue(socketMetric_b_1.isConnected()); - Assert.assertEquals(1, socketMetric_b_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_b_1, socketMetric_b_1.getEndpointMetric()); + Assertions.assertTrue(socketMetric_b_1.isConnected()); + Assertions.assertEquals(1, socketMetric_b_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 6; clientMetrics_b.disconnected(socketMetric_b_1, null); - Assert.assertEquals(6, endpointMetric_b_1.getLastNanoTime()); - Assert.assertFalse(socketMetric_b_1.isConnected()); - Assert.assertEquals(1, socketMetric_b_1.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); - Assert.assertEquals(2, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(0, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(6, ((DefaultClientEndpointMetric) endpointMetric_b_1).getLastNanoTime()); + Assertions.assertFalse(socketMetric_b_1.isConnected()); + Assertions.assertEquals(1, socketMetric_b_1.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(2, socketMetric_b_1.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(0, socketMetric_b_1.getEndpointMetric().getCurrentConnectionCount()); } { - Assert.assertSame(endpointMetric_b_2, socketMetric_b_2.getEndpointMetric()); - Assert.assertTrue(socketMetric_b_2.isConnected()); - Assert.assertEquals(1, socketMetric_b_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(1, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(1, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertSame(endpointMetric_b_2, socketMetric_b_2.getEndpointMetric()); + Assertions.assertTrue(socketMetric_b_2.isConnected()); + Assertions.assertEquals(1, socketMetric_b_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(1, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(1, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); nanoTime = 7; clientMetrics_b.disconnected(socketMetric_b_2, null); - Assert.assertEquals(7, endpointMetric_b_2.getLastNanoTime()); - Assert.assertFalse(socketMetric_b_2.isConnected()); - Assert.assertEquals(1, socketMetric_b_2.getConnectedTime()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); - Assert.assertEquals(2, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); - Assert.assertEquals(0, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); + Assertions.assertEquals(7, ((DefaultClientEndpointMetric) endpointMetric_b_2).getLastNanoTime()); + Assertions.assertFalse(socketMetric_b_2.isConnected()); + Assertions.assertEquals(1, socketMetric_b_2.getConnectedTime()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getConnectCount()); + Assertions.assertEquals(2, socketMetric_b_2.getEndpointMetric().getDisconnectCount()); + Assertions.assertEquals(0, socketMetric_b_2.getEndpointMetric().getCurrentConnectionCount()); } } @@ -248,18 +256,9 @@ public void bytesReadAndWritten() { clientMetrics_b.bytesRead(socketMetric_b_2, address2, 1); clientMetrics_b.bytesWritten(socketMetric_b_2, address2, 1); - Assert.assertEquals(2, endpointMetric_a_1.getBytesRead()); - Assert.assertEquals(2, endpointMetric_a_2.getBytesRead()); - Assert.assertEquals(2, endpointMetric_a_1.getBytesWritten()); - Assert.assertEquals(2, endpointMetric_a_2.getBytesWritten()); - } - - @SuppressWarnings("deprecation") - @Test - public void meaningless() { - Assert.assertTrue(clientMetrics_a.isEnabled()); - - clientMetrics_a.exceptionOccurred(null, null, null); - clientMetrics_a.close(); + Assertions.assertEquals(2, endpointMetric_a_1.getBytesRead()); + Assertions.assertEquals(2, endpointMetric_a_2.getBytesRead()); + Assertions.assertEquals(2, endpointMetric_a_1.getBytesWritten()); + Assertions.assertEquals(2, endpointMetric_a_2.getBytesWritten()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpServerMetrics.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpServerMetrics.java index c6ed45e3a9b..f9b93f1ce99 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpServerMetrics.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultTcpServerMetrics.java @@ -21,19 +21,16 @@ import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultTcpSocketMetric; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.net.NetServerOptions; import io.vertx.core.net.SocketAddress; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestDefaultTcpServerMetrics { - @Mocked - Vertx vertx; VertxOptions vertxOptions = new VertxOptions(); @@ -80,18 +77,18 @@ public class TestDefaultTcpServerMetrics { @Before public void setup() { vertxOptions.setMetricsOptions(metricsOptionsEx); - defaultVertxMetrics = new DefaultVertxMetrics(vertx, vertxOptions); + defaultVertxMetrics = new DefaultVertxMetrics(vertxOptions); metrics_listen1_server1 = (DefaultTcpServerMetrics) defaultVertxMetrics - .createMetrics(listen1_addr, options); + .createNetServerMetrics(options, listen1_addr); metrics_listen1_server2 = (DefaultTcpServerMetrics) defaultVertxMetrics - .createMetrics(listen1_addr, options); + .createNetServerMetrics(options, listen1_addr); endpointMetric1 = metrics_listen1_server1.getEndpointMetric(); metrics_listen2_server1 = (DefaultTcpServerMetrics) defaultVertxMetrics - .createMetrics(listen2_addr, options); + .createNetServerMetrics(options, listen2_addr); metrics_listen2_server2 = (DefaultTcpServerMetrics) defaultVertxMetrics - .createMetrics(listen2_addr, options); + .createNetServerMetrics(options, listen2_addr); endpointMetric2 = metrics_listen2_server1.getEndpointMetric(); socketMetric_listen1_1 = metrics_listen1_server1.connected(anyRemoteAddr, remoteName); @@ -108,11 +105,11 @@ public void createMetrics() { instances.put(metrics_listen1_server2, null); instances.put(metrics_listen2_server1, null); instances.put(metrics_listen2_server2, null); - Assert.assertEquals(4, instances.size()); + Assertions.assertEquals(4, instances.size()); - Assert.assertSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen1_server2.getEndpointMetric()); - Assert.assertNotSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen2_server1.getEndpointMetric()); - Assert.assertSame(metrics_listen2_server1.getEndpointMetric(), metrics_listen2_server2.getEndpointMetric()); + Assertions.assertSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen1_server2.getEndpointMetric()); + Assertions.assertNotSame(metrics_listen1_server1.getEndpointMetric(), metrics_listen2_server1.getEndpointMetric()); + Assertions.assertSame(metrics_listen2_server1.getEndpointMetric(), metrics_listen2_server2.getEndpointMetric()); } @Test @@ -123,16 +120,16 @@ public void connectionCount() { instances.put(socketMetric_listen2_1, null); instances.put(socketMetric_listen2_2, null); instances.put(socketMetric_listen2_3, null); - Assert.assertEquals(5, instances.size()); + Assertions.assertEquals(5, instances.size()); - Assert.assertTrue(socketMetric_listen1_1.isConnected()); - Assert.assertTrue(socketMetric_listen1_2.isConnected()); - Assert.assertTrue(socketMetric_listen2_1.isConnected()); - Assert.assertTrue(socketMetric_listen2_2.isConnected()); - Assert.assertTrue(socketMetric_listen2_3.isConnected()); + Assertions.assertTrue(socketMetric_listen1_1.isConnected()); + Assertions.assertTrue(socketMetric_listen1_2.isConnected()); + Assertions.assertTrue(socketMetric_listen2_1.isConnected()); + Assertions.assertTrue(socketMetric_listen2_2.isConnected()); + Assertions.assertTrue(socketMetric_listen2_3.isConnected()); - Assert.assertEquals(2, endpointMetric1.getCurrentConnectionCount()); - Assert.assertEquals(3, endpointMetric2.getCurrentConnectionCount()); + Assertions.assertEquals(2, endpointMetric1.getCurrentConnectionCount()); + Assertions.assertEquals(3, endpointMetric2.getCurrentConnectionCount()); // disconnect metrics_listen1_server1.disconnected(socketMetric_listen1_1, anyRemoteAddr); @@ -141,14 +138,14 @@ public void connectionCount() { metrics_listen2_server2.disconnected(socketMetric_listen2_2, anyRemoteAddr); metrics_listen2_server2.disconnected(socketMetric_listen2_3, anyRemoteAddr); - Assert.assertFalse(socketMetric_listen1_1.isConnected()); - Assert.assertFalse(socketMetric_listen1_2.isConnected()); - Assert.assertFalse(socketMetric_listen2_1.isConnected()); - Assert.assertFalse(socketMetric_listen2_2.isConnected()); - Assert.assertFalse(socketMetric_listen2_3.isConnected()); + Assertions.assertFalse(socketMetric_listen1_1.isConnected()); + Assertions.assertFalse(socketMetric_listen1_2.isConnected()); + Assertions.assertFalse(socketMetric_listen2_1.isConnected()); + Assertions.assertFalse(socketMetric_listen2_2.isConnected()); + Assertions.assertFalse(socketMetric_listen2_3.isConnected()); - Assert.assertEquals(0, endpointMetric1.getCurrentConnectionCount()); - Assert.assertEquals(0, endpointMetric2.getCurrentConnectionCount()); + Assertions.assertEquals(0, endpointMetric1.getCurrentConnectionCount()); + Assertions.assertEquals(0, endpointMetric2.getCurrentConnectionCount()); } @Test @@ -159,8 +156,8 @@ public void bytesRead() { metrics_listen2_server2.bytesRead(socketMetric_listen2_2, anyRemoteAddr, 4); metrics_listen2_server2.bytesRead(socketMetric_listen2_3, anyRemoteAddr, 5); - Assert.assertEquals(3, endpointMetric1.getBytesRead()); - Assert.assertEquals(12, endpointMetric2.getBytesRead()); + Assertions.assertEquals(3, endpointMetric1.getBytesRead()); + Assertions.assertEquals(12, endpointMetric2.getBytesRead()); } @Test @@ -171,17 +168,7 @@ public void bytesWritten() { metrics_listen2_server2.bytesWritten(socketMetric_listen2_2, anyRemoteAddr, 4); metrics_listen2_server2.bytesWritten(socketMetric_listen2_3, anyRemoteAddr, 5); - Assert.assertEquals(3, endpointMetric1.getBytesWritten()); - Assert.assertEquals(12, endpointMetric2.getBytesWritten()); - } - - @SuppressWarnings("deprecation") - @Test - public void meaningless() { - Assert.assertSame(listen1_addr, metrics_listen1_server1.getEndpointMetric().getAddress()); - Assert.assertTrue(metrics_listen1_server1.isEnabled()); - - metrics_listen1_server1.exceptionOccurred(null, null, null); - metrics_listen1_server1.close(); + Assertions.assertEquals(3, endpointMetric1.getBytesWritten()); + Assertions.assertEquals(12, endpointMetric2.getBytesWritten()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultVertxMetricsFactory.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultVertxMetricsFactory.java index a96f23c7fa1..ccc67374c82 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultVertxMetricsFactory.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestDefaultVertxMetricsFactory.java @@ -16,36 +16,28 @@ */ package org.apache.servicecomb.foundation.vertx.metrics; -import org.junit.Assert; import org.junit.Test; -import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.metrics.MetricsOptions; import io.vertx.core.spi.metrics.VertxMetrics; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestDefaultVertxMetricsFactory { - @Mocked - Vertx vertx; VertxOptions options = new VertxOptions(); DefaultVertxMetricsFactory factory = new DefaultVertxMetricsFactory(); - @SuppressWarnings("deprecation") @Test public void metrics() { MetricsOptions metricsOptions = factory.newOptions(); options.setMetricsOptions(metricsOptions); - VertxMetrics vertxMetrics = factory.metrics(vertx, options); + VertxMetrics vertxMetrics = factory.metrics(options); - Assert.assertSame(factory, metricsOptions.getFactory()); - Assert.assertTrue(metricsOptions.isEnabled()); + Assertions.assertTrue(metricsOptions.isEnabled()); - Assert.assertSame(factory.getVertxMetrics(), vertxMetrics); - Assert.assertSame(vertx, ((DefaultVertxMetrics) vertxMetrics).getVertx()); - Assert.assertTrue(vertxMetrics.isMetricsEnabled()); - Assert.assertTrue(vertxMetrics.isEnabled()); + Assertions.assertSame(factory.getVertxMetrics(), vertxMetrics); + Assertions.assertTrue(vertxMetrics.isMetricsEnabled()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestMetricsOptionsEx.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestMetricsOptionsEx.java index 19f3241ac04..ced6ecb2996 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestMetricsOptionsEx.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/metrics/TestMetricsOptionsEx.java @@ -18,30 +18,30 @@ import java.util.concurrent.TimeUnit; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestMetricsOptionsEx { MetricsOptionsEx metricsOptionsEx = new MetricsOptionsEx(); @Test public void interval() { - Assert.assertEquals(TimeUnit.MINUTES.toMillis(1), + Assertions.assertEquals(TimeUnit.MINUTES.toMillis(1), metricsOptionsEx.getCheckClientEndpointMetricIntervalInMilliseconds()); metricsOptionsEx.setCheckClientEndpointMetricIntervalInMinute(2); - Assert.assertEquals(TimeUnit.MINUTES.toMillis(2), + Assertions.assertEquals(TimeUnit.MINUTES.toMillis(2), metricsOptionsEx.getCheckClientEndpointMetricIntervalInMilliseconds()); } @Test public void expired() { - Assert.assertEquals(TimeUnit.MINUTES.toNanos(15), metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); + Assertions.assertEquals(TimeUnit.MINUTES.toNanos(15), metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); metricsOptionsEx.setCheckClientEndpointMetricExpiredInNano(10); - Assert.assertEquals(10, metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); + Assertions.assertEquals(10, metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); metricsOptionsEx.setCheckClientEndpointMetricExpiredInMinute(60); - Assert.assertEquals(TimeUnit.MINUTES.toNanos(60), metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); + Assertions.assertEquals(TimeUnit.MINUTES.toNanos(60), metricsOptionsEx.getCheckClientEndpointMetricExpiredInNano()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpParser.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpParser.java index 167ff0406cd..5a1f7b4af12 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpParser.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpParser.java @@ -19,10 +19,10 @@ import java.io.UnsupportedEncodingException; import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; -import org.junit.Assert; -import org.junit.Test; import io.vertx.core.buffer.Buffer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestTcpParser { long msgId; @@ -33,13 +33,10 @@ public class TestTcpParser { @Test public void test() throws UnsupportedEncodingException { - TcpBufferHandler output = new TcpBufferHandler() { - @Override - public void handle(long _msgId, Buffer _headerBuffer, Buffer _bodyBuffer) { - msgId = _msgId; - headerBuffer = _headerBuffer; - bodyBuffer = _bodyBuffer; - } + TcpBufferHandler output = (_msgId, _headerBuffer, _bodyBuffer) -> { + msgId = _msgId; + headerBuffer = _headerBuffer; + bodyBuffer = _bodyBuffer; }; byte[] header = new byte[] {1, 2, 3}; @@ -54,8 +51,8 @@ public void handle(long _msgId, Buffer _headerBuffer, Buffer _bodyBuffer) { parser.handle(os.getBuffer()); os.close(); - Assert.assertEquals(1, msgId); - Assert.assertArrayEquals(header, headerBuffer.getBytes()); - Assert.assertArrayEquals(body, bodyBuffer.getBytes()); + Assertions.assertEquals(1, msgId); + Assertions.assertArrayEquals(header, headerBuffer.getBytes()); + Assertions.assertArrayEquals(body, bodyBuffer.getBytes()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServer.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServer.java deleted file mode 100644 index b95bfc30a58..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServer.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.foundation.vertx.server; - -import java.net.InetSocketAddress; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.foundation.vertx.metrics.DefaultTcpServerMetrics; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.net.NetServer; -import io.vertx.core.net.NetServerOptions; -import io.vertx.core.net.NetSocket; -import io.vertx.core.net.impl.NetSocketImpl; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestTcpServer { - static class TcpServerForTest extends TcpServer { - public TcpServerForTest(URIEndpointObject endpointObject) { - super(endpointObject); - } - - @Override - protected TcpServerConnection createTcpServerConnection() { - return new TcpServerConnection() { - @Override - public void init(NetSocket netSocket) { - super.init(netSocket); - } - }; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void testTcpServerNonSSL(@Mocked Vertx vertx, @Mocked AsyncResultCallback callback, - @Mocked NetServer netServer) { - new Expectations() { - { - vertx.createNetServer(); - result = netServer; - netServer.connectHandler((Handler) any); - netServer.listen(anyInt, anyString, (Handler) any); - } - }; - URIEndpointObject endpointObject = new URIEndpointObject("highway://127.0.0.1:6663"); - TcpServer server = new TcpServerForTest(endpointObject); - // assert done in Expectations - server.init(vertx, "", callback); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void testTcpServerSSL(@Mocked Vertx vertx, @Mocked AsyncResultCallback callback, - @Mocked NetServer netServer) { - new Expectations() { - { - vertx.createNetServer((NetServerOptions) any); - result = netServer; - netServer.connectHandler((Handler) any); - netServer.listen(anyInt, anyString, (Handler) any); - } - }; - URIEndpointObject endpointObject = new URIEndpointObject("highway://127.0.0.1:6663?sslEnabled=true"); - TcpServer server = new TcpServerForTest(endpointObject); - // assert done in Expectations - server.init(vertx, "", callback); - } - - Handler connectHandler; - - boolean netSocketClosed; - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void testConnectionLimit(@Mocked Vertx vertx, @Mocked AsyncResultCallback callback, - @Mocked NetServer netServer, @Mocked NetSocketImpl netSocket) { - DefaultServerEndpointMetric endpointMetric = new DefaultServerEndpointMetric(null); - DefaultTcpServerMetrics tcpServerMetrics = new DefaultTcpServerMetrics(endpointMetric); - - new MockUp(netServer) { - @Mock - NetServer connectHandler(Handler handler) { - connectHandler = handler; - return netServer; - } - }; - new MockUp(netSocket) { - @Mock - void close() { - netSocketClosed = true; - } - }; - new Expectations() { - { - vertx.createNetServer((NetServerOptions) any); - result = netServer; - netServer.listen(anyInt, anyString, (Handler) any); - netSocket.metrics(); - result = tcpServerMetrics; - } - }; - URIEndpointObject endpointObject = new URIEndpointObject("highway://127.0.0.1:6663?sslEnabled=true"); - TcpServer server = new TcpServerForTest(endpointObject) { - @Override - protected int getConnectionLimit() { - return 2; - } - }; - // assert done in Expectations - server.init(vertx, "", callback); - - // no problem - endpointMetric.onConnect(); - endpointMetric.onConnect(); - connectHandler.handle(netSocket); - - // reject - endpointMetric.onConnect(); - connectHandler.handle(netSocket); - Assert.assertTrue(netSocketClosed); - Assert.assertEquals(1, endpointMetric.getRejectByConnectionLimitCount()); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServerConnection.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServerConnection.java index 3047042f2ff..ac15a8e6baf 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServerConnection.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/server/TestTcpServerConnection.java @@ -16,21 +16,24 @@ */ package org.apache.servicecomb.foundation.vertx.server; -import org.junit.Assert; -import org.junit.Test; - +import io.vertx.core.net.SocketAddress; import io.vertx.core.net.impl.NetSocketImpl; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestTcpServerConnection { @Test - public void test(@Mocked NetSocketImpl netSocket) { + public void test() { + SocketAddress socketAddress = Mockito.mock(SocketAddress.class); + NetSocketImpl netSocket = Mockito.mock(NetSocketImpl.class); + Mockito.when(netSocket.remoteAddress()).thenReturn(socketAddress); TcpServerConnection connection = new TcpServerConnection(); connection.setProtocol("p"); connection.setZipName("z"); connection.init(netSocket); - Assert.assertEquals(netSocket, connection.getNetSocket()); + Assertions.assertEquals(netSocket, connection.getNetSocket()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestBufferInputStream.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestBufferInputStream.java index a8adb22e196..40be5d48642 100644 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestBufferInputStream.java +++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestBufferInputStream.java @@ -17,15 +17,19 @@ package org.apache.servicecomb.foundation.vertx.stream; -import java.io.UnsupportedEncodingException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; -import io.netty.buffer.ByteBuf; +import io.vertx.core.buffer.Buffer; public class TestBufferInputStream { @@ -33,7 +37,7 @@ public class TestBufferInputStream { @Before public void setUp() throws Exception { - ByteBuf buffer = Mockito.mock(ByteBuf.class); + Buffer buffer = Mockito.mock(Buffer.class); instance = new BufferInputStream(buffer); } @@ -44,29 +48,53 @@ public void tearDown() throws Exception { @Test public void testRead() { - Assert.assertEquals(0, instance.read()); + Assertions.assertEquals(0, instance.read()); } @Test - public void testReadByteArray() throws UnsupportedEncodingException { - byte[] b = "csr".getBytes("UTF-8"); - Assert.assertEquals(-1, instance.read(b)); + public void testReadDecorate() throws IOException { + String text = "abcdefg123456789"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out); + gzipOutputStream.write(text.getBytes()); + gzipOutputStream.close(); + + Buffer buffer = Buffer.buffer(); + buffer.appendBytes(out.toByteArray()); + out.close(); + BufferInputStream bufferInputStream = new BufferInputStream(buffer); + GZIPInputStream gzipInputStream = new GZIPInputStream(bufferInputStream); + StringBuilder sb = new StringBuilder(); + byte[] bufferByte = new byte[256]; + int n; + while ((n = gzipInputStream.read(bufferByte)) >= 0) { + sb.append(new String(bufferByte, 0, n)); + } + gzipInputStream.close(); + + Assertions.assertEquals(text, sb.toString()); + } + + @Test + public void testReadByteArray() { + byte[] b = "csr".getBytes(StandardCharsets.UTF_8); + Assertions.assertEquals(-1, instance.read(b)); } @Test - public void testReadByteArrayIntInt() throws UnsupportedEncodingException { - byte[] b = "csr".getBytes("UTF-8"); - Assert.assertEquals(-1, instance.read(b, 1, 0)); + public void testReadByteArrayIntInt() { + byte[] b = "csr".getBytes(StandardCharsets.UTF_8); + Assertions.assertEquals(-1, instance.read(b, 1, 0)); } @Test public void testSkip() { - Assert.assertEquals(0, instance.skip(1)); + Assertions.assertEquals(0, instance.skip(1)); } @Test public void testAvailable() { - Assert.assertEquals(0, instance.available()); + Assertions.assertEquals(0, instance.available()); } @Test @@ -74,42 +102,42 @@ public void testClose() { try { instance.close(); } catch (Exception e) { - Assert.assertTrue(false); // This assertion is made to fail the test case in case the close() throws exception + Assertions.fail(); // This assertion is made to fail the test case in case the close() throws exception } } @Test public void testBufferInputStream() { - Assert.assertNotNull(instance); + Assertions.assertNotNull(instance); } @Test public void testReadBoolean() { - Assert.assertEquals(false, instance.readBoolean()); + Assertions.assertFalse(instance.readBoolean()); } @Test public void testReadShort() { - Assert.assertEquals(0, instance.readShort()); + Assertions.assertEquals(0, instance.readShort()); } @Test public void testReadInt() { - Assert.assertEquals(0, instance.readInt()); + Assertions.assertEquals(0, instance.readInt()); } @Test public void testReadLong() { - Assert.assertEquals(0, instance.readLong()); + Assertions.assertEquals(0, instance.readLong()); } @Test public void testGetIndex() { - Assert.assertEquals(0, instance.getIndex()); + Assertions.assertEquals(0, instance.getIndex()); } @Test public void testReadString() { - Assert.assertNotNull(instance.readString()); + Assertions.assertNotNull(instance.readString()); } } diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpFromPart.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpFromPart.java deleted file mode 100644 index 9ba8a28649d..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpFromPart.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.stream; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.ExecutionException; - -import javax.servlet.http.Part; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.RandomStringUtils; -import org.apache.servicecomb.foundation.common.part.InputStreamPart; -import org.apache.servicecomb.foundation.vertx.stream.InputStreamToReadStream.ReadResult; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.Context; -import io.vertx.core.Future; -import io.vertx.core.impl.SyncContext; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; - -public class TestPumpFromPart { - String src = RandomStringUtils.random(100); - - boolean inputStreamClosed; - - InputStream inputStream = new ByteArrayInputStream(src.getBytes()) { - @Override - public void close() throws IOException { - super.close(); - inputStreamClosed = true; - } - }; - - Part part; - - boolean outputStreamClosed; - - BufferOutputStream outputStream; - - IOException error = new IOException(); - - Context context = new SyncContext(); - - private void run(Context context, boolean closeOutput) throws Throwable { - inputStream.reset(); - part = new InputStreamPart("name", inputStream); - - outputStream = new BufferOutputStream() { - @Override - public void close() { - super.close(); - outputStreamClosed = true; - } - }; - - new PumpFromPart(context, part).toOutputStream(outputStream, closeOutput).get(); - } - - public void do_pump_succ(Context context) throws Throwable { - run(context, true); - - Assert.assertEquals(src, outputStream.getBuffer().toString()); - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - } - - @Test - public void pump_succ() throws Throwable { - do_pump_succ(null); - do_pump_succ(context); - } - - public void do_pump_outputNotClose(Context context) throws Throwable { - run(context, false); - - Assert.assertEquals(src, outputStream.getBuffer().toString()); - Assert.assertFalse(outputStreamClosed); - } - - @Test - public void pump_outputNotClose() throws Throwable { - do_pump_outputNotClose(null); - do_pump_outputNotClose(context); - } - - public void pump_error(Context context) { - try { - run(context, true); - Assert.fail("must throw exception"); - } catch (Throwable e) { - Assert.assertThat(e, Matchers.instanceOf(ExecutionException.class)); - Assert.assertThat(e.getCause(), Matchers.sameInstance(error)); - } - - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - } - - @Test - public void pump_read_error() throws IOException { - new MockUp() { - @Mock - void readInWorker(Future future) { - future.fail(error); - } - }; - new Expectations(IOUtils.class) { - { - IOUtils.copyLarge((InputStream) any, (OutputStream) any); - result = error; - } - }; - - pump_error(null); - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - - inputStreamClosed = false; - outputStreamClosed = false; - pump_error(context); - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - } - - @Test - public void pump_write_error() throws IOException { - new MockUp() { - @Mock - void write(byte[] b) throws IOException { - throw error; - } - }; - new Expectations(IOUtils.class) { - { - IOUtils.copyLarge((InputStream) any, (OutputStream) any); - result = error; - } - }; - - pump_error(null); - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - - inputStreamClosed = false; - outputStreamClosed = false; - pump_error(context); - Assert.assertTrue(inputStreamClosed); - Assert.assertTrue(outputStreamClosed); - } -} diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpImpl.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpImpl.java deleted file mode 100644 index 3380550e100..00000000000 --- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/stream/TestPumpImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.foundation.vertx.stream; - -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.streams.ReadStream; -import io.vertx.core.streams.WriteStream; -import mockit.Expectations; -import mockit.Mocked; - -public class TestPumpImpl { - - @Test - public void testPumpWithPending(@Mocked ReadStream rs, @Mocked WriteStream ws, @Mocked Buffer zeroBuf, - @Mocked Buffer contentBuf) { - PumpImplEx pump = new PumpImplEx<>(rs, ws); - Handler handler = pump.getDataHandler(); - new Expectations() { - { - zeroBuf.length(); - result = 0; - contentBuf.length(); - result = 1; - } - }; - handler.handle(zeroBuf); - handler.handle(contentBuf); - Assert.assertEquals(1, pump.numberPumped()); - handler.handle(contentBuf); - Assert.assertEquals(2, pump.numberPumped()); - } -} diff --git a/foundations/foundation-vertx/src/test/resources/log4j.properties b/foundations/foundation-vertx/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/foundations/foundation-vertx/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/foundations/pom.xml b/foundations/pom.xml index 8ba8bc477ab..7b3f55d334a 100644 --- a/foundations/pom.xml +++ b/foundations/pom.xml @@ -21,13 +21,14 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default foundations Java Chassis::Foundations pom + foundation-spi foundation-vertx foundation-common foundation-config @@ -35,5 +36,6 @@ foundation-ssl foundation-test-scaffolding foundation-protobuf + foundation-registry diff --git a/governance/pom.xml b/governance/pom.xml new file mode 100644 index 00000000000..3f78c36ade5 --- /dev/null +++ b/governance/pom.xml @@ -0,0 +1,100 @@ + + + + + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + 4.0.0 + + servicecomb-governance + Java Chassis::Governance + + + + org.apache.servicecomb + foundation-common + + + io.github.resilience4j + resilience4j-all + + + io.github.resilience4j + resilience4j-micrometer + + + io.micrometer + micrometer-core + + + org.apache.commons + commons-lang3 + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.yaml + snakeyaml + + + com.google.guava + guava + + + com.google.guava + failureaccess + test + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-test + test + + + io.micrometer + micrometer-registry-prometheus + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + diff --git a/governance/src/main/java/org/apache/servicecomb/governance/GovernanceCommonConfiguration.java b/governance/src/main/java/org/apache/servicecomb/governance/GovernanceCommonConfiguration.java new file mode 100644 index 00000000000..b5fd042a723 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/GovernanceCommonConfiguration.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.Map; + +import org.apache.servicecomb.governance.handler.BulkheadHandler; +import org.apache.servicecomb.governance.handler.CircuitBreakerHandler; +import org.apache.servicecomb.governance.handler.FaultInjectionHandler; +import org.apache.servicecomb.governance.handler.GovernanceCacheHandler; +import org.apache.servicecomb.governance.handler.IdentifierRateLimitingHandler; +import org.apache.servicecomb.governance.handler.InstanceBulkheadHandler; +import org.apache.servicecomb.governance.handler.InstanceIsolationHandler; +import org.apache.servicecomb.governance.handler.LoadBalanceHandler; +import org.apache.servicecomb.governance.handler.MapperHandler; +import org.apache.servicecomb.governance.handler.RateLimitingHandler; +import org.apache.servicecomb.governance.handler.RetryHandler; +import org.apache.servicecomb.governance.handler.TimeLimiterHandler; +import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension; +import org.apache.servicecomb.governance.handler.ext.AbstractInstanceIsolationExtension; +import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.governance.marker.operator.CompareOperator; +import org.apache.servicecomb.governance.marker.operator.ContainsOperator; +import org.apache.servicecomb.governance.marker.operator.ExactOperator; +import org.apache.servicecomb.governance.marker.operator.MatchOperator; +import org.apache.servicecomb.governance.marker.operator.PrefixOperator; +import org.apache.servicecomb.governance.marker.operator.SuffixOperator; +import org.apache.servicecomb.governance.properties.BulkheadProperties; +import org.apache.servicecomb.governance.properties.CircuitBreakerProperties; +import org.apache.servicecomb.governance.properties.FaultInjectionProperties; +import org.apache.servicecomb.governance.properties.GovernanceCacheProperties; +import org.apache.servicecomb.governance.properties.IdentifierRateLimitProperties; +import org.apache.servicecomb.governance.properties.InstanceBulkheadProperties; +import org.apache.servicecomb.governance.properties.InstanceIsolationProperties; +import org.apache.servicecomb.governance.properties.LoadBalanceProperties; +import org.apache.servicecomb.governance.properties.MapperProperties; +import org.apache.servicecomb.governance.properties.MatchProperties; +import org.apache.servicecomb.governance.properties.RateLimitProperties; +import org.apache.servicecomb.governance.properties.RetryProperties; +import org.apache.servicecomb.governance.properties.TimeLimiterProperties; +import org.apache.servicecomb.governance.service.MatchersService; +import org.apache.servicecomb.governance.service.MatchersServiceImpl; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.micrometer.core.instrument.MeterRegistry; + +@Configuration +public class GovernanceCommonConfiguration { + // properties configuration + @Bean + public BulkheadProperties scbBulkheadProperties() { + return new BulkheadProperties(); + } + + @Bean + public InstanceBulkheadProperties scbInstanceBulkheadProperties() { + return new InstanceBulkheadProperties(); + } + + @Bean + public CircuitBreakerProperties scbCircuitBreakerProperties() { + return new CircuitBreakerProperties(); + } + + @Bean + public InstanceIsolationProperties scbInstanceIsolationProperties() { + return new InstanceIsolationProperties(); + } + + @Bean + public MatchProperties scbMatchProperties() { + return new MatchProperties(); + } + + @Bean + public RateLimitProperties scbRateLimitProperties() { + return new RateLimitProperties(); + } + + @Bean + public IdentifierRateLimitProperties scbIdentifierRateLimitProperties() { + return new IdentifierRateLimitProperties(); + } + + @Bean + public RetryProperties scbRetryProperties() { + return new RetryProperties(); + } + + @Bean + public TimeLimiterProperties scbTimeLimiterProperties() { + return new TimeLimiterProperties(); + } + + @Bean + public GovernanceCacheProperties scbCacheProperties() { + return new GovernanceCacheProperties(); + } + + @Bean + public FaultInjectionProperties scbFaultInjectionProperties() { + return new FaultInjectionProperties(); + } + + @Bean + public LoadBalanceProperties scbLoadBalanceProperties() { + return new LoadBalanceProperties(); + } + + @Bean + public MapperProperties scbMapperProperties() { + return new MapperProperties(); + } + + // handlers configuration + @Bean + public BulkheadHandler scbBulkheadHandler(BulkheadProperties scbBulkheadProperties) { + return new BulkheadHandler(scbBulkheadProperties); + } + + @Bean + public InstanceBulkheadHandler scbInstanceBulkheadHandler(InstanceBulkheadProperties scbInstanceBulkheadProperties) { + return new InstanceBulkheadHandler(scbInstanceBulkheadProperties); + } + + @Bean + public LoadBalanceHandler scbLoadBalanceHandler(LoadBalanceProperties loadBalanceProperties) { + return new LoadBalanceHandler(loadBalanceProperties); + } + + @Bean + public CircuitBreakerHandler scbCircuitBreakerHandler(CircuitBreakerProperties scbCircuitBreakerProperties, + AbstractCircuitBreakerExtension circuitBreakerExtension) { + return new CircuitBreakerHandler(scbCircuitBreakerProperties, circuitBreakerExtension); + } + + @Bean + public InstanceIsolationHandler scbInstanceIsolationHandler(InstanceIsolationProperties scbInstanceIsolationProperties, + AbstractInstanceIsolationExtension isolationExtension, + ObjectProvider meterRegistry) { + return new InstanceIsolationHandler(scbInstanceIsolationProperties, isolationExtension, meterRegistry); + } + + @Bean + public RateLimitingHandler scbRateLimitingHandler(RateLimitProperties rateLimitProperties) { + return new RateLimitingHandler(rateLimitProperties); + } + + @Bean + public IdentifierRateLimitingHandler scbIdentifierRateLimitingHandler( + IdentifierRateLimitProperties identifierRateLimitProperties) { + return new IdentifierRateLimitingHandler(identifierRateLimitProperties); + } + + @Bean + public RetryHandler scbRetryHandler(RetryProperties retryProperties, AbstractRetryExtension retryExtension) { + return new RetryHandler(retryProperties, retryExtension); + } + + @Bean + public TimeLimiterHandler scbTimeLimiterHandler(TimeLimiterProperties timeLimiterProperties) { + return new TimeLimiterHandler(timeLimiterProperties); + } + + @Bean + public GovernanceCacheHandler scbGovernanceCacheHandler(GovernanceCacheProperties cacheProperties) { + return new GovernanceCacheHandler(cacheProperties); + } + + @Bean + public FaultInjectionHandler scbFaultInjectionHandler(FaultInjectionProperties scbFaultInjectionProperties) { + return new FaultInjectionHandler(scbFaultInjectionProperties); + } + + @Bean + public MapperHandler scbMapperHandler(MapperProperties scbMapperProperties) { + return new MapperHandler(scbMapperProperties); + } + + // request processor + @Bean + public RequestProcessor scbRequestProcessor(Map operatorMap) { + return new RequestProcessor(operatorMap); + } + + // matchers + @Bean + public MatchersService scbMatchersService(RequestProcessor requestProcessor, MatchProperties scbMatchProperties) { + return new MatchersServiceImpl(requestProcessor, scbMatchProperties); + } + + @Bean + public MatchersManager scbMatchersManager(MatchersService matchersService) { + return new MatchersManager(matchersService); + } + + // operators + @Bean + public CompareOperator scbCompareOperator() { + return new CompareOperator(); + } + + @Bean + public ContainsOperator scbContainsOperator() { + return new ContainsOperator(); + } + + @Bean + public ExactOperator scbExactOperator() { + return new ExactOperator(); + } + + @Bean + public PrefixOperator scbPrefixOperator() { + return new PrefixOperator(); + } + + @Bean + public SuffixOperator scbSuffixOperator() { + return new SuffixOperator(); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java new file mode 100644 index 00000000000..00caaafdbff --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.AbstractPolicy; +import org.apache.servicecomb.governance.service.MatchersService; + +public class MatchersManager { + private MatchersService matchersService; + + public MatchersManager(MatchersService matchersService) { + this.matchersService = matchersService; + } + + public T match(GovernanceRequestExtractor requestExtractor, Map policies) { + List sortPolicies = new ArrayList<>(policies.size()); + sortPolicies.addAll(policies.values()); + sortPolicies.sort(T::compareTo); + + for (T policy : sortPolicies) { + if (matchersService.checkMatch(requestExtractor, policy.getName())) { + return policy; + } + } + return null; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MicroserviceMeta.java b/governance/src/main/java/org/apache/servicecomb/governance/MicroserviceMeta.java new file mode 100644 index 00000000000..4aac6e6d813 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/MicroserviceMeta.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +public interface MicroserviceMeta { + String getName(); + + String getVersion(); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/entity/Configurable.java b/governance/src/main/java/org/apache/servicecomb/governance/entity/Configurable.java new file mode 100644 index 00000000000..ad15a84ac0c --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/entity/Configurable.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.entity; + +/** + * Indicates a object can be configure in configuration file or config center. + */ +public abstract class Configurable { + protected String name; + + protected String services; + + public abstract boolean isValid(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getServices() { + return this.services; + } + + public void setServices(String services) { + this.services = services; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceConfigurationChangedEvent.java b/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceConfigurationChangedEvent.java new file mode 100644 index 00000000000..bce4ec729e7 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceConfigurationChangedEvent.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.event; + +import java.util.Set; + +public class GovernanceConfigurationChangedEvent { + private final Set changedConfigurations; + + public GovernanceConfigurationChangedEvent(Set changedConfigurations) { + this.changedConfigurations = changedConfigurations; + } + + public Set getChangedConfigurations() { + return changedConfigurations; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceEventManager.java b/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceEventManager.java new file mode 100644 index 00000000000..a89103174a2 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/event/GovernanceEventManager.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.event; + +import com.google.common.eventbus.EventBus; + +public class GovernanceEventManager { + private static final EventBus eventBus = new EventBus(); + + public static EventBus getEventBus() { + return eventBus; + } + + public static void post(Object event) { + eventBus.post(event); + } + + public static void register(Object subscriber) { + eventBus.register(subscriber); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/exception/IllegalArgsOperatorException.java b/governance/src/main/java/org/apache/servicecomb/governance/exception/IllegalArgsOperatorException.java new file mode 100644 index 00000000000..a00502b33b5 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/exception/IllegalArgsOperatorException.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.exception; + +public class IllegalArgsOperatorException extends RuntimeException { + private static final long serialVersionUID = 793575987576638624L; + + public IllegalArgsOperatorException(String message) { + super(message); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java new file mode 100644 index 00000000000..d28392e413c --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import org.apache.servicecomb.governance.MatchersManager; +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.AbstractPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.Subscribe; + +import io.micrometer.core.instrument.MeterRegistry; + +public abstract class AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGovernanceHandler.class); + + protected final DisposableMap processors; + + private final Object lock = new Object(); + + protected MatchersManager matchersManager; + + protected MeterRegistry meterRegistry; + + protected AbstractGovernanceHandler() { + GovernanceEventManager.register(this); + processors = new DisposableMap<>(this::onConfigurationChanged); + } + + @Autowired + public void setMatchersManager(MatchersManager matchersManager) { + this.matchersManager = matchersManager; + } + + @Autowired(required = false) + public void setMeterRegistry(MeterRegistry meterRegistry) { + this.meterRegistry = meterRegistry; + } + + public PROCESSOR getActuator(GovernanceRequestExtractor requestExtractor) { + POLICY policy = matchPolicy(requestExtractor); + if (policy == null) { + return null; + } + + String key = createKey(requestExtractor, policy); + if (key == null) { + return null; + } + + Disposable processor = processors.get(key); + if (processor == null) { + synchronized (lock) { + processor = processors.get(key); + if (processor == null) { + processor = createProcessor(key, requestExtractor, policy); + processors.put(key, processor); + } + } + } + + return processor.get(); + } + + protected abstract String createKey(GovernanceRequestExtractor requestExtractor, POLICY policy); + + protected abstract POLICY matchPolicy(GovernanceRequestExtractor requestExtractor); + + protected abstract Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + POLICY policy); + + protected void onConfigurationChanged(String key) { + Disposable processor = processors.remove(key); + if (processor != null) { + LOGGER.info("remove governance processor {}", key); + processor.dispose(); + } + } + + @Subscribe + public void onDynamicConfigurationListener(GovernanceConfigurationChangedEvent event) { + event.getChangedConfigurations().forEach(this::onConfigurationChanged); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java new file mode 100644 index 00000000000..12d9ddc4eb2 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.BulkheadPolicy; +import org.apache.servicecomb.governance.properties.BulkheadProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadConfig; +import io.github.resilience4j.bulkhead.BulkheadRegistry; +import io.github.resilience4j.micrometer.tagged.BulkheadMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedBulkheadMetrics; + +public class BulkheadHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(BulkheadHandler.class); + + private final BulkheadProperties bulkheadProperties; + + public BulkheadHandler(BulkheadProperties bulkheadProperties) { + this.bulkheadProperties = bulkheadProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, BulkheadPolicy policy) { + return bulkheadProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public BulkheadPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, bulkheadProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, BulkheadPolicy policy) { + return getBulkhead(key, policy); + } + + private Disposable getBulkhead(String key, BulkheadPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + BulkheadConfig config = BulkheadConfig.custom() + .maxConcurrentCalls(policy.getMaxConcurrentCalls()) + .maxWaitDuration(Duration.parse(policy.getMaxWaitDuration())) + .build(); + + BulkheadRegistry registry = BulkheadRegistry.of(config); + if (meterRegistry != null) { + TaggedBulkheadMetrics + .ofBulkheadRegistry(BulkheadMetricNames.custom() + .availableConcurrentCallsMetricName(bulkheadProperties.getConfigKey() + ".available.concurrent.calls") + .maxAllowedConcurrentCallsMetricName( + bulkheadProperties.getConfigKey() + ".max.allowed.concurrent.calls").build(), registry) + .bindTo(meterRegistry); + } + return new DisposableBulkhead(key, registry, registry.bulkhead(key)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java new file mode 100644 index 00000000000..39082661b24 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; +import org.apache.servicecomb.governance.properties.CircuitBreakerProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; +import io.github.resilience4j.micrometer.tagged.CircuitBreakerMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics; + +public class CircuitBreakerHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(CircuitBreakerHandler.class); + + private final CircuitBreakerProperties circuitBreakerProperties; + + private final AbstractCircuitBreakerExtension circuitBreakerExtension; + + public CircuitBreakerHandler(CircuitBreakerProperties circuitBreakerProperties, + AbstractCircuitBreakerExtension circuitBreakerExtension) { + this.circuitBreakerProperties = circuitBreakerProperties; + this.circuitBreakerExtension = circuitBreakerExtension; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, CircuitBreakerPolicy policy) { + return this.circuitBreakerProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public CircuitBreakerPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, circuitBreakerProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + CircuitBreakerPolicy policy) { + return getCircuitBreaker(key, policy); + } + + private Disposable getCircuitBreaker(String key, CircuitBreakerPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy); + + CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() + .failureRateThreshold(policy.getFailureRateThreshold()) + .slowCallRateThreshold(policy.getSlowCallRateThreshold()) + .waitDurationInOpenState(Duration.parse(policy.getWaitDurationInOpenState())) + .slowCallDurationThreshold(Duration.parse(policy.getSlowCallDurationThreshold())) + .permittedNumberOfCallsInHalfOpenState(policy.getPermittedNumberOfCallsInHalfOpenState()) + .minimumNumberOfCalls(policy.getMinimumNumberOfCalls()) + .slidingWindowType(policy.getSlidingWindowTypeEnum()) + .slidingWindowSize(Integer.parseInt(policy.getSlidingWindowSize())) + .recordException(e -> circuitBreakerExtension.isFailedResult(policy.getRecordFailureStatus(), e)) + .recordResult(r -> circuitBreakerExtension.isFailedResult(policy.getRecordFailureStatus(), r)) + .build(); + CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); + if (meterRegistry != null) { + TaggedCircuitBreakerMetrics + .ofCircuitBreakerRegistry(CircuitBreakerMetricNames.custom() + .callsMetricName(this.circuitBreakerProperties.getConfigKey() + ".calls") + .notPermittedCallsMetricName(this.circuitBreakerProperties.getConfigKey() + ".not.permitted.calls") + .stateMetricName(this.circuitBreakerProperties.getConfigKey() + ".state") + .bufferedCallsMetricName(this.circuitBreakerProperties.getConfigKey() + ".buffered.calls") + .slowCallsMetricName(this.circuitBreakerProperties.getConfigKey() + ".slow.calls") + .failureRateMetricName(this.circuitBreakerProperties.getConfigKey() + ".failure.rate") + .slowCallRateMetricName(this.circuitBreakerProperties.getConfigKey() + ".slow.call.rate") + .build(), circuitBreakerRegistry) + .bindTo(meterRegistry); + } + return new DisposableCircuitBreaker(key, circuitBreakerRegistry, + circuitBreakerRegistry.circuitBreaker(key, circuitBreakerConfig)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/Disposable.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/Disposable.java new file mode 100644 index 00000000000..8f6e68909da --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/Disposable.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +public abstract class Disposable { + private long lastAccessed; + + protected Disposable() { + lastAccessed = System.currentTimeMillis(); + } + + public abstract void dispose(); + + public V get() { + lastAccessed = System.currentTimeMillis(); + return getValue(); + } + + public abstract V getValue(); + + public abstract String getKey(); + + public long lastAccessed() { + return lastAccessed; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableBulkhead.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableBulkhead.java new file mode 100644 index 00000000000..41f7ccc5212 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableBulkhead.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadRegistry; + +public class DisposableBulkhead extends Disposable { + private final String key; + + private final BulkheadRegistry bulkheadRegistry; + + private final Bulkhead bulkhead; + + public DisposableBulkhead(String key, BulkheadRegistry bulkheadRegistry, + Bulkhead bulkhead) { + this.key = key; + this.bulkheadRegistry = bulkheadRegistry; + this.bulkhead = bulkhead; + } + + @Override + public void dispose() { + bulkheadRegistry.remove(key); + } + + @Override + public Bulkhead getValue() { + return bulkhead; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableCircuitBreaker.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableCircuitBreaker.java new file mode 100644 index 00000000000..d85292ee593 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableCircuitBreaker.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; + +public class DisposableCircuitBreaker extends Disposable { + private final CircuitBreaker circuitBreaker; + + private final CircuitBreakerRegistry circuitBreakerRegistry; + + private final String key; + + public DisposableCircuitBreaker(String key, CircuitBreakerRegistry registry, CircuitBreaker circuitBreaker) { + this.key = key; + this.circuitBreaker = circuitBreaker; + this.circuitBreakerRegistry = registry; + } + + @Override + public void dispose() { + this.circuitBreakerRegistry.remove(key); + } + + @Override + public CircuitBreaker getValue() { + return circuitBreaker; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableHolder.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableHolder.java new file mode 100644 index 00000000000..9108df2a91a --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableHolder.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +public class DisposableHolder extends Disposable { + private final E e; + + private final String key; + + public DisposableHolder(String key, E e) { + this.key = key; + this.e = e; + } + + @Override + public void dispose() { + + } + + @Override + public E getValue() { + return e; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableMap.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableMap.java new file mode 100644 index 00000000000..d5d78668fe0 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableMap.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * check if some items are expired when put new item to map and remove expired items. + */ +public class DisposableMap extends ConcurrentHashMap> { + private static final long serialVersionUID = 7249069246763182397L; + + public interface RemoveListener { + void onRemoveEntry(String k); + } + + private static final int EXPIRE_TIME = 10 * 60 * 1000; + + private final RemoveListener listener; + + public DisposableMap(RemoveListener listener) { + this.listener = listener; + } + + @Override + public Disposable put(String key, Disposable value) { + Disposable result = super.put(key, value); + + checkExpired(); + + return result; + } + + private void checkExpired() { + List expired = new ArrayList<>(); + this.values().forEach(v -> { + if (System.currentTimeMillis() - v.lastAccessed() >= EXPIRE_TIME) { + expired.add(v.getKey()); + } + }); + expired.forEach(listener::onRemoveEntry); + } + + @Override + public Disposable get(Object key) { + return super.get(key); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRateLimiter.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRateLimiter.java new file mode 100644 index 00000000000..a078cb58215 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRateLimiter.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RateLimiterRegistry; + +public class DisposableRateLimiter extends Disposable { + private final String key; + + private final RateLimiter rateLimiter; + + private final RateLimiterRegistry registry; + + public DisposableRateLimiter(String key, RateLimiter rateLimiter, + RateLimiterRegistry registry) { + this.key = key; + this.rateLimiter = rateLimiter; + this.registry = registry; + } + + @Override + public void dispose() { + registry.remove(key); + } + + @Override + public RateLimiter getValue() { + return rateLimiter; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRetry.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRetry.java new file mode 100644 index 00000000000..c7e7be86b6f --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableRetry.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import io.github.resilience4j.retry.Retry; +import io.github.resilience4j.retry.RetryRegistry; + +public class DisposableRetry extends Disposable { + private final String key; + + private final RetryRegistry registry; + + private final Retry retry; + + public DisposableRetry(String key, RetryRegistry registry, Retry retry) { + this.key = key; + this.registry = registry; + this.retry = retry; + } + + @Override + public void dispose() { + registry.remove(key); + } + + @Override + public Retry getValue() { + return retry; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java new file mode 100644 index 00000000000..4a23b72d69c --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/DisposableTimeLimiter.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import io.github.resilience4j.timelimiter.TimeLimiter; +import io.github.resilience4j.timelimiter.TimeLimiterRegistry; + +public class DisposableTimeLimiter extends Disposable { + private final String key; + + private final TimeLimiterRegistry timeLimiterRegistry; + + private final TimeLimiter timeLimiter; + + public DisposableTimeLimiter(String key, TimeLimiterRegistry registry, TimeLimiter timeLimiter) { + this.key = key; + this.timeLimiterRegistry = registry; + this.timeLimiter = timeLimiter; + } + + @Override + public void dispose() { + timeLimiterRegistry.remove(key); + } + + @Override + public TimeLimiter getValue() { + return timeLimiter; + } + + @Override + public String getKey() { + return key; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/FaultInjectionHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/FaultInjectionHandler.java new file mode 100644 index 00000000000..e44b1685fe5 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/FaultInjectionHandler.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; +import org.apache.servicecomb.governance.processor.injection.Fault; +import org.apache.servicecomb.governance.processor.injection.FaultInjectionUtil; +import org.apache.servicecomb.governance.properties.FaultInjectionProperties; + +public class FaultInjectionHandler extends AbstractGovernanceHandler { + + private final FaultInjectionProperties faultInjectionProperties; + + public FaultInjectionHandler(FaultInjectionProperties faultInjectionProperties) { + this.faultInjectionProperties = faultInjectionProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, FaultInjectionPolicy policy) { + return FaultInjectionProperties.MATCH_FAULT_INJECTION_KEY + "." + policy.getName(); + } + + @Override + public FaultInjectionPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, faultInjectionProperties.getParsedEntity()); + } + + @Override + protected DisposableHolder createProcessor(String key, GovernanceRequestExtractor requestExtractor, + FaultInjectionPolicy policy) { + return new DisposableHolder<>(key, FaultInjectionUtil.getFault(key, policy)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java new file mode 100644 index 00000000000..7e7b6e6dd72 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovernanceCacheHandler.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.GovernanceCachePolicy; +import org.apache.servicecomb.governance.properties.GovernanceCacheProperties; +import org.apache.servicecomb.governance.service.GovernanceCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +public class GovernanceCacheHandler + extends AbstractGovernanceHandler, GovernanceCachePolicy> { + private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceCacheHandler.class); + + private final GovernanceCacheProperties cacheProperties; + + public GovernanceCacheHandler(GovernanceCacheProperties cacheProperties) { + this.cacheProperties = cacheProperties; + } + + @Override + public GovernanceCachePolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, cacheProperties.getParsedEntity()); + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, GovernanceCachePolicy policy) { + return cacheProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + protected Disposable> createProcessor(String key, GovernanceRequestExtractor requestExtractor, + GovernanceCachePolicy policy) { + return getGovernanceCache(key, policy); + } + + protected Disposable> getGovernanceCache(String key, GovernanceCachePolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + Cache cache = CacheBuilder.newBuilder() + .expireAfterWrite(Duration.parse(policy.getTtl())) + .maximumSize(policy.getMaximumSize()) + .concurrencyLevel(policy.getConcurrencyLevel()) + .build(); + GovernanceCache governanceCache = GovernanceCache.of(cache); + return new DisposableHolder<>(key, governanceCache); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/IdentifierRateLimitingHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/IdentifierRateLimitingHandler.java new file mode 100644 index 00000000000..26751c64dfa --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/IdentifierRateLimitingHandler.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.IdentifierRateLimitingPolicy; +import org.apache.servicecomb.governance.properties.IdentifierRateLimitProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.micrometer.tagged.RateLimiterMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedRateLimiterMetrics; +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RateLimiterConfig; +import io.github.resilience4j.ratelimiter.RateLimiterRegistry; + +public class IdentifierRateLimitingHandler extends + AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(IdentifierRateLimitingHandler.class); + + private final IdentifierRateLimitProperties rateLimitProperties; + + public IdentifierRateLimitingHandler(IdentifierRateLimitProperties rateLimitProperties) { + this.rateLimitProperties = rateLimitProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, IdentifierRateLimitingPolicy policy) { + if (StringUtils.isEmpty(policy.getIdentifier()) || + StringUtils.isEmpty(requestExtractor.header(policy.getIdentifier()))) { + LOGGER.info("identifier rate limiting is not properly configured, identifier is empty."); + return null; + } + return this.rateLimitProperties.getConfigKey() + + "." + policy.getName() + + "." + requestExtractor.header(policy.getIdentifier()); + } + + @Override + protected void onConfigurationChanged(String key) { + if (key.startsWith(this.rateLimitProperties.getConfigKey())) { + for (String processorKey : processors.keySet()) { + if (processorKey.startsWith(key)) { + Disposable processor = processors.remove(processorKey); + if (processor != null) { + LOGGER.info("remove identifier rate limiting processor {}", key); + processor.dispose(); + } + } + } + } + } + + @Override + public IdentifierRateLimitingPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, rateLimitProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + IdentifierRateLimitingPolicy policy) { + return getRateLimiter(key, policy); + } + + private Disposable getRateLimiter(String key, IdentifierRateLimitingPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + RateLimiterConfig config = RateLimiterConfig.custom() + .limitForPeriod(policy.getRate()) + .limitRefreshPeriod(Duration.parse(policy.getLimitRefreshPeriod())) + .timeoutDuration(Duration.parse(policy.getTimeoutDuration())) + .build(); + RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.of(config); + if (meterRegistry != null) { + TaggedRateLimiterMetrics + .ofRateLimiterRegistry(RateLimiterMetricNames.custom() + .availablePermissionsMetricName( + this.rateLimitProperties.getConfigKey() + ".available.permissions") + .waitingThreadsMetricName(this.rateLimitProperties.getConfigKey() + ".waiting.threads") + .build(), + rateLimiterRegistry) + .bindTo(meterRegistry); + } + return new DisposableRateLimiter(key, rateLimiterRegistry.rateLimiter(key), rateLimiterRegistry); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceBulkheadHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceBulkheadHandler.java new file mode 100644 index 00000000000..e90f2472915 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceBulkheadHandler.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.BulkheadPolicy; +import org.apache.servicecomb.governance.properties.InstanceBulkheadProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadConfig; +import io.github.resilience4j.bulkhead.BulkheadRegistry; +import io.github.resilience4j.micrometer.tagged.BulkheadMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedBulkheadMetrics; + +public class InstanceBulkheadHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(InstanceBulkheadHandler.class); + + private final InstanceBulkheadProperties bulkheadProperties; + + public InstanceBulkheadHandler(InstanceBulkheadProperties bulkheadProperties) { + this.bulkheadProperties = bulkheadProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, BulkheadPolicy policy) { + return this.bulkheadProperties.getConfigKey() + + "." + policy.getName() + + "." + requestExtractor.serviceName() + + "." + requestExtractor.instanceId(); + } + + @Override + protected void onConfigurationChanged(String key) { + if (key.startsWith(this.bulkheadProperties.getConfigKey())) { + for (String processorKey : processors.keySet()) { + if (processorKey.startsWith(key)) { + Disposable processor = processors.remove(processorKey); + if (processor != null) { + LOGGER.info("remove instance bulkhead processor {}", key); + processor.dispose(); + } + } + } + } + } + + @Override + public BulkheadPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + if (StringUtils.isEmpty(requestExtractor.serviceName()) || StringUtils.isEmpty( + requestExtractor.instanceId())) { + LOGGER.info("Instance bulkhead is not properly configured, service id or instance id is empty."); + return null; + } + return matchersManager.match(requestExtractor, bulkheadProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, BulkheadPolicy policy) { + return getBulkhead(key, policy); + } + + private Disposable getBulkhead(String key, BulkheadPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + BulkheadConfig config = BulkheadConfig.custom() + .maxConcurrentCalls(policy.getMaxConcurrentCalls()) + .maxWaitDuration(Duration.parse(policy.getMaxWaitDuration())) + .build(); + + BulkheadRegistry registry = BulkheadRegistry.of(config); + if (meterRegistry != null) { + TaggedBulkheadMetrics + .ofBulkheadRegistry(BulkheadMetricNames.custom() + .availableConcurrentCallsMetricName( + this.bulkheadProperties.getConfigKey() + ".available.concurrent.calls") + .maxAllowedConcurrentCallsMetricName( + this.bulkheadProperties.getConfigKey() + ".max.allowed.concurrent.calls").build(), + registry) + .bindTo(meterRegistry); + } + return new DisposableBulkhead(key, registry, registry.bulkhead(key, config)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java new file mode 100644 index 00000000000..894dd170e99 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/InstanceIsolationHandler.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.handler.ext.AbstractInstanceIsolationExtension; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; +import org.apache.servicecomb.governance.properties.InstanceIsolationProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; + +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; +import io.github.resilience4j.micrometer.tagged.CircuitBreakerMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics; +import io.micrometer.core.instrument.MeterRegistry; + +public final class InstanceIsolationHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(InstanceIsolationHandler.class); + + private final InstanceIsolationProperties instanceIsolationProperties; + + private final AbstractInstanceIsolationExtension isolationExtension; + + private final MeterRegistry meterRegistry; + + public InstanceIsolationHandler(InstanceIsolationProperties instanceIsolationProperties, + AbstractInstanceIsolationExtension isolationExtension, + ObjectProvider meterRegistry) { + this.instanceIsolationProperties = instanceIsolationProperties; + this.isolationExtension = isolationExtension; + this.meterRegistry = meterRegistry.getIfAvailable(); + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, CircuitBreakerPolicy policy) { + return this.instanceIsolationProperties.getConfigKey() + + "." + policy.getName() + + "." + requestExtractor.serviceName() + + "." + requestExtractor.instanceId(); + } + + @Override + protected void onConfigurationChanged(String key) { + if (key.startsWith(this.instanceIsolationProperties.getConfigKey())) { + for (String processorKey : processors.keySet()) { + if (processorKey.startsWith(key)) { + Disposable circuitBreaker = processors.remove(processorKey); + if (circuitBreaker != null) { + LOGGER.info("remove instance isolation processor {}", key); + circuitBreaker.dispose(); + } + } + } + } + } + + @Override + public CircuitBreakerPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + if (StringUtils.isEmpty(requestExtractor.serviceName()) || StringUtils.isEmpty( + requestExtractor.instanceId())) { + LOGGER.debug("Isolation is not properly configured, service id or instance id is empty."); + return null; + } + return matchersManager.match(requestExtractor, instanceIsolationProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + CircuitBreakerPolicy policy) { + return getCircuitBreaker(key, policy); + } + + private Disposable getCircuitBreaker(String key, CircuitBreakerPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() + .failureRateThreshold(policy.getFailureRateThreshold()) + .slowCallRateThreshold(policy.getSlowCallRateThreshold()) + .waitDurationInOpenState(Duration.parse(policy.getWaitDurationInOpenState())) + .slowCallDurationThreshold(Duration.parse(policy.getSlowCallDurationThreshold())) + .permittedNumberOfCallsInHalfOpenState(policy.getPermittedNumberOfCallsInHalfOpenState()) + .minimumNumberOfCalls(policy.getMinimumNumberOfCalls()) + .slidingWindowType(policy.getSlidingWindowTypeEnum()) + .slidingWindowSize(Integer.parseInt(policy.getSlidingWindowSize())) + .recordException(e -> isolationExtension.isFailedResult(policy.getRecordFailureStatus(), e)) + .recordResult(r -> isolationExtension.isFailedResult(policy.getRecordFailureStatus(), r)) + .build(); + CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); + if (meterRegistry != null) { + TaggedCircuitBreakerMetrics + .ofCircuitBreakerRegistry(CircuitBreakerMetricNames.custom() + .callsMetricName(this.instanceIsolationProperties.getConfigKey() + ".calls") + .notPermittedCallsMetricName( + this.instanceIsolationProperties.getConfigKey() + ".not.permitted.calls") + .stateMetricName(this.instanceIsolationProperties.getConfigKey() + ".state") + .bufferedCallsMetricName(this.instanceIsolationProperties.getConfigKey() + ".buffered.calls") + .slowCallsMetricName(this.instanceIsolationProperties.getConfigKey() + ".slow.calls") + .failureRateMetricName(this.instanceIsolationProperties.getConfigKey() + ".failure.rate") + .slowCallRateMetricName(this.instanceIsolationProperties.getConfigKey() + ".slow.call.rate") + .build(), circuitBreakerRegistry) + .bindTo(meterRegistry); + } + return new DisposableCircuitBreaker(key, circuitBreakerRegistry, + circuitBreakerRegistry.circuitBreaker(key, circuitBreakerConfig)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/LoadBalanceHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/LoadBalanceHandler.java new file mode 100644 index 00000000000..ab549c759f2 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/LoadBalanceHandler.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.LoadBalancerPolicy; +import org.apache.servicecomb.governance.processor.loadbanlance.LoadBalance; +import org.apache.servicecomb.governance.properties.LoadBalanceProperties; + +public class LoadBalanceHandler extends AbstractGovernanceHandler { + + private final LoadBalanceProperties loadBalanceProperties; + + public LoadBalanceHandler(LoadBalanceProperties loadBalanceProperties) { + this.loadBalanceProperties = loadBalanceProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, LoadBalancerPolicy policy) { + return this.loadBalanceProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public LoadBalancerPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, loadBalanceProperties.getParsedEntity()); + } + + @Override + protected DisposableHolder createProcessor(String key, GovernanceRequestExtractor requestExtractor, + LoadBalancerPolicy policy) { + return new DisposableHolder<>(key, LoadBalance.getLoadBalance(key, policy)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/MapperHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/MapperHandler.java new file mode 100644 index 00000000000..53726a2b0e4 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/MapperHandler.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.MapperPolicy; +import org.apache.servicecomb.governance.processor.mapping.Mapper; +import org.apache.servicecomb.governance.properties.MapperProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MapperHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(RateLimitingHandler.class); + + private final MapperProperties mapperProperties; + + public MapperHandler(MapperProperties mapperProperties) { + this.mapperProperties = mapperProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, MapperPolicy policy) { + return mapperProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public MapperPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, mapperProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + MapperPolicy policy) { + return getMapper(key, policy); + } + + private Disposable getMapper(String key, MapperPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + return new DisposableHolder<>(key, Mapper.create(policy.getTarget())); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java new file mode 100644 index 00000000000..e70ae60f78e --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.RateLimitingPolicy; +import org.apache.servicecomb.governance.properties.RateLimitProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.micrometer.tagged.RateLimiterMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedRateLimiterMetrics; +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RateLimiterConfig; +import io.github.resilience4j.ratelimiter.RateLimiterRegistry; + +public class RateLimitingHandler extends AbstractGovernanceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(RateLimitingHandler.class); + + private final RateLimitProperties rateLimitProperties; + + public RateLimitingHandler(RateLimitProperties rateLimitProperties) { + this.rateLimitProperties = rateLimitProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, RateLimitingPolicy policy) { + return this.rateLimitProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public RateLimitingPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, rateLimitProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + RateLimitingPolicy policy) { + return getRateLimiter(key, policy); + } + + private Disposable getRateLimiter(String key, RateLimitingPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy.toString()); + + RateLimiterConfig config = RateLimiterConfig.custom() + .limitForPeriod(policy.getRate()) + .limitRefreshPeriod(Duration.parse(policy.getLimitRefreshPeriod())) + .timeoutDuration(Duration.parse(policy.getTimeoutDuration())) + .build(); + RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.of(config); + if (meterRegistry != null) { + TaggedRateLimiterMetrics + .ofRateLimiterRegistry(RateLimiterMetricNames.custom() + .availablePermissionsMetricName( + this.rateLimitProperties.getConfigKey() + ".available.permissions") + .waitingThreadsMetricName(this.rateLimitProperties.getConfigKey() + ".waiting.threads") + .build(), + rateLimiterRegistry) + .bindTo(meterRegistry); + } + return new DisposableRateLimiter(key, rateLimiterRegistry.rateLimiter(key), rateLimiterRegistry); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java new file mode 100644 index 00000000000..f7f2476f667 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.RetryPolicy; +import org.apache.servicecomb.governance.properties.RetryProperties; +import org.apache.servicecomb.governance.utils.GovernanceUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.core.IntervalFunction; +import io.github.resilience4j.micrometer.tagged.RetryMetricNames; +import io.github.resilience4j.micrometer.tagged.TaggedRetryMetrics; +import io.github.resilience4j.retry.Retry; +import io.github.resilience4j.retry.RetryConfig; +import io.github.resilience4j.retry.RetryRegistry; + +public class RetryHandler extends AbstractGovernanceHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RetryHandler.class); + + private final RetryProperties retryProperties; + + private final AbstractRetryExtension retryExtension; + + public RetryHandler(RetryProperties retryProperties, AbstractRetryExtension retryExtension) { + this.retryProperties = retryProperties; + this.retryExtension = retryExtension; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, RetryPolicy policy) { + return this.retryProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public RetryPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, retryProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + RetryPolicy policy) { + return getRetry(key, policy); + } + + private Disposable getRetry(String key, RetryPolicy retryPolicy) { + LOGGER.info("applying new policy {} for {}", key, retryPolicy.toString()); + + RetryConfig config = RetryConfig.custom() + .maxAttempts(retryPolicy.getMaxAttempts() + 1) + .retryOnResult(response -> retryExtension.isFailedResult(retryPolicy.getRetryOnResponseStatus(), response)) + .retryOnException(exception -> retryExtension.isFailedResult(retryPolicy.getRetryOnResponseStatus(), exception)) + .intervalFunction(getIntervalFunction(retryPolicy)) + .failAfterMaxAttempts(retryPolicy.isFailAfterMaxAttempts()) + .build(); + + RetryRegistry registry = RetryRegistry.of(config); + if (meterRegistry != null) { + TaggedRetryMetrics + .ofRetryRegistry(RetryMetricNames.custom() + .callsMetricName(this.retryProperties.getConfigKey() + ".calls") + .build(), + registry) + .bindTo(meterRegistry); + } + return new DisposableRetry(key, registry, registry.retry(key)); + } + + private IntervalFunction getIntervalFunction(RetryPolicy retryPolicy) { + if (GovernanceUtils.STRATEGY_RANDOM_BACKOFF.equals(retryPolicy.getRetryStrategy())) { + return IntervalFunction.ofExponentialRandomBackoff(Duration.parse(retryPolicy.getInitialInterval()), + retryPolicy.getMultiplier(), retryPolicy.getRandomizationFactor()); + } + return IntervalFunction.of(Duration.parse(retryPolicy.getWaitDuration())); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java new file mode 100644 index 00000000000..d9f03034d07 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/TimeLimiterHandler.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler; + +import java.time.Duration; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.TimeLimiterPolicy; +import org.apache.servicecomb.governance.properties.TimeLimiterProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.resilience4j.micrometer.tagged.TaggedTimeLimiterMetrics; +import io.github.resilience4j.micrometer.tagged.TimeLimiterMetricNames; +import io.github.resilience4j.timelimiter.TimeLimiter; +import io.github.resilience4j.timelimiter.TimeLimiterConfig; +import io.github.resilience4j.timelimiter.TimeLimiterRegistry; + +public class TimeLimiterHandler extends AbstractGovernanceHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(TimeLimiterHandler.class); + + private final TimeLimiterProperties timeLimiterProperties; + + public TimeLimiterHandler(TimeLimiterProperties timeLimiterProperties) { + this.timeLimiterProperties = timeLimiterProperties; + } + + @Override + protected String createKey(GovernanceRequestExtractor requestExtractor, TimeLimiterPolicy policy) { + return timeLimiterProperties.getConfigKey() + "." + policy.getName(); + } + + @Override + public TimeLimiterPolicy matchPolicy(GovernanceRequestExtractor requestExtractor) { + return matchersManager.match(requestExtractor, timeLimiterProperties.getParsedEntity()); + } + + @Override + public Disposable createProcessor(String key, GovernanceRequestExtractor requestExtractor, + TimeLimiterPolicy policy) { + return getTimeLimiter(key, policy); + } + + private Disposable getTimeLimiter(String key, TimeLimiterPolicy policy) { + LOGGER.info("applying new policy {} for {}", key, policy); + TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom() + .timeoutDuration(Duration.parse(policy.getTimeoutDuration())) + .cancelRunningFuture(policy.isCancelRunningFuture()) + .build(); + TimeLimiterRegistry timeLimiterRegistry = TimeLimiterRegistry.of(timeLimiterConfig); + if (meterRegistry != null) { + TaggedTimeLimiterMetrics.ofTimeLimiterRegistry(TimeLimiterMetricNames.custom() + .callsMetricName(timeLimiterProperties.getConfigKey() + ".calls") + .build(), timeLimiterRegistry).bindTo(meterRegistry); + } + return new DisposableTimeLimiter(key, timeLimiterRegistry, timeLimiterRegistry.timeLimiter(key)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractCircuitBreakerExtension.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractCircuitBreakerExtension.java new file mode 100644 index 00000000000..bf885a9003d --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractCircuitBreakerExtension.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +public abstract class AbstractCircuitBreakerExtension extends AbstractFailurePredictor { + +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractFailurePredictor.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractFailurePredictor.java new file mode 100644 index 00000000000..e7fea24f962 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractFailurePredictor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler.ext; + +import java.util.List; +import java.util.stream.IntStream; + +import org.apache.commons.lang3.StringUtils; + +public abstract class AbstractFailurePredictor implements FailurePredictor { + @Override + public boolean isFailedResult(List statusList, Object result) { + String statusCode = extractStatusCode(result); + if (StringUtils.isEmpty(statusCode)) { + return false; + } + return statusCodeContains(statusList, statusCode); + } + + protected abstract String extractStatusCode(Object result); + + protected static boolean statusCodeContains(List statusList, String responseStatus) { + return statusList.stream().anyMatch(status -> statusCodeMatch(status, responseStatus)); + } + + private static boolean statusCodeMatch(String status, String responseStatus) { + if (status == null) { + return false; + } + if (responseStatus.length() != status.length()) { + return false; + } + char[] statusChar = status.toCharArray(); + char[] responseChar = responseStatus.toCharArray(); + return IntStream.range(0, statusChar.length).noneMatch(i -> + statusChar[i] != responseChar[i] && statusChar[i] != 'x'); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractInstanceIsolationExtension.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractInstanceIsolationExtension.java new file mode 100644 index 00000000000..6b4a5a9934d --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractInstanceIsolationExtension.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +public abstract class AbstractInstanceIsolationExtension extends AbstractFailurePredictor { + +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractRetryExtension.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractRetryExtension.java new file mode 100644 index 00000000000..cd21bdacc24 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/AbstractRetryExtension.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +public abstract class AbstractRetryExtension extends AbstractFailurePredictor { + +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ClientRecoverPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ClientRecoverPolicy.java new file mode 100644 index 00000000000..fc8c86a55ae --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ClientRecoverPolicy.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +public interface ClientRecoverPolicy { + + T apply(Throwable th); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/FailurePredictor.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/FailurePredictor.java new file mode 100644 index 00000000000..c07ebe39bdd --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/FailurePredictor.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.handler.ext; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.SocketTimeoutException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.SSLHandshakeException; + +import com.google.common.collect.ImmutableMap; + +import io.netty.handler.ssl.SslHandshakeTimeoutException; +import io.vertx.core.VertxException; + +public interface FailurePredictor { + Map, List> STRICT_RETRIABLE = + ImmutableMap., List>builder() + .put(ConnectException.class, Collections.emptyList()) + .put(SocketTimeoutException.class, Collections.emptyList()) + /* + * deal with some special exceptions caused by the server side close the connection + */ + .put(IOException.class, Collections.singletonList("Connection reset by peer")) + .put(VertxException.class, Collections.singletonList("Connection was closed")) + .put(NoRouteToHostException.class, Collections.emptyList()) + .put(SSLHandshakeException.class, Collections.emptyList()) + .put(SslHandshakeTimeoutException.class, Collections.emptyList()) + .build(); + + boolean isFailedResult(List statusList, Object result); + + default boolean isFailedResult(List statusList, Throwable e) { + return canRetryForException(STRICT_RETRIABLE, e); + } + + static boolean canRetryForException(Map, List> retryList, + Throwable throwableToSearchIn) { + // retry on exception type on message match + int infiniteLoopPreventionCounter = 10; + while (throwableToSearchIn != null && infiniteLoopPreventionCounter > 0) { + infiniteLoopPreventionCounter--; + for (Entry, List> c : retryList.entrySet()) { + Class key = c.getKey(); + if (key.isAssignableFrom(throwableToSearchIn.getClass())) { + if (c.getValue() == null || c.getValue().isEmpty()) { + return true; + } else { + String msg = throwableToSearchIn.getMessage(); + for (String val : c.getValue()) { + if (val.equals(msg)) { + return true; + } + } + } + } + } + throwableToSearchIn = throwableToSearchIn.getCause(); + } + return false; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ServerRecoverPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ServerRecoverPolicy.java new file mode 100644 index 00000000000..4662c46dd38 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/handler/ext/ServerRecoverPolicy.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +public interface ServerRecoverPolicy { + + T apply(Throwable th); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/CustomMatcher.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/CustomMatcher.java new file mode 100644 index 00000000000..c6ec5363791 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/CustomMatcher.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.marker; + +public class CustomMatcher { + + private String customMatcherHandler; + + private String customMatcherParameters; + + public String getCustomMatcherHandler() { + return customMatcherHandler; + } + + public void setCustomMatcherHandler(String customMatcherHandler) { + this.customMatcherHandler = customMatcherHandler; + } + + public String getCustomMatcherParameters() { + return customMatcherParameters; + } + + public void setCustomMatcherParameters(String customMatcherParameters) { + this.customMatcherParameters = customMatcherParameters; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java new file mode 100644 index 00000000000..e3ac0b2abce --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequest.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker; + +import java.util.Collections; +import java.util.Map; + +import org.springframework.util.LinkedCaseInsensitiveMap; + +public class GovernanceRequest implements GovernanceRequestExtractor { + /** + * headers with this request, maybe null. + * For provider: headers indicates the request headers to me. + * For consumer: headers indicates the request headers to the target. + */ + private Map headers = Collections.emptyMap(); + + /** + * Queries with this request, maybe null. + * For provider: Queries indicates the request params to me. + * For consumer: Queries indicates the request params to the target. + */ + private Map queries = Collections.emptyMap(); + + /** + * api path with this request, maybe null. For REST, e.g. /foo/bar; For RPC, e.g. MySchema.sayHello + * For provider: uri indicates the request uri to me. + * For consumer: uri indicates the request uri to the target. + */ + private String apiPath; + + /** + * method with this request, maybe null. + * For provider: method indicates the request method to me. + * For consumer: method indicates the request method to the target. + */ + private String method; + + /** + * instance id with this request, maybe null. + * For provider: instanceId indicates who calls me. + * For consumer: instanceId indicates the target instance. + */ + private String instanceId; + + /** + * microservice id (microservice name or application name + microservice name) with this request, maybe null. + * For provider: serviceName indicates who calls me. + * For consumer: serviceName indicates the target service. + */ + private String serviceName; + + /** + * sourceRequest the source request for creating this governanceRequest + * For provider: uri indicates the request to me. + * For consumer: uri indicates the request to the target. + * the type of sourceRequest could be ClientRequest, ServerWebExchange, HttpRequest, HttpServletRequest and so on, + * User will use this request to extract the information he need + */ + private Object sourceRequest; + + @Override + public String header(String key) { + return headers.get(key); + } + + @Override + public String query(String key) { + return queries.get(key); + } + + public Map getHeaders() { + return headers; + } + + public Map getQueries() { + return queries; + } + + public void setHeaders(Map headers) { + Map temp = new LinkedCaseInsensitiveMap<>(); + temp.putAll(headers); + this.headers = temp; + } + + public void setQueries(Map queries) { + Map temp = new LinkedCaseInsensitiveMap<>(); + temp.putAll(queries); + this.queries = temp; + } + + @Override + public String apiPath() { + return apiPath; + } + + public void setApiPath(String apiPath) { + this.apiPath = apiPath; + } + + @Override + public String method() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + @Override + public String instanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + @Override + public String serviceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public Object sourceRequest() { + return sourceRequest; + } + + public void setSourceRequest(Object sourceRequest) { + this.sourceRequest = sourceRequest; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequestExtractor.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequestExtractor.java new file mode 100644 index 00000000000..28beb8e8384 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovernanceRequestExtractor.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker; + +public interface GovernanceRequestExtractor { + String apiPath(); + + String method(); + + String header(String key); + + String query(String key); + + String instanceId(); + + String serviceName(); + + Object sourceRequest(); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java new file mode 100644 index 00000000000..6fb18fada3d --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/Matcher.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.governance.marker.operator.RawOperator; + +public class Matcher { + private String name; + + private Map headers; + + private Map queries; + + private RawOperator apiPath; + + private List method; + + private String serviceName; + + private CustomMatcher customMatcher; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getQueries() { + return queries; + } + + public void setQueries(Map queries) { + this.queries = queries; + } + + public RawOperator getApiPath() { + return apiPath; + } + + public void setApiPath(RawOperator apiPath) { + this.apiPath = apiPath; + } + + public List getMethod() { + return method; + } + + public void setMethod(List method) { + this.method = method; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public CustomMatcher getCustomMatcher() { + return customMatcher; + } + + public void setCustomMatcher(CustomMatcher customMatcher) { + this.customMatcher = customMatcher; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java new file mode 100644 index 00000000000..9651d8a7740 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/RequestProcessor.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.marker.operator.MatchOperator; +import org.apache.servicecomb.governance.marker.operator.RawOperator; +import org.apache.servicecomb.governance.utils.CustomMatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Request Processor checks if a request matches a configuration. + */ +public class RequestProcessor implements ApplicationContextAware { + + private static final Logger LOGGER = LoggerFactory.getLogger(RequestProcessor.class); + + public static final String errorMessageForNotImplements = " didn't implement interface org.apache.servicecomb.governance.utils.CustomMatch"; + + public static final String errorMessageForAbstractClass = " should be a instantiable class rather than abstract class or other else"; + + public static final String infoMessageForCreatingClass = "is not in spring container, create one and register it to spring container"; + + private final Map operatorMap; + + private ApplicationContext applicationContext; + + public RequestProcessor(Map operatorMap) { + this.operatorMap = new HashMap<>(operatorMap.size()); + operatorMap.forEach((k, v) -> this.operatorMap.put(v.name(), v)); + } + + public boolean match(GovernanceRequestExtractor request, Matcher matcher) { + if (!methodMatch(request, matcher)) { + return false; + } + if (!apiPathMatch(request, matcher)) { + return false; + } + if (!headersMatch(request, matcher)) { + return false; + } + if (!queriesMatch(request, matcher)) { + return false; + } + if (!serviceNameMatch(request, matcher)) { + return false; + } + return customMatch(request, matcher); + } + + private boolean serviceNameMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getServiceName() == null) { + return true; + } + return matcher.getServiceName().equals(request.serviceName()); + } + + private boolean headersMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getHeaders() == null) { + return true; + } + for (Entry entry : matcher.getHeaders().entrySet()) { + if (request.header(entry.getKey()) == null || + !operatorMatch(request.header(entry.getKey()), entry.getValue())) { + return false; + } + } + return true; + } + + private boolean queriesMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getQueries() == null) { + return true; + } + for (Entry entry : matcher.getQueries().entrySet()) { + if (request.query(entry.getKey()) == null || + !operatorMatch(request.query(entry.getKey()), entry.getValue())) { + return false; + } + } + return true; + } + + private boolean apiPathMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getApiPath() == null) { + return true; + } + return operatorMatch(request.apiPath(), matcher.getApiPath()); + } + + private boolean methodMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getMethod() == null) { + return true; + } + return matcher.getMethod().contains(request.method()); + } + + private boolean operatorMatch(String str, RawOperator rawOperator) { + if (rawOperator.isEmpty()) { + return false; + } + + for (Entry entry : rawOperator.entrySet()) { + MatchOperator operator = operatorMap.get(entry.getKey()); + if (operator == null) { + LOGGER.error("unsupported operator:" + entry.getKey() + ", please use one of :" + operatorMap.keySet()); + return false; + } + if (!operator.match(str, entry.getValue())) { + return false; + } + } + return true; + } + + private boolean customMatch(GovernanceRequestExtractor request, Matcher matcher) { + if (matcher.getCustomMatcher() == null) { + return true; + } + String customMatcherHandlerName = matcher.getCustomMatcher().getCustomMatcherHandler(); + String customMatcherParameters = matcher.getCustomMatcher().getCustomMatcherParameters(); + + if (StringUtils.isEmpty(customMatcherHandlerName) || StringUtils.isEmpty(customMatcherParameters)) { + return true; + } + + CustomMatch customMatcherHandler = generateHandler(customMatcherHandlerName); + return customMatcherHandler.matchRequest(request, customMatcherParameters); + } + + private CustomMatch getBeanByHandlerName(String customMatcherHandler) { + Object extractObject = null; + if (applicationContext.containsBean(customMatcherHandler)) { + extractObject = applicationContext.getBean(customMatcherHandler); + if (!(extractObject instanceof CustomMatch)) { + LOGGER.error("{} {}", customMatcherHandler, errorMessageForNotImplements); + throw new RuntimeException(customMatcherHandler + errorMessageForNotImplements); + } + return (CustomMatch) extractObject; + } + return null; + } + + + public CustomMatch generateHandler(String customMatcherHandler) { + CustomMatch extractObject = getBeanByHandlerName(customMatcherHandler); + if (extractObject != null) { + return extractObject; + } + + LOGGER.info("{} {}", customMatcherHandler, infoMessageForCreatingClass); + Class extractionHandlerClass = null; + try { + extractionHandlerClass = Class.forName(customMatcherHandler); + } catch (ClassNotFoundException e) { + LOGGER.error(e.getMessage(), e); + throw new RuntimeException(e); + } + + if (!CustomMatch.class.isAssignableFrom(extractionHandlerClass)) { + LOGGER.error("{} {}", customMatcherHandler, errorMessageForNotImplements); + throw new RuntimeException(customMatcherHandler + errorMessageForNotImplements); + } + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(extractionHandlerClass); + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext; + registry.registerBeanDefinition(customMatcherHandler, builder.getBeanDefinition()); + try { + extractObject = (CustomMatch) applicationContext.getBean(customMatcherHandler); + return extractObject; + } catch (BeansException e) { + LOGGER.error(e.getMessage(), e); + throw new RuntimeException(customMatcherHandler + errorMessageForAbstractClass, e); + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java new file mode 100644 index 00000000000..73dcd526c9a --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker; + +import java.util.List; + +import org.apache.servicecomb.governance.entity.Configurable; + +public class TrafficMarker extends Configurable { + private List matches; + + @Override + public boolean isValid() { + if (matches == null || matches.isEmpty()) { + return false; + } + return true; + } + + public List getMatches() { + return matches; + } + + public void setMatches(List matches) { + this.matches = matches; + } + + public boolean checkMatch(GovernanceRequestExtractor extractor, RequestProcessor requestProcessor) { + return this.matches.stream().anyMatch(match -> requestProcessor.match(extractor, match)); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/CompareOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/CompareOperator.java new file mode 100644 index 00000000000..5b73b9aa939 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/CompareOperator.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker.operator; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.servicecomb.governance.exception.IllegalArgsOperatorException; + +public class CompareOperator implements MatchOperator { + + private final Set charSet = new HashSet<>(); + + public CompareOperator() { + charSet.add('>'); + charSet.add('<'); + charSet.add('='); + charSet.add('!'); + } + + @Override + public String name() { + return "compare"; + } + + /** + * 支持 {@code > < = >= <= !} 后面加数字 + * + * @param targetStr + * @param patternStr + * @return + */ + @Override + public boolean match(String targetStr, String patternStr) { + char[] chars = patternStr.toCharArray(); + if (isLegalChar(chars[0]) && isLegalChar(chars[1])) { + return process(targetStr, patternStr.substring(0, 2), patternStr.substring(2)); + } else if (isLegalChar(chars[0])) { + return process(targetStr, patternStr.substring(0, 1), patternStr.substring(1)); + } else { + throw new IllegalArgsOperatorException("operator " + patternStr + " is illegal."); + } + } + + private boolean process(String targetStr, String charStr, String numStr) { + double result; + double target; + try { + target = Double.parseDouble(targetStr); + if (numStr.startsWith("-")) { + result = -Double.parseDouble(numStr.substring(1)); + } else { + result = Double.parseDouble(numStr); + } + } catch (NumberFormatException e) { + throw new IllegalArgsOperatorException("operator " + charStr + numStr + " is illegal."); + } + switch (charStr) { + case ">": + return target > result; + case "<": + return target < result; + case "=": + return doubleEquals(target, result); + case ">=": + return target >= result; + case "<=": + return target <= result; + case "!": + case "!=": + return !doubleEquals(target, result); + default: + throw new IllegalArgsOperatorException("operator " + charStr + numStr + " is illegal."); + } + } + + private boolean isLegalChar(char c) { + return charSet.contains(c); + } + + private boolean doubleEquals(double target, double result) { + return Math.abs(target - result) < 1e-6; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ContainsOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ContainsOperator.java new file mode 100644 index 00000000000..faa40521441 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ContainsOperator.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker.operator; + +public class ContainsOperator implements MatchOperator { + + @Override + public String name() { + return "contains"; + } + + @Override + public boolean match(String targetStr, String patternStr) { + return targetStr.contains(patternStr); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ExactOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ExactOperator.java new file mode 100644 index 00000000000..cee8d48a27e --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/ExactOperator.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker.operator; + +import org.apache.commons.lang3.StringUtils; + +public class ExactOperator implements MatchOperator { + + @Override + public String name() { + return "exact"; + } + + @Override + public boolean match(String targetStr, String patternStr) { + return StringUtils.equals(targetStr, patternStr); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/MatchOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/MatchOperator.java new file mode 100644 index 00000000000..28abc1b8df5 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/MatchOperator.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker.operator; + +public interface MatchOperator { + String name(); + + boolean match(String targetStr, String patternStr); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/PrefixOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/PrefixOperator.java new file mode 100644 index 00000000000..6bb84c45a53 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/PrefixOperator.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.marker.operator; + +import org.apache.commons.lang3.StringUtils; + +public class PrefixOperator implements MatchOperator { + @Override + public String name() { + return "prefix"; + } + + @Override + public boolean match(String requestValue, String patternValue) { + return StringUtils.startsWith(requestValue, patternValue); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/RawOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/RawOperator.java new file mode 100644 index 00000000000..48bd06d8cd8 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/RawOperator.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.marker.operator; + +import java.util.HashMap; + +public class RawOperator extends HashMap { + private static final long serialVersionUID = 659728839992490564L; +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/SuffixOperator.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/SuffixOperator.java new file mode 100644 index 00000000000..99adf9fed1e --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/operator/SuffixOperator.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.marker.operator; + +import org.apache.commons.lang3.StringUtils; + +public class SuffixOperator implements MatchOperator { + @Override + public String name() { + return "suffix"; + } + + @Override + public boolean match(String requestValue, String patternValue) { + return StringUtils.endsWith(requestValue, patternValue); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java new file mode 100644 index 00000000000..c1638bde086 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.entity.Configurable; +import org.apache.servicecomb.governance.utils.GovernanceUtils; + +public abstract class AbstractPolicy extends Configurable implements Comparable { + protected int order = 0; + + @Override + public boolean isValid() { + return !StringUtils.isEmpty(name); + } + + @Override + public int compareTo(AbstractPolicy o) { + return this.order - o.order; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + private Duration parseToDuration(String time, Duration defaultValue) { + if (StringUtils.isEmpty(time)) { + return defaultValue; + } + if (time.matches(GovernanceUtils.DIGIT_REGEX)) { + if (Long.parseLong(time) < 0) { + throw new RuntimeException("The value of time should not be less than 0."); + } + return Duration.ofMillis(Long.parseLong(time)); + } + return Duration.parse(GovernanceUtils.DIGIT_PREFIX + time); + } + + public String stringOfDuration(String time, Duration defaultValue) { + return parseToDuration(time, defaultValue).toString(); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/BulkheadPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/BulkheadPolicy.java new file mode 100644 index 00000000000..e542ae9a091 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/BulkheadPolicy.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +public class BulkheadPolicy extends AbstractPolicy { + + public static final int DEFAULT_MAX_CONCURRENT_CALLS = 1000; + + public static final Duration DEFAULT_MAX_WAIT_DURATION = Duration.ofMillis(0); + + private int maxConcurrentCalls = DEFAULT_MAX_CONCURRENT_CALLS; + + private String maxWaitDuration = DEFAULT_MAX_WAIT_DURATION.toString(); + + public int getMaxConcurrentCalls() { + return maxConcurrentCalls; + } + + public void setMaxConcurrentCalls(int maxConcurrentCalls) { + this.maxConcurrentCalls = maxConcurrentCalls; + } + + public String getMaxWaitDuration() { + return maxWaitDuration; + } + + public void setMaxWaitDuration(String maxWaitDuration) { + this.maxWaitDuration = stringOfDuration(maxWaitDuration, DEFAULT_MAX_WAIT_DURATION); + } + + @Override + public boolean isValid() { + if (maxConcurrentCalls < 0) { + return false; + } + if (Duration.parse(maxWaitDuration).toMillis() < 0) { + return false; + } + return super.isValid(); + } + + @Override + public String toString() { + return "BulkheadPolicy{" + + "maxConcurrentCalls=" + maxConcurrentCalls + + ", maxWaitDuration=" + maxWaitDuration + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/CircuitBreakerPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/CircuitBreakerPolicy.java new file mode 100644 index 00000000000..1d1bdfeec79 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/CircuitBreakerPolicy.java @@ -0,0 +1,243 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.utils.GovernanceUtils; +import org.springframework.util.CollectionUtils; + +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.SlidingWindowType; + +public class CircuitBreakerPolicy extends AbstractPolicy { + + public static final float DEFAULT_FAILURE_RATE_THRESHOLD = 50; + + public static final float DEFAULT_SLOW_CALL_RATE_THRESHOLD = 100; + + public static final Duration DEFAULT_WAIT_DURATION_IN_OPEN_STATUS = Duration.ofMillis(60000); + + //ms + public static final Duration DEFAULT_SLOW_CALL_DURATION_THRESHOLD = Duration.ofMillis(60000); + + // the number of permitted calls when the CircuitBreaker is half open. + public static final int DEFAULT_PERMITTED = 10; + + public static final int DEFAULT_MINIMUM_NUMBER_CALLS = 100; + + public static final String DEFAULT_SLIDING_WINDOW_SIZE = "100"; + + public static final String DEFAULT_FAILURE_RESPONSE_STATUS_502 = "502"; + + public static final String DEFAULT_FAILURE_RESPONSE_STATUS_503 = "503"; + + public static final List DEFAULT_STATUS_LIST = Arrays.asList(DEFAULT_FAILURE_RESPONSE_STATUS_502, + DEFAULT_FAILURE_RESPONSE_STATUS_503); + + private float failureRateThreshold = DEFAULT_FAILURE_RATE_THRESHOLD; + + private float slowCallRateThreshold = DEFAULT_SLOW_CALL_RATE_THRESHOLD; + + private String waitDurationInOpenState = DEFAULT_WAIT_DURATION_IN_OPEN_STATUS.toString(); + + private String slowCallDurationThreshold = DEFAULT_SLOW_CALL_DURATION_THRESHOLD.toString(); + + private int permittedNumberOfCallsInHalfOpenState = DEFAULT_PERMITTED; + + private int minimumNumberOfCalls = DEFAULT_MINIMUM_NUMBER_CALLS; + + private String slidingWindowType; + + private String slidingWindowSize = DEFAULT_SLIDING_WINDOW_SIZE; + + //status code that need record as a failure + private List recordFailureStatus = DEFAULT_STATUS_LIST; + + //force close this circuit breaker. This parameter is not used by circuit breaker directly + private boolean forceClosed = false; + + //force open this circuit breaker. This parameter is not used by circuit breaker directly + private boolean forceOpen = false; + + public CircuitBreakerPolicy() { + } + + @Override + public boolean isValid() { + if (failureRateThreshold > 100.0F || failureRateThreshold <= 0.0F) { + return false; + } + if (slowCallRateThreshold > 100.0F || slowCallRateThreshold <= 0.0F) { + return false; + } + if (Duration.parse(waitDurationInOpenState).toMillis() <= 0) { + return false; + } + if (Duration.parse(slowCallDurationThreshold).toMillis() <= 0) { + return false; + } + if (permittedNumberOfCallsInHalfOpenState <= 0) { + return false; + } + if (minimumNumberOfCalls <= 0) { + return false; + } + + return super.isValid(); + } + + public float getFailureRateThreshold() { + return failureRateThreshold; + } + + public void setFailureRateThreshold(float failureRateThreshold) { + this.failureRateThreshold = failureRateThreshold; + } + + public float getSlowCallRateThreshold() { + return slowCallRateThreshold; + } + + public void setSlowCallRateThreshold(float slowCallRateThreshold) { + this.slowCallRateThreshold = slowCallRateThreshold; + } + + public String getWaitDurationInOpenState() { + return waitDurationInOpenState; + } + + public void setWaitDurationInOpenState(String waitDurationInOpenState) { + this.waitDurationInOpenState = stringOfDuration(waitDurationInOpenState, DEFAULT_WAIT_DURATION_IN_OPEN_STATUS); + } + + public String getSlowCallDurationThreshold() { + return slowCallDurationThreshold; + } + + public void setSlowCallDurationThreshold(String slowCallDurationThreshold) { + this.slowCallDurationThreshold = stringOfDuration(slowCallDurationThreshold, DEFAULT_SLOW_CALL_DURATION_THRESHOLD); + } + + public int getPermittedNumberOfCallsInHalfOpenState() { + return permittedNumberOfCallsInHalfOpenState; + } + + public void setPermittedNumberOfCallsInHalfOpenState(int permittedNumberOfCallsInHalfOpenState) { + this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState; + } + + public int getMinimumNumberOfCalls() { + return minimumNumberOfCalls; + } + + public void setMinimumNumberOfCalls(int minimumNumberOfCalls) { + this.minimumNumberOfCalls = minimumNumberOfCalls; + } + + public SlidingWindowType getSlidingWindowTypeEnum() { + if (StringUtils.isEmpty(slidingWindowType)) { + return SlidingWindowType.TIME_BASED; + } + + try { + return SlidingWindowType.valueOf(slidingWindowType); + } catch (Exception e) { + return SlidingWindowType.TIME_BASED; + } + } + + public String getSlidingWindowType() { + return this.slidingWindowType; + } + + public void setSlidingWindowType(String slidingWindowType) { + this.slidingWindowType = slidingWindowType; + } + + // time's unit is second + public String getSlidingWindowSize() { + return slidingWindowSize; + } + + public void setSlidingWindowSize(String slidingWindowSize) { + this.slidingWindowSize = getValue(slidingWindowSize); + } + + private String getValue(String slidingWindowSize) { + if (StringUtils.isEmpty(slidingWindowSize)) { + return DEFAULT_SLIDING_WINDOW_SIZE; + } + if (slidingWindowSize.matches(GovernanceUtils.DIGIT_REGEX)) { + if (Long.parseLong(slidingWindowSize) < 0) { + throw new RuntimeException("The value should be more than 0."); + } + return slidingWindowSize; + } + Duration duration = Duration.parse(GovernanceUtils.DIGIT_PREFIX + slidingWindowSize); + return String.valueOf(duration.getSeconds()); + } + + public List getRecordFailureStatus() { + if (CollectionUtils.isEmpty(this.recordFailureStatus)) { + return DEFAULT_STATUS_LIST; + } + return this.recordFailureStatus; + } + + public void setRecordFailureStatus(List recordFailureStatus) { + if (recordFailureStatus == null) { + return; + } + this.recordFailureStatus = recordFailureStatus.stream().filter(e -> !StringUtils.isEmpty(e)) + .collect(Collectors.toList()); + } + + public boolean isForceClosed() { + return forceClosed; + } + + public void setForceClosed(boolean forceClosed) { + this.forceClosed = forceClosed; + } + + public boolean isForceOpen() { + return forceOpen; + } + + public void setForceOpen(boolean forceOpen) { + this.forceOpen = forceOpen; + } + + @Override + public String toString() { + return "CircuitBreakerPolicy{" + + "failureRateThreshold=" + failureRateThreshold + + ", slowCallRateThreshold=" + slowCallRateThreshold + + ", waitDurationInOpenState=" + waitDurationInOpenState + + ", slowCallDurationThreshold=" + slowCallDurationThreshold + + ", permittedNumberOfCallsInHalfOpenState=" + permittedNumberOfCallsInHalfOpenState + + ", minimumNumberOfCalls=" + minimumNumberOfCalls + + ", slidingWindowType='" + slidingWindowType + '\'' + + ", slidingWindowSize=" + slidingWindowSize + + ", recordFailureStatus=" + recordFailureStatus + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/FaultInjectionPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/FaultInjectionPolicy.java new file mode 100644 index 00000000000..4f9500d692e --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/FaultInjectionPolicy.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +import org.apache.servicecomb.governance.processor.injection.FaultInjectionConst; + +public class FaultInjectionPolicy extends AbstractPolicy { + public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(0); + + private String type = FaultInjectionConst.TYPE_DELAY; + + private String delayTime = DEFAULT_TIMEOUT_DURATION.toString(); + + private int percentage = -1; + + private int errorCode = 500; + + private boolean forceClosed = false; + + private String fallbackType = FaultInjectionConst.FALLBACK_THROWEXCEPTION; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDelayTime() { + return delayTime; + } + + public void setDelayTime(String delayTime) { + this.delayTime = stringOfDuration(delayTime, Duration.ofMillis(-1)); + } + + public int getPercentage() { + return percentage; + } + + public void setPercentage(int percentage) { + this.percentage = percentage; + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public long getDelayTimeToMillis() { + return Duration.parse(delayTime).toMillis(); + } + + public boolean isForceClosed() { + return forceClosed; + } + + public void setForceClosed(boolean forceClosed) { + this.forceClosed = forceClosed; + } + + public String getFallbackType() { + return fallbackType; + } + + public void setFallbackType(String fallbackType) { + this.fallbackType = fallbackType; + } + + @Override + public boolean isValid() { + if (getDelayTimeToMillis() < 0 && FaultInjectionConst.TYPE_DELAY.equals(type)) { + return false; + } + if ((getErrorCode() < FaultInjectionConst.ERROR_CODE_MIN + || getErrorCode() > FaultInjectionConst.ERROR_CODE_MAX) + && FaultInjectionConst.TYPE_ABORT.equals(type)) { + return false; + } + return super.isValid(); + } + + @Override + public String toString() { + return "FaultInjectionPolicy{" + + "type=" + type + + ", delayTime=" + delayTime + + ", percentage=" + percentage + + ", errorCode=" + errorCode + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java new file mode 100644 index 00000000000..719c9cf4134 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceCachePolicy.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +public class GovernanceCachePolicy extends AbstractPolicy { + public static final Duration DEFAULT_TTL = Duration.ofMillis(21600000); + + public static final long DEFAULT_MAXIMUM_SIZE = 60000; + + public static final int DEFAULT_CONCURRENCY_LEVEL = 8; + + private String ttl = DEFAULT_TTL.toString(); + + private long maximumSize = DEFAULT_MAXIMUM_SIZE; + + private int concurrencyLevel = DEFAULT_CONCURRENCY_LEVEL; + + public String getTtl() { + return ttl; + } + + public void setTtl(String ttl) { + this.ttl = stringOfDuration(ttl, DEFAULT_TTL); + } + + public Long getMaximumSize() { + return maximumSize; + } + + public void setMaximumSize(Long maximumSize) { + this.maximumSize = maximumSize; + } + + public int getConcurrencyLevel() { + return concurrencyLevel; + } + + public void setConcurrencyLevel(int concurrencyLevel) { + this.concurrencyLevel = concurrencyLevel; + } + + @Override + public String toString() { + return "CachePolicy{" + "ttl=" + ttl + ",concurrencyLevel=" + concurrencyLevel + ", maximumSize=" + maximumSize + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/IdentifierRateLimitingPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/IdentifierRateLimitingPolicy.java new file mode 100644 index 00000000000..e49da76ffff --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/IdentifierRateLimitingPolicy.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import org.apache.commons.lang3.StringUtils; + +public class IdentifierRateLimitingPolicy extends RateLimitingPolicy { + /** + * header name used to identify this rate limiter + */ + protected String identifier; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public boolean isValid() { + if (StringUtils.isEmpty(identifier)) { + return false; + } + return super.isValid(); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/LoadBalancerPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/LoadBalancerPolicy.java new file mode 100644 index 00000000000..4e7e07e9f58 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/LoadBalancerPolicy.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.policy; + +public class LoadBalancerPolicy extends AbstractPolicy { + private String rule; + + public String getRule() { + return rule; + } + + public void setRule(String rule) { + this.rule = rule; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/MapperPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/MapperPolicy.java new file mode 100644 index 00000000000..76db6933602 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/MapperPolicy.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.policy; + +import java.util.Map; + +public class MapperPolicy extends AbstractPolicy { + private Map target; + + public Map getTarget() { + return target; + } + + public void setTarget(Map target) { + this.target = target; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/RateLimitingPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/RateLimitingPolicy.java new file mode 100644 index 00000000000..29a9f6d9f69 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/RateLimitingPolicy.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +public class RateLimitingPolicy extends AbstractPolicy { + + public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(0); + + public static final Duration DEFAULT_LIMIT_REFRESH_PERIOD = Duration.ofMillis(1000); + + public static final int DEFAULT_LIMIT_FOR_PERIOD = 1000; + + protected String timeoutDuration = DEFAULT_TIMEOUT_DURATION.toString(); + + protected String limitRefreshPeriod = DEFAULT_LIMIT_REFRESH_PERIOD.toString(); + + // 配置项名称使用 rate, 对应于 resilience4j 的 limitForPeriod + protected int rate = DEFAULT_LIMIT_FOR_PERIOD; + + public String getTimeoutDuration() { + return timeoutDuration; + } + + public void setTimeoutDuration(String timeoutDuration) { + this.timeoutDuration = stringOfDuration(timeoutDuration, DEFAULT_TIMEOUT_DURATION); + } + + public String getLimitRefreshPeriod() { + return limitRefreshPeriod; + } + + public void setLimitRefreshPeriod(String limitRefreshPeriod) { + this.limitRefreshPeriod = stringOfDuration(limitRefreshPeriod, DEFAULT_LIMIT_REFRESH_PERIOD); + } + + public int getRate() { + return rate; + } + + public void setRate(int rate) { + this.rate = rate; + } + + public RateLimitingPolicy() { + } + + @Override + public boolean isValid() { + if (Duration.parse(timeoutDuration).toMillis() < 0) { + return false; + } + if (Duration.parse(limitRefreshPeriod).toMillis() <= 0) { + return false; + } + if (rate <= 0) { + return false; + } + return super.isValid(); + } + + @Override + public String toString() { + return "RateLimitingPolicy{" + + "timeoutDuration=" + timeoutDuration + + ", limitRefreshPeriod=" + limitRefreshPeriod + + ", rate=" + rate + " req/s" + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/RetryPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/RetryPolicy.java new file mode 100644 index 00000000000..726121a2c20 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/RetryPolicy.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +public class RetryPolicy extends AbstractPolicy { + + public static final int DEFAULT_MAX_ATTEMPTS = 3; + + public static final Duration DEFAULT_WAIT_DURATION = Duration.ofMillis(1); + + public static final String DEFAULT_RETRY_ON_RESPONSE_STATUS_502 = "502"; + + public static final String DEFAULT_RETRY_ON_RESPONSE_STATUS_503 = "503"; + + public static final List DEFAULT_STATUS_LIST = Arrays.asList(DEFAULT_RETRY_ON_RESPONSE_STATUS_502, + DEFAULT_RETRY_ON_RESPONSE_STATUS_503); + + private static final Duration INITIAL_INTERVAL = Duration.ofMillis(1000); + + private static final float MULTIPLIER = 2; + + private static final double RANDOMIZATION_FACTOR = 0.5; + + private static final String DEFAULT_RETRY_STRATEGY = "FixedInterval"; + + //max retry attempts + private int maxAttempts = DEFAULT_MAX_ATTEMPTS; + + //wait duration for each retry + private String waitDuration = DEFAULT_WAIT_DURATION.toString(); + + //status code that need retry + private List retryOnResponseStatus = DEFAULT_STATUS_LIST; + + //retry strategy + private String retryStrategy = DEFAULT_RETRY_STRATEGY; + + // initial interval for backoff retry + private String initialInterval = INITIAL_INTERVAL.toString(); + + // multiplier for backoff retry + private float multiplier = MULTIPLIER; + + // randomization factor for backoff retry + private double randomizationFactor = RANDOMIZATION_FACTOR; + + // if throw an MaxRetriesExceededException if retry condition is based on result + private boolean failAfterMaxAttempts = false; + + // if retry on the same instance. This property is not directly used in + // RetryHandler, but used for loadbalancers + private int retryOnSame = 0; + + public List getRetryOnResponseStatus() { + if (CollectionUtils.isEmpty(retryOnResponseStatus)) { + return DEFAULT_STATUS_LIST; + } + return retryOnResponseStatus; + } + + public void setRetryOnResponseStatus(List retryOnResponseStatus) { + if (retryOnResponseStatus == null) { + return; + } + this.retryOnResponseStatus = retryOnResponseStatus.stream().filter(e -> !StringUtils.isEmpty(e)) + .collect(Collectors.toList()); + } + + public int getMaxAttempts() { + return maxAttempts; + } + + public void setMaxAttempts(int maxAttempts) { + this.maxAttempts = maxAttempts; + } + + public String getWaitDuration() { + return Duration.parse(waitDuration).toMillis() < 1 ? DEFAULT_WAIT_DURATION.toString() : waitDuration; + } + + public void setWaitDuration(String waitDuration) { + this.waitDuration = stringOfDuration(waitDuration, DEFAULT_WAIT_DURATION); + } + + public String getRetryStrategy() { + if (StringUtils.isEmpty(retryStrategy)) { + retryStrategy = DEFAULT_RETRY_STRATEGY; + } + return retryStrategy; + } + + public void setRetryStrategy(String retryStrategy) { + this.retryStrategy = retryStrategy; + } + + public String getInitialInterval() { + return initialInterval; + } + + public void setInitialInterval(String initialInterval) { + this.initialInterval = stringOfDuration(initialInterval, INITIAL_INTERVAL); + } + + public float getMultiplier() { + return multiplier; + } + + public void setMultiplier(float multiplier) { + this.multiplier = multiplier; + } + + public double getRandomizationFactor() { + return randomizationFactor; + } + + public void setRandomizationFactor(double randomizationFactor) { + this.randomizationFactor = randomizationFactor; + } + + public boolean isFailAfterMaxAttempts() { + return failAfterMaxAttempts; + } + + public void setFailAfterMaxAttempts(boolean failAfterMaxAttempts) { + this.failAfterMaxAttempts = failAfterMaxAttempts; + } + + public int getRetryOnSame() { + return retryOnSame; + } + + public void setRetryOnSame(int retryOnSame) { + this.retryOnSame = retryOnSame; + } + + @Override + public boolean isValid() { + if (maxAttempts < 1) { + return false; + } + if (Duration.parse(waitDuration).toMillis() < 0) { + return false; + } + if (Duration.parse(initialInterval).toMillis() < 10) { + return false; + } + return super.isValid(); + } + + @Override + public String toString() { + return "RetryPolicy{" + + "maxAttempts=" + maxAttempts + + ", waitDuration=" + waitDuration + + ", retryOnResponseStatus='" + retryOnResponseStatus + '\'' + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java new file mode 100644 index 00000000000..e00300127d6 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/TimeLimiterPolicy.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.policy; + +import java.time.Duration; + +public class TimeLimiterPolicy extends AbstractPolicy { + public static final Duration DEFAULT_TIMEOUT_DURATION = Duration.ofMillis(1000); + + public static final boolean DEFAULT_CANCEL_RUNNING_FUTURE = true; + + private String timeoutDuration = DEFAULT_TIMEOUT_DURATION.toString(); + + private boolean cancelRunningFuture = DEFAULT_CANCEL_RUNNING_FUTURE; + + public String getTimeoutDuration() { + return timeoutDuration; + } + + public void setTimeoutDuration(String timeoutDuration) { + this.timeoutDuration = stringOfDuration(timeoutDuration, DEFAULT_TIMEOUT_DURATION); + } + + public boolean isCancelRunningFuture() { + return cancelRunningFuture; + } + + public void setCancelRunningFuture(boolean cancelRunningFuture) { + this.cancelRunningFuture = cancelRunningFuture; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbortFault.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbortFault.java new file mode 100644 index 00000000000..c6423967601 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbortFault.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AbortFault extends AbstractFault { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbortFault.class); + + public static final String ABORTED_ERROR_MSG = "aborted by fault inject"; + + public AbortFault(String key, FaultInjectionPolicy policy) { + super(key, policy); + } + + @Override + public boolean injectFault(FaultParam faultParam) { + return shouldAbort(faultParam, policy); + } + + private boolean shouldAbort(FaultParam param, FaultInjectionPolicy policy) { + // get the config values related to abort. + int abortPercent = policy.getPercentage(); + if (abortPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: Abort percentage is not configured"); + return false; + } + + // check fault abort condition. + return FaultInjectionUtil.isFaultNeedToInject(param.getReqCount(), abortPercent); + } + + @Override + public int getOrder() { + return 200; + } + + @Override + public String getName() { + return FaultInjectionConst.TYPE_ABORT; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbstractFault.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbstractFault.java new file mode 100644 index 00000000000..c225ea9a2c6 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/AbstractFault.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; + +public abstract class AbstractFault implements Fault { + protected String key; + + protected FaultInjectionPolicy policy; + + public AbstractFault(String key, FaultInjectionPolicy policy) { + this.key = key; + this.policy = policy; + } + + @Override + public boolean injectFault() { + if (policy.isForceClosed()) { + return false; + } + FaultParam faultParam = FaultInjectionUtil.initFaultParam(key); + return injectFault(faultParam); + } + + @Override + public String getKey() { + return key; + } + + @Override + public FaultInjectionPolicy getPolicy() { + return policy; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/DelayFault.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/DelayFault.java new file mode 100644 index 00000000000..bc82c9178ff --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/DelayFault.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DelayFault extends AbstractFault { + private static final Logger LOGGER = LoggerFactory.getLogger(DelayFault.class); + + public DelayFault(String key, FaultInjectionPolicy policy) { + super(key, policy); + } + + @Override + public int getOrder() { + return 100; + } + + @Override + public boolean injectFault(FaultParam faultParam) { + if (!shouldDelay(faultParam, policy)) { + return false; + } + + LOGGER.debug("Fault injection: delay is added for the request by fault inject handler"); + long delay = policy.getDelayTimeToMillis(); + if (delay == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: delay is not configured"); + return false; + } + + executeDelay(faultParam, delay); + return false; + } + + private void executeDelay(FaultParam faultParam, long delay) { + Sleepable sleepable = faultParam.getSleepable(); + if (sleepable != null) { + sleepable.sleep(delay); + } + } + + private boolean shouldDelay(FaultParam param, FaultInjectionPolicy policy) { + int delayPercent = policy.getPercentage(); + if (delayPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: delay percentage is not configured"); + return false; + } + // check fault delay condition. + return FaultInjectionUtil.isFaultNeedToInject(param.getReqCount(), delayPercent); + } + + @Override + public String getName() { + return FaultInjectionConst.TYPE_DELAY; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Fault.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Fault.java new file mode 100644 index 00000000000..204186eaed4 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Fault.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; + +import io.vavr.CheckedFunction0; + +public interface Fault { + static CheckedFunction0 decorateCheckedSupplier(Fault fault, CheckedFunction0 supplier) { + return () -> { + if (fault.injectFault()) { + if (FaultInjectionConst.FALLBACK_THROWEXCEPTION.equals(fault.getPolicy().getFallbackType())) { + throw new FaultInjectionException( + FaultResponse.createFail(fault.getPolicy().getErrorCode(), AbortFault.ABORTED_ERROR_MSG)); + } else { + return null; + } + } + return supplier.apply(); + }; + } + + int getOrder(); + + String getName(); + + /* + * If true is returned,the downgrade governance policy is executed. + * Otherwise,the original request is directly executed. + * */ + boolean injectFault(); + + /* + * If true is returned,the downgrade governance policy is executed. + * Otherwise,the original request is directly executed. + * */ + boolean injectFault(FaultParam faultParam); + + String getKey(); + + FaultInjectionPolicy getPolicy(); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionConst.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionConst.java new file mode 100644 index 00000000000..35f27691028 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionConst.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +/** + * Handles the all constant values for fault injection. + */ +public class FaultInjectionConst { + + public static final int FAULT_INJECTION_DEFAULT_VALUE = -1; + + public static final String TYPE_DELAY = "delay"; + + public static final String TYPE_ABORT = "abort"; + + public static final String FALLBACK_THROWEXCEPTION = "ThrowException"; + + public static final String FALLBACK_RETURNNULL = "ReturnNull"; + + public static final int ERROR_CODE_MIN = 200; + + public static final int ERROR_CODE_MAX = 600; +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionDecorators.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionDecorators.java new file mode 100644 index 00000000000..e5eb7e0ffce --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionDecorators.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import io.vavr.CheckedFunction0; + +public interface FaultInjectionDecorators { + static FaultInjectionDecorateCheckedSupplier ofCheckedSupplier(CheckedFunction0 supplier) { + return new FaultInjectionDecorateCheckedSupplier<>(supplier); + } + + class FaultInjectionDecorateCheckedSupplier { + + private CheckedFunction0 supplier; + + protected FaultInjectionDecorateCheckedSupplier(CheckedFunction0 supplier) { + this.supplier = supplier; + } + + public FaultInjectionDecorateCheckedSupplier withFaultInjection(Fault fault) { + supplier = Fault.decorateCheckedSupplier(fault, supplier); + return this; + } + + public T get() throws Throwable { + return supplier.apply(); + } + } + +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionException.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionException.java new file mode 100644 index 00000000000..13058eca196 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionException.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +public class FaultInjectionException extends RuntimeException { + private static final long serialVersionUID = 1675558351029273343L; + + private final FaultResponse faultResponse; + + public FaultInjectionException(FaultResponse faultResponse) { + super(faultResponse.getErrorMsg()); + this.faultResponse = faultResponse; + } + + public FaultResponse getFaultResponse() { + return faultResponse; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionUtil.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionUtil.java new file mode 100644 index 00000000000..c7a1fdb6d7d --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultInjectionUtil.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; + +import io.vertx.core.Context; +import io.vertx.core.Vertx; + +/** + * Handles the count for all request based key[transport + microservice qualified name]. + */ +public final class FaultInjectionUtil { + + private FaultInjectionUtil() { + } + + /** + * key is transport+operQualifiedName + */ + private static final Map REQUEST_COUNT = new ConcurrentHashMapEx<>(); + + /** + * Returns total requests per provider for operational level. + * + * @param key + * transport+operational name + * @return long total requests + */ + public static AtomicLong getOperMetTotalReq(String key) { + return REQUEST_COUNT.computeIfAbsent(key, p -> new AtomicLong(1)); + } + + /** + * It will check the delay/abort condition based on request count and percentage + * received. + * + * @param reqCount total request count of the uri + * @param percentage the percentage of hitting fault injection + * @return true: delay/abort is needed. false: delay/abort is not needed. + */ + public static boolean isFaultNeedToInject(long reqCount, int percentage) { + /* + * Example: delay/abort percentage configured is 10% and Get the count(suppose + * if it is 10th request) from map and calculate resultNew(10th request) and + * requestOld(9th request). Like this for every request it will calculate + * current request count and previous count. if both not matched need to add + * delay/abort otherwise no need to add. + */ + + // calculate the value with current request count. + long resultNew = (reqCount * percentage) / 100; + + // calculate the value with previous count value. + long resultOld = ((reqCount - 1) * percentage) / 100; + + // if both are not matching then delay/abort should be added. + return (resultNew != resultOld); + } + + public static Fault getFault(String key, FaultInjectionPolicy policy) { + Fault fault = null; + if (FaultInjectionConst.TYPE_DELAY.equals(policy.getType())) { + fault = new DelayFault(key, policy); + } else if (FaultInjectionConst.TYPE_ABORT.equals(policy.getType())) { + fault = new AbortFault(key, policy); + } + return fault; + } + + public static FaultParam initFaultParam(String key) { + AtomicLong reqCount = FaultInjectionUtil.getOperMetTotalReq(key); + // increment the request count here after checking the delay/abort condition. + long reqCountCurrent = reqCount.getAndIncrement(); + + FaultParam param = new FaultParam(reqCountCurrent); + Context currentContext = Vertx.currentContext(); + if (currentContext != null && currentContext.owner() != null && currentContext.isEventLoopContext()) { + param.setSleepable( + (delay) -> currentContext.owner().setTimer(delay, timeId -> {})); + } + return param; + } + +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultParam.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultParam.java new file mode 100644 index 00000000000..9cd4c6611cb --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultParam.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Fault injection parameters which decides the fault injection condition. + */ +public class FaultParam { + private static final Logger LOGGER = LoggerFactory.getLogger(FaultParam.class); + + private final long reqCount; + + private Sleepable sleepable = (delay) -> { + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + LOGGER.info("Interrupted exception is received"); + } + }; + + public long getReqCount() { + return reqCount; + } + + public FaultParam(long reqCount) { + this.reqCount = reqCount; + } + + public Sleepable getSleepable() { + return sleepable; + } + + public void setSleepable(Sleepable sleepable) { + this.sleepable = sleepable; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultResponse.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultResponse.java new file mode 100644 index 00000000000..01b8fc8d263 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/FaultResponse.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +public class FaultResponse { + + private int errorCode; + + private String errorMsg; + + public static FaultResponse createFail(int errorCode, String errorMsg) { + FaultResponse faultResponse = new FaultResponse(); + faultResponse.setErrorCode(errorCode); + faultResponse.setErrorMsg(errorMsg); + return faultResponse; + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Sleepable.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Sleepable.java new file mode 100644 index 00000000000..22a95074f29 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/injection/Sleepable.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.injection; + +public interface Sleepable { + /** + * sleep some time + * @param delay time unit is millisecond + */ + void sleep(long delay); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalance.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalance.java new file mode 100644 index 00000000000..105c4fc59dc --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalance.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.loadbanlance; + +import org.apache.servicecomb.governance.policy.LoadBalancerPolicy; + +public interface LoadBalance { + + static LoadBalance getLoadBalance(String key, LoadBalancerPolicy policy) { + LoadBalance loadBalance = new LoadBalanceImpl(policy.getRule()); + return loadBalance; + } + + String getRule(); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalanceImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalanceImpl.java new file mode 100644 index 00000000000..48fb023fac7 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/loadbanlance/LoadBalanceImpl.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.loadbanlance; + +public class LoadBalanceImpl implements LoadBalance { + private final String rule; + + public LoadBalanceImpl(String rule) { + this.rule = rule; + } + + public String getRule() { + return rule; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/processor/mapping/Mapper.java b/governance/src/main/java/org/apache/servicecomb/governance/processor/mapping/Mapper.java new file mode 100644 index 00000000000..f9c435ecec1 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/processor/mapping/Mapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.processor.mapping; + +import java.util.Map; + +public interface Mapper { + static Mapper create(Map target) { + return () -> target; + } + + Map target(); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java new file mode 100644 index 00000000000..62d6cc2c7e9 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.BulkheadPolicy; + +public class BulkheadProperties extends PolicyProperties { + public static final String MATCH_BULKHEAD_KEY = "servicecomb.bulkhead"; + + public BulkheadProperties() { + super(MATCH_BULKHEAD_KEY); + } + + public BulkheadProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return BulkheadPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java new file mode 100644 index 00000000000..96aa701ad70 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; + +public class CircuitBreakerProperties extends PolicyProperties { + public static final String MATCH_CIRCUITBREAKER_KEY = "servicecomb.circuitBreaker"; + + public CircuitBreakerProperties() { + super(MATCH_CIRCUITBREAKER_KEY); + } + + public CircuitBreakerProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return CircuitBreakerPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/FaultInjectionProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/FaultInjectionProperties.java new file mode 100644 index 00000000000..3a881352cb4 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/FaultInjectionProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; + +public class FaultInjectionProperties extends PolicyProperties { + public static final String MATCH_FAULT_INJECTION_KEY = "servicecomb.faultInjection"; + + public FaultInjectionProperties() { + super(MATCH_FAULT_INJECTION_KEY); + } + + public FaultInjectionProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return FaultInjectionPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java new file mode 100644 index 00000000000..9ae9a8daa96 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceCacheProperties.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.GovernanceCachePolicy; + +public class GovernanceCacheProperties extends PolicyProperties { + public static final String MATCH_CACHE_KEY = "servicecomb.cache"; + + public GovernanceCacheProperties() { + super(MATCH_CACHE_KEY); + } + + public GovernanceCacheProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return GovernanceCachePolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java new file mode 100644 index 00000000000..05f42dfa5b1 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.MicroserviceMeta; +import org.apache.servicecomb.governance.entity.Configurable; +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; +import org.springframework.util.CollectionUtils; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.representer.Representer; + +import com.google.common.eventbus.Subscribe; + +public abstract class GovernanceProperties implements InitializingBean { + private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceProperties.class); + + private final Representer representer = new Representer(new DumperOptions()); + + private final String configKey; + + protected Environment environment; + + private MicroserviceMeta microserviceMeta; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setMicroserviceMeta(MicroserviceMeta microserviceMeta) { + this.microserviceMeta = microserviceMeta; + } + + protected Map parsedEntity; + + protected Class entityClass; + + protected GovernanceProperties(String key) { + configKey = key; + representer.getPropertyUtils().setSkipMissingProperties(true); + GovernanceEventManager.register(this); + entityClass = getEntityClass(); + } + + public String getConfigKey() { + return this.configKey; + } + + @Override + public void afterPropertiesSet() { + parsedEntity = parseEntity(readPropertiesFromPrefix()); + } + + @Subscribe + public void onConfigurationChangedEvent(GovernanceConfigurationChangedEvent event) { + for (String key : event.getChangedConfigurations()) { + if (key.startsWith(configKey + ".")) { + String mapKey = key.substring((configKey + ".").length()); + parsedEntity.remove(mapKey); + T entityItem = parseEntityItem(mapKey, environment.getProperty(key)); + if (entityItem != null) { + parsedEntity.put(mapKey, entityItem); + } + } + } + } + + private Map readPropertiesFromPrefix() { + Set allKeys = getAllKeys(environment); + Map result = new HashMap<>(); + allKeys.forEach(key -> { + if (key.startsWith(configKey + ".")) { + result.put(key.substring(configKey.length() + 1), environment.getProperty(key)); + } + }); + return result; + } + + private Set getAllKeys(Environment environment) { + Set allKeys = new HashSet<>(); + + if (!(environment instanceof ConfigurableEnvironment)) { + return allKeys; + } + + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + + for (PropertySource propertySource : configurableEnvironment.getPropertySources()) { + getProperties(propertySource, allKeys); + } + return allKeys; + } + + private void getProperties(PropertySource propertySource, + Set allKeys) { + if (propertySource instanceof CompositePropertySource) { + // recursively get EnumerablePropertySource + CompositePropertySource compositePropertySource = (CompositePropertySource) propertySource; + compositePropertySource.getPropertySources().forEach(ps -> getProperties(ps, allKeys)); + return; + } + if (propertySource instanceof EnumerablePropertySource) { + EnumerablePropertySource enumerablePropertySource = (EnumerablePropertySource) propertySource; + Collections.addAll(allKeys, enumerablePropertySource.getPropertyNames()); + return; + } + + LOGGER.debug("None EnumerablePropertySource ignored in {}, propertySourceName = [{}]", this.getClass().getName(), + propertySource.getName()); + } + + public Map getParsedEntity() { + return this.parsedEntity; + } + + protected Map parseEntity(Map yamlEntity) { + if (CollectionUtils.isEmpty(yamlEntity)) { + return new HashMap<>(); + } + + Map resultMap = new HashMap<>(); + for (Entry entry : yamlEntity.entrySet()) { + T marker = parseEntityItem(entry.getKey(), entry.getValue()); + if (marker != null) { + resultMap.put(entry.getKey(), marker); + } + } + return resultMap; + } + + protected abstract Class getEntityClass(); + + protected T parseEntityItem(String key, String value) { + if (StringUtils.isEmpty(value)) { + return null; + } + + try { + Yaml entityParser = new Yaml(new Constructor(new TypeDescription(entityClass, entityClass), new LoaderOptions()), + representer); + T result = entityParser.loadAs(value, entityClass); + result.setName(key); + + if (!result.isValid()) { + LOGGER.warn("Entity configuration is not valid and ignored. Key [{}], value [{}]", key, value); + return null; + } + if (!servicesMatch(result.getServices())) { + LOGGER.info("Configuration belongs to other service is ignored. Key [{}]", key); + return null; + } + return result; + } catch (RuntimeException e) { + LOGGER.error("governance config yaml is illegal : {}", e.getMessage()); + } + return null; + } + + private boolean servicesMatch(String services) { + if (StringUtils.isEmpty(services)) { + return true; + } + + return Arrays.stream(services.split(",")).anyMatch(service -> { + String[] serviceAndVersion = service.split(":"); + if (serviceAndVersion.length == 1) { + return microserviceMeta.getName().equals(serviceAndVersion[0]); + } else if (serviceAndVersion.length == 2) { + return microserviceMeta.getName().equals(serviceAndVersion[0]) && microserviceMeta.getVersion() + .equals(serviceAndVersion[1]); + } else { + return false; + } + }); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/IdentifierRateLimitProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/IdentifierRateLimitProperties.java new file mode 100644 index 00000000000..7db52c45b4b --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/IdentifierRateLimitProperties.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.IdentifierRateLimitingPolicy; + +public class IdentifierRateLimitProperties extends PolicyProperties { + public static final String MATCH_RATE_LIMIT_KEY = "servicecomb.identifierRateLimiting"; + + public IdentifierRateLimitProperties() { + super(MATCH_RATE_LIMIT_KEY); + } + + public IdentifierRateLimitProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return IdentifierRateLimitingPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceBulkheadProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceBulkheadProperties.java new file mode 100644 index 00000000000..12627046745 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceBulkheadProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.BulkheadPolicy; + +public class InstanceBulkheadProperties extends PolicyProperties { + public static final String MATCH_INSTANCE_BULKHEAD_KEY = "servicecomb.instanceBulkhead"; + + public InstanceBulkheadProperties() { + super(MATCH_INSTANCE_BULKHEAD_KEY); + } + + public InstanceBulkheadProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return BulkheadPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceIsolationProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceIsolationProperties.java new file mode 100644 index 00000000000..e47193fd340 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/InstanceIsolationProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; + +public class InstanceIsolationProperties extends PolicyProperties { + public static final String MATCH_INSTANCE_ISOLATION_KEY = "servicecomb.instanceIsolation"; + + public InstanceIsolationProperties() { + super(MATCH_INSTANCE_ISOLATION_KEY); + } + + public InstanceIsolationProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return CircuitBreakerPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/LoadBalanceProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/LoadBalanceProperties.java new file mode 100644 index 00000000000..892bbb8a580 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/LoadBalanceProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.LoadBalancerPolicy; + +public class LoadBalanceProperties extends PolicyProperties { + public static final String MATCH_LOADBANLANCER_KEY = "servicecomb.loadbalance"; + + public LoadBalanceProperties() { + super(MATCH_LOADBANLANCER_KEY); + } + + public LoadBalanceProperties(String key) { + super(key); + } + + @Override + protected Class getEntityClass() { + return LoadBalancerPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/MapperProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/MapperProperties.java new file mode 100644 index 00000000000..5a20d4dd346 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/MapperProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.MapperPolicy; + +public class MapperProperties extends PolicyProperties { + public static final String MATCH_MAPPER_KEY = "servicecomb.mapper"; + + public MapperProperties() { + super(MATCH_MAPPER_KEY); + } + + public MapperProperties(String key) { + super(key); + } + + @Override + protected Class getEntityClass() { + return MapperPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java new file mode 100644 index 00000000000..ca551e9c781 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.marker.TrafficMarker; + +public class MatchProperties extends GovernanceProperties { + public static final String MATCH_POLICY_KEY = "servicecomb.matchGroup"; + + public MatchProperties() { + super(MATCH_POLICY_KEY); + } + + @Override + public Class getEntityClass() { + return TrafficMarker.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java new file mode 100644 index 00000000000..4bd53d83fce --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.AbstractPolicy; + +public abstract class PolicyProperties extends GovernanceProperties { + protected PolicyProperties(String key) { + super(key); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java new file mode 100644 index 00000000000..c3c09434636 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + + +import org.apache.servicecomb.governance.policy.RateLimitingPolicy; + +public class RateLimitProperties extends PolicyProperties { + public static final String MATCH_RATE_LIMIT_KEY = "servicecomb.rateLimiting"; + + public RateLimitProperties() { + super(MATCH_RATE_LIMIT_KEY); + } + + public RateLimitProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return RateLimitingPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java new file mode 100644 index 00000000000..50106c2a003 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + +import org.apache.servicecomb.governance.policy.RetryPolicy; + +public class RetryProperties extends PolicyProperties { + public static final String MATCH_RETRY_KEY = "servicecomb.retry"; + + public RetryProperties() { + super(MATCH_RETRY_KEY); + } + + public RetryProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return RetryPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java new file mode 100644 index 00000000000..daca14f57f4 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/TimeLimiterProperties.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.properties; + + +import org.apache.servicecomb.governance.policy.TimeLimiterPolicy; + +public class TimeLimiterProperties extends PolicyProperties { + public static final String MATCH_TIMELIMITER_KEY = "servicecomb.timeLimiter"; + + public TimeLimiterProperties() { + super(MATCH_TIMELIMITER_KEY); + } + + public TimeLimiterProperties(String key) { + super(key); + } + + @Override + public Class getEntityClass() { + return TimeLimiterPolicy.class; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java new file mode 100644 index 00000000000..35014272fd9 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCache.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.service; + +import com.google.common.cache.Cache; + +import java.util.Objects; + +public interface GovernanceCache { + static GovernanceCache of(Cache cache) { + Objects.requireNonNull(cache, "Cache must not be null"); + return new GovernanceCacheImpl<>(cache); + } + + V getValueFromCache(K cacheKey); + + void putValueIntoCache(K cacheKey, V value); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java new file mode 100644 index 00000000000..a7dcfa5d4e7 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/GovernanceCacheImpl.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.service; + +import com.google.common.cache.Cache; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GovernanceCacheImpl implements GovernanceCache { + + private static final Logger LOG = LoggerFactory.getLogger(GovernanceCacheImpl.class); + + private final Cache cache; + + public GovernanceCacheImpl(Cache cache) { + this.cache = cache; + } + + public V getValueFromCache(K cacheKey) { + try { + return cache.getIfPresent(cacheKey); + } catch (Exception exception) { + LOG.warn("Failed to get a value from Cache", exception); + return null; + } + } + + @Override + public void putValueIntoCache(K cacheKey, V value) { + try { + cache.put(cacheKey, value); + } catch (Exception exception) { + LOG.warn("Failed to put a value into Cache {}", exception); + } + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java new file mode 100644 index 00000000000..1b0f0b42f9a --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance.service; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; + +public interface MatchersService { + boolean checkMatch(GovernanceRequestExtractor governanceRequest, String key); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java new file mode 100644 index 00000000000..cc851f16892 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.service; + +import java.util.Map; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.governance.marker.TrafficMarker; +import org.apache.servicecomb.governance.properties.MatchProperties; + +public class MatchersServiceImpl implements MatchersService { + private final RequestProcessor requestProcessor; + + private final MatchProperties matchProperties; + + public MatchersServiceImpl(RequestProcessor requestProcessor, MatchProperties matchProperties) { + this.requestProcessor = requestProcessor; + this.matchProperties = matchProperties; + } + + @Override + public boolean checkMatch(GovernanceRequestExtractor governanceRequest, String key) { + Map parsedEntity = matchProperties.getParsedEntity(); + + TrafficMarker trafficMarker = parsedEntity.get(key); + + if (trafficMarker == null) { + return false; + } + + return trafficMarker.checkMatch(governanceRequest, requestProcessor); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/utils/CustomMatch.java b/governance/src/main/java/org/apache/servicecomb/governance/utils/CustomMatch.java new file mode 100644 index 00000000000..d2627e82af8 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/utils/CustomMatch.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.utils; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; + +public interface CustomMatch { + boolean matchRequest(GovernanceRequestExtractor requestExtractor, String parameters); +} diff --git a/governance/src/main/java/org/apache/servicecomb/governance/utils/GovernanceUtils.java b/governance/src/main/java/org/apache/servicecomb/governance/utils/GovernanceUtils.java new file mode 100644 index 00000000000..28c4ed2a407 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/governance/utils/GovernanceUtils.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.utils; + +public final class GovernanceUtils { + public static final String DIGIT_REGEX = "-{0,1}[0-9]{1,10}"; + + public static final String DIGIT_PREFIX = "PT"; + + public static final String STRATEGY_RANDOM_BACKOFF = "RandomBackoff"; +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/RouterCommonConfiguration.java b/governance/src/main/java/org/apache/servicecomb/router/RouterCommonConfiguration.java new file mode 100644 index 00000000000..9aa881ee8df --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/RouterCommonConfiguration.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.match.RouterRuleMatcher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class RouterCommonConfiguration { + @Bean + public RouterRuleCache scbRouterRuleCache(Environment environment) { + return new RouterRuleCache(environment); + } + + @Bean + public RouterRuleMatcher scbRouterRuleMatcher(RouterRuleCache routerRuleCache, RequestProcessor requestProcessor) { + return new RouterRuleMatcher(routerRuleCache, requestProcessor); + } + + @Bean + public RouterFilter scbRouterFilter(RouterRuleMatcher routerRuleMatcher, RouterRuleCache routerRuleCache) { + return new RouterFilter(routerRuleMatcher, routerRuleCache); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/RouterFilter.java b/governance/src/main/java/org/apache/servicecomb/router/RouterFilter.java new file mode 100644 index 00000000000..ab742e8613d --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/RouterFilter.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.apache.servicecomb.router.match.RouterRuleMatcher; +import org.apache.servicecomb.router.model.PolicyRuleItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +public class RouterFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(RouterFilter.class); + + private final RouterRuleMatcher routerRuleMatcher; + + private final RouterRuleCache routerRuleCache; + + public RouterFilter(RouterRuleMatcher routerRuleMatcher, RouterRuleCache routerRuleCache) { + this.routerRuleMatcher = routerRuleMatcher; + this.routerRuleCache = routerRuleCache; + } + + public List getFilteredListOfServers(List list, + String targetServiceName, GovernanceRequestExtractor extractor, RouterDistributor distributor) { + if (CollectionUtils.isEmpty(list)) { + return list; + } + if (StringUtils.isEmpty(targetServiceName)) { + return list; + } + // 1.init and cache + if (!routerRuleCache.doInit(targetServiceName)) { + LOGGER.debug("route management init failed"); + return list; + } + // 2.match rule + PolicyRuleItem invokeRule = routerRuleMatcher.match(targetServiceName, extractor); + + if (invokeRule == null) { + LOGGER.debug("route management match rule failed"); + return list; + } + + LOGGER.debug("route management match rule success: {}", invokeRule); + + // 3.distribute select endpoint + List resultList = distributor.distribute(targetServiceName, list, invokeRule); + + LOGGER.debug("route management distribute rule success: {}", resultList); + + return resultList; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java b/governance/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java new file mode 100644 index 00000000000..7828c82d3a7 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/cache/RouterRuleCache.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.cache; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.router.model.PolicyRuleItem; +import org.apache.servicecomb.router.model.ServiceInfoCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.representer.Representer; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.Subscribe; + +public class RouterRuleCache { + private static final Logger LOGGER = LoggerFactory.getLogger(RouterRuleCache.class); + + public static final String ROUTE_RULE_PREFIX = "servicecomb.routeRule."; + + private static final String ROUTE_RULE = "servicecomb.routeRule.%s"; + + public static final String GLOBAL_ROUTE_RULE_KEY = "servicecomb.globalRouteRule"; + + private final Environment environment; + + private final ConcurrentHashMap serviceInfoCacheMap = new ConcurrentHashMap<>(); + + private final Object lock = new Object(); + + private final Representer representer = new Representer(new DumperOptions()); + + public RouterRuleCache(Environment environment) { + this.environment = environment; + representer.getPropertyUtils().setSkipMissingProperties(true); + GovernanceEventManager.register(this); + } + + /** + * cache and register callback + * + * return false when: 1. parsing error 2. rule is null + */ + public boolean doInit(String targetServiceName) { + if (!isServerContainRule(targetServiceName)) { + return false; + } + if (!serviceInfoCacheMap.containsKey(targetServiceName)) { + synchronized (lock) { + if (serviceInfoCacheMap.containsKey(targetServiceName)) { + return true; + } + return addAllRule(targetServiceName); + } + } + return true; + } + + @Subscribe + public void onConfigurationChangedEvent(GovernanceConfigurationChangedEvent event) { + for (String key : event.getChangedConfigurations()) { + if (key.startsWith(ROUTE_RULE_PREFIX)) { + serviceInfoCacheMap.remove(key.substring(ROUTE_RULE_PREFIX.length())); + } + if (key.equals(GLOBAL_ROUTE_RULE_KEY)) { + serviceInfoCacheMap.clear(); + } + } + } + + private boolean addAllRule(String targetServiceName) { + String ruleStr = environment.getProperty(String.format(ROUTE_RULE, targetServiceName), ""); + if (StringUtils.isEmpty(ruleStr)) { + ruleStr = environment.getProperty(GLOBAL_ROUTE_RULE_KEY, ""); + } + if (StringUtils.isEmpty(ruleStr)) { + return false; + } + List policyRuleItemList; + try { + Yaml entityParser = new Yaml( + new Constructor(new TypeDescription(PolicyRuleItem[].class, PolicyRuleItem[].class), new LoaderOptions()), + representer); + policyRuleItemList = Arrays + .asList(entityParser.loadAs(ruleStr, PolicyRuleItem[].class)); + } catch (Exception e) { + LOGGER.warn("Route management serialization for service {} failed: {}", targetServiceName, e.getMessage()); + return false; + } + if (CollectionUtils.isEmpty(policyRuleItemList)) { + LOGGER.warn("Route management serialization for service {} is empty", targetServiceName); + return false; + } + ServiceInfoCache serviceInfoCache = new ServiceInfoCache(policyRuleItemList); + serviceInfoCacheMap.put(targetServiceName, serviceInfoCache); + LOGGER.info("Route management serialization service {} rules success, content: {}", targetServiceName, + serviceInfoCache.getAllrule()); + return true; + } + + /** + * if a server don't have rule , avoid registered too many callback , it may cause memory leak + */ + private boolean isServerContainRule(String targetServiceName) { + return !StringUtils.isEmpty(environment.getProperty(String.format(ROUTE_RULE, targetServiceName), "")) || + !StringUtils.isEmpty(environment.getProperty(GLOBAL_ROUTE_RULE_KEY, "")); + } + + public ConcurrentHashMap getServiceInfoCacheMap() { + return serviceInfoCacheMap; + } + + @VisibleForTesting + void refresh() { + serviceInfoCacheMap.clear(); + } + + public void refresh(String targetServiceName) { + serviceInfoCacheMap.remove(targetServiceName); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/distribute/AbstractRouterDistributor.java b/governance/src/main/java/org/apache/servicecomb/router/distribute/AbstractRouterDistributor.java new file mode 100644 index 00000000000..d3905dfb133 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/distribute/AbstractRouterDistributor.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.distribute; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.model.PolicyRuleItem; +import org.apache.servicecomb.router.model.RouteItem; +import org.apache.servicecomb.router.model.TagItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +public abstract class AbstractRouterDistributor implements + RouterDistributor { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRouterDistributor.class); + + private Function getVersion; + + private Function getServerName; + + private Function> getProperties; + + private RouterRuleCache routerRuleCache; + + @Autowired + public void setRouterRuleCache(RouterRuleCache routerRuleCache) { + this.routerRuleCache = routerRuleCache; + } + + protected AbstractRouterDistributor() { + } + + /** + * distribute logic: + * 1、First according to the set route rules to choose target instances, if have just return. + * 2、if route rules not match instance, check if fallback rules are set, if set and match instances then return. + * 3、if route and fallback routes all have not match instance, then if route rules weight count less 100, return + * unset instances, otherwise return all instances. + * @param targetServiceName + * @param list + * @param invokeRule + * @return + */ + @Override + public List distribute(String targetServiceName, List list, PolicyRuleItem invokeRule) { + invokeRule.check(); + + // unSetTags instance list + List unSetTagInstances = new ArrayList<>(); + + // record fallback router targItem instance + Map> fallbackVersionServerMap = new HashMap<>(); + + // get tag instance map, fallbackVersionServerMap, unSetTagInstances + Map> versionServerMap = getDistributList(targetServiceName, list, invokeRule, + unSetTagInstances, fallbackVersionServerMap); + + // weight calculation to obtain the next tags instance + TagItem targetTag = getFilteredServerTagItem(invokeRule, targetServiceName); + if (targetTag != null && versionServerMap.containsKey(targetTag)) { + return versionServerMap.get(targetTag); + } + + if (!fallbackVersionServerMap.isEmpty()) { + // weight calculation to obtain the next fallback tags instance + TagItem fallbackTargetTag = getFallbackFilteredServerTagItem(invokeRule, targetServiceName); + if (fallbackTargetTag != null && fallbackVersionServerMap.containsKey(fallbackTargetTag)) { + return fallbackVersionServerMap.get(fallbackTargetTag); + } + } + + // has weightLess situation and unSetTagInstances has values + if (invokeRule.isWeightLess() && !unSetTagInstances.isEmpty()) { + return unSetTagInstances; + } + if (invokeRule.isEmptyProtection()) { + return list; + } + + // weight set 100 but not matched any instance, then return empty when emptyProtection close + return Collections.emptyList(); + } + + @Override + public void init(Function getVersion, + Function getServerName, + Function> getProperties) { + this.getVersion = getVersion; + this.getServerName = getServerName; + this.getProperties = getProperties; + } + + public TagItem getFilteredServerTagItem(PolicyRuleItem rule, String targetServiceName) { + return routerRuleCache.getServiceInfoCacheMap().get(targetServiceName) + .getNextInvokeVersion(rule); + } + + public TagItem getFallbackFilteredServerTagItem(PolicyRuleItem rule, String targetServiceName) { + return routerRuleCache.getServiceInfoCacheMap().get(targetServiceName) + .getFallbackNextInvokeVersion(rule); + } + + /** + * 1.filter set route rules targetService, build fallback targetService map and unSetTagInstances list. + * 2.establish map is a more complicate way than direct traversal, because of multiple matches. + * + * the method getProperties() contains other field that we don't need. + */ + private Map> getDistributList(String serviceName, List list, + PolicyRuleItem invokeRule, List unSetTagInstances, Map> fallbackVersionMap) { + Map> versionServerMap = new HashMap<>(); + for (INSTANCE instance : list) { + //get server + if (getServerName.apply(instance).equals(serviceName)) { + TagItem tagItem = new TagItem(getVersion.apply(instance), getProperties.apply(instance)); + // route most matching TagItem + TagItem targetTag = buildTargetTag(invokeRule.getRoute(), tagItem); + if (targetTag != null) { + if (!versionServerMap.containsKey(targetTag)) { + versionServerMap.put(targetTag, new ArrayList<>()); + } + versionServerMap.get(targetTag).add(instance); + } else { + // not matched, placed in the unset tag instances collection + unSetTagInstances.add(instance); + } + // ensure the tags can build when set for both route and fallback at the same time + if (!CollectionUtils.isEmpty(invokeRule.getFallback())) { + // fallback most matching TagItem + TagItem targetTagFallback = buildTargetTag(invokeRule.getFallback(), tagItem); + if (!fallbackVersionMap.containsKey(targetTagFallback)) { + fallbackVersionMap.put(targetTagFallback, new ArrayList<>()); + } + fallbackVersionMap.get(targetTagFallback).add(instance); + } + } + } + return versionServerMap; + } + + private TagItem buildTargetTag(List route, TagItem tagItem) { + int maxMatch = 0; + TagItem targetTag = null; + // obtain the rule with the most parameter matches + for (RouteItem entry : route) { + if (entry.getTagitem() == null){ + continue; + } + int nowMatch = entry.getTagitem().matchNum(tagItem); + if (nowMatch > maxMatch) { + maxMatch = nowMatch; + targetTag = entry.getTagitem(); + } + } + return targetTag; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/distribute/RouterDistributor.java b/governance/src/main/java/org/apache/servicecomb/router/distribute/RouterDistributor.java new file mode 100644 index 00000000000..5f5babdec34 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/distribute/RouterDistributor.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.distribute; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.apache.servicecomb.router.model.PolicyRuleItem; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public interface RouterDistributor { + + void init(Function getVersion, + Function getServerName, + Function> getProperties); + + List distribute(String targetServiceName, List list, PolicyRuleItem invokeRule); +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/exception/RouterIllegalParamException.java b/governance/src/main/java/org/apache/servicecomb/router/exception/RouterIllegalParamException.java new file mode 100644 index 00000000000..9647a853ea8 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/exception/RouterIllegalParamException.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.exception; + +/** + * @author GuoYl123 + * @since 2019/11/4 + **/ +public class RouterIllegalParamException extends RuntimeException { + + private static final long serialVersionUID = 4359709211352400087L; + + public RouterIllegalParamException(String message) { + super(message); + } + + public RouterIllegalParamException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/match/RouterRuleMatcher.java b/governance/src/main/java/org/apache/servicecomb/router/match/RouterRuleMatcher.java new file mode 100644 index 00000000000..dd2ba78d7d3 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/match/RouterRuleMatcher.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.match; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.model.PolicyRuleItem; + +public class RouterRuleMatcher { + private final RouterRuleCache routerRuleCache; + + private final RequestProcessor requestProcessor; + + public RouterRuleMatcher(RouterRuleCache routerRuleCache, RequestProcessor requestProcessor) { + this.routerRuleCache = routerRuleCache; + this.requestProcessor = requestProcessor; + } + + public PolicyRuleItem match(String serviceName, GovernanceRequestExtractor request) { + for (PolicyRuleItem rule : routerRuleCache.getServiceInfoCacheMap().get(serviceName) + .getAllrule()) { + if (rule.getMatch() == null || requestProcessor.match(request, rule.getMatch())) { + return rule; + } + } + return null; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/model/HeaderRule.java b/governance/src/main/java/org/apache/servicecomb/router/model/HeaderRule.java new file mode 100644 index 00000000000..7a8afeda77f --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/model/HeaderRule.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.model; + +import org.apache.servicecomb.router.exception.RouterIllegalParamException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public class HeaderRule { + + private static final Logger LOGGER = LoggerFactory.getLogger(HeaderRule.class); + + private String regex; + + private boolean caseInsensitive = true; + + private String exact; + + public HeaderRule() { + } + + public boolean match(String str) { + if (str == null) { + return false; + } + if (exact == null && regex == null) { + throw new RouterIllegalParamException( + "route management regex and exact can not br null at same time."); + } + if (caseInsensitive) { + str = str.toLowerCase(); + exact = exact == null ? null : exact.toLowerCase(); + regex = regex == null ? null : regex.toLowerCase(); + } + if (exact != null && !str.equals(exact)) { + return false; + } + try { + if (regex != null && !str.matches(regex)) { + return false; + } + } catch (Exception e) { + LOGGER.error("route management wrong regular expression format: {}", regex); + return false; + } + return true; + } + + public String getRegex() { + return regex; + } + + public void setRegex(String regex) { + this.regex = regex; + } + + public boolean isCaseInsensitive() { + return caseInsensitive; + } + + public void setCaseInsensitive(boolean caseInsensitive) { + this.caseInsensitive = caseInsensitive; + } + + public String getExact() { + return exact; + } + + public void setExact(String exact) { + this.exact = exact; + } + + @Override + public String toString() { + return "HeaderRule{" + + "regex='" + regex + '\'' + + ", caseInsensitive=" + caseInsensitive + + ", exact='" + exact + '\'' + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/model/PolicyRuleItem.java b/governance/src/main/java/org/apache/servicecomb/router/model/PolicyRuleItem.java new file mode 100644 index 00000000000..0700a2618d8 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/model/PolicyRuleItem.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.model; + +import java.util.List; + +import org.apache.servicecomb.governance.marker.Matcher; +import org.apache.servicecomb.router.exception.RouterIllegalParamException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public class PolicyRuleItem implements Comparable { + + private static final Logger LOGGER = LoggerFactory.getLogger(PolicyRuleItem.class); + + private Integer precedence; + + private Matcher match; + + private List route; + + private Integer total; + + private boolean weightLess = false; + + private List fallback; + + private Integer fallbackTotal; + + private boolean emptyProtection = true; + + public PolicyRuleItem() { + } + + /** + * if weight is less than 100, fill with minimum version + * + */ + public void check() { + if (CollectionUtils.isEmpty(route)) { + throw new RouterIllegalParamException("canary rule list can not be null"); + } + int sum = 0; + for (RouteItem item : route) { + if (item.getWeight() == null) { + throw new RouterIllegalParamException("canary rule weight can not be null"); + } + sum += item.getWeight(); + } + if (sum > 100) { + LOGGER.warn("canary rule weight sum is more than 100"); + } else if (sum < 100) { + weightLess = true; + route.add(new RouteItem(100 - sum, null)); + } + } + + @Override + public int compareTo(PolicyRuleItem param) { + return Integer.compare(param.precedence, this.precedence); + } + + public Integer getPrecedence() { + return precedence; + } + + public void setPrecedence(Integer precedence) { + this.precedence = precedence; + } + + public Matcher getMatch() { + return match; + } + + public void setMatch(Matcher match) { + this.match = match; + } + + public List getRoute() { + return route; + } + + public void setRoute(List route) { + this.route = route; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public boolean isWeightLess() { + return weightLess; + } + + public void setWeightLess(boolean weightLess) { + this.weightLess = weightLess; + } + + public List getFallback() { + return fallback; + } + + public void setFallback(List fallback) { + this.fallback = fallback; + } + + public Integer getFallbackTotal() { + return fallbackTotal; + } + + public void setFallbackTotal(Integer fallbackTotal) { + this.fallbackTotal = fallbackTotal; + } + + public boolean isEmptyProtection() { + return emptyProtection; + } + + public void setEmptyProtection(boolean emptyProtection) { + this.emptyProtection = emptyProtection; + } + + @Override + public String toString() { + return "PolicyRuleItem{" + + "precedence=" + precedence + + ", match=" + match + + ", route=" + route + + ", total=" + total + + ", weightLess=" + weightLess + + ", fallback=" + fallback + + ", fallbackTotal=" + fallbackTotal + + ", emptyProtection=" + emptyProtection + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/model/RouteItem.java b/governance/src/main/java/org/apache/servicecomb/router/model/RouteItem.java new file mode 100644 index 00000000000..5f1d6e9f8df --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/model/RouteItem.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.model; + +import java.util.Map; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public class RouteItem implements Comparable { + + private Integer weight; + /** + * for load balance + */ + private Integer currentWeight = 0; + + private Map tags; + + private TagItem tagitem; + + + public void initTagItem() { + if (tags != null) { + tagitem = new TagItem(tags); + } + } + + public void addCurrentWeight() { + currentWeight += weight; + } + + public void reduceCurrentWeight(int total) { + currentWeight -= total; + } + + public RouteItem() { + } + + public RouteItem(Integer weight, TagItem tags) { + this.weight = weight; + this.tagitem = tags; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCurrentWeight() { + return currentWeight; + } + + public void setCurrentWeight(Integer currentWeight) { + this.currentWeight = currentWeight; + } + + public Map getTags() { + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + public TagItem getTagitem() { + return tagitem; + } + + public void setTagitem(TagItem tagitem) { + this.tagitem = tagitem; + } + + @Override + public int compareTo(RouteItem param) { + return Integer.compare(param.weight, this.weight); + } + + @Override + public String toString() { + return "RouteItem{" + + "weight=" + weight + + ", currentWeight=" + currentWeight + + ", tags=" + tags + + ", tagitem=" + tagitem + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/model/ServiceInfoCache.java b/governance/src/main/java/org/apache/servicecomb/router/model/ServiceInfoCache.java new file mode 100644 index 00000000000..232f1da6338 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/model/ServiceInfoCache.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.model; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.util.CollectionUtils; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public class ServiceInfoCache { + private final List allrule; + + /** + * for default version + */ + private TagItem latestVersionTag; + + public ServiceInfoCache(List policyRuleItemList) { + this.allrule = policyRuleItemList.stream().sorted().collect(Collectors.toList()); + + this.getAllrule().forEach(rule -> { + rule.getRoute().forEach(RouteItem::initTagItem); + if (!CollectionUtils.isEmpty(rule.getFallback())) { + rule.getFallback().forEach(RouteItem::initTagItem); + } + }); + } + + public TagItem getNextInvokeVersion(PolicyRuleItem policyRuleItem) { + List rule = policyRuleItem.getRoute(); + if (policyRuleItem.getTotal() == null) { + policyRuleItem.setTotal(rule.stream().mapToInt(RouteItem::getWeight).sum()); + } + return calculateWeight(rule, policyRuleItem.getTotal()); + } + + public TagItem getFallbackNextInvokeVersion(PolicyRuleItem policyRuleItem) { + List rule = policyRuleItem.getFallback(); + if (policyRuleItem.getFallbackTotal() == null) { + policyRuleItem.setFallbackTotal(rule.stream().mapToInt(RouteItem::getWeight).sum()); + } + return calculateWeight(rule, policyRuleItem.getFallbackTotal()); + } + + private TagItem calculateWeight(List rule, int total) { + rule.forEach(RouteItem::addCurrentWeight); + int maxIndex = 0, maxWeight = -1; + for (int i = 0; i < rule.size(); i++) { + if (maxWeight < rule.get(i).getCurrentWeight()) { + maxIndex = i; + maxWeight = rule.get(i).getCurrentWeight(); + } + } + rule.get(maxIndex).reduceCurrentWeight(total); + return rule.get(maxIndex).getTagitem(); + } + + public List getAllrule() { + return allrule; + } + + public TagItem getLatestVersionTag() { + return latestVersionTag; + } + + public void setLatestVersionTag(TagItem latestVersionTag) { + this.latestVersionTag = latestVersionTag; + } + + @Override + public String toString() { + return "ServiceInfoCache{" + + "allrule=" + allrule + + ", latestVersionTag=" + latestVersionTag + + '}'; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/model/TagItem.java b/governance/src/main/java/org/apache/servicecomb/router/model/TagItem.java new file mode 100644 index 00000000000..a7a20fab7ea --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/model/TagItem.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * @author GuoYl123 + * @since 2019/10/17 + **/ +public class TagItem { + + private static final String VERSION = "version"; + + private String version; + + private Map param; + + public TagItem() { + } + + public TagItem(String version, Map param) { + this.version = version; + this.param = param; + } + + public TagItem(String version) { + this.version = version; + Map param = new HashMap<>(); + param.put(VERSION, version); + this.param = param; + } + + public TagItem(Map param) { + if (param.containsKey(VERSION)) { + this.version = param.get(VERSION); + } + this.param = param; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Map getParam() { + return param; + } + + public void setParam(Map param) { + this.param = param; + } + + @Override + public int hashCode() { + return Objects.hash(getVersion(), getParam()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TagItem)) { + return false; + } + TagItem tagItem = (TagItem) o; + return Objects.equals(getVersion(), tagItem.getVersion()) && + Objects.equals(getParam(), tagItem.getParam()); + } + + /** + * return match num + * + * @param item + * @return + */ + public int matchNum(TagItem item) { + int cnt = 0; + if (version != null && !version.equals(item.version)) { + return 0; + } + for (Map.Entry entry : param.entrySet()) { + if (item.getParam().containsKey(entry.getKey()) && + !item.getParam().get(entry.getKey()).equals(entry.getValue())) { + return 0; + } + cnt++; + } + return cnt; + } +} diff --git a/governance/src/main/java/org/apache/servicecomb/router/util/VersionCompareUtil.java b/governance/src/main/java/org/apache/servicecomb/router/util/VersionCompareUtil.java new file mode 100644 index 00000000000..1af7b521155 --- /dev/null +++ b/governance/src/main/java/org/apache/servicecomb/router/util/VersionCompareUtil.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.util; + +import org.apache.servicecomb.foundation.common.Version; + +public class VersionCompareUtil { + public static int compareVersion(String version1, String version2) { + return new Version(version1).compareTo(new Version(version2)); + } +} diff --git a/governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..a67e4ed8d0a --- /dev/null +++ b/governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,19 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.governance.GovernanceCommonConfiguration +org.apache.servicecomb.router.RouterCommonConfiguration diff --git a/governance/src/test/java/org/apache/servicecomb/governance/AbstractFailurePredictorTest.java b/governance/src/test/java/org/apache/servicecomb/governance/AbstractFailurePredictorTest.java new file mode 100644 index 00000000000..dedeba80053 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/AbstractFailurePredictorTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.governance.handler.ext.AbstractFailurePredictor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AbstractFailurePredictorTest { + class MyAbstractFailurePredictor extends AbstractFailurePredictor { + MyAbstractFailurePredictor() { + } + + @Override + protected String extractStatusCode(Object result) { + return (String) result; + } + + @Override + public boolean isFailedResult(List statusList, Throwable e) { + return super.isFailedResult(statusList, e); + } + } + + @Test + public void testCodeMatch() { + AbstractFailurePredictor predictor = new MyAbstractFailurePredictor(); + List statusList = Arrays.asList("500"); + Assertions.assertTrue(predictor.isFailedResult(statusList, "500")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "502")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "400")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "444")); + + statusList = Arrays.asList("5x0"); + Assertions.assertTrue(predictor.isFailedResult(statusList, "500")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "502")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "400")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "444")); + + statusList = Arrays.asList(null, "xx", "5x0"); + Assertions.assertTrue(predictor.isFailedResult(statusList, "500")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "502")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "400")); + Assertions.assertFalse(predictor.isFailedResult(statusList, "444")); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/BulkheadHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/BulkheadHandlerTest.java new file mode 100644 index 00000000000..59703d4ee7a --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/BulkheadHandlerTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.BulkheadHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.policy.BulkheadPolicy; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class BulkheadHandlerTest { + private BulkheadHandler bulkheadHandler; + + @Autowired + public void setInstanceIsolationHandler(BulkheadHandler scbBulkheadHandler) { + this.bulkheadHandler = scbBulkheadHandler; + } + + @Test + public void testMatchPriorityPolicy() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead"); + BulkheadPolicy policy = bulkheadHandler.matchPolicy(request); + Assertions.assertEquals("demo-bulkhead-priority", policy.getName()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/CustomMatchTest.java b/governance/src/test/java/org/apache/servicecomb/governance/CustomMatchTest.java new file mode 100644 index 00000000000..a0e0c2d8ab9 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/CustomMatchTest.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.marker.CustomMatcher; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.marker.Matcher; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.governance.mockclasses.service.MockConfigurationForCustomMatcher; +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.junit.jupiter.api.Assertions; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class, MockConfigurationForCustomMatcher.class}) +public class CustomMatchTest { + + private RequestProcessor requestProcessor; + + @Autowired + public void setRequestProcessor(RequestProcessor requestProcessor) { + this.requestProcessor = requestProcessor; + } + + private Matcher generateMatcher(String customMatcherHandler, String customMatcherParameters) { + CustomMatcher customMatcher = new CustomMatcher(); + customMatcher.setCustomMatcherHandler(customMatcherHandler); + customMatcher.setCustomMatcherParameters(customMatcherParameters); + Matcher matcher = new Matcher(); + matcher.setCustomMatcher(customMatcher); + return matcher; + } + + @Test + public void test_should_pass_when_value_class_empty() { + GovernanceRequest request = new GovernanceRequest(); + Matcher mockMatcher = generateMatcher("", ""); + Assert.assertTrue(this.requestProcessor.match(request, mockMatcher)); + mockMatcher = generateMatcher("", "bill"); + Assert.assertTrue(this.requestProcessor.match(request, mockMatcher)); + mockMatcher = generateMatcher("classWithAnnotation", ""); + Assert.assertTrue(this.requestProcessor.match(request, mockMatcher)); + } + + @Test + public void test_should_pass_when_value_class_match() { + GovernanceRequest request = new GovernanceRequest(); + Matcher mockMatcher = generateMatcher("classWithAnnotation", "bill"); + Assert.assertTrue(this.requestProcessor.match(request, mockMatcher)); + } + + @Test + public void test_should_throw_exception_when_class_not_found() { + GovernanceRequest request = new GovernanceRequest(); + try { + Matcher mockMatcher = generateMatcher("classWithAnnotationNotFound", "bill"); + this.requestProcessor.match(request, mockMatcher); + Assertions.fail("an exception is expected!"); + } catch (Exception e) { + Assert.assertTrue(e.getCause() instanceof ClassNotFoundException); + } + } + + @Test + public void test_should_pass_when_multiple_value() { + GovernanceRequest request = new GovernanceRequest(); + Matcher mockMatcher = generateMatcher("classWithAnnotation", "bill,bill2"); + Assert.assertTrue(this.requestProcessor.match(request, mockMatcher)); + } + + @Test + public void test_should_throw_exception_when_not_implements_interface() { + GovernanceRequest request = new GovernanceRequest(); + try { + Matcher mockMatcher = generateMatcher("classNotImplements", "bill,bill2"); + this.requestProcessor.match(request, mockMatcher); + Assertions.fail("an exception is expected!"); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains(RequestProcessor.errorMessageForNotImplements)); + } + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FaultInjectionTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FaultInjectionTest.java new file mode 100644 index 00000000000..7733b8ed44f --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/FaultInjectionTest.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.governance.handler.FaultInjectionHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.processor.injection.Fault; +import org.apache.servicecomb.governance.processor.injection.FaultInjectionDecorators; +import org.apache.servicecomb.governance.processor.injection.FaultInjectionDecorators.FaultInjectionDecorateCheckedSupplier; +import org.apache.servicecomb.governance.processor.injection.FaultInjectionException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class FaultInjectionTest { + private FaultInjectionHandler faultInjectionHandler; + + private FaultInjectionHandler faultInjectionHandler2; + + @Autowired + public void setFaultInjectionHandler(FaultInjectionHandler scbFaultInjectionHandler, + @Qualifier("faultInjectionHandler2") FaultInjectionHandler faultInjectionHandler2) { + this.faultInjectionHandler = scbFaultInjectionHandler; + this.faultInjectionHandler2 = faultInjectionHandler2; + } + + public FaultInjectionTest() { + } + + @Test + public void test_delay_fault_injection_service_name_work() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/faultInjectDelay"); + request.setServiceName("srcService"); + + Fault fault = faultInjectionHandler.getActuator(request); + ds.withFaultInjection(fault); + + Assertions.assertEquals("test", ds.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + long startTime = System.currentTimeMillis(); + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + // delayTime is 2S + if (System.currentTimeMillis() - startTime > 1000) { + expected.set(true); + } + } catch (Throwable e) { + notExpected.set(true); + } + cd.countDown(); + }).start(); + } + //timeout should be bigger than delayTime + cd.await(10, TimeUnit.SECONDS); + Assertions.assertFalse(notExpected.get()); + Assertions.assertTrue(expected.get()); + } + + @Test + public void test_abort_fault_injection_service_name_work() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/faultInjectAbort"); + request.setServiceName("srcService"); + + Fault fault = faultInjectionHandler.getActuator(request); + ds.withFaultInjection(fault); + + Assertions.assertEquals("test", ds.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (FaultInjectionException e) { + expected.set(true); + } catch (Throwable e) { + notExpected.set(true); + } + cd.countDown(); + }).start(); + } + cd.await(1, TimeUnit.SECONDS); + Assertions.assertFalse(notExpected.get()); + Assertions.assertTrue(expected.get()); + } + + @Test + public void test_fallback_returnNull_work() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/returnNull"); + request.setServiceName("returnNull"); + + Fault fault = faultInjectionHandler.getActuator(request); + ds.withFaultInjection(fault); + Assertions.assertEquals(null, ds.get()); + } + + @Test + public void test_fallback_ThrowException_work() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/throwException"); + request.setServiceName("ThrowException"); + + Fault fault = faultInjectionHandler.getActuator(request); + ds.withFaultInjection(fault); + boolean expected = false; + try { + ds.get(); + } catch (FaultInjectionException e) { + if (e.getFaultResponse().getErrorCode() == 500) { + expected = true; + } + } + Assertions.assertEquals(true, expected); + } + + @Test + public void test_fallback_forceClosed_work() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/forceClosed"); + request.setServiceName("forceClosed"); + + Fault fault = faultInjectionHandler.getActuator(request); + ds.withFaultInjection(fault); + Assertions.assertEquals("test", ds.get()); + } + + @Test + public void test_fallback_ThrowException_work_handler2() throws Throwable { + FaultInjectionDecorateCheckedSupplier ds = + FaultInjectionDecorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/throwException"); + request.setServiceName("ThrowException"); + + Fault fault = faultInjectionHandler2.getActuator(request); + ds.withFaultInjection(fault); + boolean expected = false; + try { + ds.get(); + } catch (FaultInjectionException e) { + if (e.getFaultResponse().getErrorCode() == 500) { + expected = true; + } + } + Assertions.assertEquals(true, expected); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java new file mode 100644 index 00000000000..a4b751fd95d --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.governance.handler.RateLimitingHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier; +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RequestNotPermitted; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class FlowControlTest { + private RateLimitingHandler rateLimitingHandler; + + @Autowired + public void setRateLimitingHandler(RateLimitingHandler rateLimitingHandler) { + this.rateLimitingHandler = rateLimitingHandler; + } + + public FlowControlTest() { + } + + @Test + public void test_rate_limiting_work() throws Throwable { + DecorateCheckedSupplier ds = Decorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/hello"); + + RateLimiter rateLimiter = rateLimitingHandler.getActuator(request); + ds.withRateLimiter(rateLimiter); + + Assertions.assertEquals("test", ds.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (Throwable e) { + if (e instanceof RequestNotPermitted) { + expected.set(true); + } else { + notExpected.set(true); + } + } + cd.countDown(); + }).start(); + } + cd.await(1, TimeUnit.SECONDS); + Assertions.assertTrue(expected.get()); + Assertions.assertFalse(notExpected.get()); + } + + @Test + public void test_rate_limiting_service_name_work() throws Throwable { + DecorateCheckedSupplier ds = Decorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/helloServiceName"); + request.setServiceName("srcService"); + + RateLimiter rateLimiter = rateLimitingHandler.getActuator(request); + ds.withRateLimiter(rateLimiter); + + Assertions.assertEquals("test", ds.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (Throwable e) { + if (e instanceof RequestNotPermitted) { + expected.set(true); + } else { + notExpected.set(true); + } + } + cd.countDown(); + }).start(); + } + cd.await(1, TimeUnit.SECONDS); + Assertions.assertTrue(expected.get()); + Assertions.assertFalse(notExpected.get()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java new file mode 100644 index 00000000000..ac26c3f3bdd --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernanceCacheHandlerTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + + +import org.apache.servicecomb.governance.handler.GovernanceCacheHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.policy.GovernanceCachePolicy; +import org.apache.servicecomb.governance.service.GovernanceCache; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class GovernanceCacheHandlerTest { + private GovernanceCacheHandler governanceCacheHandler; + + @Autowired + public void setInstanceIsolationHandler(@Autowired GovernanceCacheHandler governanceCacheHandler) { + this.governanceCacheHandler = governanceCacheHandler; + } + + @Test + public void testMatchPriorityPolicy() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/governanceCache"); + GovernanceCachePolicy policy = governanceCacheHandler.matchPolicy(request); + Assertions.assertEquals("demo-governanceCache", policy.getName()); + GovernanceCache governanceCache = governanceCacheHandler.getActuator(request); + governanceCache.putValueIntoCache("governance", "Cache"); + Object cache = governanceCache.getValueFromCache("governance"); + Assertions.assertEquals("Cache", cache); + governanceCache.putValueIntoCache("response", null); + Object response = governanceCache.getValueFromCache("response"); + Assertions.assertNull(response); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java new file mode 100644 index 00000000000..5b71a2ac3b8 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java @@ -0,0 +1,484 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.time.Duration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.governance.marker.Matcher; +import org.apache.servicecomb.governance.marker.TrafficMarker; +import org.apache.servicecomb.governance.policy.AbstractPolicy; +import org.apache.servicecomb.governance.policy.BulkheadPolicy; +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; +import org.apache.servicecomb.governance.policy.FaultInjectionPolicy; +import org.apache.servicecomb.governance.policy.GovernanceCachePolicy; +import org.apache.servicecomb.governance.policy.RateLimitingPolicy; +import org.apache.servicecomb.governance.policy.RetryPolicy; +import org.apache.servicecomb.governance.policy.TimeLimiterPolicy; +import org.apache.servicecomb.governance.processor.injection.FaultInjectionConst; +import org.apache.servicecomb.governance.properties.BulkheadProperties; +import org.apache.servicecomb.governance.properties.CircuitBreakerProperties; +import org.apache.servicecomb.governance.properties.FaultInjectionProperties; +import org.apache.servicecomb.governance.properties.GovernanceCacheProperties; +import org.apache.servicecomb.governance.properties.GovernanceProperties; +import org.apache.servicecomb.governance.properties.InstanceIsolationProperties; +import org.apache.servicecomb.governance.properties.MatchProperties; +import org.apache.servicecomb.governance.properties.RateLimitProperties; +import org.apache.servicecomb.governance.properties.RetryProperties; +import org.apache.servicecomb.governance.properties.TimeLimiterProperties; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class GovernancePropertiesTest { + private List> propertiesList; + + private MatchProperties matchProperties; + + private BulkheadProperties bulkheadProperties; + + private CircuitBreakerProperties circuitBreakerProperties; + + private TimeLimiterProperties timeLimiterProperties; + + private GovernanceCacheProperties governanceCacheProperties; + + private InstanceIsolationProperties instanceIsolationProperties; + + private RateLimitProperties rateLimitProperties; + + private RetryProperties retryProperties; + + private FaultInjectionProperties faultInjectionProperties; + + private Environment environment; + + @Autowired + public void setPropertiesList(List> propertiesList) { + this.propertiesList = propertiesList; + } + + @Autowired + public void setMatchProperties(MatchProperties scbMatchProperties) { + this.matchProperties = scbMatchProperties; + } + + @Autowired + public void setBulkheadProperties(BulkheadProperties scbBulkheadProperties) { + this.bulkheadProperties = scbBulkheadProperties; + } + + @Autowired + public void setCircuitBreakerProperties(CircuitBreakerProperties scbCircuitBreakerProperties) { + this.circuitBreakerProperties = scbCircuitBreakerProperties; + } + + @Autowired + public void setTimeLimiterProperties(TimeLimiterProperties scbTimeLimiterProperties) { + this.timeLimiterProperties = scbTimeLimiterProperties; + } + + @Autowired + public void setGovernanceCacheProperties(GovernanceCacheProperties scbGovernanceCacheProperties) { + this.governanceCacheProperties = scbGovernanceCacheProperties; + } + + @Autowired + public void setRateLimitProperties(RateLimitProperties scbRateLimitProperties) { + this.rateLimitProperties = scbRateLimitProperties; + } + + @Autowired + public void setInstanceIsolationProperties(InstanceIsolationProperties scbInstanceIsolationProperties) { + this.instanceIsolationProperties = scbInstanceIsolationProperties; + } + + @Autowired + public void setRetryProperties(RetryProperties scbRetryProperties) { + this.retryProperties = scbRetryProperties; + } + + @Autowired + public void setFaultInjectionProperties( + FaultInjectionProperties scbFaultInjectionProperties) { + this.faultInjectionProperties = scbFaultInjectionProperties; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setDynamicValues(Map dynamicValues) { + this.dynamicValues = dynamicValues; + } + + public GovernancePropertiesTest() { + } + + private Map dynamicValues = new HashMap<>(); + + private static final float DELTA = 0.0000001f; + + @BeforeEach + public void setUp() { + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + + if (configurableEnvironment.getPropertySources().contains("testDynamicChange")) { + configurableEnvironment.getPropertySources().remove("testDynamicChange"); + } + + configurableEnvironment.getPropertySources() + .addFirst(new EnumerablePropertySource>("testDynamicChange", dynamicValues) { + @Override + public Object getProperty(String s) { + return this.getSource().get(s); + } + + @Override + public String[] getPropertyNames() { + return this.getSource().keySet().toArray(new String[0]); + } + }); + } + + @AfterEach + public void tearDown() { + Set keys = dynamicValues.keySet(); + keys.forEach(k -> dynamicValues.put(k, null)); + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + } + + @Test + public void test_all_bean_is_loaded() { + Assertions.assertEquals(16, propertiesList.size()); + } + + @Test + public void test_match_properties_successfully_loaded() { + Map markers = matchProperties.getParsedEntity(); + TrafficMarker demoRateLimiting = markers.get("demo-rateLimiting"); + List matchers = demoRateLimiting.getMatches(); + Assertions.assertEquals(1, matchers.size()); + Matcher matcher = matchers.get(0); + Assertions.assertEquals("/hello", matcher.getApiPath().get("exact")); + + TrafficMarker demoBulkhead = markers.get("demo-bulkhead"); + matchers = demoBulkhead.getMatches(); + Assertions.assertEquals(2, matchers.size()); + matcher = matchers.get(0); + Assertions.assertEquals("/bulkhead", matcher.getApiPath().get("exact")); + Assertions.assertEquals("matchPath", matcher.getName()); + } + + @Test + public void test_match_properties_delete() { + Map markers = matchProperties.getParsedEntity(); + Assertions.assertEquals(null, markers.get("test")); + dynamicValues.put("servicecomb.matchGroup.test", "matches:\n" + + " - apiPath:\n" + + " exact: \"/hello2\"\n" + + " name: match0"); + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + markers = matchProperties.getParsedEntity(); + Assertions.assertEquals(1, markers.get("test").getMatches().size()); + tearDown(); + markers = matchProperties.getParsedEntity(); + Assertions.assertEquals(null, markers.get("test")); + } + + @Test + public void test_match_properties_changed() { + dynamicValues.put("servicecomb.matchGroup.demo-rateLimiting", "matches:\n" + + " - apiPath:\n" + + " exact: \"/hello2\"\n" + + " name: match0"); + dynamicValues.put("servicecomb.matchGroup.demo-rateLimiting2", "matches:\n" + + " - apiPath:\n" + + " exact: \"/hello2\"\n" + + " name: match0"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map markers = matchProperties.getParsedEntity(); + TrafficMarker demoRateLimiting = markers.get("demo-rateLimiting"); + List matchers = demoRateLimiting.getMatches(); + Assertions.assertEquals(1, matchers.size()); + Matcher matcher = matchers.get(0); + Assertions.assertEquals("/hello2", matcher.getApiPath().get("exact")); + + demoRateLimiting = markers.get("demo-rateLimiting2"); + matchers = demoRateLimiting.getMatches(); + Assertions.assertEquals(1, matchers.size()); + matcher = matchers.get(0); + Assertions.assertEquals("/hello2", matcher.getApiPath().get("exact")); + } + + @Test + public void test_bulkhead_properties_changed() { + dynamicValues.put("servicecomb.bulkhead.demo-bulkhead", "rules:\n" + + "maxConcurrentCalls: 2\n" + + "maxWaitDuration: 2000"); + dynamicValues.put("servicecomb.bulkhead.bulkhead1", "rules:\n" + + "maxConcurrentCalls: 3\n" + + "maxWaitDuration: 3000"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(3, policies.size()); + BulkheadPolicy policy = policies.get("demo-bulkhead"); + Assertions.assertEquals(2, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(2000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + + policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(3, policies.size()); + policy = policies.get("bulkhead1"); + Assertions.assertEquals(3, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(3000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + Assertions.assertEquals("bulkhead1", policy.getName()); + } + + @Test + public void test_bulkhead_properties_bound() { + dynamicValues.put("servicecomb.bulkhead.test-bulkhead1", "rules:\n" + + "maxConcurrentCalls: 0\n" + + "maxWaitDuration: 2000"); + dynamicValues.put("servicecomb.bulkhead.test-bulkhead2", "rules:\n" + + "maxConcurrentCalls: 1000\n" + + "maxWaitDuration: 0"); + dynamicValues.put("servicecomb.bulkhead.test-bulkhead3", "rules:\n" + + "maxConcurrentCalls: 0\n" + + "maxWaitDuration: 2S"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(5, policies.size()); + BulkheadPolicy policy = policies.get("test-bulkhead1"); + Assertions.assertEquals(0, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(2000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + + policy = policies.get("test-bulkhead2"); + Assertions.assertEquals(1000, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(0, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + Assertions.assertEquals("test-bulkhead2", policy.getName()); + + policy = policies.get("test-bulkhead3"); + Assertions.assertEquals(0, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(2000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + Assertions.assertEquals("test-bulkhead3", policy.getName()); + } + + @Test + public void test_bulkhead_properties_successfully_loaded() { + Map policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(2, policies.size()); + BulkheadPolicy policy = policies.get("demo-bulkhead"); + Assertions.assertEquals(1, policy.getMaxConcurrentCalls()); + Assertions.assertEquals(3000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + } + + @Test + public void test_timelimiter_properties_successfully_loaded() { + Map policies = timeLimiterProperties.getParsedEntity(); + Assertions.assertEquals(2, policies.size()); + TimeLimiterPolicy timeLimiterPolicy = policies.get("demo-timeLimiter-other"); + Assertions.assertEquals(2000, Duration.parse(timeLimiterPolicy.getTimeoutDuration()).toMillis()); + Assertions.assertEquals(false, timeLimiterPolicy.isCancelRunningFuture()); + } + + @Test + public void test_timelimiter_properties_bound() { + dynamicValues.put("servicecomb.timeLimiter.name1", "rules:\n" + + "timeoutDuration: 5000\n" + + "cancelRunningFuture: false"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = timeLimiterProperties.getParsedEntity(); + Assertions.assertEquals(3, policies.size()); + TimeLimiterPolicy policy = policies.get("name1"); + Assertions.assertEquals(false, policy.isCancelRunningFuture()); + Assertions.assertEquals(5000, Duration.parse(policy.getTimeoutDuration()).toMillis()); + } + + @Test + public void test_governanceCache_properties_successfully_loaded() { + Map policies = governanceCacheProperties.getParsedEntity(); + Assertions.assertEquals(2, policies.size()); + GovernanceCachePolicy governanceCachePolicy = policies.get("demo-governanceCache-other"); + Assertions.assertEquals(15, governanceCachePolicy.getConcurrencyLevel()); + Assertions.assertEquals(50000, governanceCachePolicy.getMaximumSize()); + Assertions.assertEquals(666666, Duration.parse(governanceCachePolicy.getTtl()).toMillis()); + } + + @Test + public void test_governanceCache_properties_bound() { + dynamicValues.put("servicecomb.cache.name1", "rules:\n" + + "ttl: 3000000\n" + + "maximumSize: 2000\n" + + "concurrencyLevel: 6"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = governanceCacheProperties.getParsedEntity(); + Assertions.assertEquals(3, policies.size()); + GovernanceCachePolicy policy = policies.get("name1"); + Assertions.assertEquals(3000000, Duration.parse(policy.getTtl()).toMillis()); + Assertions.assertEquals(2000, policy.getMaximumSize()); + Assertions.assertEquals(6, policy.getConcurrencyLevel()); + } + + @Test + public void test_circuit_breaker_properties_successfully_loaded() { + Map policies = circuitBreakerProperties.getParsedEntity(); + Assertions.assertEquals(1, policies.size()); + CircuitBreakerPolicy policy = policies.get("demo-circuitBreaker"); + Assertions.assertEquals(2, policy.getMinimumNumberOfCalls()); + Assertions.assertEquals("2", policy.getSlidingWindowSize()); + } + + @Test + public void test_circuit_breaker_properties_Of_windows_size() { + dynamicValues.put("servicecomb.circuitBreaker.name1", "rules:\n" + + "slidingWindowType: count\n" + + "slidingWindowSize: 2"); + dynamicValues.put("servicecomb.circuitBreaker.name2", "rules:\n" + + "slidingWindowType: time\n" + + "slidingWindowSize: 2"); + dynamicValues.put("servicecomb.circuitBreaker.name3", "rules:\n" + + "slidingWindowType: test\n" + + "slidingWindowSize: 1M"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = circuitBreakerProperties.getParsedEntity(); + Assertions.assertEquals(4, policies.size()); + CircuitBreakerPolicy policy = policies.get("name1"); + Assertions.assertEquals("count", policy.getSlidingWindowType()); + Assertions.assertEquals("2", policy.getSlidingWindowSize()); + + policy = policies.get("name2"); + Assertions.assertEquals("time", policy.getSlidingWindowType()); + Assertions.assertEquals("2", policy.getSlidingWindowSize()); + + policy = policies.get("name3"); + Assertions.assertEquals("60", policy.getSlidingWindowSize()); + } + + @Test + public void test_circuit_breaker_properties_Of_type() { + dynamicValues.put("servicecomb.circuitBreaker.type1", "rules:\n" + + "failureRateThreshold: 20\n" + + "slowCallRateThreshold: 100"); + dynamicValues.put("servicecomb.circuitBreaker.type2", "rules:\n" + + "failureRateThreshold: 20.33\n" + + "slowCallRateThreshold: 0.01"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = circuitBreakerProperties.getParsedEntity(); + CircuitBreakerPolicy policy = policies.get("type1"); + Assertions.assertEquals(20.0f, policy.getFailureRateThreshold(), DELTA); + Assertions.assertEquals(100.0f, policy.getSlowCallRateThreshold(), DELTA); + + policy = policies.get("type2"); + Assertions.assertEquals(20.33f, policy.getFailureRateThreshold(), DELTA); + Assertions.assertEquals(0.01f, policy.getSlowCallRateThreshold(), DELTA); + } + + @Test + public void test_rate_limit_properties_successfully_loaded() { + Map policies = rateLimitProperties.getParsedEntity(); + Assertions.assertEquals(2, policies.size()); + RateLimitingPolicy policy = policies.get("demo-rateLimiting"); + Assertions.assertEquals(1, policy.getRate()); + } + + @Test + public void test_retry_properties_successfully_loaded() { + Map policies = retryProperties.getParsedEntity(); + Assertions.assertEquals(1, policies.size()); + RetryPolicy policy = policies.get("demo-retry"); + Assertions.assertEquals(3, policy.getMaxAttempts()); + } + + + @Test + public void test_properties_changed_to_duration() { + dynamicValues.put("servicecomb.bulkhead.test1", "rules:\n" + + "maxConcurrentCalls: 2\n" + + "maxWaitDuration: 2S"); + dynamicValues.put("servicecomb.bulkhead.test2", "rules:\n" + + "maxConcurrentCalls: 3\n" + + "maxWaitDuration: 1M"); + + GovernanceEventManager.post(new GovernanceConfigurationChangedEvent(new HashSet<>(dynamicValues.keySet()))); + + Map policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(4, policies.size()); + BulkheadPolicy policy = policies.get("test1"); + Assertions.assertEquals(2000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + + policies = bulkheadProperties.getParsedEntity(); + Assertions.assertEquals(4, policies.size()); + policy = policies.get("test2"); + Assertions.assertEquals(60000, Duration.parse(policy.getMaxWaitDuration()).toMillis()); + } + + @Test + public void test_instance_isolation_properties_successfully_loaded() { + Map policies = instanceIsolationProperties.getParsedEntity(); + Assertions.assertEquals(1, policies.size()); + CircuitBreakerPolicy policy = policies.get("demo-allOperation"); + Assertions.assertEquals(2, policy.getMinimumNumberOfCalls()); + Assertions.assertEquals("2", policy.getSlidingWindowSize()); + } + + @Test + public void test_fault_injection_properties_successfully_loaded() { + Map policies = faultInjectionProperties.getParsedEntity(); + Assertions.assertEquals(5, policies.size()); + FaultInjectionPolicy policy = policies.get("demo-faultInjectDelay"); + Assertions.assertEquals(FaultInjectionConst.TYPE_DELAY, policy.getType()); + Assertions.assertEquals(2000, policy.getDelayTimeToMillis()); + Assertions.assertEquals(100, policy.getPercentage()); + + policy = policies.get("demo-faultInjectAbort"); + Assertions.assertEquals(FaultInjectionConst.TYPE_ABORT, policy.getType()); + Assertions.assertEquals(50, policy.getPercentage()); + Assertions.assertEquals(500, policy.getErrorCode()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/IdentifierRateLimitingHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/IdentifierRateLimitingHandlerTest.java new file mode 100644 index 00000000000..1aed8e4a302 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/IdentifierRateLimitingHandlerTest.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.governance.handler.IdentifierRateLimitingHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier; +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RequestNotPermitted; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class IdentifierRateLimitingHandlerTest { + private IdentifierRateLimitingHandler rateLimitingHandler; + + @Autowired + public void setRateLimitingHandler(IdentifierRateLimitingHandler rateLimitingHandler) { + this.rateLimitingHandler = rateLimitingHandler; + } + + public IdentifierRateLimitingHandlerTest() { + } + + @Test + public void test_rate_limiting_work() throws Throwable { + DecorateCheckedSupplier ds = Decorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/hello"); + Map headers = new HashMap<>(); + headers.put("test", "1234"); + request.setHeaders(headers); + + RateLimiter rateLimiter = rateLimitingHandler.getActuator(request); + ds.withRateLimiter(rateLimiter); + + Assertions.assertEquals("test", ds.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (Throwable e) { + if (e instanceof RequestNotPermitted) { + expected.set(true); + } else { + notExpected.set(true); + } + } + cd.countDown(); + }).start(); + } + cd.await(1, TimeUnit.SECONDS); + Assertions.assertTrue(expected.get()); + Assertions.assertFalse(notExpected.get()); + } + + @Test + public void test_rate_limiting_service_name_work() throws Throwable { + DecorateCheckedSupplier ds = Decorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/helloServiceName"); + request.setServiceName("srcService"); + Map headers = new HashMap<>(); + headers.put("test", "1234"); + request.setHeaders(headers); + + RateLimiter rateLimiter = rateLimitingHandler.getActuator(request); + ds.withRateLimiter(rateLimiter); + + Assertions.assertEquals("test", ds.get()); + + headers = new HashMap<>(); + headers.put("test", "12345"); + request.setHeaders(headers); + + RateLimiter rateLimiter2 = rateLimitingHandler.getActuator(request); + DecorateCheckedSupplier ds2 = Decorators.ofCheckedSupplier(() -> "test2"); + ds2.withRateLimiter(rateLimiter2); + Assertions.assertEquals("test2", ds2.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread(() -> { + try { + Object result = ds.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (Throwable e) { + if (e instanceof RequestNotPermitted) { + expected.set(true); + } else { + notExpected.set(true); + } + } + cd.countDown(); + }).start(); + } + cd.await(1, TimeUnit.SECONDS); + Assertions.assertTrue(expected.get()); + Assertions.assertFalse(notExpected.get()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/InstanceBulkheadHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/InstanceBulkheadHandlerTest.java new file mode 100644 index 00000000000..de5213ef520 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/InstanceBulkheadHandlerTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.governance.handler.InstanceBulkheadHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadFullException; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class InstanceBulkheadHandlerTest { + private InstanceBulkheadHandler instanceBulkheadHandler; + + @Autowired + public void setInstanceBulkheadHandler(InstanceBulkheadHandler instanceBulkheadHandler) { + this.instanceBulkheadHandler = instanceBulkheadHandler; + } + + @Test + public void test_instance_bulkhead_work() throws Throwable { + + // instance1 + DecorateCheckedSupplier dsInstance1 = Decorators.ofCheckedSupplier(() -> "wake"); + + GovernanceRequest requestInstance1 = new GovernanceRequest(); + requestInstance1.setInstanceId("instance01"); + requestInstance1.setServiceName("service01"); + requestInstance1.setApiPath("/test"); + + Bulkhead bulkheadInstance1 = instanceBulkheadHandler.getActuator(requestInstance1); + dsInstance1.withBulkhead(bulkheadInstance1); + + // instance2 + DecorateCheckedSupplier dsInstance2 = Decorators.ofCheckedSupplier(() -> { + Thread.sleep(1000); + return "sleep"; + }); + + GovernanceRequest requestInstance2 = new GovernanceRequest(); + requestInstance2.setInstanceId("instance02"); + requestInstance2.setServiceName("service01"); + requestInstance2.setApiPath("/test"); + + Bulkhead bulkheadInstance2 = instanceBulkheadHandler.getActuator(requestInstance2); + dsInstance2.withBulkhead(bulkheadInstance2); + + Executor executor = Executors.newFixedThreadPool(4); + AtomicInteger wakeCount = new AtomicInteger(0); + AtomicInteger sleepCount = new AtomicInteger(0); + AtomicInteger errorCount = new AtomicInteger(0); + AtomicInteger rejectCount = new AtomicInteger(0); + CountDownLatch countDownLatch = new CountDownLatch(100); + for (int i = 0; i < 100; i++) { + final int num = i; + executor.execute(() -> { + // 50% for each server + if (num % 2 == 0) { + runCommand(dsInstance1, wakeCount, sleepCount, errorCount, rejectCount, countDownLatch); + } else { + runCommand(dsInstance2, wakeCount, sleepCount, errorCount, rejectCount, countDownLatch); + } + }); + } + countDownLatch.await(100, TimeUnit.SECONDS); + Assertions.assertEquals(50, wakeCount.get()); + Assertions.assertEquals(2, sleepCount.get()); + Assertions.assertEquals(0, errorCount.get()); + Assertions.assertEquals(48, rejectCount.get()); + } + + private void runCommand(DecorateCheckedSupplier ds, AtomicInteger wakeCount, AtomicInteger sleepCount, + AtomicInteger errorCount, AtomicInteger rejectCount, CountDownLatch countDownLatch) { + try { + String result = ds.get(); + if ("wake".equals(result)) { + wakeCount.incrementAndGet(); + } else if ("sleep".equals(result)) { + sleepCount.incrementAndGet(); + } else { + errorCount.incrementAndGet(); + } + } catch (BulkheadFullException e) { + rejectCount.incrementAndGet(); + } catch (Throwable e) { + errorCount.incrementAndGet(); + } + countDownLatch.countDown(); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java b/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java new file mode 100644 index 00000000000..0a6c8f23e14 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/InstanceIsolationTest.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.net.ConnectException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.governance.handler.InstanceIsolationHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.github.resilience4j.circuitbreaker.CallNotPermittedException; +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.prometheusmetrics.PrometheusMeterRegistry; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class InstanceIsolationTest { + private InstanceIsolationHandler instanceIsolationHandler; + + private MeterRegistry meterRegistry; + + @Autowired + public void setInstanceIsolationHandler(InstanceIsolationHandler instanceIsolationHandler, + MeterRegistry meterRegistry) { + this.instanceIsolationHandler = instanceIsolationHandler; + this.meterRegistry = meterRegistry; + } + + @Test + public void test_instance_isolation_work() throws Throwable { + AtomicInteger counter = new AtomicInteger(0); + + DecorateCheckedSupplier ds = Decorators.ofCheckedSupplier(() -> { + int run = counter.getAndIncrement(); + if (run == 0) { + return "test"; + } + if (run == 1) { + throw new ConnectException("test exception"); + } + return "test"; + }); + + DecorateCheckedSupplier ds2 = Decorators.ofCheckedSupplier(() -> "test"); + + GovernanceRequest request = new GovernanceRequest(); + request.setInstanceId("instance01"); + request.setServiceName("service01"); + request.setApiPath("/test"); + + CircuitBreaker circuitBreaker = instanceIsolationHandler.getActuator(request); + ds.withCircuitBreaker(circuitBreaker); + + // isolation from error + Assertions.assertEquals("test", ds.get()); + Assertions.assertThrows(ConnectException.class, ds::get); + + Assertions.assertThrows(CallNotPermittedException.class, ds::get); + Assertions.assertThrows(CallNotPermittedException.class, ds::get); + + Assertions.assertThrows(CallNotPermittedException.class, ds::get); + Assertions.assertThrows(CallNotPermittedException.class, ds::get); + Assertions.assertThrows(CallNotPermittedException.class, ds::get); + + // isolation do not influence other instances + GovernanceRequest request2 = new GovernanceRequest(); + request2.setInstanceId("instance02"); + request2.setServiceName("service01"); + request2.setApiPath("/test"); + + CircuitBreaker circuitBreaker2 = instanceIsolationHandler.getActuator(request2); + ds2.withCircuitBreaker(circuitBreaker2); + + Assertions.assertEquals("test", ds2.get()); + Assertions.assertEquals("test", ds2.get()); + Assertions.assertEquals("test", ds2.get()); + Assertions.assertEquals("test", ds2.get()); + + assertMetricsNotFinish(); + + // recover from isolation + Thread.sleep(1000); + + Assertions.assertEquals("test", ds.get()); + Assertions.assertEquals("test", ds.get()); + Assertions.assertEquals("test", ds2.get()); + Assertions.assertEquals("test", ds2.get()); + + assertMetricsFinish(); + } + + private void assertMetricsNotFinish() { + String result = ((PrometheusMeterRegistry) meterRegistry).scrape(); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_state{name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance01\",state=\"open\"} 1.0")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_state{name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance02\",state=\"closed\"} 1.0")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_calls_seconds_count{kind=\"successful\",name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance01\"} 1")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_calls_seconds_count{kind=\"successful\",name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance02\"} 4")); + } + + private void assertMetricsFinish() { + String result = ((PrometheusMeterRegistry) meterRegistry).scrape(); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_state{name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance01\",state=\"closed\"} 1.0")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_state{name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance02\",state=\"closed\"} 1.0")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_calls_seconds_count{kind=\"successful\",name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance01\"} 3")); + Assertions.assertTrue(result.contains( + "servicecomb_instanceIsolation_calls_seconds_count{kind=\"successful\",name=\"servicecomb.instanceIsolation.demo-allOperation.service01.instance02\"} 6")); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/LoadBalancerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/LoadBalancerTest.java new file mode 100644 index 00000000000..9973cbc56c7 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/LoadBalancerTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.LoadBalanceHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.processor.loadbanlance.LoadBalance; +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class LoadBalancerTest { + private LoadBalanceHandler loadBalanceHandler; + + @Autowired + public void setLoadBalanceHandler(LoadBalanceHandler loadBalanceHandler) { + this.loadBalanceHandler = loadBalanceHandler; + } + + public LoadBalancerTest() { + + } + + @Test + public void test_loadbalance_random() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/loadrandom"); + request.setServiceName("loadrandom"); + LoadBalance loadBalance = loadBalanceHandler.getActuator(request); + Assert.assertEquals("Random", loadBalance.getRule()); + } + + @Test + public void test_loadbalance_roundRobin() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/loadroundRobin"); + request.setServiceName("loadroundRobin"); + LoadBalance loadBalance = loadBalanceHandler.getActuator(request); + Assert.assertEquals("RoundRobin", loadBalance.getRule()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MapperTest.java b/governance/src/test/java/org/apache/servicecomb/governance/MapperTest.java new file mode 100644 index 00000000000..4a4607fefc3 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MapperTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.governance.handler.MapperHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.processor.mapping.Mapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class MapperTest { + private MapperHandler mapperHandler; + + private MapperHandler mapperHandler2; + + @Autowired + public void setMapperHandler(MapperHandler scbMapperHandler, @Qualifier("mapperHandler2") MapperHandler mapperHandler2) { + this.mapperHandler = scbMapperHandler; + this.mapperHandler2 = mapperHandler2; + } + + @Test + public void test_mapper_work() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/mapper/v1"); + Mapper mapper = mapperHandler.getActuator(request); + Assertions.assertEquals(2, mapper.target().size()); + Assertions.assertEquals("127.0.0.1", mapper.target().get("host")); + Assertions.assertEquals("8080", mapper.target().get("port")); + } + + @Test + public void test_mapper_query_work() { + GovernanceRequest request = new GovernanceRequest(); + Map queries = new HashMap<>(); + queries.put("name", "bob"); + request.setQueries(queries); + Mapper mapper = mapperHandler.getActuator(request); + Assertions.assertEquals(1, mapper.target().size()); + Assertions.assertEquals("$Q{name}", mapper.target().get("user-id")); + } + + @Test + public void test_mapper2_work() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/mapper/v1"); + Mapper mapper = mapperHandler2.getActuator(request); + Assertions.assertEquals(2, mapper.target().size()); + Assertions.assertEquals("127.0.0.1", mapper.target().get("host")); + Assertions.assertEquals("9090", mapper.target().get("port")); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockCircuitBreakerExtension.java b/governance/src/test/java/org/apache/servicecomb/governance/MockCircuitBreakerExtension.java new file mode 100644 index 00000000000..c66cac8fbfa --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockCircuitBreakerExtension.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension; + +public class MockCircuitBreakerExtension extends AbstractCircuitBreakerExtension { + @Override + protected String extractStatusCode(Object result) { + return "200"; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockConfiguration.java b/governance/src/test/java/org/apache/servicecomb/governance/MockConfiguration.java new file mode 100644 index 00000000000..85c04f39590 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockConfiguration.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.BulkheadHandler; +import org.apache.servicecomb.governance.handler.CircuitBreakerHandler; +import org.apache.servicecomb.governance.handler.FaultInjectionHandler; +import org.apache.servicecomb.governance.handler.MapperHandler; +import org.apache.servicecomb.governance.handler.ext.AbstractCircuitBreakerExtension; +import org.apache.servicecomb.governance.properties.BulkheadProperties; +import org.apache.servicecomb.governance.properties.CircuitBreakerProperties; +import org.apache.servicecomb.governance.properties.FaultInjectionProperties; +import org.apache.servicecomb.governance.properties.MapperProperties; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.micrometer.prometheusmetrics.PrometheusConfig; +import io.micrometer.prometheusmetrics.PrometheusMeterRegistry; + + +@Configuration +public class MockConfiguration { + @Bean + public MockMicroserviceMeta mockMicroserviceMeta() { + return new MockMicroserviceMeta(); + } + + @Bean + public MockRetryExtension mockRetryExtension() { + return new MockRetryExtension(); + } + + @Bean + public MockCircuitBreakerExtension circuitBreakerExtension() { + return new MockCircuitBreakerExtension(); + } + + @Bean + public MockInstanceIsolationExtension instanceIsolationExtension() { + return new MockInstanceIsolationExtension(); + } + + @Bean + public PrometheusMeterRegistry meterRegistry() { + return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + } + + @Bean + public MapperProperties mapperProperties2() { + return new MapperProperties(MapperProperties.MATCH_MAPPER_KEY + "2"); + } + + @Bean + public MapperHandler mapperHandler2(@Qualifier("mapperProperties2") MapperProperties mapperProperties) { + return new MapperHandler(mapperProperties); + } + + @Bean + public BulkheadProperties bulkheadProperties2() { + return new BulkheadProperties(BulkheadProperties.MATCH_BULKHEAD_KEY + "2"); + } + + @Bean + public BulkheadHandler bulkheadHandler2(@Qualifier("bulkheadProperties2") BulkheadProperties bulkheadProperties) { + return new BulkheadHandler(bulkheadProperties); + } + + @Bean + public CircuitBreakerProperties circuitBreakerProperties2() { + return new CircuitBreakerProperties(CircuitBreakerProperties.MATCH_CIRCUITBREAKER_KEY + "2"); + } + + @Bean + public CircuitBreakerHandler circuitBreakerHandler2( + @Qualifier("circuitBreakerProperties2") CircuitBreakerProperties circuitBreakerProperties, + AbstractCircuitBreakerExtension circuitBreakerExtension) { + return new CircuitBreakerHandler(circuitBreakerProperties, circuitBreakerExtension); + } + + @Bean + public FaultInjectionProperties faultInjectionProperties2() { + return new FaultInjectionProperties(FaultInjectionProperties.MATCH_FAULT_INJECTION_KEY + "2"); + } + + @Bean + public FaultInjectionHandler faultInjectionHandler2( + @Qualifier("faultInjectionProperties2") FaultInjectionProperties faultInjectionProperties) { + return new FaultInjectionHandler(faultInjectionProperties); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockInstanceIsolationExtension.java b/governance/src/test/java/org/apache/servicecomb/governance/MockInstanceIsolationExtension.java new file mode 100644 index 00000000000..86f0ce99b37 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockInstanceIsolationExtension.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.ext.AbstractInstanceIsolationExtension; + +public class MockInstanceIsolationExtension extends AbstractInstanceIsolationExtension { + @Override + protected String extractStatusCode(Object result) { + return "200"; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockMicroserviceMeta.java b/governance/src/test/java/org/apache/servicecomb/governance/MockMicroserviceMeta.java new file mode 100644 index 00000000000..ca68e2b3a39 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockMicroserviceMeta.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +public class MockMicroserviceMeta implements MicroserviceMeta { + @Override + public String getName() { + return "myself"; + } + + @Override + public String getVersion() { + return "1.0"; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockRetryExtension.java b/governance/src/test/java/org/apache/servicecomb/governance/MockRetryExtension.java new file mode 100644 index 00000000000..2badc9c1548 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockRetryExtension.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.List; + +import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension; + + +public class MockRetryExtension extends AbstractRetryExtension { + @Override + public boolean isFailedResult(List statusList, Object result) { + return false; + } + + @Override + protected String extractStatusCode(Object result) { + return null; + } + + @Override + public boolean isFailedResult(List statusList, Throwable e) { + return false; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/OperatorTest.java b/governance/src/test/java/org/apache/servicecomb/governance/OperatorTest.java new file mode 100644 index 00000000000..7c0670acb93 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/OperatorTest.java @@ -0,0 +1,297 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.time.Duration; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.marker.Matcher; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.governance.marker.operator.RawOperator; +import org.apache.servicecomb.governance.policy.RetryPolicy; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class OperatorTest { + private RequestProcessor requestProcessor; + + @Autowired + public void setRequestProcessor(RequestProcessor requestProcessor) { + this.requestProcessor = requestProcessor; + } + + @Test + public void test_unknown_operator() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/test"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("unknown", "/test"); + matcher.setApiPath(apiPath); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_exact_api_path_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("exact", "/bulkhead"); + matcher.setApiPath(apiPath); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_prefix_api_path_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead/hello"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("prefix", "/bulkhead"); + matcher.setApiPath(apiPath); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_prefix_api_path_not_match_null() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead/hello"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("prefix", null); + matcher.setApiPath(apiPath); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_suffix_api_path_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/api/bulkhead"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("suffix", "/bulkhead"); + matcher.setApiPath(apiPath); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_suffix_api_path_not_match_null() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/api/bulkhead"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("suffix", null); + matcher.setApiPath(apiPath); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_exact_api_path_not_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead/"); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("exact", "/bulkhead"); + matcher.setApiPath(apiPath); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + request.setApiPath("/bulkhead"); + request.setApiPath(null); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + request.setApiPath("/bulkhead"); + apiPath.clear(); + matcher.setApiPath(apiPath); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_exact_api_path_match_header_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead"); + request.setMethod("GET"); + Map reqHeaders = new HashMap<>(); + reqHeaders.put("header1", "value1"); + request.setHeaders(reqHeaders); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("exact", "/bulkhead"); + matcher.setApiPath(apiPath); + matcher.setMethod(Arrays.asList("GET")); + Map headers = new HashMap<>(); + RawOperator header1 = new RawOperator(); + header1.put("exact", "value1"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_exact_api_path_match_header_not_match() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/bulkhead"); + request.setMethod("GET"); + Map reqHeaders = new HashMap<>(); + reqHeaders.put("header1", "value2"); + request.setHeaders(reqHeaders); + Matcher matcher = new Matcher(); + RawOperator apiPath = new RawOperator(); + apiPath.put("exact", "/bulkhead"); + matcher.setApiPath(apiPath); + matcher.setMethod(Arrays.asList("GET")); + Map headers = new HashMap<>(); + RawOperator header1 = new RawOperator(); + header1.put("exact", "value1"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + reqHeaders.clear(); + request.setHeaders(reqHeaders); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_header_low_case() { + GovernanceRequest request = new GovernanceRequest(); + Map reqHeaders = new HashMap<>(); + reqHeaders.put("hEadeR", "100"); + request.setHeaders(reqHeaders); + Matcher matcher = new Matcher(); + Map headers = new HashMap<>(); + RawOperator header1 = new RawOperator(); + header1.put("compare", ">10"); + headers.put("HeAder", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_compare_header_match() { + GovernanceRequest request = new GovernanceRequest(); + Map reqHeaders = new HashMap<>(); + reqHeaders.put("header1", "100"); + request.setHeaders(reqHeaders); + Matcher matcher = new Matcher(); + Map headers = new HashMap<>(); + + RawOperator header1 = new RawOperator(); + header1.put("compare", ">10"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", ">=10"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "<1000"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "<=1000"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "=100"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertTrue(requestProcessor.match(request, matcher)); + } + + @Test + public void test_compare_header_not_match() { + GovernanceRequest request = new GovernanceRequest(); + Map reqHeaders = new HashMap<>(); + reqHeaders.put("header1", "100"); + request.setHeaders(reqHeaders); + Matcher matcher = new Matcher(); + Map headers = new HashMap<>(); + + RawOperator header1 = new RawOperator(); + header1.put("compare", ">1000"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", ">=1000"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "<10"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "<=10"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + + header1 = new RawOperator(); + header1.put("compare", "=200"); + headers.put("header1", header1); + matcher.setHeaders(headers); + Assertions.assertFalse(requestProcessor.match(request, matcher)); + } + + @Test + public void test_time_changed_to_duration() { + RetryPolicy retryPolicy = new RetryPolicy(); + String result; + result = retryPolicy.stringOfDuration("100", Duration.ofMillis(10)); + Assertions.assertEquals("PT0.1S", result); + Assertions.assertEquals(100, Duration.parse(result).toMillis()); + + result = retryPolicy.stringOfDuration("3S", Duration.ofMillis(10)); + Assertions.assertEquals("PT3S", result); + Assertions.assertEquals(3000, Duration.parse(result).toMillis()); + + result = retryPolicy.stringOfDuration("1M", Duration.ofMillis(10)); + Assertions.assertEquals("PT1M", result); + Assertions.assertEquals(60000, Duration.parse(result).toMillis()); + + result = retryPolicy.stringOfDuration("1H", Duration.ofMillis(10)); + Assertions.assertEquals("PT1H", result); + Assertions.assertEquals(3600000, Duration.parse(result).toMillis()); + + result = retryPolicy.stringOfDuration("3", Duration.ofMillis(10)); + Assertions.assertEquals("PT0.003S", result); + Assertions.assertEquals(3, Duration.parse(result).toMillis()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/RetryHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/RetryHandlerTest.java new file mode 100644 index 00000000000..073cfc44534 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/RetryHandlerTest.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + +import org.apache.servicecomb.governance.handler.Disposable; +import org.apache.servicecomb.governance.handler.RetryHandler; +import org.apache.servicecomb.governance.handler.ext.AbstractRetryExtension; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.policy.RetryPolicy; +import org.apache.servicecomb.governance.properties.RetryProperties; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import io.github.resilience4j.retry.MaxRetriesExceededException; +import io.github.resilience4j.retry.Retry; + +public class RetryHandlerTest { + @Test + public void testNotFailAfterMaxAttemptsWhenThrow() { + AbstractRetryExtension retryExtension = Mockito.mock(AbstractRetryExtension.class); + RetryProperties retryProperties = Mockito.mock(RetryProperties.class); + GovernanceRequest governanceRequest = Mockito.mock(GovernanceRequest.class); + Mockito.when(retryExtension.isFailedResult(Mockito.any(), Mockito.any())).thenReturn(true); + + RetryPolicy retryPolicy = new RetryPolicy(); + retryPolicy.setName("test"); + retryPolicy.setFailAfterMaxAttempts(false); + RetryHandler retryHandler = new RetryHandler(retryProperties, retryExtension); + + Disposable retry = retryHandler.createProcessor(retryPolicy.getName(), governanceRequest, retryPolicy); + Assertions.assertThrows(IllegalStateException.class, () -> retry.get().executeCheckedSupplier(() -> { + throw new IllegalStateException(); + })); + } + + @Test + public void testFailAfterMaxAttemptsWhenThrow() { + AbstractRetryExtension retryExtension = Mockito.mock(AbstractRetryExtension.class); + RetryProperties retryProperties = Mockito.mock(RetryProperties.class); + GovernanceRequest governanceRequest = Mockito.mock(GovernanceRequest.class); + Mockito.when(retryExtension.isFailedResult(Mockito.any(), Mockito.any())).thenReturn(true); + + RetryPolicy retryPolicy = new RetryPolicy(); + retryPolicy.setName("test"); + retryPolicy.setFailAfterMaxAttempts(true); + RetryHandler retryHandler = new RetryHandler(retryProperties, retryExtension); + + Disposable retry = retryHandler.createProcessor(retryPolicy.getName(), governanceRequest, retryPolicy); + Assertions.assertThrows(IllegalStateException.class, () -> retry.get().executeCheckedSupplier(() -> { + throw new IllegalStateException(); + })); + } + + @Test + public void testFailAfterMaxAttemptsOnResult() { + AbstractRetryExtension retryExtension = Mockito.mock(AbstractRetryExtension.class); + RetryProperties retryProperties = Mockito.mock(RetryProperties.class); + GovernanceRequest governanceRequest = Mockito.mock(GovernanceRequest.class); + Mockito.when(retryExtension.isFailedResult(Mockito.any(), (Object) Mockito.any())).thenReturn(true); + + RetryPolicy retryPolicy = new RetryPolicy(); + retryPolicy.setName("test"); + retryPolicy.setFailAfterMaxAttempts(true); + RetryHandler retryHandler = new RetryHandler(retryProperties, retryExtension); + + Disposable retry = retryHandler.createProcessor(retryPolicy.getName(), governanceRequest, retryPolicy); + Assertions.assertThrows(MaxRetriesExceededException.class, + () -> retry.get().executeCheckedSupplier(() -> -1)); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java b/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java new file mode 100644 index 00000000000..742c7118417 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/TimeLimiterHandlerTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.governance; + +import java.time.Duration; + +import org.apache.servicecomb.governance.handler.TimeLimiterHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.policy.TimeLimiterPolicy; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.github.resilience4j.timelimiter.TimeLimiter; + +@SpringBootTest +@ContextConfiguration(classes = {GovernanceCommonConfiguration.class, MockConfiguration.class}) +public class TimeLimiterHandlerTest { + private TimeLimiterHandler timeLimiterHandler; + + @Autowired + public void setInstanceIsolationHandler(TimeLimiterHandler timeLimiterHandler) { + this.timeLimiterHandler = timeLimiterHandler; + } + + @Test + public void testMatchPriorityPolicy() { + GovernanceRequest request = new GovernanceRequest(); + request.setApiPath("/timeLimiter"); + TimeLimiterPolicy policy = timeLimiterHandler.matchPolicy(request); + Assertions.assertEquals("demo-timeLimiter", policy.getName()); + TimeLimiter timeLimiter = timeLimiterHandler.getActuator(request); + Duration timeoutDuration = timeLimiter.getTimeLimiterConfig().getTimeoutDuration(); + Assertions.assertEquals(2000, timeoutDuration.toMillis()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/handler/ext/RetryExtensionTest.java b/governance/src/test/java/org/apache/servicecomb/governance/handler/ext/RetryExtensionTest.java new file mode 100644 index 00000000000..41157a9b079 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/handler/ext/RetryExtensionTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.handler.ext; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.SocketTimeoutException; +import java.util.Arrays; +import java.util.List; + + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import io.vertx.core.VertxException; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RetryExtensionTest { + + @Test + public void test_status_code_to_contains() { + List statusList = Arrays.asList("502", "503"); + boolean result = AbstractRetryExtension.statusCodeContains(statusList, "502"); + Assertions.assertTrue(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "504"); + Assertions.assertFalse(result); + + statusList = Arrays.asList("5xx", "4x4", "4x", "x32", "xx6"); + result = AbstractRetryExtension.statusCodeContains(statusList, "502"); + Assertions.assertTrue(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "504"); + Assertions.assertTrue(result); + + statusList = Arrays.asList("4x4", "x32", "xx6"); + result = AbstractRetryExtension.statusCodeContains(statusList, "402"); + Assertions.assertFalse(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "404"); + Assertions.assertTrue(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "332"); + Assertions.assertTrue(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "446"); + Assertions.assertTrue(result); + + statusList = Arrays.asList("4x", "x3x", "x5"); + result = AbstractRetryExtension.statusCodeContains(statusList, "446"); + Assertions.assertFalse(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "455"); + Assertions.assertFalse(result); + + result = AbstractRetryExtension.statusCodeContains(statusList, "434"); + Assertions.assertTrue(result); + } + + @Test + public void testRetryWithConnectionException() { + Exception target = new ConnectException("connection refused"); + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + } + + @Test + public void testRetryWithSocketTimeout() { + Exception target = new SocketTimeoutException("Read timed out"); + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + } + + @Test + public void testRetryWithIOException() { + Exception target = new IOException("Connection reset by peer"); + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + + target = new IOException("Target not exist"); + root = new Exception(target); + canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertFalse(canRetry); + } + + @Test + public void testRetryVertxException() { + Exception target = new VertxException("Connection was closed"); + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + + target = new IOException(""); + root = new Exception(target); + canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertFalse(canRetry); + } + + @Test + public void testRetryNoRouteToHostException() { + Exception target = new NoRouteToHostException("Host is unreachable"); + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + + target = new NoRouteToHostException("No route to host"); + root = new Exception(target); + canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + } + + @Test + public void testRetryEqualTen() { + Exception target = new ConnectException("connection refused"); + for (int i = 0; i < 8; i++) { + target = new Exception("Level" + i, target); + } + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertTrue(canRetry); + } + + @Test + public void testRetryOverTen() { + Exception target = new ConnectException("connection refused"); + for (int i = 0; i < 9; i++) { + target = new Exception("Level" + i, target); + } + Exception root = new Exception(target); + boolean canRetry = FailurePredictor.canRetryForException(FailurePredictor.STRICT_RETRIABLE, root); + Assertions.assertFalse(canRetry); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassNotImplements.java b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassNotImplements.java new file mode 100644 index 00000000000..51336e60ed5 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassNotImplements.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.mockclasses; + +import org.springframework.stereotype.Component; +import org.apache.servicecomb.governance.marker.GovernanceRequest; + +@Component +public class ClassNotImplements { + public boolean matchRequest(GovernanceRequest request, String parameters) { + return true; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassWithAnnotation.java b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassWithAnnotation.java new file mode 100644 index 00000000000..263d442f40b --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/ClassWithAnnotation.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.mockclasses; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.mockclasses.service.MockProfileClassUserService; +import org.apache.servicecomb.governance.utils.CustomMatch; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ClassWithAnnotation implements CustomMatch { + @Autowired + MockProfileClassUserService service; + + @Override + public boolean matchRequest(GovernanceRequestExtractor requestExtractor, String parameters) { + String profileValue = service.getUser(); + return Stream.of(parameters.split(",")).collect(Collectors.toSet()).contains(profileValue); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/CustomMatchDemo.java b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/CustomMatchDemo.java new file mode 100644 index 00000000000..dba57a48dd5 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/CustomMatchDemo.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.mockclasses; + +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.utils.CustomMatch; + +public class CustomMatchDemo implements CustomMatch { + + private CustomMatchDemo() { + + } + + @Override + public boolean matchRequest(GovernanceRequestExtractor requestExtractor, String parameters) { + return true; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockConfigurationForCustomMatcher.java b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockConfigurationForCustomMatcher.java new file mode 100644 index 00000000000..7668ddc8e28 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockConfigurationForCustomMatcher.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.mockclasses.service; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan("org.apache.servicecomb.governance.mockclasses") +public class MockConfigurationForCustomMatcher { +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockProfileClassUserService.java b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockProfileClassUserService.java new file mode 100644 index 00000000000..31aa5479cef --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/mockclasses/service/MockProfileClassUserService.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance.mockclasses.service; + +import org.springframework.stereotype.Service; + +@Service +public class MockProfileClassUserService { + public String getUser() { + return "bill"; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/ExampleDistributor.java b/governance/src/test/java/org/apache/servicecomb/router/ExampleDistributor.java new file mode 100644 index 00000000000..42fdfad0367 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/ExampleDistributor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.router; + +import org.apache.servicecomb.router.distribute.AbstractRouterDistributor; +import org.springframework.stereotype.Component; + +@Component +public class ExampleDistributor extends AbstractRouterDistributor { + public ExampleDistributor() { + init(ServiceIns::getVersion, ServiceIns::getServerName, ServiceIns::getTags); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfig2Test.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfig2Test.java new file mode 100644 index 00000000000..cc8cc9ce96c --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfig2Test.java @@ -0,0 +1,279 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.distribute.RouterDistributor; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorDynamicConfig2Test { + private static final String TARGET_SERVICE_NAME = "test_server"; + + public static final String CONFIG_KEY = RouterRuleCache.ROUTE_RULE_PREFIX + TARGET_SERVICE_NAME; + + private static final String RULE_STRING = "" + + " - precedence: 2\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " appId:\n" + + " regex: 01\n" + + " caseInsensitive: false\n" + + " userId:\n" + + " exact: 01\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + + private Environment environment; + + private RouterFilter routerFilter; + + private RouterDistributor testDistributor; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setTestDistributor(RouterDistributor testDistributor) { + this.testDistributor = testDistributor; + } + + private final Map dynamicValues = new HashMap<>(); + + @BeforeEach + public void setUp() { + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + + if (configurableEnvironment.getPropertySources().contains("testDynamicChange")) { + configurableEnvironment.getPropertySources().remove("testDynamicChange"); + } + + configurableEnvironment.getPropertySources() + .addFirst(new EnumerablePropertySource>("testDynamicChange", dynamicValues) { + @Override + public Object getProperty(String s) { + return this.getSource().get(s); + } + + @Override + public String[] getPropertyNames() { + return this.getSource().keySet().toArray(new String[0]); + } + }); + + dynamicValues.put(CONFIG_KEY, RULE_STRING); + + postConfigurationChangedEvent(); + } + + private void postConfigurationChangedEvent() { + Set changedKeys = new HashSet<>(); + changedKeys.add(CONFIG_KEY); + GovernanceConfigurationChangedEvent newEvent = new GovernanceConfigurationChangedEvent(changedKeys); + GovernanceEventManager.post(newEvent); + } + + @Test + public void testMatchPrecedenceHigher() { + GovernanceRequest governanceRequest = new GovernanceRequest(); + Map headers = new HashMap<>(); + headers.put("userId", "01"); + headers.put("appId", "01"); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("2.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.setVersion("1.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(1, resultServerList.size()); + Assertions.assertEquals("01", resultServerList.get(0).getId()); + } + + @Test + public void testCaseSensitiveNotMatch() { + String rule = "" + + " - precedence: 1\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 2\n" + + " match:\n" + + " headers:\n" + + " userId:\n" + + " exact: user01\n" + + " caseInsensitive: false\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + dynamicValues.put(CONFIG_KEY, rule); + postConfigurationChangedEvent(); + + Map headers = new HashMap<>(); + headers.put("userId", "User01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("2.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.setVersion("1.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(1, resultServerList.size()); + Assertions.assertEquals("01", resultServerList.get(0).getId()); + Assertions.assertEquals("2.0", resultServerList.get(0).getVersion()); + } + + @Test + public void testNoneMatch() { + String rule = "" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " userId:\n" + + " regex: user02\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 2\n" + + " match:\n" + + " headers:\n" + + " userId:\n" + + " exact: user01\n" + + " caseInsensitive: false\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + dynamicValues.put(CONFIG_KEY, rule); + postConfigurationChangedEvent(); + + Map headers = new HashMap<>(); + headers.put("userId", "User01"); + headers.put("appId", "App01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("2.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.setVersion("1.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(2, resultServerList.size()); + } + + @Test + public void testOneMatchButNoInstance() { + String rule = "" + + " - precedence: 1\n" + + " match:\n" + + " headers:\n" + + " appId:\n" + + " regex: app02\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 2\n" + + " match:\n" + + " headers:\n" + + " userId:\n" + + " exact: user01\n" + + " caseInsensitive: false\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + dynamicValues.put(CONFIG_KEY, rule); + postConfigurationChangedEvent(); + + Map headers = new HashMap<>(); + headers.put("userId", "user01"); + headers.put("appId", "app02"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("1.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.setVersion("1.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(2, resultServerList.size()); + } + + private List mainFilter(List serverList, GovernanceRequestExtractor requestExtractor) { + return routerFilter + .getFilteredListOfServers(serverList, TARGET_SERVICE_NAME, requestExtractor, + testDistributor); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfigTest.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfigTest.java new file mode 100644 index 00000000000..4418a30829b --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorDynamicConfigTest.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorDynamicConfigTest { + private static final String TARGET_SERVICE_NAME = "test_server"; + + private static final String RULE_STRING = "" + + " - precedence: 2 #优先级\n" + + " match: #匹配策略\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"01\"\n" + + " route: #路由规则\n" + + " - weight: 50\n" + + " tags:\n" + + " version: 1.1\n" + + " - precedence: 1\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"02\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 3\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"03\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + + private Environment environment; + + private RouterFilter routerFilter; + + private RouterDistributor testDistributor; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setTestDistributor(RouterDistributor testDistributor) { + this.testDistributor = testDistributor; + } + + public RouterDistributorDynamicConfigTest() { + } + + private final Map dynamicValues = new HashMap<>(); + + @BeforeEach + public void setUp() { + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + + if (configurableEnvironment.getPropertySources().contains("testDynamicChange")) { + configurableEnvironment.getPropertySources().remove("testDynamicChange"); + } + + configurableEnvironment.getPropertySources() + .addFirst(new EnumerablePropertySource>("testDynamicChange", dynamicValues) { + @Override + public Object getProperty(String s) { + return this.getSource().get(s); + } + + @Override + public String[] getPropertyNames() { + return this.getSource().keySet().toArray(new String[0]); + } + }); + + dynamicValues.put(RouterRuleCache.ROUTE_RULE_PREFIX + TARGET_SERVICE_NAME, RULE_STRING); + + Set changedKeys = new HashSet<>(); + changedKeys.add(RouterRuleCache.ROUTE_RULE_PREFIX + TARGET_SERVICE_NAME); + GovernanceConfigurationChangedEvent newEvent = new GovernanceConfigurationChangedEvent(changedKeys); + GovernanceEventManager.post(newEvent); + } + + + @Test + public void testHeaderIsEmpty() { + List list = getMockList(); + List serverList = mainFilter(list, new GovernanceRequest()); + Assertions.assertEquals(2, serverList.size()); + } + + @Test + public void testVersionNotMatch() { + Map headerMap = new HashMap<>(); + headerMap.put("userId", "02"); + headerMap.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headerMap); + List list = getMockList(); + list.remove(1); + List serverList = mainFilter(list, governanceRequest); + Assertions.assertEquals(1, serverList.size()); + Assertions.assertEquals("01", serverList.get(0).getId()); + } + + @Test + public void testVersionMatch() { + Map headers = new HashMap<>(); + headers.put("userId", "01"); + headers.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + List serverList = mainFilter(getMockList(), governanceRequest); + Assertions.assertEquals(1, serverList.size()); + Assertions.assertEquals("02", serverList.get(0).getId()); + } + + @Test + public void testMatchPrecedenceLower() { + Map headers = new HashMap<>(); + headers.put("userId", "02"); + headers.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + List serverList = mainFilter(getMockList(), governanceRequest); + Assertions.assertEquals(1, serverList.size()); + Assertions.assertEquals("01", serverList.get(0).getId()); + } + + @Test + public void testMatchPrecedenceHigher() { + Map headers = new HashMap<>(); + headers.put("userId", "03"); + headers.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("2.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.addTags("app", "a"); + ins2.setVersion("1.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(1, resultServerList.size()); + Assertions.assertEquals("02", resultServerList.get(0).getId()); + } + + private List getMockList() { + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("2.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.addTags("app", "a"); + serverList.add(ins1); + serverList.add(ins2); + return serverList; + } + + private List mainFilter(List serverList, + GovernanceRequestExtractor governanceRequestExtractor) { + return routerFilter + .getFilteredListOfServers(serverList, TARGET_SERVICE_NAME, governanceRequestExtractor, + testDistributor); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileConfigTest.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileConfigTest.java new file mode 100644 index 00000000000..54ebcb05823 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileConfigTest.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorFileConfigTest { + private static final String TARGET_SERVICE_NAME = "test_server1"; + + private RouterFilter routerFilter; + + private RouterDistributor routerDistributor; + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setRouterDistributor(RouterDistributor routerDistributor) { + this.routerDistributor = routerDistributor; + } + + @Test + public void testDistribute() { + List list = initServiceList(); + HashMap header = new HashMap<>(); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(header); + + List listOfServers = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME, governanceRequest, routerDistributor); + Assertions.assertNotNull(listOfServers); + for (ServiceIns server : listOfServers) { + Assertions.assertEquals(TARGET_SERVICE_NAME, server.getServerName()); + } + int serverNum1 = 0; + int serverNum2 = 0; + + for (int i = 0; i < 10; i++) { + List serverList = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME, governanceRequest, routerDistributor); + for (ServiceIns serviceIns : serverList) { + if ("01".equals(serviceIns.getId())) { + serverNum1++; + } else if ("02".equals(serviceIns.getId())) { + serverNum2++; + } + } + } + boolean flag = false; + if (Math.round(serverNum2 * 1.0 / serverNum1) == 4) { + flag = true; + } + Assertions.assertTrue(flag); + } + + List initServiceList() { + ServiceIns serviceIns1 = new ServiceIns("01", "test_server1"); + ServiceIns serviceIns2 = new ServiceIns("02", "test_server1"); + serviceIns1.setVersion("1.0"); + serviceIns2.setVersion("2.0"); + serviceIns1.addTags("x-group", "red"); + serviceIns2.addTags("x-group", "green"); + List list = new ArrayList<>(); + list.add(serviceIns1); + list.add(serviceIns2); + return list; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWeightLessTest.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWeightLessTest.java new file mode 100644 index 00000000000..68b04bc9cdb --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWeightLessTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorFileWeightLessTest { + private static final String TARGET_SERVICE_NAME = "test_server2"; + + private RouterFilter routerFilter; + + private RouterDistributor routerDistributor; + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setRouterDistributor(RouterDistributor routerDistributor) { + this.routerDistributor = routerDistributor; + } + + @Test + public void testDistribute() { + List list = initServiceList(); + HashMap header = new HashMap<>(); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(header); + List listOfServers = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME, governanceRequest, routerDistributor); + Assertions.assertNotNull(listOfServers); + for (ServiceIns server : listOfServers) { + Assertions.assertEquals(TARGET_SERVICE_NAME, server.getServerName()); + } + int serverNum1 = 0; + int unSetTagNum = 0; + + for (int i = 0; i < 10; i++) { + List serverList = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME, governanceRequest, routerDistributor); + for (ServiceIns serviceIns : serverList) { + if ("01".equals(serviceIns.getId())) { + serverNum1++; + } else if ("02".equals(serviceIns.getId())) { + unSetTagNum++; + } + } + } + boolean flag = false; + if (Math.round(unSetTagNum * 1.0 / serverNum1) == 4) { + flag = true; + } + Assertions.assertTrue(flag); + } + + List initServiceList() { + ServiceIns serviceIns1 = new ServiceIns("01", "test_server2"); + ServiceIns serviceIns2 = new ServiceIns("02", "test_server2"); + serviceIns1.setVersion("1.0"); + serviceIns2.setVersion("2.0"); + serviceIns1.addTags("x-group", "red"); + serviceIns2.addTags("x-group", "green"); + List list = new ArrayList<>(); + list.add(serviceIns1); + list.add(serviceIns2); + return list; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWithFallbackTest.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWithFallbackTest.java new file mode 100644 index 00000000000..2d7a1064557 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorFileWithFallbackTest.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorFileWithFallbackTest { + private static final String TARGET_SERVICE_NAME_WITHOUT_FALLBACK = "test_server3"; + + private static final String TARGET_SERVICE_NAME_WITH_FALLBACK = "test_server4"; + + private static final String TARGET_SERVICE_NAME_ROUTE_FALLBACK = "test_server5"; + + private RouterFilter routerFilter; + + private RouterDistributor routerDistributor; + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setRouterDistributor(RouterDistributor routerDistributor) { + this.routerDistributor = routerDistributor; + } + + @Test + public void testDistributeWithoutFallback() { + List list = initServiceList(TARGET_SERVICE_NAME_WITHOUT_FALLBACK); + HashMap header = new HashMap<>(); + header.put("canary", "canary"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(header); + List listOfServers = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_WITHOUT_FALLBACK, governanceRequest, routerDistributor); + Assertions.assertNotNull(listOfServers); + for (ServiceIns server : listOfServers) { + Assertions.assertEquals(TARGET_SERVICE_NAME_WITHOUT_FALLBACK, server.getServerName()); + } + int serverNum1 = 0; + int serverNum2 = 0; + + for (int i = 0; i < 10; i++) { + List serverList = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_WITHOUT_FALLBACK, governanceRequest, routerDistributor); + for (ServiceIns serviceIns : serverList) { + if ("01".equals(serviceIns.getId())) { + serverNum1++; + } else if ("02".equals(serviceIns.getId())) { + serverNum2++; + } + } + } + Assertions.assertTrue(serverNum2 == serverNum1); + } + + @Test + public void testDistributeWithFallback() { + List list = initServiceList(TARGET_SERVICE_NAME_WITH_FALLBACK); + HashMap header = new HashMap<>(); + header.put("canary", "canary"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(header); + List listOfServers = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_WITH_FALLBACK, governanceRequest, routerDistributor); + Assertions.assertNotNull(listOfServers); + for (ServiceIns server : listOfServers) { + Assertions.assertEquals(TARGET_SERVICE_NAME_WITH_FALLBACK, server.getServerName()); + } + int serverNum1 = 0; + int serverNum2 = 0; + + for (int i = 0; i < 10; i++) { + List serverList = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_WITH_FALLBACK, governanceRequest, routerDistributor); + for (ServiceIns serviceIns : serverList) { + if ("01".equals(serviceIns.getId())) { + serverNum1++; + } else if ("02".equals(serviceIns.getId())) { + serverNum2++; + } + } + } + Assertions.assertTrue((serverNum2 + serverNum1) == serverNum1); + } + + @Test + public void testDistributeRouteAndFallbackHaveSame() { + List list = initServiceList(TARGET_SERVICE_NAME_ROUTE_FALLBACK); + HashMap header = new HashMap<>(); + header.put("canary", "canary"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(header); + List listOfServers = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_ROUTE_FALLBACK, governanceRequest, routerDistributor); + Assertions.assertNotNull(listOfServers); + for (ServiceIns server : listOfServers) { + Assertions.assertEquals(TARGET_SERVICE_NAME_ROUTE_FALLBACK, server.getServerName()); + } + int serverNum1 = 0; + int serverNum2 = 0; + + for (int i = 0; i < 20; i++) { + List serverList = routerFilter + .getFilteredListOfServers(list, TARGET_SERVICE_NAME_ROUTE_FALLBACK, governanceRequest, routerDistributor); + for (ServiceIns serviceIns : serverList) { + if ("01".equals(serviceIns.getId())) { + serverNum1++; + } else if ("02".equals(serviceIns.getId())) { + serverNum2++; + } + } + } + boolean flag = false; + if (Math.round(serverNum1 * 1.0 / serverNum2) == 3) { + flag = true; + } + Assertions.assertTrue(flag); + } + + List initServiceList(String serviceName) { + ServiceIns serviceIns1 = new ServiceIns("01", serviceName); + ServiceIns serviceIns2 = new ServiceIns("02", serviceName); + serviceIns1.setVersion("1.0"); + serviceIns2.setVersion("2.0"); + serviceIns1.addTags("x-group", "red"); + serviceIns2.addTags("x-group", "green"); + List list = new ArrayList<>(); + list.add(serviceIns1); + list.add(serviceIns2); + return list; + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorGlobalConfigTest.java b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorGlobalConfigTest.java new file mode 100644 index 00000000000..89a54d76979 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/RouterDistributorGlobalConfigTest.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.router; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.governance.event.GovernanceConfigurationChangedEvent; +import org.apache.servicecomb.governance.event.GovernanceEventManager; +import org.apache.servicecomb.governance.marker.GovernanceRequest; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.router.cache.RouterRuleCache; +import org.apache.servicecomb.router.distribute.RouterDistributor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigDataApplicationContextInitializer.class) +public class RouterDistributorGlobalConfigTest { + private static final String TARGET_SERVICE_NAME = "test_server"; + + public static final String CONFIG_KEY = RouterRuleCache.ROUTE_RULE_PREFIX + TARGET_SERVICE_NAME; + + private static final String RULE_STRING = "" + + " - precedence: 1\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"02\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 2\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"03\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + + private Environment environment; + + private RouterFilter routerFilter; + + private RouterDistributor testDistributor; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setRouterFilter(RouterFilter routerFilter) { + this.routerFilter = routerFilter; + } + + @Autowired + public void setTestDistributor(RouterDistributor testDistributor) { + this.testDistributor = testDistributor; + } + + public RouterDistributorGlobalConfigTest() { + } + + private final Map dynamicValues = new HashMap<>(); + + @BeforeEach + public void setUp() { + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + + if (configurableEnvironment.getPropertySources().contains("testDynamicChange")) { + configurableEnvironment.getPropertySources().remove("testDynamicChange"); + } + + configurableEnvironment.getPropertySources() + .addFirst(new EnumerablePropertySource>("testDynamicChange", dynamicValues) { + @Override + public Object getProperty(String s) { + return this.getSource().get(s); + } + + @Override + public String[] getPropertyNames() { + return this.getSource().keySet().toArray(new String[0]); + } + }); + + dynamicValues.put(RouterRuleCache.GLOBAL_ROUTE_RULE_KEY, RULE_STRING); + postConfigurationChangedEvent(RouterRuleCache.GLOBAL_ROUTE_RULE_KEY); + } + + @Test + public void testUseGlobalRouteRule() { + Map headers = new HashMap<>(); + headers.put("userId", "03"); + headers.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("1.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.addTags("app", "a"); + ins2.setVersion("2.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(1, resultServerList.size()); + Assertions.assertEquals("01", resultServerList.get(0).getId()); + } + + @Test + public void testUseProviderRouteRule() { + String rule = "" + + " - precedence: 1\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"03\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 2.0\n" + + " - precedence: 2\n" + + " match:\n" + + " headers: #header匹配\n" + + " appId:\n" + + " exact: \"01\"\n" + + " userId:\n" + + " exact: \"02\"\n" + + " route:\n" + + " - weight: 100\n" + + " tags:\n" + + " version: 1.0\n"; + dynamicValues.put(CONFIG_KEY, rule); + postConfigurationChangedEvent(CONFIG_KEY); + + Map headers = new HashMap<>(); + headers.put("userId", "03"); + headers.put("appId", "01"); + GovernanceRequest governanceRequest = new GovernanceRequest(); + governanceRequest.setHeaders(headers); + + List serverList = new ArrayList<>(); + ServiceIns ins1 = new ServiceIns("01", TARGET_SERVICE_NAME); + ins1.setVersion("1.0"); + ServiceIns ins2 = new ServiceIns("02", TARGET_SERVICE_NAME); + ins2.addTags("app", "a"); + ins2.setVersion("2.0"); + serverList.add(ins1); + serverList.add(ins2); + + List resultServerList = mainFilter(serverList, governanceRequest); + Assertions.assertEquals(1, resultServerList.size()); + Assertions.assertEquals("02", resultServerList.get(0).getId()); + } + + private List mainFilter(List serverList, + GovernanceRequestExtractor governanceRequestExtractor) { + return routerFilter + .getFilteredListOfServers(serverList, TARGET_SERVICE_NAME, governanceRequestExtractor, + testDistributor); + } + + private void postConfigurationChangedEvent(String changKey) { + Set changedKeys = new HashSet<>(); + changedKeys.add(changKey); + GovernanceConfigurationChangedEvent newEvent = new GovernanceConfigurationChangedEvent(changedKeys); + GovernanceEventManager.post(newEvent); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/ServiceIns.java b/governance/src/test/java/org/apache/servicecomb/router/ServiceIns.java new file mode 100644 index 00000000000..7600d09d7ca --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/ServiceIns.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.router; + +import java.util.HashMap; +import java.util.Map; + +public class ServiceIns { + String version = "1.1"; + + String serverName; + + Map tags = new HashMap<>(); + + private final String id; + + public ServiceIns(String id, String serverName) { + this.id = id; + this.serverName = serverName; + } + + public String getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getServerName() { + return serverName; + } + + public Map getTags() { + return tags; + } + + public void setVersion(String version) { + this.version = version; + } + + public void addTags(String key, String v) { + tags.put(key, v); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/router/VersionCompareUtilTest.java b/governance/src/test/java/org/apache/servicecomb/router/VersionCompareUtilTest.java new file mode 100644 index 00000000000..d4438a956a1 --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/router/VersionCompareUtilTest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router; + +import org.apache.servicecomb.router.util.VersionCompareUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class VersionCompareUtilTest { + + @Test + public void testVersion() { + Assertions.assertTrue(VersionCompareUtil.compareVersion("0.0.1", "0.0.0") > 0); + Assertions.assertEquals(0, VersionCompareUtil.compareVersion("0.0.0", "0.0.0")); + Assertions.assertTrue(VersionCompareUtil.compareVersion("0.0.0", "0.0.1") < 0); + Assertions.assertEquals(0, VersionCompareUtil.compareVersion("0.0.0", "0.0.0.0")); + Assertions.assertTrue(VersionCompareUtil.compareVersion("0.0.1", "0.0.0.0") > 0); + Assertions.assertTrue(VersionCompareUtil.compareVersion("0.0.1", "0.0.0.0") > 0); + } +} diff --git a/governance/src/test/resources/META-INF/spring/bean.xml b/governance/src/test/resources/META-INF/spring/bean.xml new file mode 100644 index 00000000000..5ff6c6e05cc --- /dev/null +++ b/governance/src/test/resources/META-INF/spring/bean.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/governance/src/test/resources/application.yaml b/governance/src/test/resources/application.yaml new file mode 100644 index 00000000000..ce981ac1ea2 --- /dev/null +++ b/governance/src/test/resources/application.yaml @@ -0,0 +1,298 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + matchGroup: + demo-timeLimiter: | + matches: + - apiPath: + prefix: "/timeLimiter" + demo-governanceCache: | + matches: + - apiPath: + prefix: "/governanceCache" + demo-loadbalance-random: | + matches: + - serviceName: "loadrandom" + demo-loadbalance-roundRobin: | + matches: + - serviceName: "loadroundRobin" + demo-fallback-returnNull: | + matches: + - serviceName: "returnNull" + demo-fallback-ThrowException: | + matches: + - serviceName: "ThrowException" + demo-faultInject-forceClosed: | + matches: + - serviceName: "forceClosed" + demo-allOperation: | + matches: + - apiPath: + prefix: "/" + demo-rateLimiting: | + matches: + - apiPath: + exact: "/hello" + demo-rateLimiting-servicename: | + matches: + - apiPath: + exact: "/helloServiceName" + serviceName: "srcService" + wrong-name-inogred: | + wrong: some + demo-retry: | + matches: + - apiPath: + exact: "/retry" + demo-circuitBreaker: | + matches: + - apiPath: + exact: "/circuitBreaker" + demo-bulkhead: | + matches: + - name: matchPath + apiPath: + exact: "/bulkhead" + - name: matchHeader + headers: + x-token: + exact: token + demo-bulkhead-priority: | + matches: + - apiPath: + exact: "/bulkhead" + demo-bulkhead-other: | + matches: + - apiPath: + exact: "/bulkhead" + services: other:1.0 + demo-faultInjectDelay: | + matches: + - apiPath: + contains: "/faultInjectDelay" + demo-faultInjectAbort: | + matches: + - apiPath: + contains: "/faultInjectAbort" + demo-mapper: | + matches: + - apiPath: + prefix: "/mapper" + demo-mapper-query: | + matches: + - queries: + name: + exact: "bob" + rateLimiting: + demo-rateLimiting: | + rate: 1 + demo-rateLimiting-servicename: | + rate: 1 + wrongIgnored: | + rate: 0 + identifierRateLimiting: + demo-rateLimiting: | + rate: 1 + identifier: test + demo-rateLimiting-servicename: | + rate: 1 + identifier: test + timeLimiter: + demo-timeLimiter: | + timeoutDuration: 2000 + cancelRunningFuture: true + demo-timeLimiter-other: | + timeoutDuration: 2000 + cancelRunningFuture: false + cache: + demo-governanceCache: | + ttl: 36000000 + maximumSize: 50000 + concurrencyLevel: 10 + demo-governanceCache-other: | + ttl: 666666 + maximumSize: 50000 + concurrencyLevel: 15 + retry: + demo-retry: | + maxAttempts: 3 + wrongIgnored: | + maxAttempts: -1 + circuitBreaker: + demo-circuitBreaker: | + minimumNumberOfCalls: 2 + slidingWindowSize: 2 + slidingWindowType: COUNT_BASED + services: myself:1.0,other + wrongIgnored: | + rules: + match: demo-circuitBreaker.xx + minimumNumberOfCalls: -1 + bulkhead: + demo-bulkhead: | + order: 1 + maxConcurrentCalls: 1 + maxWaitDuration: 3000 + services: myself:1.0 + demo-bulkhead-priority: | + order: 0 + maxConcurrentCalls: 1 + maxWaitDuration: 3000 + services: myself:1.0 + demo-bulkhead-other: | + maxConcurrentCalls: 1 + maxWaitDuration: 3000 + services: other:1.0 + wrongIgnored: | + rules: + match: demo-bulkhead.xx + maxWaitDuration: -1 + instanceIsolation: + demo-allOperation: | + minimumNumberOfCalls: 2 + slidingWindowSize: 2 + slidingWindowType: COUNT_BASED + waitDurationInOpenState: 1000 + instanceBulkhead: + demo-allOperation: | + maxConcurrentCalls: 2 + maxWaitDuration: 10 + faultInjection: + demo-fallback-ThrowException: | + type: abort + percentage: 100 + demo-fallback-returnNull: | + fallbackType: ReturnNull + type: abort + percentage: 100 + demo-faultInject-forceClosed: | + forceClosed: true + fallbackType: ReturnNull + demo-faultInjectDelay: | + delayTime: 2S + type: delay + percentage: 100 + demo-faultInjectAbort: | + type: abort + percentage: 50 + errorCode: 500 + wrongIgnored: | + delayTime: -1 + type: ERROR + faultInjection2: + demo-fallback-ThrowException: | + type: abort + percentage: 100 + loadbalance: + demo-loadbalance-random: | + rule: Random + demo-loadbalance-roundRobin: | + rule: RoundRobin + mapper: + demo-mapper: | + target: + host: 127.0.0.1 + port: 8080 + demo-mapper-query: | + target: + user-id: $Q{name} + mapper2: + demo-mapper: | + target: + host: 127.0.0.1 + port: 9090 + routeRule: + test_server1: | # 服务名 + - precedence: 1 # 优先级,数字越大,优先级越高。 + match: # 请求匹配规则。0..N个,不配置表示匹配。 + headers: # header 匹配 + region: # 如果配置了多个 header,那么所有的 header 规则都必须和请求匹配 + exact: 'providerRegion' + type: + regex: gray_[a-z]+ # java 正则表达式匹配 + route: # 路由规则 + - weight: 20 # 权重值 + tags: + version: 1.0.0 # 实例标记。满足标记条件的实例放到这一组。 + - weight: 80 # 权重值 + tags: + version: 2.0.0 # 实例标记。满足标记条件的实例放到这一组。 + + - precedence: 2 + route: + - weight: 20 + tags: + x-group: red + - weight: 80 + tags: + x-group: green + + test_server2: | # 服务名 + - precedence: 1 + route: + - weight: 20 + tags: + x-group: red + + test_server3: | # 服务名 + - precedence: 2 + match: + headers: + canary: + exact: 'canary' + route: + - weight: 20 + tags: + version: 1.0.0 + - weight: 80 + tags: + version: 2.0.0 + test_server4: | # 服务名 + - precedence: 2 + match: + headers: + canary: + exact: 'canary' + route: + - weight: 20 + tags: + version: 1.0.0 + - weight: 80 + tags: + version: 2.0.0 + fallback: + - weight: 100 + tags: + x-group: red + test_server5: | # 服务名 + - precedence: 2 + match: + headers: + canary: + exact: 'canary' + route: + - weight: 50 + tags: + x-group: red + fallback: + - weight: 50 + tags: + x-group: red + - weight: 50 + tags: + x-group: green diff --git a/gpg-sec.tar.enc b/gpg-sec.tar.enc deleted file mode 100644 index 2d4f786fbda..00000000000 Binary files a/gpg-sec.tar.enc and /dev/null differ diff --git a/handlers/handler-bizkeeper/pom.xml b/handlers/handler-bizkeeper/pom.xml deleted file mode 100644 index 2559519a218..00000000000 --- a/handlers/handler-bizkeeper/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - handlers - 1.2.0-SNAPSHOT - - - handler-bizkeeper - Java Chassis::Handlers::Bizkeeper - - - UTF-8 - - - - - org.apache.servicecomb - java-chassis-core - - - - com.netflix.hystrix - hystrix-core - - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - org.apache.servicecomb - foundation-metrics - - - - - diff --git a/handlers/handler-bizkeeper/readme.MD b/handlers/handler-bizkeeper/readme.MD deleted file mode 100644 index 698fc80167e..00000000000 --- a/handlers/handler-bizkeeper/readme.MD +++ /dev/null @@ -1,3 +0,0 @@ -参考: -hystrix: https://github.com/Netflix/Hystrix/wiki -design: http://code.huawei.com/CSE/CSE/wikis/design \ No newline at end of file diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BeansHolder.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BeansHolder.java deleted file mode 100644 index 41f5efa5694..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BeansHolder.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import java.util.List; - -import javax.inject.Inject; - -public class BeansHolder { - @Inject - private List policies; - - public void init() { - for (FallbackPolicy policy : this.policies) { - FallbackPolicyManager.addPolicy(policy); - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperCommand.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperCommand.java deleted file mode 100644 index a582041f2f2..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperCommand.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.hystrix.HystrixObservableCommand; -import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; - -import rx.Observable; - -/** - * 接管调用链的处理流程,处理完成后,将结果交给调用链。额外还提供了请求缓存的功能和容错/降级处理能力。 - * - */ -public abstract class BizkeeperCommand extends HystrixObservableCommand { - private static final Logger LOG = LoggerFactory.getLogger(BizkeeperCommand.class); - - private final Invocation invocation; - - private final String type; - - protected BizkeeperCommand(String type, Invocation invocation, HystrixObservableCommand.Setter setter) { - super(setter); - this.type = type; - this.invocation = invocation; - } - - @Override - protected String getCacheKey() { - if (HystrixRequestContext.isCurrentThreadInitialized()) { - StringBuilder sb = new StringBuilder(); - sb.append(this.getCommandGroup().name()); - sb.append("-"); - sb.append(this.getCommandKey().name()); - return sb.toString(); - } else { - return super.getCacheKey(); - } - } - - @Override - protected Observable resumeWithFallback() { - Throwable cause = getFailedExecutionException(); - Observable observable = Observable.create(f -> { - try { - f.onNext(FallbackPolicyManager.getFallbackResponse(type, cause, invocation)); - f.onCompleted(); - } catch (Exception e) { - LOG.warn("fallback failed due to:" + e.getMessage()); - throw e; - } - }); - return observable; - } - - @Override - protected Observable construct() { - Observable observable = Observable.create(f -> { - try { - invocation.next(resp -> { - if (isFailedResponse(resp)) { - // e should implements toString - LOG.warn("bizkeeper command {} failed due to {}", invocation.getInvocationQualifiedName(), - resp.getResult()); - f.onError(resp.getResult()); - FallbackPolicyManager.record(type, invocation, resp, false); - } else { - f.onNext(resp); - f.onCompleted(); - FallbackPolicyManager.record(type, invocation, resp, true); - } - }); - } catch (Exception e) { - LOG.warn("bizkeeper command {} execute failed due to {}", invocation.getInvocationQualifiedName(), - e.getClass().getName()); - f.onError(e); - } - }); - return observable; - } - - protected abstract boolean isFailedResponse(Response resp); -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperExceptionUtils.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperExceptionUtils.java deleted file mode 100644 index 3cea72fab37..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperExceptionUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.exception.CseException; -import org.apache.servicecomb.core.exception.ExceptionUtils; - -public class BizkeeperExceptionUtils extends ExceptionUtils { - public static final String SERVICECOMB_BIZKEEPER_FALLBACK = "servicecomb.bizkeeper.fallback"; - - static { - ERROR_DESC_MGR.register(SERVICECOMB_BIZKEEPER_FALLBACK, - "This is a fallback call from circuit breaker. " - + "\n You can add fallback logic by catching this exception. " + "\n info: operation=%s."); - } - - public static CseException createBizkeeperException(String code, Throwable cause, Object... args) { - String msg = String.format(ERROR_DESC_MGR.ensureFindValue(code), args); - return new CseException(code, msg, cause); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandler.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandler.java deleted file mode 100644 index a79741f0147..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandler.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixInvokable; -import com.netflix.hystrix.HystrixObservable; -import com.netflix.hystrix.strategy.HystrixPlugins; -import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook; - -import rx.Observable; - -/** - * 提供createBizkeeperCommand抽象接口来创建不同的处理链实例。 - * - */ -public abstract class BizkeeperHandler implements Handler { - private static final Logger LOG = LoggerFactory.getLogger(BizkeeperHandler.class); - - protected final String groupname; - - static { - try { - HystrixPlugins.getInstance().registerPropertiesStrategy(HystrixPropertiesStrategyExt.getInstance()); - } catch (IllegalStateException e) { - LOG.warn("Hystrix properties already registered. Dynamic configuration may not work.", e); - } - try { - HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixCommandExecutionHook() { - @Override - public Exception onExecutionError(HystrixInvokable commandInstance, Exception e) { - LOG.warn("bizkeeper execution error, info={}", ExceptionUtils.getExceptionMessageWithoutTrace(e)); - return e; //by default, just pass through - } - }); - } catch (IllegalStateException e) { - LOG.warn("HystrixCommandExecutionHook already registered.", e); - } - } - - private BizkeeperHandlerDelegate delegate; - - public BizkeeperHandler(String groupname) { - this.groupname = groupname; - delegate = new BizkeeperHandlerDelegate(this); - } - - protected abstract BizkeeperCommand createBizkeeperCommand(Invocation invocation); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) { - HystrixObservable command = delegate.createBizkeeperCommand(invocation); - - Observable observable = command.toObservable(); - observable.subscribe(asyncResp::complete, error -> { - LOG.warn("catch error in bizkeeper:" + error.getMessage()); - asyncResp.fail(invocation.getInvocationType(), error); - }, () -> { - - }); - } - - protected void setCommonProperties(Invocation invocation, HystrixCommandProperties.Setter setter) { - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandlerDelegate.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandlerDelegate.java deleted file mode 100644 index e3b755b5d06..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperHandlerDelegate.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -import com.netflix.hystrix.HystrixObservable; - -import rx.Observable; -import rx.Subscription; -import rx.subjects.ReplaySubject; - -public class BizkeeperHandlerDelegate { - - private BizkeeperHandler handler; - - public BizkeeperHandlerDelegate(BizkeeperHandler handler) { - this.handler = handler; - } - - protected HystrixObservable createBizkeeperCommand(Invocation invocation) { - if (Configuration.INSTANCE.isFallbackForce(handler.groupname, - invocation.getMicroserviceName(), - invocation.getOperationMeta().getMicroserviceQualifiedName())) { - return forceFallbackCommand(invocation); - } - return handler.createBizkeeperCommand(invocation); - } - - protected HystrixObservable forceFallbackCommand(Invocation invocation) { - return new HystrixObservable() { - @Override - public Observable observe() { - ReplaySubject subject = ReplaySubject.create(); - final Subscription sourceSubscription = toObservable().subscribe(subject); - return subject.doOnUnsubscribe(sourceSubscription::unsubscribe); - } - - @Override - public Observable toObservable() { - return Observable.create(f -> { - try { - f.onNext(FallbackPolicyManager.getFallbackResponse(handler.groupname, null, invocation)); - } catch (Exception e) { - f.onError(e); - } - }); - } - }; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperRequestContext.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperRequestContext.java deleted file mode 100644 index d65229c5b20..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/BizkeeperRequestContext.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; - -/** - * 使用缓存功能的时候,需要首先使用BizkeeperRequestContext来初始化上下文 - * - */ -public final class BizkeeperRequestContext { - private HystrixRequestContext context; - - private BizkeeperRequestContext(HystrixRequestContext context) { - this.context = context; - } - - public static BizkeeperRequestContext initializeContext() { - return new BizkeeperRequestContext(HystrixRequestContext.initializeContext()); - } - - public void shutdown() { - this.context.shutdown(); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java deleted file mode 100644 index 22a2cfcdcd7..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CommandKey.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; - -import com.netflix.hystrix.HystrixCommandGroupKey; -import com.netflix.hystrix.HystrixCommandKey; - -/** - * 创建对应的Key值 - * - */ -public final class CommandKey { - private CommandKey() { - } - - public static HystrixCommandGroupKey toHystrixCommandGroupKey(String type, Invocation invocation) { - return CustomizeCommandGroupKey.asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName(), - invocation); - } - - public static HystrixCommandKey toHystrixCommandKey(String type, Invocation invocation) { - return HystrixCommandKey.Factory - .asKey(type + "." + invocation.getOperationMeta().getMicroserviceQualifiedName()); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/Configuration.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/Configuration.java deleted file mode 100644 index 5286fbcd42d..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/Configuration.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import com.netflix.config.DynamicPropertyFactory; - -public final class Configuration { - //isolation - private static final String ISOLATION = "servicecomb.isolation."; - - private static final String ISOLATION_TIMEOUT_IN_MILLISECONDS = "timeoutInMilliseconds"; - - private static final String ISOLATION_TIMEOUT_IN_MILLISECONDS_OLD = - ".businessKeeper.command.execution.isolation.thread.timeoutInMilliseconds"; - - private static final String ISOLATION_TIMEOUT_ENABLED = "timeout.enabled"; - - private static final String ISOLATION_MAX_CONCURRENT_REQUESTS = "maxConcurrentRequests"; - - //circuit breaker - private static final String CIRCUIT_BREAKER = "servicecomb.circuitBreaker."; - - private static final String CIRCUIT_BREAKER_ENABLED = "enabled"; - - private static final String CIRCUIT_BREAKER_FORCEOPEN = "forceOpen"; - - private static final String CIRCUIT_BREAKER_FORCECLOSED = "forceClosed"; - - private static final String CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS = "sleepWindowInMilliseconds"; - - private static final String CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD = "requestVolumeThreshold"; - - private static final String CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE = "errorThresholdPercentage"; - - // fallback - // following items only supports consumer - private static final String FALLBACK = "servicecomb.fallback."; - - private static final String FALLBACK_ENABLED = "enabled"; - - private static final String FALLBACK_FORCE = "force"; - - private static final String FALLBACK_MAX_CONCURRENT_REQUESTS = "maxConcurrentRequests"; - - // fallbackpolicy - private static final String FALLBACKPOLICY = "servicecomb.fallbackpolicy."; - - private static final String FALLBACKPOLICY_POLICY = "policy"; - - public static final String FALLBACKPOLICY_POLICY_THROW = "throwexception"; - - public static final String FALLBACKPOLICY_POLICY_RETURN = "returnnull"; - - private static final int DEFAULT_ISOLATION_TIMEOUT = 30000; - - private static final int DEFAULT_MAX_CONCURRENT_REQUESTS = 1000; - - private static final int DEFAULT_SLEEP_WINDOW = 15000; - - private static final int DEFAULT_VOLUME_THRESHOLD = 20; - - private static final int DEFAULT_THRESHOLD_PERCENTAGE = 50; - - public static final Configuration INSTANCE = new Configuration(); - - private Configuration() { - - } - - public int getIsolationTimeoutInMilliseconds(String type, String microserviceName, - String qualifiedOperationName) { - int timeout; - String p = getProperty("30000", - ISOLATION + type + "." + qualifiedOperationName + "." + ISOLATION_TIMEOUT_IN_MILLISECONDS, - ISOLATION + type + "." + microserviceName + "." + ISOLATION_TIMEOUT_IN_MILLISECONDS, - ISOLATION + type + "." + ISOLATION_TIMEOUT_IN_MILLISECONDS, - // 2.0 compatible - type + "." + microserviceName + ISOLATION_TIMEOUT_IN_MILLISECONDS_OLD, - type + ".default" + ISOLATION_TIMEOUT_IN_MILLISECONDS_OLD); - try { - timeout = Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_ISOLATION_TIMEOUT; - } - if (timeout > 0) { - return timeout; - } - return DEFAULT_ISOLATION_TIMEOUT; - } - - public boolean getIsolationTimeoutEnabled(String type, String microserviceName, - String qualifiedOperationName) { - String p = getProperty("false", - ISOLATION + type + "." + qualifiedOperationName + "." + ISOLATION_TIMEOUT_ENABLED, - ISOLATION + type + "." + microserviceName + "." + ISOLATION_TIMEOUT_ENABLED, - ISOLATION + type + "." + ISOLATION_TIMEOUT_ENABLED); - return Boolean.parseBoolean(p); - } - - public int getIsolationMaxConcurrentRequests(String type, String microserviceName, - String qualifiedOperationName) { - int concurrentRequests; - String p = getProperty("1000", - ISOLATION + type + "." + qualifiedOperationName + "." + ISOLATION_MAX_CONCURRENT_REQUESTS, - ISOLATION + type + "." + microserviceName + "." + ISOLATION_MAX_CONCURRENT_REQUESTS, - ISOLATION + type + "." + ISOLATION_MAX_CONCURRENT_REQUESTS); - try { - concurrentRequests = Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_MAX_CONCURRENT_REQUESTS; - } - if (concurrentRequests > 0) { - return concurrentRequests; - } - return DEFAULT_MAX_CONCURRENT_REQUESTS; - } - - public boolean isCircuitBreakerEnabled(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("true", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." + CIRCUIT_BREAKER_ENABLED, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_ENABLED, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_ENABLED); - return Boolean.parseBoolean(p); - } - - public boolean isCircuitBreakerForceOpen(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("false", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." + CIRCUIT_BREAKER_FORCEOPEN, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_FORCEOPEN, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_FORCEOPEN); - return Boolean.parseBoolean(p); - } - - public boolean isCircuitBreakerForceClosed(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("false", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." + CIRCUIT_BREAKER_FORCECLOSED, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_FORCECLOSED, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_FORCECLOSED); - return Boolean.parseBoolean(p); - } - - public int getCircuitBreakerSleepWindowInMilliseconds(String type, String microserviceName, - String qualifiedOperationName) { - String p = getProperty("15000", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." - + CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS); - try { - return Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_SLEEP_WINDOW; - } - } - - public int getCircuitBreakerRequestVolumeThreshold(String type, String microserviceName, - String qualifiedOperationName) { - String p = getProperty("20", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." - + CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD); - try { - return Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_VOLUME_THRESHOLD; - } - } - - public int getCircuitBreakerErrorThresholdPercentage(String type, String microserviceName, - String qualifiedOperationName) { - String p = getProperty("50", - CIRCUIT_BREAKER + type + "." + qualifiedOperationName + "." - + CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, - CIRCUIT_BREAKER + type + "." + microserviceName + "." + CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, - CIRCUIT_BREAKER + type + "." + CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE); - try { - return Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_THRESHOLD_PERCENTAGE; - } - } - - public boolean isFallbackEnabled(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("true", - FALLBACK + type + "." + qualifiedOperationName + "." + FALLBACK_ENABLED, - FALLBACK + type + "." + microserviceName + "." + FALLBACK_ENABLED, - FALLBACK + type + "." + FALLBACK_ENABLED); - return Boolean.parseBoolean(p); - } - - public boolean isFallbackForce(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("false", - FALLBACK + type + "." + qualifiedOperationName + "." + FALLBACK_FORCE, - FALLBACK + type + "." + microserviceName + "." + FALLBACK_FORCE, - FALLBACK + type + "." + FALLBACK_FORCE); - return Boolean.parseBoolean(p); - } - - public int getFallbackMaxConcurrentRequests(String type, String microserviceName, String qualifiedOperationName) { - String p = getProperty("10", - FALLBACK + type + "." + qualifiedOperationName + "." + FALLBACK_MAX_CONCURRENT_REQUESTS, - FALLBACK + type + "." + microserviceName + "." + FALLBACK_MAX_CONCURRENT_REQUESTS, - FALLBACK + type + "." + FALLBACK_MAX_CONCURRENT_REQUESTS); - try { - return Integer.parseInt(p); - } catch (NumberFormatException e) { - return DEFAULT_MAX_CONCURRENT_REQUESTS; - } - } - - public String getFallbackPolicyPolicy(String type, String microserviceName, String qualifiedOperationName) { - return getProperty(null, - FALLBACKPOLICY + type + "." + qualifiedOperationName + "." + FALLBACKPOLICY_POLICY, - FALLBACKPOLICY + type + "." + microserviceName + "." + FALLBACKPOLICY_POLICY, - FALLBACKPOLICY + type + "." + FALLBACKPOLICY_POLICY); - } - - private String getProperty(String defaultValue, String... keys) { - String property = null; - for (String key : keys) { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); - if (property != null) { - break; - } - } - - if (property != null) { - return property; - } else { - return defaultValue; - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperCommand.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperCommand.java deleted file mode 100644 index e43bfbd1e75..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class ConsumerBizkeeperCommand extends BizkeeperCommand { - protected ConsumerBizkeeperCommand(String type, Invocation invocation, - com.netflix.hystrix.HystrixObservableCommand.Setter setter) { - super(type, invocation, setter); - } - - @Override - protected boolean isFailedResponse(Response resp) { - if (resp.isFailed()) { - if (InvocationException.class.isInstance(resp.getResult())) { - InvocationException e = (InvocationException) resp.getResult(); - return e.getStatusCode() == ExceptionFactory.CONSUMER_INNER_STATUS_CODE; - } else { - return true; - } - } else { - return false; - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperHandler.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperHandler.java deleted file mode 100644 index 28848d5be53..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ConsumerBizkeeperHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; - -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixObservableCommand; - -/** - * 客户端调用链处理流程 - * - */ -public class ConsumerBizkeeperHandler extends BizkeeperHandler { - private static final String COMMAND_GROUP = "Consumer"; - - public ConsumerBizkeeperHandler() { - super(COMMAND_GROUP); - } - - @Override - protected BizkeeperCommand createBizkeeperCommand(Invocation invocation) { - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - setCommonProperties(invocation, setter); - - BizkeeperCommand command = new ConsumerBizkeeperCommand(groupname, invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey(groupname, invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey(groupname, invocation)) - .andCommandPropertiesDefaults(setter)); - return command; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java deleted file mode 100644 index 79183b7189e..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/CustomizeCommandGroupKey.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; - -import com.netflix.hystrix.HystrixCommandGroupKey; -import com.netflix.hystrix.HystrixKey; -import com.netflix.hystrix.util.InternMap; - -/** - * 通过定制CommandGroupKey,目的是携带Invocation部分静态信息,便于CircutBreakerEvent获取 - */ -public class CustomizeCommandGroupKey extends HystrixKey.HystrixKeyDefault implements HystrixCommandGroupKey { - - private Invocation instance; - - public CustomizeCommandGroupKey(String key) { - super(key); - } - - private static final InternMap intern = - new InternMap( - new InternMap.ValueConstructor() { - @Override - public CustomizeCommandGroupKey create(String key) { - return new CustomizeCommandGroupKey(key); - } - }); - - public static HystrixCommandGroupKey asKey(String key, Invocation invocation) { - CustomizeCommandGroupKey result = intern.interned(key); - result.setInvocation(invocation); - return result; - } - - public void setInvocation(Invocation invocation) { - this.instance = invocation; - } - - public Invocation getInstance() { - return instance; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicy.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicy.java deleted file mode 100644 index 75b1eb4472f..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicy.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -public interface FallbackPolicy { - String name(); - - Response getFallbackResponse(Invocation invocation); - - default void record(Invocation invocation, Response response, boolean isSuccess) { - - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicyManager.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicyManager.java deleted file mode 100644 index 1382f0a9404..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FallbackPolicyManager.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -public class FallbackPolicyManager { - private static final Map POLICIES = new HashMap<>(); - - public static void addPolicy(FallbackPolicy policy) { - POLICIES.put(policy.name().toLowerCase(), policy); - } - - public static void record(String type, Invocation invocation, Response response, boolean isSuccess) { - FallbackPolicy policy = getPolicy(type, invocation); - if (policy != null) { - policy.record(invocation, response, isSuccess); - } - } - - public static Response getFallbackResponse(String type, Throwable error, Invocation invocation) { - FallbackPolicy policy = getPolicy(type, invocation); - if (policy != null) { - return policy.getFallbackResponse(invocation); - } else { - return Response.failResp(invocation.getInvocationType(), - BizkeeperExceptionUtils - .createBizkeeperException(BizkeeperExceptionUtils.SERVICECOMB_BIZKEEPER_FALLBACK, - error, - invocation.getOperationMeta().getMicroserviceQualifiedName())); - } - } - - private static FallbackPolicy getPolicy(String type, Invocation invocation) { - String policyKey = Configuration.INSTANCE.getFallbackPolicyPolicy(type, - invocation.getMicroserviceName(), - invocation.getOperationMeta().getMicroserviceQualifiedName()); - FallbackPolicy policy = null; - if (policyKey != null) { - policy = POLICIES.get(policyKey.toLowerCase()); - } - return policy; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FromCacheFallbackPolicy.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FromCacheFallbackPolicy.java deleted file mode 100644 index e992e196a09..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/FromCacheFallbackPolicy.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.stereotype.Component; - -@Component -public class FromCacheFallbackPolicy implements FallbackPolicy { - private static final String POLICY_NAME = "fromCache"; - - private Map cachedResponse = new ConcurrentHashMap<>(); - - @Override - public String name() { - return POLICY_NAME; - } - - @Override - public Response getFallbackResponse(Invocation invocation) { - if (cachedResponse.get(invocation.getInvocationQualifiedName()) != null) { - return cachedResponse.get(invocation.getInvocationQualifiedName()); - } else { - return Response.succResp(null); - } - } - - @Override - public void record(Invocation invocation, Response response, boolean isSuccess) { - if (isSuccess) { - cachedResponse.put(invocation.getInvocationQualifiedName(), response); - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java deleted file mode 100644 index 406ecf11181..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java +++ /dev/null @@ -1,553 +0,0 @@ -/** - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is forked from https://github.com/Netflix/Hystrix/blob/master/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandProperties.java - -package org.apache.servicecomb.bizkeeper; - -import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forBoolean; -import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forInteger; -import static com.netflix.hystrix.strategy.properties.HystrixPropertiesChainedProperty.forString; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.strategy.properties.HystrixDynamicProperty; -import com.netflix.hystrix.strategy.properties.HystrixProperty; - -public class HystrixCommandPropertiesExt extends HystrixCommandProperties { - - private static final Logger LOGGER = LoggerFactory.getLogger(HystrixCommandProperties.class); - - /* defaults */ - /* package */ - // default => statisticalWindow: 10000 = 10 seconds (and default of 10 - // buckets so each bucket is 1 second) - static final Integer DEFAULT_METRICSROLLINGSTATISTICALWINDOW = 10000; - - // default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second - // window so each bucket is 1 second - private static final Integer DEFAULT_METRICSROLLINGSTATISTICALWINDOWBUCKETS = 10; - - // default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds - // must occur before statistics matter - private static final Integer DEFAULT_CIRCUITBREAKERREQUESTVOLUMETHRESHOLD = 20; - - // default => sleepWindow: 15000 = 15 seconds that we will sleep before trying - // again after tripping the circuit - private static final Integer DEFAULT_CIRCUITBREAKERSLEEPWINDOWINMILLISECONDS = 15000; - - // default => errorThresholdPercentage = 50 = if 50%+ of requests in 10 - // seconds are failures or latent then we will trip the circuit - private static final Integer DEFAULT_CIRCUITBREAKERERRORTHRESHOLDPERCENTAGE = 50; - - // default => forceCircuitOpen = false (we want to allow traffic) - private static final Boolean DEFAULT_CIRCUITBREAKERFORCEOPEN = false; - - /* package */ - // default => ignoreErrors = false - static final Boolean DEFAULT_CIRCUITBREAKERFORCECLOSED = false; - - // default => executionTimeoutInMilliseconds: 30000 = 30 second - private static final Integer DEFAULT_EXECUTIONTIMEOUTINMILLISECONDS = 30000; - - private static final Boolean DEFAULT_EXECUTIONTIMEOUTENABLED = false; - - private static final ExecutionIsolationStrategy DEFAULT_ISOLATIONSTRATEGY = ExecutionIsolationStrategy.SEMAPHORE; - - private static final Boolean DEFAULT_EXECUTIONISOLATIONTHREADINTERRUPTONTIMEOUT = true; - - private static final Boolean DEFAULT_METRICSROLLINGPERCENTILEENABLED = false; - - private static final Boolean DEFAULT_REQUESTCACHEENABLED = true; - - private static final Integer DEFAULT_FALLBACKISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS = 10; - - private static final Boolean DEFAULT_FALLBACKENABLED = true; - - private static final Integer DEFAULT_EXECUTIONISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS = 1000; - - private static final Boolean DEFAULT_REQUESTLOGENABLED = true; - - private static final Boolean DEFAULT_CIRCUITBREAKERENABLED = true; - - // default to 1 minute for RollingPercentile - private static final Integer DEFAULT_METRICSROLLINGPERCENTILEWINDOW = 60000; - - // default to 6 buckets (10 seconds each in 60 second window) - private static final Integer DEFAULT_METRICSROLLINGPERCENTILEWINDOWBUCKETS = 6; - - // default to 100 values max per bucket - private static final Integer DEFAULT_METRICSROLLINGPERCENTILEBUCKETSIZE = 100; - - // default to 1000ms as max frequency between allowing snapshots of health - // (error percentage etc) - private static final Integer DEFAULT_METRICSHEALTHSNAPSHOTINTERVALINMILLISECONDS = 1000; - - private static final int COMMAND_KEY_LENGTH = 3; - - @SuppressWarnings("unused") - private final HystrixCommandKey key; - - // number of requests that must be made within a statisticalWindow before - // open/close decisions are made using stats - private final HystrixProperty circuitBreakerRequestVolumeThreshold; - - // milliseconds after tripping circuit before allowing retry - private final HystrixProperty circuitBreakerSleepWindowInMilliseconds; - - // Whether circuit breaker should be enabled. - private final HystrixProperty circuitBreakerEnabled; - - // % of 'marks' that must be failed to trip the circuit - private final HystrixProperty circuitBreakerErrorThresholdPercentage; - - // a property to allow forcing the circuit open (stopping all requests) - private final HystrixProperty circuitBreakerForceOpen; - - // a property to allow ignoring errors and therefore never trip 'open' (ie. - // allow all traffic through) - private final HystrixProperty circuitBreakerForceClosed; - - // Whether a command should be executed in a separate thread or not. - private final HystrixProperty executionIsolationStrategy; - - // Timeout value in milliseconds for a command - private final HystrixProperty executionTimeoutInMilliseconds; - - // Whether timeout should be triggered - private final HystrixProperty executionTimeoutEnabled; - - // What thread-pool this command should run in (if running on a separate - // thread). - private final HystrixProperty executionIsolationThreadPoolKeyOverride; - - // Number of permits for execution semaphore - private final HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests; - - // Number of permits for fallback semaphore - private final HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests; - - // Whether fallback should be attempted. - private final HystrixProperty fallbackEnabled; - - // Whether an underlying Future/Thread (when runInSeparateThread == true) - // should be interrupted after a timeout - private final HystrixProperty executionIsolationThreadInterruptOnTimeout; - - // milliseconds back that will be tracked - private final HystrixProperty metricsRollingStatisticalWindowInMilliseconds; - - // number of buckets in the statisticalWindow - private final HystrixProperty metricsRollingStatisticalWindowBuckets; - - // Whether monitoring should be enabled (SLA and Tracers). - private final HystrixProperty metricsRollingPercentileEnabled; - - // number of milliseconds that will be tracked in RollingPercentile - private final HystrixProperty metricsRollingPercentileWindowInMilliseconds; - - // number of buckets percentileWindow will be divided into - private final HystrixProperty metricsRollingPercentileWindowBuckets; - - // how many values will be stored in each percentileWindowBucket - private final HystrixProperty metricsRollingPercentileBucketSize; - - // time between health snapshots - private final HystrixProperty metricsHealthSnapshotIntervalInMilliseconds; - - // whether command request logging is enabled. - private final HystrixProperty requestLogEnabled; - - // Whether request caching is enabled. - private final HystrixProperty requestCacheEnabled; - - protected HystrixCommandPropertiesExt(HystrixCommandKey key) { - this(key, HystrixCommandProperties.Setter(), "servicecomb"); - } - - protected HystrixCommandPropertiesExt(HystrixCommandKey key, HystrixCommandProperties.Setter builder) { - this(key, builder, "servicecomb"); - } - - protected HystrixCommandPropertiesExt(HystrixCommandKey key, HystrixCommandProperties.Setter builder, - String propertyPrefix) { - super(key, builder, propertyPrefix); - this.key = key; - this.circuitBreakerEnabled = getProperty(propertyPrefix, - "circuitBreaker", - key, - "enabled", - builder.getCircuitBreakerEnabled(), - DEFAULT_CIRCUITBREAKERENABLED); - this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, - "circuitBreaker", - key, - "requestVolumeThreshold", - builder.getCircuitBreakerRequestVolumeThreshold(), - DEFAULT_CIRCUITBREAKERREQUESTVOLUMETHRESHOLD); - this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, - "circuitBreaker", - key, - "sleepWindowInMilliseconds", - builder.getCircuitBreakerSleepWindowInMilliseconds(), - DEFAULT_CIRCUITBREAKERSLEEPWINDOWINMILLISECONDS); - this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, - "circuitBreaker", - key, - "errorThresholdPercentage", - builder.getCircuitBreakerErrorThresholdPercentage(), - DEFAULT_CIRCUITBREAKERERRORTHRESHOLDPERCENTAGE); - this.circuitBreakerForceOpen = getProperty(propertyPrefix, - "circuitBreaker", - key, - "forceOpen", - builder.getCircuitBreakerForceOpen(), - DEFAULT_CIRCUITBREAKERFORCEOPEN); - this.circuitBreakerForceClosed = getProperty(propertyPrefix, - "circuitBreaker", - key, - "forceClosed", - builder.getCircuitBreakerForceClosed(), - DEFAULT_CIRCUITBREAKERFORCECLOSED); - this.executionIsolationStrategy = getProperty(propertyPrefix, - "isolation", - key, - "strategy", - builder.getExecutionIsolationStrategy(), - DEFAULT_ISOLATIONSTRATEGY); - this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, - "isolation", - key, - "timeoutInMilliseconds", - builder.getExecutionTimeoutInMilliseconds(), - DEFAULT_EXECUTIONTIMEOUTINMILLISECONDS); - this.executionTimeoutEnabled = getProperty(propertyPrefix, - "isolation", - key, - "timeout.enabled", - builder.getExecutionTimeoutEnabled(), - DEFAULT_EXECUTIONTIMEOUTENABLED); - this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, - "isolation", - key, - "interruptOnTimeout", - builder.getExecutionIsolationThreadInterruptOnTimeout(), - DEFAULT_EXECUTIONISOLATIONTHREADINTERRUPTONTIMEOUT); - this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, - "isolation", - key, - "maxConcurrentRequests", - builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), - DEFAULT_EXECUTIONISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS); - this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, - "fallback", - key, - "maxConcurrentRequests", - builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), - DEFAULT_FALLBACKISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS); - this.fallbackEnabled = getProperty(propertyPrefix, - "fallback", - key, - "enabled", - builder.getFallbackEnabled(), - DEFAULT_FALLBACKENABLED); - this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, - "metrics", - key, - "rollingStats.timeInMilliseconds", - builder.getMetricsRollingStatisticalWindowInMilliseconds(), - DEFAULT_METRICSROLLINGSTATISTICALWINDOW); - this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, - "metrics", - key, - "rollingStats.numBuckets", - builder.getMetricsRollingStatisticalWindowBuckets(), - DEFAULT_METRICSROLLINGSTATISTICALWINDOWBUCKETS); - this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, - "metrics", - key, - "rollingPercentile.enabled", - builder.getMetricsRollingPercentileEnabled(), - DEFAULT_METRICSROLLINGPERCENTILEENABLED); - this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, - "metrics", - key, - "rollingPercentile.timeInMilliseconds", - builder.getMetricsRollingPercentileWindowInMilliseconds(), - DEFAULT_METRICSROLLINGPERCENTILEWINDOW); - this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, - "metrics", - key, - "rollingPercentile.numBuckets", - builder.getMetricsRollingPercentileWindowBuckets(), - DEFAULT_METRICSROLLINGPERCENTILEWINDOWBUCKETS); - this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, - "metrics", - key, - "rollingPercentile.bucketSize", - builder.getMetricsRollingPercentileBucketSize(), - DEFAULT_METRICSROLLINGPERCENTILEBUCKETSIZE); - this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, - "metrics", - key, - "healthSnapshot.intervalInMilliseconds", - builder.getMetricsHealthSnapshotIntervalInMilliseconds(), - DEFAULT_METRICSHEALTHSNAPSHOTINTERVALINMILLISECONDS); - this.requestCacheEnabled = getProperty(propertyPrefix, - "requestCache", - key, - "enabled", - builder.getRequestCacheEnabled(), - DEFAULT_REQUESTCACHEENABLED); - this.requestLogEnabled = getProperty(propertyPrefix, - "requestLog", - key, - "enabled", - builder.getRequestLogEnabled(), - DEFAULT_REQUESTLOGENABLED); - - // threadpool doesn't have a global override, only instance level makes - // sense - this.executionIsolationThreadPoolKeyOverride = forString() - .add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null) - .build(); - } - - @Override - public HystrixProperty circuitBreakerEnabled() { - return circuitBreakerEnabled; - } - - @Override - public HystrixProperty circuitBreakerErrorThresholdPercentage() { - return circuitBreakerErrorThresholdPercentage; - } - - @Override - public HystrixProperty circuitBreakerForceClosed() { - return circuitBreakerForceClosed; - } - - @Override - public HystrixProperty circuitBreakerForceOpen() { - return circuitBreakerForceOpen; - } - - @Override - public HystrixProperty circuitBreakerRequestVolumeThreshold() { - return circuitBreakerRequestVolumeThreshold; - } - - @Override - public HystrixProperty circuitBreakerSleepWindowInMilliseconds() { - return circuitBreakerSleepWindowInMilliseconds; - } - - @Override - public HystrixProperty executionIsolationSemaphoreMaxConcurrentRequests() { - return executionIsolationSemaphoreMaxConcurrentRequests; - } - - @Override - public HystrixProperty executionIsolationStrategy() { - return executionIsolationStrategy; - } - - @Override - public HystrixProperty executionIsolationThreadInterruptOnTimeout() { - return executionIsolationThreadInterruptOnTimeout; - } - - @Override - public HystrixProperty executionIsolationThreadPoolKeyOverride() { - return executionIsolationThreadPoolKeyOverride; - } - - @Override - @Deprecated // prefer {@link #executionTimeoutInMilliseconds} - public HystrixProperty executionIsolationThreadTimeoutInMilliseconds() { - return executionTimeoutInMilliseconds; - } - - @Override - public HystrixProperty executionTimeoutInMilliseconds() { - return executionIsolationThreadTimeoutInMilliseconds(); - } - - @Override - public HystrixProperty executionTimeoutEnabled() { - return executionTimeoutEnabled; - } - - @Override - public HystrixProperty fallbackIsolationSemaphoreMaxConcurrentRequests() { - return fallbackIsolationSemaphoreMaxConcurrentRequests; - } - - @Override - public HystrixProperty fallbackEnabled() { - return fallbackEnabled; - } - - @Override - public HystrixProperty metricsHealthSnapshotIntervalInMilliseconds() { - return metricsHealthSnapshotIntervalInMilliseconds; - } - - @Override - public HystrixProperty metricsRollingPercentileBucketSize() { - return metricsRollingPercentileBucketSize; - } - - @Override - public HystrixProperty metricsRollingPercentileEnabled() { - return metricsRollingPercentileEnabled; - } - - @Override - @Deprecated - public HystrixProperty metricsRollingPercentileWindow() { - return metricsRollingPercentileWindowInMilliseconds; - } - - @Override - public HystrixProperty metricsRollingPercentileWindowInMilliseconds() { - return metricsRollingPercentileWindowInMilliseconds; - } - - @Override - public HystrixProperty metricsRollingPercentileWindowBuckets() { - return metricsRollingPercentileWindowBuckets; - } - - @Override - public HystrixProperty metricsRollingStatisticalWindowInMilliseconds() { - return metricsRollingStatisticalWindowInMilliseconds; - } - - @Override - public HystrixProperty metricsRollingStatisticalWindowBuckets() { - return metricsRollingStatisticalWindowBuckets; - } - - @Override - public HystrixProperty requestCacheEnabled() { - return requestCacheEnabled; - } - - @Override - public HystrixProperty requestLogEnabled() { - return requestLogEnabled; - } - - private HystrixProperty getProperty(String propertyPrefix, String command, - HystrixCommandKey key, String instanceProperty, ExecutionIsolationStrategy builderOverrideValue, - ExecutionIsolationStrategy defaultValue) { - return new ExecutionIsolationStrategyHystrixProperty(builderOverrideValue, key, propertyPrefix, command, - defaultValue, instanceProperty); - } - - private static final class ExecutionIsolationStrategyHystrixProperty - implements HystrixProperty { - private final HystrixDynamicProperty property; - - private volatile ExecutionIsolationStrategy value; - - private final ExecutionIsolationStrategy defaultValue; - - private ExecutionIsolationStrategyHystrixProperty(ExecutionIsolationStrategy builderOverrideValue, - HystrixCommandKey key, String propertyPrefix, String command, ExecutionIsolationStrategy defaultValue, - String instanceProperty) { - this.defaultValue = defaultValue; - String overrideValue = null; - if (builderOverrideValue != null) { - overrideValue = builderOverrideValue.name(); - } - property = forString() - .add(propertyPrefix + "." + command + "." + key.name() + "." + instanceProperty, null) - .add(propertyPrefix + "." + command + "." + serviceKey(key.name()) + "." + instanceProperty, - overrideValue) - .add(propertyPrefix + "." + command + "." + typeKey(key.name()) + "." + instanceProperty, - defaultValue.name()) - .build(); - - // initialize the enum value from the property - parseProperty(); - - // use a callback to handle changes so we only handle the parse cost - // on updates rather than every fetch - // when the property value changes we'll update the value - property.addCallback(this::parseProperty); - } - - @Override - public ExecutionIsolationStrategy get() { - return value; - } - - private void parseProperty() { - try { - value = ExecutionIsolationStrategy.valueOf(property.get()); - } catch (Exception e) { - LOGGER.error("Unable to derive ExecutionIsolationStrategy from property value: " + property.get(), e); - // use the default value - value = defaultValue; - } - } - } - - private static String serviceKey(String key) { - String[] keyparts = key.split("\\.", COMMAND_KEY_LENGTH); - if (keyparts.length == COMMAND_KEY_LENGTH) { - return keyparts[0] + "." + keyparts[1]; - } - return key; - } - - private static String typeKey(String key) { - int index = key.indexOf("."); - if (index > 0) { - return key.substring(0, index); - } - return key; - } - - private HystrixProperty getProperty(String propertyPrefix, String command, HystrixCommandKey key, - String instanceProperty, Integer builderOverrideValue, - Integer defaultValue) { - return forInteger() - .add(propertyPrefix + "." + command + "." + key.name() + "." + instanceProperty, null) - .add(propertyPrefix + "." + command + "." + serviceKey(key.name()) + "." + instanceProperty, - null) - .add(propertyPrefix + "." + command + "." + typeKey(key.name()) + "." + instanceProperty, - builderOverrideValue == null ? defaultValue : builderOverrideValue) - .build(); - } - - private HystrixProperty getProperty(String propertyPrefix, String command, HystrixCommandKey key, - String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) { - return forBoolean() - .add(propertyPrefix + "." + command + "." + key.name() + "." + instanceProperty, null) - .add(propertyPrefix + "." + command + "." + serviceKey(key.name()) + "." + instanceProperty, - null) - .add(propertyPrefix + "." + command + "." + typeKey(key.name()) + "." + instanceProperty, - builderOverrideValue == null ? defaultValue : builderOverrideValue) - .build(); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixPropertiesStrategyExt.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixPropertiesStrategyExt.java deleted file mode 100644 index a766e718627..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixPropertiesStrategyExt.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixCommandProperties.Setter; -import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; - -/** - * 定制HystrixPropertiesStrategy。 配置需要支持动态生效和调整, 默认的hystrix实现会根据CommonKey进行缓存。 - * CircuitBreake需要统计并记录请求数据,需要缓存并保证每个commandKey对应一个Breaker;单纯清理CommandKey无法动态生效。 - * 参考:HystrixCircuitBreaker.Factory.getInstance(commandKey, groupKey, - * properties, metrics) - * - */ -public final class HystrixPropertiesStrategyExt extends HystrixPropertiesStrategy { - - private static final HystrixPropertiesStrategyExt INSTANCE = new HystrixPropertiesStrategyExt(); - - private final Map commandPropertiesMap = new ConcurrentHashMap<>(); - - private HystrixPropertiesStrategyExt() { - } - - public static HystrixPropertiesStrategyExt getInstance() { - return INSTANCE; - } - - @Override - public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, Setter builder) { - HystrixCommandProperties commandProperties = commandPropertiesMap.get(commandKey.name()); - if (commandProperties == null) { - commandProperties = new HystrixCommandPropertiesExt(commandKey, builder); - commandPropertiesMap.putIfAbsent(commandKey.name(), commandProperties); - } - return commandProperties; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperCommand.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperCommand.java deleted file mode 100644 index 4ef5a629e3c..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class ProviderBizkeeperCommand extends BizkeeperCommand { - protected ProviderBizkeeperCommand(String type, Invocation invocation, - com.netflix.hystrix.HystrixObservableCommand.Setter setter) { - super(type, invocation, setter); - } - - @Override - protected boolean isFailedResponse(Response resp) { - if (resp.isFailed()) { - if (InvocationException.class.isInstance(resp.getResult())) { - InvocationException e = (InvocationException) resp.getResult(); - return e.getStatusCode() == ExceptionFactory.PRODUCER_INNER_STATUS_CODE; - } else { - return true; - } - } else { - return false; - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperHanlder.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperHanlder.java deleted file mode 100644 index 8f688a48aa4..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ProviderBizkeeperHanlder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; - -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixObservableCommand; - -/** - * 服务端调用链处理流程 - * - */ -public class ProviderBizkeeperHanlder extends BizkeeperHandler { - private static final String COMMAND_GROUP = "Provider"; - - public ProviderBizkeeperHanlder() { - super(COMMAND_GROUP); - } - - @Override - protected BizkeeperCommand createBizkeeperCommand(Invocation invocation) { - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(false) - .withRequestLogEnabled(false); - setCommonProperties(invocation, setter); - - BizkeeperCommand command = new ProviderBizkeeperCommand(groupname, invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey(groupname, invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey(groupname, invocation)) - .andCommandPropertiesDefaults(setter)); - return command; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ReturnNullFallbackPolicy.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ReturnNullFallbackPolicy.java deleted file mode 100644 index b4b0a5fa99f..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ReturnNullFallbackPolicy.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.stereotype.Component; - -@Component -public class ReturnNullFallbackPolicy implements FallbackPolicy { - private static final String POLICY_NAME = "returnNull"; - - @Override - public String name() { - return POLICY_NAME; - } - - @Override - public Response getFallbackResponse(Invocation invocation) { - return Response.succResp(null); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ThrowExceptionFallbackPolicy.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ThrowExceptionFallbackPolicy.java deleted file mode 100644 index 1376510900d..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/ThrowExceptionFallbackPolicy.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.stereotype.Component; - -@Component -public class ThrowExceptionFallbackPolicy implements FallbackPolicy { - private static final String POLICY_NAME = "throwException"; - - @Override - public String name() { - return POLICY_NAME; - } - - @Override - public Response getFallbackResponse(Invocation invocation) { - return Response.failResp(invocation.getInvocationType(), - BizkeeperExceptionUtils - .createBizkeeperException(BizkeeperExceptionUtils.SERVICECOMB_BIZKEEPER_FALLBACK, - null, - invocation.getOperationMeta().getMicroserviceQualifiedName())); - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java deleted file mode 100644 index c9f7a8ed898..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEvent.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper.event; - - -import org.apache.servicecomb.bizkeeper.CustomizeCommandGroupKey; -import org.apache.servicecomb.foundation.common.event.AlarmEvent; - -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixCommandMetrics; - -public class CircutBreakerEvent extends AlarmEvent { - - private String role; - - private String microservice; - - private String schema; - - private String operation; - - //当前总请求数 - private long currentTotalRequest; - - //当前请求出错计数 - private long currentErrorCount; - - //当前请求出错百分比 - private long currentErrorPercentage; - - private int requestVolumeThreshold; - - private int sleepWindowInMilliseconds; - - private int errorThresholdPercentage; - - public CircutBreakerEvent(HystrixCommandKey commandKey, Type type) { - super(type); - HystrixCommandMetrics hystrixCommandMetrics = HystrixCommandMetrics.getInstance(commandKey); - if (hystrixCommandMetrics != null) { - if (hystrixCommandMetrics.getCommandGroup() instanceof CustomizeCommandGroupKey) { - CustomizeCommandGroupKey customCommandGroupKey = - (CustomizeCommandGroupKey) hystrixCommandMetrics.getCommandGroup(); - this.microservice = customCommandGroupKey.getInstance().getMicroserviceName(); - this.role = customCommandGroupKey.getInstance().getInvocationType().name(); - this.schema = customCommandGroupKey.getInstance().getSchemaId(); - this.operation = customCommandGroupKey.getInstance().getOperationName(); - } - this.currentTotalRequest = hystrixCommandMetrics.getHealthCounts().getTotalRequests(); - this.currentErrorPercentage = hystrixCommandMetrics.getHealthCounts().getErrorCount(); - this.currentErrorCount = hystrixCommandMetrics.getHealthCounts().getErrorPercentage(); - this.requestVolumeThreshold = hystrixCommandMetrics.getProperties().circuitBreakerRequestVolumeThreshold().get(); - this.sleepWindowInMilliseconds = - hystrixCommandMetrics.getProperties().circuitBreakerSleepWindowInMilliseconds().get(); - this.errorThresholdPercentage = - hystrixCommandMetrics.getProperties().circuitBreakerErrorThresholdPercentage().get(); - } - } - - public String getRole() { - return role; - } - - public String getMicroservice() { - return microservice; - } - - public String getSchema() { - return schema; - } - - public String getOperation() { - return operation; - } - - public long getCurrentTotalRequest() { - return currentTotalRequest; - } - - public long getCurrentErrorCount() { - return currentErrorCount; - } - - public long getCurrentErrorPercentage() { - return currentErrorPercentage; - } - - public int getRequestVolumeThreshold() { - return requestVolumeThreshold; - } - - public int getSleepWindowInMilliseconds() { - return sleepWindowInMilliseconds; - } - - public int getErrorThresholdPercentage() { - return errorThresholdPercentage; - } -} diff --git a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java b/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java deleted file mode 100644 index 3b47b5f204d..00000000000 --- a/handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/event/CircutBreakerEventNotifier.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper.event; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type; - -import com.google.common.eventbus.EventBus; -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixEventType; -import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier; - -public class CircutBreakerEventNotifier extends HystrixEventNotifier { - - /** - * 使用circuitFlag来记录被熔断的接口 - */ - private ConcurrentHashMapEx circuitFlag = new ConcurrentHashMapEx<>(); - - EventBus eventBus = EventManager.getEventBus(); - - @Override - public void markEvent(HystrixEventType eventType, HystrixCommandKey key) { - String keyName = key.name(); - AtomicBoolean flag = circuitFlag.computeIfAbsent(keyName, k -> new AtomicBoolean()); - switch (eventType) { - case SHORT_CIRCUITED: - if (flag.compareAndSet(false, true)) { - eventBus.post(new CircutBreakerEvent(key, Type.OPEN)); - } - break; - - case SUCCESS: - if (flag.compareAndSet(true, false)) { - eventBus.post(new CircutBreakerEvent(key, Type.CLOSE)); - } - break; - - default: - break; - } - } -} diff --git a/handlers/handler-bizkeeper/src/main/resources/META-INF/spring/cse.bean.xml b/handlers/handler-bizkeeper/src/main/resources/META-INF/spring/cse.bean.xml deleted file mode 100644 index a362a92fb5e..00000000000 --- a/handlers/handler-bizkeeper/src/main/resources/META-INF/spring/cse.bean.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/handlers/handler-bizkeeper/src/main/resources/config/cse.handler.xml b/handlers/handler-bizkeeper/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 4253c44d825..00000000000 --- a/handlers/handler-bizkeeper/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties b/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties deleted file mode 100644 index 74eb50f74e7..00000000000 --- a/handlers/handler-bizkeeper/src/main/resources/hystrix-plugins.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -hystrix.plugin.HystrixEventNotifier.implementation=org.apache.servicecomb.bizkeeper.event.CircutBreakerEventNotifier diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java deleted file mode 100644 index 9629d32c799..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperCommand.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixObservableCommand; -import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; - -import rx.Observable; - -public class TestBizkeeperCommand { - - @Test - public void testGetCacheKeyProvider() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ProviderBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - String str = bizkeeperCommand.getCacheKey(); - Assert.assertNull(str); - - Response resp = Mockito.mock(Response.class); - Mockito.when(resp.isFailed()).thenReturn(false); - Assert.assertEquals(false, bizkeeperCommand.isFailedResponse(resp)); - Mockito.when(resp.isFailed()).thenReturn(true); - InvocationException excp = Mockito.mock(InvocationException.class); - Mockito.when(resp.getResult()).thenReturn(excp); - Mockito.when(excp.getStatusCode()).thenReturn(400); - Assert.assertEquals(false, bizkeeperCommand.isFailedResponse(resp)); - Mockito.when(resp.getResult()).thenReturn(excp); - Mockito.when(excp.getStatusCode()).thenReturn(590); - Assert.assertEquals(true, bizkeeperCommand.isFailedResponse(resp)); - } - - @Test - public void testResumeWithFallbackProvider() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ProviderBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - Observable observe = bizkeeperCommand.resumeWithFallback(); - Assert.assertNotNull(observe); - } - - @Test - public void testConstructProvider() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ProviderBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - Observable response = bizkeeperCommand.construct(); - Assert.assertNotNull(response); - } - - @Test - public void testGetCacheKeyWithContextInitializedProvider() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ProviderBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - HystrixRequestContext.initializeContext(); - String cacheKey = bizkeeperCommand.getCacheKey(); - Assert.assertNotNull(cacheKey); - } - - @Test - public void testGetCacheKeyConsumer() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ConsumerBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - String str = bizkeeperCommand.getCacheKey(); - Assert.assertNull(str); - - Response resp = Mockito.mock(Response.class); - Mockito.when(resp.isFailed()).thenReturn(false); - Assert.assertEquals(false, bizkeeperCommand.isFailedResponse(resp)); - Mockito.when(resp.isFailed()).thenReturn(true); - InvocationException excp = Mockito.mock(InvocationException.class); - Mockito.when(resp.getResult()).thenReturn(excp); - Mockito.when(excp.getStatusCode()).thenReturn(400); - Assert.assertEquals(false, bizkeeperCommand.isFailedResponse(resp)); - Mockito.when(resp.getResult()).thenReturn(excp); - Mockito.when(excp.getStatusCode()).thenReturn(490); - Assert.assertEquals(true, bizkeeperCommand.isFailedResponse(resp)); - } - - @Test - public void testResumeWithFallbackConsumer() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ConsumerBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - Observable observe = bizkeeperCommand.resumeWithFallback(); - Assert.assertNotNull(observe); - } - - @Test - public void testConstructConsumer() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ConsumerBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - Observable response = bizkeeperCommand.construct(); - Assert.assertNotNull(response); - } - - @Test - public void testGetCacheKeyWithContextInitializedConsumer() { - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ConsumerBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - - HystrixRequestContext.initializeContext(); - String cacheKey = bizkeeperCommand.getCacheKey(); - Assert.assertNotNull(cacheKey); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperExceptionUtils.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperExceptionUtils.java deleted file mode 100644 index 294b33d47d1..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperExceptionUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.exception.CseException; -import org.junit.Assert; -import org.junit.Test; - -public class TestBizkeeperExceptionUtils { - - @Test - public void testCreateBizkeeperException() { - Assert.assertEquals("servicecomb.bizkeeper.fallback", BizkeeperExceptionUtils.SERVICECOMB_BIZKEEPER_FALLBACK); - CseException cseException = BizkeeperExceptionUtils.createBizkeeperException("servicecomb.bizkeeper.fallback", - new Throwable(), - "ARGS"); - Assert.assertNotNull(cseException); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java deleted file mode 100644 index 9d049cb920f..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperHandler.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.netflix.hystrix.HystrixCommandProperties; -import com.netflix.hystrix.HystrixObservableCommand; -import com.netflix.hystrix.strategy.HystrixPlugins; - -public class TestBizkeeperHandler extends BizkeeperHandler { - - BizkeeperHandler bizkeeperHandler = null; - - private static final String GROUP_NAME = "Group_Name"; - - Invocation invocation = null; - - AsyncResponse asyncResp = null; - - public TestBizkeeperHandler() { - super(GROUP_NAME); - } - - @Before - public void setUp() throws Exception { - bizkeeperHandler = new TestBizkeeperHandler(); - invocation = Mockito.mock(Invocation.class); - asyncResp = Mockito.mock(AsyncResponse.class); - - FallbackPolicyManager.addPolicy(new ReturnNullFallbackPolicy()); - FallbackPolicyManager.addPolicy(new ThrowExceptionFallbackPolicy()); - FallbackPolicyManager.addPolicy(new FromCacheFallbackPolicy()); - } - - @After - public void tearDown() throws Exception { - bizkeeperHandler = null; - invocation = null; - asyncResp = null; - } - - @Test - public void testHandleWithException() { - boolean validAssert; - HystrixPlugins.reset(); - try { - validAssert = true; - bizkeeperHandler.handle(invocation, asyncResp); - } catch (Exception e) { - validAssert = false; - } - Assert.assertFalse(validAssert); - } - - @Test - public void testHandle() { - boolean validAssert; - - try { - Assert.assertNotNull(bizkeeperHandler); - Mockito.when(invocation.getMicroserviceName()).thenReturn("test1"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - validAssert = true; - - bizkeeperHandler.handle(invocation, asyncResp); - } catch (Exception exce) { - validAssert = false; - } - Assert.assertTrue(validAssert); - } - - @Test - public void testSetCommonProperties() { - boolean validAssert; - try { - validAssert = true; - HystrixPlugins.reset(); - HystrixCommandProperties.Setter setter = Mockito.mock(HystrixCommandProperties.Setter.class); - bizkeeperHandler.setCommonProperties(invocation, setter); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - } - - @Override - protected BizkeeperCommand createBizkeeperCommand(Invocation invocation) { - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false); - - BizkeeperCommand bizkeeperCommand = new ConsumerBizkeeperCommand("groupname", invocation, - HystrixObservableCommand.Setter - .withGroupKey(CommandKey.toHystrixCommandGroupKey("groupname", invocation)) - .andCommandKey(CommandKey.toHystrixCommandKey("groupname", invocation)) - .andCommandPropertiesDefaults(setter)); - return bizkeeperCommand; - } - - @Test - public void testHandleForceThrowException() throws Exception { - Mockito.when(invocation.getMicroserviceName()).thenReturn("testHandleForceThrowException"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) - .thenReturn("testHandleForceThrowException"); - System.setProperty("servicecomb.fallback.Group_Name.testHandleForceThrowException.force", "true"); - System.setProperty("servicecomb.fallbackpolicy.Group_Name.testHandleForceThrowException.policy", "throwexception"); - bizkeeperHandler.handle(invocation, f -> { - Assert.assertTrue(f.isFailed()); - }); - } - - @Test - public void testHandleForceReturnnull() throws Exception { - Mockito.when(invocation.getMicroserviceName()).thenReturn("testHandleForceReturnnull"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) - .thenReturn("testHandleForceReturnnull"); - System.setProperty("servicecomb.fallback.Group_Name.testHandleForceReturnnull.force", "true"); - System.setProperty("servicecomb.fallbackpolicy.Group_Name.testHandleForceReturnnull.policy", "returnnull"); - bizkeeperHandler.handle(invocation, f -> { - Assert.assertTrue(f.isSuccessed()); - Assert.assertNull(f.getResult()); - }); - } - - @Test - public void testHandleInError() throws Exception { - Mockito.when(invocation.getMicroserviceName()).thenReturn("testHandleInError"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) - .thenReturn("testHandleInError"); - FallbackPolicy policy = Mockito.mock(FallbackPolicy.class); - Mockito.when(policy.name()).thenReturn("throwException"); - Mockito.when(policy.getFallbackResponse(Mockito.any(Invocation.class))).thenThrow(new RuntimeException()); - FallbackPolicyManager.addPolicy(policy); - System.setProperty("servicecomb.fallbackpolicy.groupname.testHandleInError.policy", "throwException"); - Mockito.doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) { - AsyncResponse asyncRsp = invocation.getArgumentAt(0, AsyncResponse.class); - asyncRsp.fail(InvocationType.CONSUMER, new Exception("testHandleInError")); - return null; - } - }).when(invocation).next(Mockito.any(AsyncResponse.class)); - bizkeeperHandler.handle(invocation, f -> { - Assert.assertTrue(f.isFailed()); - }); - } - - @Test - public void testHandlNextException() throws Exception { - Mockito.when(invocation.getMicroserviceName()).thenReturn("testHandlNextException"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) - .thenReturn("testHandlNextException"); - Mockito.doThrow(new Exception("testHandlNextException")).when(invocation).next(Mockito.any(AsyncResponse.class)); - bizkeeperHandler.handle(invocation, f -> { - Assert.assertTrue(f.isFailed()); - }); - } - - @Test - public void testHandleSuccess() throws Exception { - Mockito.when(invocation.getMicroserviceName()).thenReturn("testHandleSuccess"); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()) - .thenReturn("testHandleSuccess"); - Mockito.doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) { - AsyncResponse asyncRsp = invocation.getArgumentAt(0, AsyncResponse.class); - asyncRsp.success(""); - return null; - } - }).when(invocation).next(Mockito.any(AsyncResponse.class)); - bizkeeperHandler.handle(invocation, f -> { - Assert.assertTrue(f.isSuccessed()); - }); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperRequestContext.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperRequestContext.java deleted file mode 100644 index d0fc7a92f81..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestBizkeeperRequestContext.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.junit.Assert; -import org.junit.Test; - -/** - * - * - */ -public class TestBizkeeperRequestContext { - - @Test - public void testInitializeContext() { - - BizkeeperRequestContext bizkeeperRequestContext = BizkeeperRequestContext.initializeContext(); - Assert.assertNotNull(bizkeeperRequestContext); - } - - @Test - public void testShutdown() { - BizkeeperRequestContext bizkeeperRequestContext = BizkeeperRequestContext.initializeContext(); - boolean validAssert; - - try { - bizkeeperRequestContext.shutdown(); - validAssert = true; - } catch (Exception e) { - validAssert = false; - } - - Assert.assertTrue(validAssert); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java deleted file mode 100644 index 29c03caa98d..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCommandKey.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.hystrix.HystrixCommandGroupKey; -import com.netflix.hystrix.HystrixCommandKey; - -/** - * - * - */ -public class TestCommandKey { - - @Test - public void testToHystrixCommandGroupKey() { - Invocation invocation = Mockito.mock(Invocation.class); - - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - Assert.assertNotNull(invocation); - HystrixCommandGroupKey hystrixCommandGroupKey = CommandKey.toHystrixCommandGroupKey("groupname", invocation); - Assert.assertNotNull(hystrixCommandGroupKey); - } - - @Test - public void testToHystrixCommandKey() { - - Invocation invocation = Mockito.mock(Invocation.class); - - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - Assert.assertNotNull(invocation); - HystrixCommandKey hystrixCommandGroupKey = CommandKey.toHystrixCommandKey("groupname", invocation); - Assert.assertNotNull(hystrixCommandGroupKey); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConfiguration.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConfiguration.java deleted file mode 100644 index 6ec7e4d528c..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConfiguration.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestConfiguration { - @Test - public void testConfiguration() { - - assertNotNull(Configuration.INSTANCE); - assertEquals("returnnull", Configuration.FALLBACKPOLICY_POLICY_RETURN); - assertEquals("throwexception", Configuration.FALLBACKPOLICY_POLICY_THROW); - - Configuration c = Configuration.INSTANCE; - Invocation invocation = Mockito.mock(Invocation.class); - String test2 = invocation.getMicroserviceName(); - - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceName()).thenReturn("testqualify"); - - int res = c.getIsolationTimeoutInMilliseconds("groupname", test2, "testqualify"); - assertEquals(30000, res); - boolean b1 = c.getIsolationTimeoutEnabled("groupname", test2, "testqualify"); - assertFalse(b1); - int res1 = c.getIsolationMaxConcurrentRequests("groupname", test2, "testqualify"); - assertEquals(1000, res1); - boolean b2 = c.isCircuitBreakerEnabled("groupname", test2, "testqualify"); - assertTrue(b2); - String str = c.getFallbackPolicyPolicy("groupname", test2, "testqualify"); - // no need to give default value now - assertEquals(null, str); - - assertFalse(c.isCircuitBreakerForceOpen("groupname", test2, "testqualify")); - assertFalse(c.isCircuitBreakerForceClosed("groupname", test2, "testqualify")); - assertEquals(15000, c.getCircuitBreakerSleepWindowInMilliseconds("groupname", test2, "testqualify")); - assertEquals(20, c.getCircuitBreakerRequestVolumeThreshold("groupname", test2, "testqualify")); - assertEquals(50, c.getCircuitBreakerErrorThresholdPercentage("groupname", test2, "testqualify")); - assertTrue(c.isFallbackEnabled("groupname", test2, "testqualify")); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java deleted file mode 100644 index b50a5d0e8a3..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestConsumerBizkeeperHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.hystrix.strategy.HystrixPlugins; - -/** - * - * - */ -public class TestConsumerBizkeeperHandler { - - @Test - public void testCreateBizkeeperCommand() { - HystrixPlugins.reset(); - ConsumerBizkeeperHandler consumerBizkeeperHandler = new ConsumerBizkeeperHandler(); - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - - CommandKey.toHystrixCommandGroupKey("groupname", invocation); - CommandKey.toHystrixCommandKey("groupname", invocation); - BizkeeperCommand command = consumerBizkeeperHandler.createBizkeeperCommand(invocation); - Assert.assertNotNull(command); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java deleted file mode 100644 index 9bcf64eaa4b..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestCustomCommandGroupKey.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestCustomCommandGroupKey { - @Test - public void testToHystrixCommandGroupKey() { - Invocation invocation = Mockito.mock(Invocation.class); - CustomizeCommandGroupKey customizeCommandGroupKey = - (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation); - Assert.assertEquals(invocation, customizeCommandGroupKey.getInstance()); - } - - @Test - public void testOOM() { - Invocation invocation1 = Mockito.mock(Invocation.class); - Invocation invocation2 = Mockito.mock(Invocation.class); - CustomizeCommandGroupKey customizeCommandGroupKey1 = - (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation1); - CustomizeCommandGroupKey customizeCommandGroupKey2 = - (CustomizeCommandGroupKey) CustomizeCommandGroupKey.asKey("key", invocation2); - Assert.assertEquals(customizeCommandGroupKey1, customizeCommandGroupKey2); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestFallbackPolicyManager.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestFallbackPolicyManager.java deleted file mode 100644 index b2545998300..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestFallbackPolicyManager.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.exception.CseException; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestFallbackPolicyManager { - @Test - public void testFallbackPolicyManager(final @Mocked Configuration config, final @Mocked Invocation invocation, - final @Mocked OperationMeta operation) { - FallbackPolicyManager.addPolicy(new ReturnNullFallbackPolicy()); - FallbackPolicyManager.addPolicy(new ThrowExceptionFallbackPolicy()); - FallbackPolicyManager.addPolicy(new FromCacheFallbackPolicy()); - - new Expectations() { - { - invocation.getMicroserviceName(); - result = "testservice"; - invocation.getOperationMeta(); - result = operation; - operation.getMicroserviceQualifiedName(); - result = "testservice.schema.returnnull"; - config.getFallbackPolicyPolicy("Consumer", "testservice", "testservice.schema.returnnull"); - result = "returnnull"; - } - }; - - Assert.assertEquals((String) null, - FallbackPolicyManager.getFallbackResponse("Consumer", null, invocation).getResult()); - - new Expectations() { - { - invocation.getMicroserviceName(); - result = "testservice"; - invocation.getOperationMeta(); - result = operation; - operation.getMicroserviceQualifiedName(); - result = "testservice.schema.throwexception"; - config.getFallbackPolicyPolicy("Consumer", "testservice", "testservice.schema.throwexception"); - result = "throwexception"; - } - }; - Assert.assertEquals(CseException.class, - ((Exception) FallbackPolicyManager.getFallbackResponse("Consumer", null, invocation).getResult()).getCause() - .getClass()); - - new Expectations() { - { - invocation.getMicroserviceName(); - result = "testservice"; - invocation.getOperationMeta(); - result = operation; - operation.getMicroserviceQualifiedName(); - result = "testservice.schema.fromcache"; - config.getFallbackPolicyPolicy("Consumer", "testservice", "testservice.schema.fromcache"); - result = "fromcache"; - invocation.getInvocationQualifiedName(); - result = "testservice.schema.fromcache"; - } - }; - FallbackPolicyManager.record("Consumer", invocation, Response.succResp("mockedsuccess"), true); - FallbackPolicyManager.record("Consumer", invocation, Response.succResp("mockedfailure"), false); - Assert.assertEquals("mockedsuccess", - FallbackPolicyManager.getFallbackResponse("Consumer", null, invocation).getResult()); - - new Expectations() { - { - invocation.getMicroserviceName(); - result = "testservice"; - invocation.getOperationMeta(); - result = operation; - operation.getMicroserviceQualifiedName(); - result = "testservice.schema.unknown"; - config.getFallbackPolicyPolicy("Consumer", "testservice", "testservice.schema.unknown"); - result = "unknown"; - } - }; - Assert.assertEquals(CseException.class, - ((Exception) FallbackPolicyManager.getFallbackResponse("Consumer", null, invocation).getResult()).getCause() - .getClass()); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestHystrixPropertiesStrategyExt.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestHystrixPropertiesStrategyExt.java deleted file mode 100644 index 3c563aded37..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestHystrixPropertiesStrategyExt.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import static org.junit.Assert.assertNotNull; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixCommandProperties; - -/** - * - */ -public class TestHystrixPropertiesStrategyExt { - - @Test - public void testGetCommandPropertiesCacheKey() { - - assertNotNull(HystrixPropertiesStrategyExt.getInstance()); - - HystrixPropertiesStrategyExt hps = HystrixPropertiesStrategyExt.getInstance(); - HystrixCommandKey commandKey = Mockito.mock(HystrixCommandKey.class); - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceName()).thenReturn("testqualify"); - - HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() - .withRequestCacheEnabled(true) - .withRequestLogEnabled(false) - .withFallbackIsolationSemaphoreMaxConcurrentRequests( - Configuration.INSTANCE.getFallbackMaxConcurrentRequests("groupname", - "testing", - invocation.getOperationMeta().getMicroserviceQualifiedName())); - - String str1 = hps.getCommandPropertiesCacheKey(commandKey, setter); - Assert.assertNull(str1); - } - - @Test - public void testgetCommandProperties() { - HystrixCommandKey commandKey = Mockito.mock(HystrixCommandKey.class); - Mockito.when(commandKey.name()) - .thenReturn("provider.HystrixPropertiesStrategyExtTest.testgetCommandProperties"); - HystrixCommandProperties commandPro = HystrixPropertiesStrategyExt.getInstance() - .getCommandProperties(commandKey, HystrixCommandProperties.Setter()); - Assert.assertTrue(commandPro.circuitBreakerEnabled().get()); - Assert.assertEquals(Integer.valueOf(50), commandPro.circuitBreakerErrorThresholdPercentage().get()); - Assert.assertFalse(commandPro.circuitBreakerForceClosed().get()); - Assert.assertFalse(commandPro.circuitBreakerForceOpen().get()); - Assert.assertEquals(Integer.valueOf(20), commandPro.circuitBreakerRequestVolumeThreshold().get()); - Assert.assertEquals(Integer.valueOf(15000), commandPro.circuitBreakerSleepWindowInMilliseconds().get()); - Assert.assertEquals(Integer.valueOf(1000), commandPro.executionIsolationSemaphoreMaxConcurrentRequests().get()); - Assert.assertTrue(commandPro.executionIsolationThreadInterruptOnTimeout().get()); - Assert.assertEquals(null, commandPro.executionIsolationThreadPoolKeyOverride().get()); - Assert.assertEquals(Integer.valueOf(30000), commandPro.executionTimeoutInMilliseconds().get()); - Assert.assertFalse(commandPro.executionTimeoutEnabled().get()); - Assert.assertEquals(Integer.valueOf(10), commandPro.fallbackIsolationSemaphoreMaxConcurrentRequests().get()); - Assert.assertTrue(commandPro.fallbackEnabled().get()); - Assert.assertEquals(Integer.valueOf(100), commandPro.metricsRollingPercentileBucketSize().get()); - Assert.assertFalse(commandPro.metricsRollingPercentileEnabled().get()); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java deleted file mode 100644 index 467993aad0e..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/TestProviderBizkeeperHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.hystrix.strategy.HystrixPlugins; - -/** - * - * - */ -public class TestProviderBizkeeperHandler { - - @Test - public void testCreateBizkeeperCommand() { - HystrixPlugins.reset(); - ProviderBizkeeperHanlder providerBizkeeperHanlder = new ProviderBizkeeperHanlder(); - - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); - Mockito.when(invocation.getOperationMeta().getMicroserviceQualifiedName()).thenReturn("test1"); - - CommandKey.toHystrixCommandGroupKey("groupname", invocation); - CommandKey.toHystrixCommandKey("groupname", invocation); - BizkeeperCommand command = providerBizkeeperHanlder.createBizkeeperCommand(invocation); - Assert.assertNotNull(command); - } -} diff --git a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java b/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java deleted file mode 100644 index 3f58ca75c9a..00000000000 --- a/handlers/handler-bizkeeper/src/test/java/org/apache/servicecomb/bizkeeper/event/TestCircutBreakerEventNotifier.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.bizkeeper.event; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.foundation.common.event.AlarmEvent; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.google.common.eventbus.Subscribe; -import com.netflix.hystrix.HystrixCommandKey; -import com.netflix.hystrix.HystrixCommandMetrics; -import com.netflix.hystrix.HystrixEventType; - -import mockit.Expectations; - -public class TestCircutBreakerEventNotifier { - private List taskList = null; - - CircutBreakerEventNotifier circutBreakerEventNotifier; - - HystrixCommandKey commandKey = null; - - Object receiveEvent = null; - - @Before - public void setUp() throws Exception { - taskList = new ArrayList<>(); - circutBreakerEventNotifier = new CircutBreakerEventNotifier(); - commandKey = Mockito.mock(HystrixCommandKey.class); - receiveEvent = new Object() { - @Subscribe - public void onEvent(AlarmEvent circutBreakerEvent) { - taskList.add(circutBreakerEvent); - } - }; - circutBreakerEventNotifier.eventBus.register(receiveEvent); - } - - @After - public void tearDown() throws Exception { - circutBreakerEventNotifier.eventBus.unregister(receiveEvent); - } - - @Test - public void testMarkEvent() { - Mockito.when(commandKey.name()).thenReturn("Consumer.springmvc.springmvcHello.sayHi"); - new Expectations(HystrixCommandMetrics.class) { - { - HystrixCommandMetrics.getInstance(commandKey); - result = null; - } - }; - circutBreakerEventNotifier.markEvent(HystrixEventType.SHORT_CIRCUITED, commandKey); - Assert.assertEquals(1, taskList.size()); - circutBreakerEventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey); - Assert.assertEquals(2, taskList.size()); - } -} diff --git a/handlers/handler-bizkeeper/src/test/resources/log4j.properties b/handlers/handler-bizkeeper/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/handlers/handler-bizkeeper/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/handlers/handler-fault-injection/pom.xml b/handlers/handler-fault-injection/pom.xml index 83bb552065d..825c63c2270 100755 --- a/handlers/handler-fault-injection/pom.xml +++ b/handlers/handler-fault-injection/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb handlers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT handler-fault-injection Java Chassis::Handlers::Fault Injection @@ -38,13 +38,13 @@ - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java deleted file mode 100644 index 26044606d42..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AbortFault extends AbstractFault { - - private static final Logger LOGGER = LoggerFactory.getLogger(AbortFault.class); - - public static final String ABORTED_ERROR_MSG = "aborted by fault inject"; - - @Override - public void injectFault(Invocation invocation, FaultParam faultParam, AsyncResponse asyncResponse) { - if (!shouldAbort(invocation, faultParam)) { - asyncResponse.success(SUCCESS_RESPONSE); - return; - } - - // get the config values related to abort percentage. - int errorCode = FaultInjectionUtil.getFaultInjectionConfig(invocation, "abort.httpStatus"); - if (errorCode == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { - LOGGER.debug("Fault injection: Abort error code is not configured"); - asyncResponse.success(SUCCESS_RESPONSE); - return; - } - - // if request need to be abort then return failure with given error code - CommonExceptionData errorData = new CommonExceptionData(ABORTED_ERROR_MSG); - asyncResponse.consumerFail(new InvocationException(errorCode, ABORTED_ERROR_MSG, errorData)); - } - - private boolean shouldAbort(Invocation invocation, FaultParam faultParam) { - // get the config values related to abort. - int abortPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation, "abort.percent"); - if (abortPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { - LOGGER.debug("Fault injection: Abort percentage is not configured"); - return false; - } - - // check fault abort condition. - return FaultInjectionUtil.isFaultNeedToInject(faultParam.getReqCount(), abortPercent); - } - - @Override - public int getOrder() { - return 200; - } -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java deleted file mode 100644 index e92a68ef560..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -public abstract class AbstractFault implements Fault { - -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerAbortFaultFilter.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerAbortFaultFilter.java new file mode 100644 index 00000000000..e4eef91ef2f --- /dev/null +++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerAbortFaultFilter.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.faultinjection; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConsumerAbortFaultFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerAbortFaultFilter.class); + + private static final String SUCCESS_RESPONSE = "success"; + + public static final String ABORTED_ERROR_MSG = "aborted by fault inject"; + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1020; + } + + @Override + public String getName() { + return "consumer-abort-fault"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (!shouldAbort(invocation)) { + return nextNode.onFilter(invocation); + } + + // get the config values related to abort percentage. + int errorCode = FaultInjectionUtil.getFaultInjectionConfig(invocation, "abort.httpStatus"); + if (errorCode == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: Abort error code is not configured"); + return CompletableFuture.completedFuture(Response.succResp(SUCCESS_RESPONSE)); + } + + // if request need to be abort then return failure with given error code + CommonExceptionData errorData = new CommonExceptionData(ABORTED_ERROR_MSG); + return CompletableFuture.failedFuture(new InvocationException(errorCode, ABORTED_ERROR_MSG, errorData)); + } + + private boolean shouldAbort(Invocation invocation) { + // get the config values related to abort. + int abortPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation, "abort.percent"); + if (abortPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: Abort percentage is not configured"); + return false; + } + + // check fault abort condition. + return FaultInjectionUtil.isFaultNeedToInject(abortPercent); + } +} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerDelayFaultFilter.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerDelayFaultFilter.java new file mode 100644 index 00000000000..e8c0f6ffd67 --- /dev/null +++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/ConsumerDelayFaultFilter.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.faultinjection; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.Context; +import io.vertx.core.Vertx; + +public class ConsumerDelayFaultFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerDelayFaultFilter.class); + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1030; + } + + @Override + public String getName() { + return "consumer-delay-fault"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (!shouldDelay(invocation)) { + return nextNode.onFilter(invocation); + } + + LOGGER.debug("Fault injection: delay is added for the request by fault inject handler"); + long delay = FaultInjectionUtil.getFaultInjectionConfig(invocation, + "delay.fixedDelay"); + if (delay == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: delay is not configured"); + return nextNode.onFilter(invocation); + } + + return executeDelay(invocation, nextNode, delay); + } + + private CompletableFuture executeDelay(Invocation invocation, FilterNode nextNode, + long delay) { + Context currentContext = Vertx.currentContext(); + if (currentContext != null && currentContext.isEventLoopContext()) { + CompletableFuture result = new CompletableFuture<>(); + currentContext.owner().setTimer(delay, timeID -> nextNode.onFilter(invocation).whenComplete((r, e) -> { + if (e == null) { + result.complete(r); + } else { + result.completeExceptionally(e); + } + } + )); + return result; + } + + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + LOGGER.info("Interrupted exception is received"); + } + return nextNode.onFilter(invocation); + } + + private boolean shouldDelay(Invocation invocation) { + int delayPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation, + "delay.percent"); + if (delayPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { + LOGGER.debug("Fault injection: delay percentage is not configured"); + return false; + } + + // check fault delay condition. + return FaultInjectionUtil.isFaultNeedToInject(delayPercent); + } +} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java deleted file mode 100644 index 38318d2deb5..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.Vertx; - -public class DelayFault extends AbstractFault { - private static final Logger LOGGER = LoggerFactory.getLogger(DelayFault.class); - - @Override - public int getOrder() { - return 100; - } - - @Override - public void injectFault(Invocation invocation, FaultParam faultParam, AsyncResponse asynResponse) { - if (!shouldDelay(invocation, faultParam, asynResponse)) { - asynResponse.success(SUCCESS_RESPONSE); - return; - } - - LOGGER.debug("Fault injection: delay is added for the request by fault inject handler"); - long delay = FaultInjectionUtil.getFaultInjectionConfig(invocation, - "delay.fixedDelay"); - if (delay == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { - LOGGER.debug("Fault injection: delay is not configured"); - asynResponse.success(SUCCESS_RESPONSE); - return; - } - - executeDelay(faultParam, asynResponse, delay); - } - - private void executeDelay(FaultParam faultParam, AsyncResponse asynResponse, long delay) { - Vertx vertx = faultParam.getVertx(); - if (vertx != null) { - vertx.setTimer(delay, timeID -> asynResponse.success(SUCCESS_RESPONSE)); - return; - } - - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - LOGGER.info("Interrupted exception is received"); - } - asynResponse.success(SUCCESS_RESPONSE); - } - - private boolean shouldDelay(Invocation invocation, FaultParam faultParam, AsyncResponse asynResponse) { - int delayPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation, - "delay.percent"); - if (delayPercent == FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE) { - LOGGER.debug("Fault injection: delay percentage is not configured"); - return false; - } - - // check fault delay condition. - return FaultInjectionUtil.isFaultNeedToInject(faultParam.getReqCount(), delayPercent); - } -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java deleted file mode 100644 index a3f254537cf..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; - -public interface Fault { - - String SUCCESS_RESPONSE = "success"; - - int getOrder(); - - void injectFault(Invocation invocation, FaultParam faultAttributes, AsyncResponse asynResponse); -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultExecutor.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultExecutor.java deleted file mode 100644 index 9a20f64c949..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultExecutor.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import java.util.List; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; - - -/** - * Implements the fault feature execution one after other. - */ -public class FaultExecutor { - private List faultInjectList; - - private int handlerIndex = 0; - - private Invocation invocation; - - private FaultParam param; - - public FaultExecutor(List faultInjectList, Invocation invocation, FaultParam param) { - this.faultInjectList = faultInjectList; - this.invocation = invocation; - this.param = param; - } - - public void execute(AsyncResponse asyncResponse) { - this.next(asyncResponse); - } - - private void next(AsyncResponse asyncResponse) { - if (handlerIndex >= faultInjectList.size()) { - asyncResponse.complete(Response.succResp("success")); - return; - } - - int runIndex = handlerIndex; - handlerIndex++; - faultInjectList.get(runIndex).injectFault(invocation, param, response -> { - if (response.isFailed()) { - asyncResponse.complete(response); - } else { - FaultExecutor.this.next(asyncResponse); - } - }); - } -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java deleted file mode 100755 index d43eb2f385a..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; - -/** - * Handles the fault injection configuration read from micro service file/config - * center. - */ -public final class FaultInjectionConfig { - - private static final Logger LOGGER = LoggerFactory.getLogger(FaultInjectionConfig.class); - - // key is configuration parameter. - private static Map cfgCallback = new ConcurrentHashMapEx<>(); - - public static int getConfigVal(String config, int defaultValue) { - DynamicIntProperty dynamicIntProperty = DynamicPropertyFactory.getInstance().getIntProperty(config, - defaultValue); - - cfgCallback.computeIfAbsent(config, key -> { - dynamicIntProperty.addCallback(() -> { - int newValue = dynamicIntProperty.get(); - String cfgName = dynamicIntProperty.getName(); - - //store the value in config center map and check for next requests. - FaultInjectionUtil.setConfigCenterValue(cfgName, new AtomicInteger(newValue)); - LOGGER.info("{} changed to {}", cfgName, newValue); - }); - return config; - }); - - return dynamicIntProperty.get(); - } -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfiguration.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfiguration.java new file mode 100644 index 00000000000..600ed5dc9f6 --- /dev/null +++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfiguration.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.faultinjection; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = FaultInjectionConfiguration.FAULT_INJECTION_ENABLED, + havingValue = "true") +public class FaultInjectionConfiguration { + public static final String FAULT_INJECTION_PREFIX = "servicecomb.faultInjection"; + + public static final String FAULT_INJECTION_ENABLED = FAULT_INJECTION_PREFIX + ".enabled"; + + @Bean + public ConsumerAbortFaultFilter scbConsumerAbortFaultFilter() { + return new ConsumerAbortFaultFilter(); + } + + @Bean + public ConsumerDelayFaultFilter scbConsumerDelayFaultFilter() { + return new ConsumerDelayFaultFilter(); + } +} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java deleted file mode 100755 index 8c292461346..00000000000 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; - -import io.vertx.core.Context; -import io.vertx.core.Vertx; - -/** - * Fault injection handler which injects the delay/abort for requests based on - * the percentage configured in service file. - * - */ - -public class FaultInjectionHandler implements Handler { - - private List faultInjectionFeatureList = SPIServiceUtils.getSortedService(Fault.class); - - //added only for unit testing - public void setFaultFeature(List faultFeature) { - faultInjectionFeatureList = faultFeature; - } - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - - // prepare the key and lookup for request count. - String key = invocation.getTransport().getName() + invocation.getMicroserviceQualifiedName(); - AtomicLong reqCount = FaultInjectionUtil.getOperMetTotalReq(key); - // increment the request count here after checking the delay/abort condition. - long reqCountCurrent = reqCount.getAndIncrement(); - - FaultParam param = new FaultParam(reqCountCurrent); - Context currentContext = Vertx.currentContext(); - if (currentContext != null && currentContext.isEventLoopContext()) { - param.setVertx(currentContext.owner()); - } - - FaultExecutor executor = new FaultExecutor(faultInjectionFeatureList, invocation, param); - executor.execute(response -> { - try { - if (response.isFailed()) { - asyncResp.complete(response); - } else { - invocation.next(asyncResp); - } - } catch (Exception e) { - asyncResp.consumerFail(e); - } - }); - } -} diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java index 57d77289b93..67c3ab86939 100755 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java +++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java @@ -23,34 +23,25 @@ import static org.apache.servicecomb.faultinjection.FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE; import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import com.google.common.annotations.VisibleForTesting; + /** * Handles the count for all request based key[transport + microservice qualified name]. */ public class FaultInjectionUtil { - - // key is transport+operQualifiedName - private static Map requestCount = new ConcurrentHashMapEx<>(); - - // key is config paramter - private static Map configCenterValue = new ConcurrentHashMapEx<>(); - - /** - * Returns total requests per provider for operational level. - * - * @param key - * transport+operational name - * @return long total requests - */ - public static AtomicLong getOperMetTotalReq(String key) { - return requestCount.computeIfAbsent(key, p -> new AtomicLong(1)); + private FaultInjectionUtil() { } + // key is config parameter + private static final Map configCenterValue = new ConcurrentHashMapEx<>(); + /** * Returns the map of config parameter key and values. * @return value of config parameter map @@ -130,34 +121,24 @@ private static int getConfigValue(String config) { return cfgMap.get(config).get(); } - value = FaultInjectionConfig.getConfigVal(config, FAULT_INJECTION_DEFAULT_VALUE); + value = LegacyPropertyFactory.getIntProperty(config, FAULT_INJECTION_DEFAULT_VALUE); return value; } /** - * It will check the delay/abort condition based on request count and percentage - * received. + * It will check the delay/abort condition based on percentage. * - * @param reqCount - * @param percentage * @return true: delay/abort is needed. false: delay/abort is not needed. */ - public static boolean isFaultNeedToInject(long reqCount, int percentage) { - /* - * Example: delay/abort percentage configured is 10% and Get the count(suppose - * if it is 10th request) from map and calculate resultNew(10th request) and - * requestOld(9th request). Like this for every request it will calculate - * current request count and previous count. if both not matched need to add - * delay/abort otherwise no need to add. - */ - - // calculate the value with current request count. - long resultNew = (reqCount * percentage) / 100; - - // calculate the value with previous count value. - long resultOld = ((reqCount - 1) * percentage) / 100; - - // if both are not matching then delay/abort should be added. - return (resultNew != resultOld); + public static boolean isFaultNeedToInject(int percentage) { + if (percentage > 0) { + return ThreadLocalRandom.current().nextInt(100) < percentage; + } + return false; + } + + @VisibleForTesting + static Map getConfigCenterValue() { + return configCenterValue; } } diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java index 92f0e84ebeb..23530f13f58 100644 --- a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java +++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java @@ -23,20 +23,10 @@ * Fault injection parameters which decides the fault injection condition. */ public class FaultParam { - private long reqCount; - private Vertx vertx; - public long getReqCount() { - return reqCount; - } - - public void setReqCount(long reqCount) { - this.reqCount = reqCount; - } + FaultParam() { - FaultParam(long reqCount) { - this.reqCount = reqCount; } public Vertx getVertx() { diff --git a/handlers/handler-fault-injection/src/main/resources/META-INF/services/org.apache.servicecomb.faultinjection.Fault b/handlers/handler-fault-injection/src/main/resources/META-INF/services/org.apache.servicecomb.faultinjection.Fault deleted file mode 100644 index 1da13d5db6a..00000000000 --- a/handlers/handler-fault-injection/src/main/resources/META-INF/services/org.apache.servicecomb.faultinjection.Fault +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.faultinjection.DelayFault -org.apache.servicecomb.faultinjection.AbortFault diff --git a/handlers/handler-fault-injection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-fault-injection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..b58acc214f3 --- /dev/null +++ b/handlers/handler-fault-injection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.faultinjection.FaultInjectionConfiguration diff --git a/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml b/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml deleted file mode 100755 index 3ceed7a6714..00000000000 --- a/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/AbortFaultTest.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/AbortFaultTest.java deleted file mode 100644 index da606e0677a..00000000000 --- a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/AbortFaultTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.DynamicProperty; - -import io.vertx.core.Vertx; -import mockit.Deencapsulation; - -public class AbortFaultTest { - private Invocation invocation; - - @SuppressWarnings("unchecked") - @Before - public void before() { - ArchaiusUtils.resetConfig(); - ((Map) Deencapsulation.getField(FaultInjectionConfig.class, "cfgCallback")).clear(); - ((Map) Deencapsulation.getField(FaultInjectionUtil.class, "requestCount")).clear(); - ((Map) Deencapsulation.getField(FaultInjectionUtil.class, "configCenterValue")).clear(); - - invocation = Mockito.mock(Invocation.class); - Transport transport = Mockito.mock(Transport.class); - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName12"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts6"); - } - - @After - public void after() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - VertxUtils.closeVertxByName("faultinjectionTest"); - } - - @Test - public void injectFaultError() { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", "421"); - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", "100"); - - assertEquals("421", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus") - .getString()); - assertEquals("100", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent") - .getString()); - - AbortFault abortFault = new AbortFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - abortFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals(421, resultHolder.value.getStatusCode()); - assertEquals("aborted by fault inject", resultHolder.value.getReasonPhrase()); - assertEquals("CommonExceptionData [message=aborted by fault inject]", resultHolder.value.getErrorData().toString()); - } - - @Test - public void injectFaultNoError() { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", "421"); - ArchaiusUtils.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", "0"); - - assertEquals("421", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus") - .getString()); - assertEquals("0", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent") - .getString()); - - AbortFault abortFault = new AbortFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - abortFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultNoPercentageConfig() { - ArchaiusUtils - .updateProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", null); - - assertNull(DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent") - .getString()); - - AbortFault abortFault = new AbortFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - abortFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultNoErrorCodeConfig() { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", "10"); - - assertEquals("10", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent") - .getString()); - - AbortFault abortFault = new AbortFault(); - FaultParam faultParam = new FaultParam(10); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - abortFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } -} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/DelayFaultTest.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/DelayFaultTest.java deleted file mode 100644 index 7b5452d296f..00000000000 --- a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/DelayFaultTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.DynamicProperty; - -import io.vertx.core.Vertx; -import mockit.Deencapsulation; - -public class DelayFaultTest { - private Invocation invocation; - - @SuppressWarnings("unchecked") - @Before - public void before() { - ArchaiusUtils.resetConfig(); - ((Map) Deencapsulation.getField(FaultInjectionConfig.class, "cfgCallback")).clear(); - ((Map) Deencapsulation.getField(FaultInjectionUtil.class, "requestCount")).clear(); - ((Map) Deencapsulation.getField(FaultInjectionUtil.class, "configCenterValue")).clear(); - - invocation = Mockito.mock(Invocation.class); - Transport transport = Mockito.mock(Transport.class); - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName12"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts6"); - } - - @After - public void after() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - VertxUtils.closeVertxByName("faultinjectionTest"); - } - - @Test - public void injectFaultVertxDelay() throws InterruptedException { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", "10"); - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "100"); - - assertEquals("10", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay") - .getString()); - assertEquals("100", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent") - .getString()); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - CountDownLatch latch = new CountDownLatch(1); - delayFault.injectFault(invocation, faultParam, response -> { - resultHolder.value = response.getResult(); - latch.countDown(); - }); - - latch.await(10, TimeUnit.SECONDS); - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultSystemDelay() throws InterruptedException { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", "10"); - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "100"); - - assertEquals("10", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay") - .getString()); - assertEquals("100", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent") - .getString()); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(1); - - Holder resultHolder = new Holder<>(); - CountDownLatch latch = new CountDownLatch(1); - delayFault.injectFault(invocation, faultParam, response -> { - resultHolder.value = response.getResult(); - latch.countDown(); - }); - - latch.await(10, TimeUnit.SECONDS); - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultNotDelay() throws InterruptedException { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", "10"); - ArchaiusUtils.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "0"); - - assertEquals("10", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay") - .getString()); - assertEquals("0", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent") - .getString()); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - CountDownLatch latch = new CountDownLatch(1); - delayFault.injectFault(invocation, faultParam, response -> { - resultHolder.value = response.getResult(); - latch.countDown(); - }); - - latch.await(3, TimeUnit.SECONDS); - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultNoPercentageConfig() { - ArchaiusUtils - .updateProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", null); - - assertNull(DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent") - .getString()); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(1); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - delayFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } - - @Test - public void injectFaultNoDelayMsConfig() { - ArchaiusUtils - .setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "10"); - - assertEquals("10", DynamicProperty - .getInstance("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent") - .getString()); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(10); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - Holder resultHolder = new Holder<>(); - delayFault.injectFault(invocation, faultParam, response -> resultHolder.value = response.getResult()); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - assertEquals("success", resultHolder.value); - } -} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerAbortFaultFilter.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerAbortFaultFilter.java new file mode 100644 index 00000000000..d44fd849b2f --- /dev/null +++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerAbortFaultFilter.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.faultinjection; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestConsumerAbortFaultFilter { + private Invocation invocation; + + private Environment environment; + + @BeforeEach + public void before() { + environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4.operations.sayBye4" + + ".policy.fault.protocols.rest.abort.percent", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4.operations.sayBye4" + + ".policy.fault.protocols.rest.abort.httpStatus", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4" + + ".policy.fault.protocols.rest.abort.percent", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4" + + ".policy.fault.protocols.rest.abort.httpStatus", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6" + + ".policy.fault.protocols.rest.abort.percent", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6" + + ".policy.fault.protocols.rest.abort.httpStatus", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.abort.percent", + int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.abort.httpStatus", + int.class, -1)) + .thenReturn(-1); + + FaultInjectionUtil.getConfigCenterValue().clear(); + + invocation = Mockito.mock(Invocation.class); + Transport transport = Mockito.mock(Transport.class); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName12"); + Mockito.when(invocation.getTransport()).thenReturn(transport); + Mockito.when(transport.getName()).thenReturn("rest"); + Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); + Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); + Mockito.when(invocation.getMicroserviceName()).thenReturn("carts6"); + } + + @AfterEach + public void after() { + } + + @AfterAll + public static void classTeardown() { + VertxUtils.blockCloseVertxByName("faultinjectionTest"); + } + + @Test + public void injectFaultError() { + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.abort.httpStatus", + int.class, -1)) + .thenReturn(421); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.abort.percent", + int.class, -1)) + .thenReturn(100); + + ConsumerAbortFaultFilter abortFault = new ConsumerAbortFaultFilter(); + + FilterNode filterNode = Mockito.mock(FilterNode.class); + + Holder resultHolder = new Holder<>(); + CompletableFuture result = abortFault.onFilter(invocation, filterNode); + result.whenComplete((r, e) -> { + if (e != null) { + resultHolder.value = (InvocationException) e; + } + }); + Assertions.assertThrows(ExecutionException.class, () -> result.get()); + Assertions.assertEquals(421, resultHolder.value.getStatusCode()); + Assertions.assertEquals("aborted by fault inject", resultHolder.value.getReasonPhrase()); + Assertions.assertEquals("CommonExceptionData [message=aborted by fault inject]", + resultHolder.value.getErrorData().toString()); + } + + @Test + public void injectFaultNoError() throws Exception { + ConsumerAbortFaultFilter abortFault = new ConsumerAbortFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = abortFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultNoPercentageConfig() throws Exception { + ConsumerAbortFaultFilter abortFault = new ConsumerAbortFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = abortFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultNoErrorCodeConfig() throws Exception { + ConsumerAbortFaultFilter abortFault = new ConsumerAbortFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = abortFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } +} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerDelayFaultFilter.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerDelayFaultFilter.java new file mode 100644 index 00000000000..381d3d01447 --- /dev/null +++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestConsumerDelayFaultFilter.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.faultinjection; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestConsumerDelayFaultFilter { + private Invocation invocation; + + private Environment environment; + + @BeforeEach + public void before() { + environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4.operations.sayBye4" + + ".policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4.operations.sayBye4" + + ".policy.fault.protocols.rest.delay.percent", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4" + + ".policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6.schemas.testSchema4" + + ".policy.fault.protocols.rest.delay.percent", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6" + + ".policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer.carts6" + + ".policy.fault.protocols.rest.delay.percent", + int.class, -1)).thenReturn(-1); + + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty( + "servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.delay.percent", + int.class, -1)) + .thenReturn(-1); + + FaultInjectionUtil.getConfigCenterValue().clear(); + + invocation = Mockito.mock(Invocation.class); + Transport transport = Mockito.mock(Transport.class); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName12"); + Mockito.when(invocation.getTransport()).thenReturn(transport); + Mockito.when(transport.getName()).thenReturn("rest"); + Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); + Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); + Mockito.when(invocation.getMicroserviceName()).thenReturn("carts6"); + } + + @AfterEach + public void after() { + } + + @AfterAll + public static void classTeardown() { + VertxUtils.blockCloseVertxByName("faultinjectionTest"); + } + + @Test + public void injectFaultVertxDelay() throws Exception { + Mockito.when(environment.getProperty("servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)) + .thenReturn(10); + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global" + + ".policy.fault.protocols.rest.delay.percent", + int.class, -1)) + .thenReturn(100); + + ConsumerDelayFaultFilter delayFault = new ConsumerDelayFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = delayFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultSystemDelay() throws Exception { + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)) + .thenReturn(10); + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", + int.class, -1)) + .thenReturn(100); + + ConsumerDelayFaultFilter delayFault = new ConsumerDelayFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = delayFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultNotDelay() throws Exception { + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", + int.class, -1)) + .thenReturn(10); + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", + int.class, -1)) + .thenReturn(0); + + ConsumerDelayFaultFilter delayFault = new ConsumerDelayFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = delayFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultNoPercentageConfig() throws Exception { + ConsumerDelayFaultFilter delayFault = new ConsumerDelayFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = delayFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } + + @Test + public void injectFaultNoDelayMsConfig() throws Exception { + Mockito.when( + environment.getProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", + int.class, -1)) + .thenReturn(10); + + ConsumerDelayFaultFilter delayFault = new ConsumerDelayFaultFilter(); + FilterNode filterNode = Mockito.mock(FilterNode.class); + Mockito.when(filterNode.onFilter(invocation)) + .thenReturn(CompletableFuture.completedFuture(Response.succResp("success"))); + CompletableFuture result = delayFault.onFilter(invocation, filterNode); + Assertions.assertEquals("success", result.get().getResult()); + } +} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java deleted file mode 100644 index 4d753810cb4..00000000000 --- a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import static org.junit.Assert.assertEquals; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests the fault injection configuration. - */ -public class TestFaultInjectConfig { - FaultInjectionConfig faultCfg; - - FaultInjectionConst faultConst; - - FaultInjectionUtil faultUtil; - - FaultParam faultParam; - - AbortFault abortFault; - - DelayFault delayFault; - - @Before - public void setUp() throws Exception { - faultCfg = new FaultInjectionConfig(); - faultConst = new FaultInjectionConst(); - faultUtil = new FaultInjectionUtil(); - faultParam = new FaultParam(10); - abortFault = new AbortFault(); - delayFault = new DelayFault(); - } - - @After - public void tearDown() throws Exception { - faultCfg = null; - faultConst = null; - faultUtil = null; - faultParam = null; - } - - @Test - public void testFaultInjectConfig() throws Exception { - int val = FaultInjectionConfig.getConfigVal("servicecomb.servicecomb.handler.consumer.faultinject.config", 0); - Assert.assertEquals(0, val); - } - - @Test - public void testConstants() { - assertEquals("servicecomb.governance.Consumer.", FaultInjectionConst.CONSUMER_FAULTINJECTION); - assertEquals("policy.fault.protocols.", FaultInjectionConst.CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS); - assertEquals(-1, FaultInjectionConst.FAULT_INJECTION_DEFAULT_VALUE); - assertEquals("servicecomb.governance.Consumer._global.", FaultInjectionConst.CONSUMER_FAULTINJECTION_GLOBAL); - assertEquals(-1, FaultInjectionConst.FAULT_INJECTION_ERROR); - } - - @Test - public void testFaultParam() { - faultParam.setReqCount(100); - faultParam.setVertx(null); - assertEquals(100, faultParam.getReqCount()); - assertEquals(null, faultParam.getVertx()); - } - - @Test - public void testFaultPriority() { - assertEquals(200, abortFault.getOrder()); - assertEquals(100, delayFault.getOrder()); - } -} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java deleted file mode 100644 index bc5585c7c64..00000000000 --- a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java +++ /dev/null @@ -1,706 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.faultinjection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import io.vertx.core.Vertx; - -/** - * Tests the fault injection handler functionality. - */ -public class TestFaultInjectHandler { - FaultInjectionHandler handler; - - Invocation invocation; - - AsyncResponse asyncResp; - - OperationMeta operationMeta; - - private Transport transport; - - Response response; - - boolean isDelay; - - boolean isAbort; - - @InjectMocks - AbortFault abortFault; - - @InjectMocks - DelayFault delayFault; - - AsyncResponse ar = new AsyncResponse() { - @Override - public void handle(Response resp) { - response = resp; - } - }; - - @Before - public void setUp() { - ArchaiusUtils.resetConfig(); - handler = new FaultInjectionHandler(); - invocation = Mockito.mock(Invocation.class); - asyncResp = Mockito.mock(AsyncResponse.class); - operationMeta = Mockito.mock(OperationMeta.class); - transport = Mockito.mock(Transport.class); - MockitoAnnotations.initMocks(this); - } - - @After - public void tearDown() { - handler = null; - invocation = null; - asyncResp = null; - operationMeta = null; - transport = null; - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - VertxUtils.closeVertxByName("faultinjectionTest"); - } - - /** - * Tests the fault injection handler functionality with default values for - * highway transport. - */ - @Test - public void testFaultInjectHandlerHighwayWithDefaultCfg() throws Exception { - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName1"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("highway"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello"); - Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("hello"); - - List faultInjectionFeatureList = Arrays.asList(abortFault, delayFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, asyncResp); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("highwayMicroserviceQualifiedName1"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with default values for rest - * transport. - */ - @Test - public void testFaultInjectHandlerRestWithDefaultCfg() throws Exception { - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName2"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello"); - Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("hello"); - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, asyncResp); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName2"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with global configuration - * with delay/abort condition. - */ - @Test - public void testFaultInjectHandlerConfigChangeGlobal() throws Exception { - - System.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", "5"); - System.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "10"); - System.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", "10"); - System.setProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName3"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello"); - Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("hello"); - - List faultInjectionFeatureList = Arrays.asList(abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, ar -> { - //this case no delay/no abort so reponse is null, it should not enter this in this block. - isDelay = true; - isAbort = true; - }); - Assert.assertFalse(isDelay); - Assert.assertFalse(isAbort); - - System.getProperties() - .remove("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties().remove("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent"); - System.getProperties().remove("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName3"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with service level configuration - * with delay/abort condition. - */ - @Test - public void testFaultInjectHandlerServiceCfgSuccess() throws Exception { - - System.setProperty("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.delay.fixedDelay", "1"); - System.setProperty("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.delay.percent", "10"); - System.setProperty("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.abort.percent", "10"); - System.setProperty("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.abort.httpStatus", "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName4"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello"); - Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts"); - - List faultInjectionFeatureList = Arrays.asList(abortFault, delayFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, ar -> { - //this case no delay/no abort so reponse is null, it should not enter this in this block. - isDelay = true; - isAbort = true; - }); - Assert.assertFalse(isDelay); - Assert.assertFalse(isAbort); - - System.getProperties().remove("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties().remove("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.delay.percent"); - System.getProperties().remove("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.abort.percent"); - System.getProperties().remove("servicecomb.governance.Consumer.carts.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName4"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with schema level configuration - * with delay/abort condition. - */ - @Test - public void testFaultInjectHandlerSchemaCfgSuccess() throws Exception { - - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.fixedDelay", - "1"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.percent", - "10"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.percent", - "10"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.httpStatus", - "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName5"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHello"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts"); - - List faultInjectionFeatureList = Arrays.asList(abortFault, delayFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, ar -> { - //this case no delay/no abort so reponse is null, it should not enter this in this block. - isDelay = true; - isAbort = true; - }); - Assert.assertFalse(isDelay); - Assert.assertFalse(isAbort); - - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName5"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with operation level configuration - * with delay/abort condition. - */ - @Test - public void testFaultInjectHandlerOperationCfgSuccess() throws Exception { - - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.fixedDelay", - "1"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.percent", - "10"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.percent", - "10"); - System.setProperty( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.httpStatus", - "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName6"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayHi"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts"); - - List faultInjectionFeatureList = Arrays.asList(abortFault, delayFault); - handler.setFaultFeature(faultInjectionFeatureList); - - handler.handle(invocation, ar -> { - //this case no delay/no abort so reponse is null, it should not enter this in this block. - isDelay = true; - isAbort = true; - }); - - Assert.assertFalse(isDelay); - Assert.assertFalse(isAbort); - - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName6"); - assertEquals(2, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for global level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent1() throws Exception { - - System.setProperty( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", - "1"); - System.setProperty( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", - "420"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName7"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye1"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema1"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts1"); - boolean validAssert; - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - try { - validAssert = true; - handler.handle(invocation, ar); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - TestFaultInjectUtil - .updateProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", 500); - TestFaultInjectUtil - .updateProperty("servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", 421); - - Holder isAsserted = new Holder<>(false); - handler.handle(invocation, ar -> { - isAsserted.value = true; - assertTrue(response.isFailed()); - }); - Assert.assertTrue(isAsserted.value); - - System.getProperties() - .remove( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName7"); - assertEquals(3, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for operation level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent2() throws Exception { - - System.setProperty( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay", - "1"); - System.setProperty( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.httpStatus", - "420"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName8"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye2"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema2"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts2"); - boolean validAssert; - long timeOld = System.currentTimeMillis(); - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - try { - validAssert = true; - handler.handle(invocation, ar); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - TestFaultInjectUtil - .updateProperty( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay", - 500); - - Holder isAsserted = new Holder<>(false); - handler.handle(invocation, ar -> { - //check whether error code return - isAsserted.value = true; - assertEquals(420, response.getStatusCode()); - assertTrue(response.isFailed()); - long timeNow = System.currentTimeMillis(); - //if really time delay is added it should be greater than 5s. - Assert.assertTrue((timeNow - timeOld) >= 500); - }); - Assert.assertTrue(isAsserted.value); - - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName8"); - assertEquals(3, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for schema level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent3() throws Exception { - - System.setProperty( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay", - "1"); - System.setProperty( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.httpStatus", - "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName9"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye3"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema3"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts3"); - boolean validAssert; - long timeOld = System.currentTimeMillis(); - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - try { - validAssert = true; - handler.handle(invocation, ar); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - TestFaultInjectUtil - .updateProperty( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay", - 500); - - Holder isAsserted = new Holder<>(false); - handler.handle(invocation, ar -> { - //check whether error code return, defaut is 421. - isAsserted.value = true; - assertEquals(421, response.getStatusCode()); - assertTrue(response.isFailed()); - long timeNow = System.currentTimeMillis(); - //if really time delay is added it should be greater than 5s. - Assert.assertTrue((timeNow - timeOld) >= 500); - }); - Assert.assertTrue(isAsserted.value); - - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove( - "servicecomb.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName9"); - assertEquals(3, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for service level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent4() throws Exception { - System.setProperty("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay", "1"); - - System.setProperty( - "servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.delay.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.abort.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.abort.httpStatus", - "421"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName10"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts4"); - boolean validAssert; - long timeOld = System.currentTimeMillis(); - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - try { - validAssert = true; - handler.handle(invocation, ar); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - TestFaultInjectUtil - .updateProperty("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay", 500); - - Holder isAsserted = new Holder<>(false); - handler.handle(invocation, ar -> { - //check whether error code return, - isAsserted.value = true; - assertEquals(421, response.getStatusCode()); - assertTrue(response.isFailed()); - long timeNow = System.currentTimeMillis(); - //if really time delay is added it should be greater than 5s. - Assert.assertTrue((timeNow - timeOld) >= 500); - }); - Assert.assertTrue(isAsserted.value); - - System.getProperties() - .remove("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts4.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName10"); - assertEquals(3, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for service level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent5() throws Exception { - System.setProperty( - "servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.delay.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.delay.fixedDelay", - "10"); - System.setProperty( - "servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.abort.percent", - "100"); - System.setProperty( - "servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.abort.httpStatus", - "500"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName11"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts5"); - boolean validAssert; - - List faultInjectionFeatureList = Arrays.asList(delayFault, abortFault); - handler.setFaultFeature(faultInjectionFeatureList); - - try { - validAssert = true; - handler.handle(invocation, ar); - } catch (Exception e) { - validAssert = false; - } - Assert.assertTrue(validAssert); - TestFaultInjectUtil - .updateProperty("servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.abort.httpStatus", "420"); - - Holder isAsserted = new Holder<>(false); - handler.handle(invocation, ar -> { - isAsserted.value = true; - assertTrue(response.isFailed()); - assertEquals(500, response.getStatusCode()); - assertEquals(420, ar.getStatusCode()); - }); - Assert.assertTrue(isAsserted.value); - - System.getProperties() - .remove("servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.delay.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.abort.percent"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts5.policy.fault.protocols.rest.abort.httpStatus"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName11"); - assertEquals(3, count.get()); - } - - /** - * Tests the fault injection handler functionality with configuration change event for service level config. - */ - @Test - public void testFaultInjectHandlerConfigChangeEvent6() { - System.setProperty("servicecomb.governance.Consumer.carts6.policy.fault.protocols.rest.delay.fixedDelay", "1000"); - - System.setProperty( - "servicecomb.governance.Consumer.carts6.policy.fault.protocols.rest.delay.percent", - "100"); - - Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName12"); - Mockito.when(invocation.getTransport()).thenReturn(transport); - Mockito.when(transport.getName()).thenReturn("rest"); - Mockito.when(invocation.getOperationName()).thenReturn("sayBye4"); - Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("carts6"); - - DelayFault delayFault = new DelayFault(); - FaultParam faultParam = new FaultParam(3); - Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjectionTest", null); - faultParam.setVertx(vertx); - - delayFault.injectFault(invocation, faultParam, ar); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts6.policy.fault.protocols.rest.delay.fixedDelay"); - System.getProperties() - .remove("servicecomb.governance.Consumer.carts6.policy.fault.protocols.rest.delay.percent"); - - AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName12"); - assertEquals(1, count.get()); - } -} diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java index ec619a7d96a..451d7205eca 100644 --- a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java +++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java @@ -17,45 +17,19 @@ package org.apache.servicecomb.faultinjection; -import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.util.ReflectionUtils; - -import com.netflix.config.DynamicProperty; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * Tests the fault inject util functionality. */ public class TestFaultInjectUtil { - private static Method updatePropertyMethod = - ReflectionUtils.findMethod(DynamicProperty.class, "updateProperty", String.class, Object.class); - - static { - updatePropertyMethod.setAccessible(true); - } - - DelayFault delayFault = Mockito.mock(DelayFault.class); - - AbortFault abortFault = Mockito.mock(AbortFault.class); - - public static void updateProperty(String key, Object value) { - ReflectionUtils.invokeMethod(updatePropertyMethod, null, key, value); - } - @Test - public void testFaultInjectUtil() throws Exception { - AtomicLong count1 = FaultInjectionUtil.getOperMetTotalReq("test"); - Assert.assertEquals(1, count1.get()); - count1.incrementAndGet(); - AtomicLong count2 = FaultInjectionUtil.getOperMetTotalReq("test"); - Assert.assertEquals(2, count2.get()); + public void testFaultInjectUtil() { FaultInjectionUtil.setConfigCenterValue("sayHi", new AtomicInteger(123)); int value = FaultInjectionUtil.getConfigCenterMap().get("sayHi").get(); - Assert.assertEquals(123, value); + Assertions.assertEquals(123, value); } } diff --git a/handlers/handler-flowcontrol-qps/pom.xml b/handlers/handler-flowcontrol-qps/pom.xml index 8aa025681cd..eb5d63a0993 100644 --- a/handlers/handler-flowcontrol-qps/pom.xml +++ b/handlers/handler-flowcontrol-qps/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb handlers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT handler-flowcontrol-qps Java Chassis::Handlers::Flow Control QPS @@ -31,13 +31,13 @@ java-chassis-core - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/Config.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/Config.java index 2c6d69ab57a..8325352d726 100644 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/Config.java +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/Config.java @@ -17,14 +17,24 @@ package org.apache.servicecomb.qps; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicBooleanProperty; -import com.netflix.config.DynamicPropertyFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; public final class Config { - private static final Logger LOGGER = LoggerFactory.getLogger(Config.class); + public static final String CONFIG_PREFIX = "servicecomb.flowcontrol."; + + public static final String STRATEGY_KEY = "servicecomb.flowcontrol.strategy"; + + public static final String ANY_SERVICE = "ANY"; + + public static final String CONSUMER_BUCKET_KEY_PREFIX = "servicecomb.flowcontrol.Consumer.qps.bucket."; + + public static final String PROVIDER_BUCKET_KEY_PREFIX = "servicecomb.flowcontrol.Provider.qps.bucket."; + + public static final String PROVIDER_BUCKET_KEY_GLOBAL = + "servicecomb.flowcontrol.Provider.qps.global.bucket"; + + public static final String CONSUMER_BUCKET_KEY_GLOBAL = + "servicecomb.flowcontrol.Consumer.qps.global.bucket"; public static final String CONSUMER_LIMIT_KEY_PREFIX = "servicecomb.flowcontrol.Consumer.qps.limit."; @@ -33,35 +43,24 @@ public final class Config { public static final String PROVIDER_LIMIT_KEY_GLOBAL = "servicecomb.flowcontrol.Provider.qps.global.limit"; + public static final String CONSUMER_LIMIT_KEY_GLOBAL = + "servicecomb.flowcontrol.Consumer.qps.global.limit"; + public static final String CONSUMER_ENABLED = "servicecomb.flowcontrol.Consumer.qps.enabled"; public static final String PROVIDER_ENABLED = "servicecomb.flowcontrol.Provider.qps.enabled"; public static Config INSTANCE = new Config(); - private final DynamicBooleanProperty consumerEanbled = - DynamicPropertyFactory.getInstance().getBooleanProperty(CONSUMER_ENABLED, true); - - private final DynamicBooleanProperty providerEanbled = - DynamicPropertyFactory.getInstance().getBooleanProperty(PROVIDER_ENABLED, true); - public Config() { - consumerEanbled.addCallback(() -> { - boolean newValue = consumerEanbled.get(); - LOGGER.info("{} changed from {} to {}", CONSUMER_ENABLED, consumerEanbled, newValue); - }); - - providerEanbled.addCallback(() -> { - boolean newValue = providerEanbled.get(); - LOGGER.info("{} changed from {} to {}", PROVIDER_ENABLED, providerEanbled, newValue); - }); + } public boolean isConsumerEnabled() { - return consumerEanbled.get(); + return LegacyPropertyFactory.getBooleanProperty(CONSUMER_ENABLED, true); } public boolean isProviderEnabled() { - return providerEanbled.get(); + return LegacyPropertyFactory.getBooleanProperty(PROVIDER_ENABLED, true); } } diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerFlowControlFilter.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerFlowControlFilter.java new file mode 100644 index 00000000000..72828b35ccf --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerFlowControlFilter.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +public class ConsumerFlowControlFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private final QpsControllerManager qpsControllerMgr; + + public ConsumerFlowControlFilter(Environment environment) { + qpsControllerMgr = new QpsControllerManager(false, environment); + } + + @VisibleForTesting + public QpsControllerManager getQpsControllerMgr() { + return qpsControllerMgr; + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER - 1990; + } + + @Override + public String getName() { + return "consumer-flow-control"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (!Config.INSTANCE.isConsumerEnabled()) { + return nextNode.onFilter(invocation); + } + + QpsStrategy qpsStrategy = qpsControllerMgr.getOrCreate(invocation.getMicroserviceName(), invocation); + if (qpsStrategy.isLimitNewRequest()) { + CommonExceptionData errorData = new CommonExceptionData( + "consumer request rejected by flow control."); + return CompletableFuture.failedFuture(new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData)); + } + + return nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java deleted file mode 100644 index bc82c6c4317..00000000000 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -/** - * For qps flow control on consumer side. - * Support 3 levels of microservice/schema/operation. - */ -public class ConsumerQpsFlowControlHandler implements Handler { - static final QpsControllerManager qpsControllerMgr = new QpsControllerManager() - .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - if (!Config.INSTANCE.isConsumerEnabled()) { - invocation.next(asyncResp); - return; - } - - QpsController qpsController = qpsControllerMgr.getOrCreate(invocation.getMicroserviceName(), invocation); - if (qpsController.isLimitNewRequest()) { - // return http status 429 - CommonExceptionData errorData = new CommonExceptionData("rejected by qps flowcontrol"); - asyncResp.consumerFail( - new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData)); - return; - } - - invocation.next(asyncResp); - } -} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/FlowControlQpsConfiguration.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/FlowControlQpsConfiguration.java new file mode 100644 index 00000000000..d5fd7702cd1 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/FlowControlQpsConfiguration.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.qps; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@ConditionalOnProperty(value = FlowControlQpsConfiguration.FLOW_CONTROL_ENABLED, + havingValue = "true") +public class FlowControlQpsConfiguration { + public static final String FLOW_CONTROL_PREFIX = "servicecomb.flowcontrol"; + + public static final String FLOW_CONTROL_ENABLED = FLOW_CONTROL_PREFIX + ".enabled"; + + @Bean + public ProviderFlowControlFilter scbProviderFlowControlFilter(Environment environment) { + return new ProviderFlowControlFilter(environment); + } + + @Bean + public ConsumerFlowControlFilter scbConsumerFlowControlFilter(Environment environment) { + return new ConsumerFlowControlFilter(environment); + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderFlowControlFilter.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderFlowControlFilter.java new file mode 100644 index 00000000000..00f78f126f1 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderFlowControlFilter.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +public class ProviderFlowControlFilter extends AbstractFilter implements ProviderFilter { + private final QpsControllerManager qpsControllerMgr; + + public ProviderFlowControlFilter(Environment environment) { + qpsControllerMgr = new QpsControllerManager(true, environment); + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 1990; + } + + @Override + public String getName() { + return "provider-flow-control"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (!Config.INSTANCE.isProviderEnabled()) { + return nextNode.onFilter(invocation); + } + + String microserviceName = invocation.getContext(CoreConst.SRC_MICROSERVICE); + QpsStrategy qpsStrategy = qpsControllerMgr.getOrCreate(microserviceName, invocation); + if (qpsStrategy.isLimitNewRequest()) { + CommonExceptionData errorData = new CommonExceptionData( + "provider request rejected by flow control."); + return CompletableFuture.failedFuture(new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData)); + } + return nextNode.onFilter(invocation); + } + + @VisibleForTesting + public QpsControllerManager getQpsControllerMgr() { + return qpsControllerMgr; + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java deleted file mode 100644 index 67ade9411d4..00000000000 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.util.StringUtils; - -public class ProviderQpsFlowControlHandler implements Handler { - static final QpsControllerManager qpsControllerMgr = new QpsControllerManager() - .setConfigKeyPrefix(Config.PROVIDER_LIMIT_KEY_PREFIX) - .setGlobalQpsController(Config.PROVIDER_LIMIT_KEY_GLOBAL); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - if (invocation.getHandlerIndex() > 0) { - // handlerIndex > 0, which means this handler is executed in handler chain. - // As this flow control logic has been executed in advance, this time it should be ignored. - invocation.next(asyncResp); - return; - } - - // The real executing position of this handler is no longer in handler chain, but in AbstractRestInvocation. - // Therefore, the Invocation#next() method should not be called below. - if (!Config.INSTANCE.isProviderEnabled()) { - return; - } - - String microserviceName = invocation.getContext(Const.SRC_MICROSERVICE); - QpsController qpsController = - StringUtils.isEmpty(microserviceName) - ? qpsControllerMgr.getGlobalQpsController() - : qpsControllerMgr.getOrCreate(microserviceName, invocation); - isLimitNewRequest(qpsController, asyncResp); - } - - private boolean isLimitNewRequest(QpsController qpsController, AsyncResponse asyncResp) { - if (qpsController.isLimitNewRequest()) { - CommonExceptionData errorData = new CommonExceptionData("rejected by qps flowcontrol"); - asyncResp.producerFail(new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData)); - return true; - } else { - return false; - } - } -} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsConst.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsConst.java index 6dae2f4133d..ab1713ec497 100644 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsConst.java +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsConst.java @@ -16,7 +16,7 @@ */ package org.apache.servicecomb.qps; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsController.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsController.java deleted file mode 100644 index 5f294baa84b..00000000000 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsController.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import java.util.concurrent.atomic.AtomicLong; - -public class QpsController { - private String key; - - private Integer qpsLimit; - - // Interval begin time - private volatile long msCycleBegin; - - // Request count between Interval begin and now in one interval - private AtomicLong requestCount = new AtomicLong(); - - // request count before an interval - private volatile long lastRequestCount = 1; - - private static final int CYCLE_LENGTH = 1000; - - public QpsController(String key, Integer qpsLimit) { - this.key = key; - this.qpsLimit = qpsLimit; - this.msCycleBegin = System.currentTimeMillis(); - } - - public String getKey() { - return key; - } - - public Integer getQpsLimit() { - return qpsLimit; - } - - public void setQpsLimit(Integer qpsLimit) { - this.qpsLimit = qpsLimit; - } - - // return true means new request need to be rejected - public boolean isLimitNewRequest() { - long newCount = requestCount.incrementAndGet(); - long msNow = System.currentTimeMillis(); - //Time jump cause the new request injected - if (msNow - msCycleBegin > CYCLE_LENGTH || msNow < msCycleBegin) { - //no need worry about concurrency problem - lastRequestCount = newCount; - msCycleBegin = msNow; - } - - // Configuration update and use is at the situation of multi-threaded concurrency - // It is possible that operation level updated to null,but schema level or microservice level does not updated - int limitValue = (qpsLimit == null) ? Integer.MAX_VALUE : qpsLimit; - return newCount - lastRequestCount >= limitValue; - } -} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java index d637e1f7842..e4cf5e18457 100644 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java @@ -17,47 +17,126 @@ package org.apache.servicecomb.qps; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.qps.strategy.AbstractQpsStrategy; +import org.apache.servicecomb.qps.strategy.IStrategyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; -import com.netflix.config.DynamicProperty; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.Subscribe; -public class QpsControllerManager { +public final class QpsControllerManager { private static final Logger LOGGER = LoggerFactory.getLogger(QpsControllerManager.class); + public static final String SEPARATOR = "."; + /** * Describe the relationship between configuration and qpsController. */ - protected final Map configQpsControllerMap = new ConcurrentHashMapEx<>(); + private final Map configQpsControllerMap = new ConcurrentHashMapEx<>(); /** * Describe the relationship between qualifiedKey(format is "microservice.schema.operation") and qpsController. */ - protected final Map qualifiedNameControllerMap = new ConcurrentHashMapEx<>(); + private final Map qualifiedNameControllerMap = new ConcurrentHashMapEx<>(); - protected QpsController globalQpsController; + private AbstractQpsStrategy globalQpsStrategy; - public static final String SEPARATOR = "."; + private final String limitKeyPrefix; + + private final String bucketKeyPrefix; + + private final String globalLimitKey; + + private final String globalBucketKey; - private String configKeyPrefix; + private final Environment environment; - public QpsController getOrCreate(String microserviceName, Invocation invocation) { + public QpsControllerManager(boolean isProvider, Environment environment) { + this.environment = environment; + if (isProvider) { + limitKeyPrefix = Config.PROVIDER_LIMIT_KEY_PREFIX; + bucketKeyPrefix = Config.PROVIDER_BUCKET_KEY_PREFIX; + globalLimitKey = Config.PROVIDER_LIMIT_KEY_GLOBAL; + globalBucketKey = Config.PROVIDER_BUCKET_KEY_GLOBAL; + } else { + limitKeyPrefix = Config.CONSUMER_LIMIT_KEY_PREFIX; + bucketKeyPrefix = Config.CONSUMER_BUCKET_KEY_PREFIX; + globalLimitKey = Config.CONSUMER_LIMIT_KEY_GLOBAL; + globalBucketKey = Config.CONSUMER_BUCKET_KEY_GLOBAL; + } + + initGlobalQpsController(); + EventManager.register(this); + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(Config.CONFIG_PREFIX)) { + configQpsControllerMap.clear(); + qualifiedNameControllerMap.clear(); + initGlobalQpsController(); + break; + } + } + } + + @VisibleForTesting + public Map getQualifiedNameControllerMap() { + return qualifiedNameControllerMap; + } + + public QpsStrategy getOrCreate(String microserviceName, Invocation invocation) { + final String name = validatedName(microserviceName); return qualifiedNameControllerMap - .computeIfAbsent(microserviceName + SEPARATOR + invocation.getOperationMeta().getSchemaQualifiedName(), key -> { - return create(key, microserviceName, invocation); - }); + .computeIfAbsent( + name + SEPARATOR + invocation.getOperationMeta().getSchemaQualifiedName(), + key -> create(key, name, invocation)); + } + + private String validatedName(String microserviceName) { + String name = microserviceName; + if (StringUtils.isEmpty(microserviceName)) { + name = Config.ANY_SERVICE; + } + return name; } /** * Create relevant qpsLimit dynamicProperty and watch the configuration change. * Search and return a valid qpsController. */ - protected QpsController create(String qualifiedNameKey, String microserviceName, Invocation invocation) { + @VisibleForTesting + AbstractQpsStrategy create(String qualifiedNameKey, String microserviceName, + Invocation invocation) { + createForService(qualifiedNameKey, microserviceName, invocation); + String qualifiedAnyServiceName = Config.ANY_SERVICE + qualifiedNameKey.substring(microserviceName.length()); + createForService(qualifiedAnyServiceName, Config.ANY_SERVICE, invocation); + + AbstractQpsStrategy strategy = searchQpsController(qualifiedNameKey); + if (strategy == null) { + strategy = searchQpsController(qualifiedAnyServiceName); + } + if (strategy == null) { + return globalQpsStrategy; + } + return strategy; + } + + private void createForService(String qualifiedNameKey, String microserviceName, + Invocation invocation) { // create "microservice" createQpsControllerIfNotExist(microserviceName); // create "microservice.schema" @@ -65,12 +144,10 @@ protected QpsController create(String qualifiedNameKey, String microserviceName, qualifiedNameKey.substring(0, microserviceName.length() + invocation.getSchemaId().length() + 1)); // create "microservice.schema.operation" createQpsControllerIfNotExist(qualifiedNameKey); - - return searchQpsController(qualifiedNameKey); } /** - *

Use qualifiedNameKey to search {@link QpsController}. + *

Use qualifiedNameKey to search {@link QpsStrategy}. * Firstly try to search "microservice.schema.operation". If no valid result found, then try "microservice.schema", * and then "microservice" or global qpsController(If there is a global qpsController).

*

This method ensures that there is always an existing qpsController returned, as the relevant qpsController has @@ -79,96 +156,75 @@ protected QpsController create(String qualifiedNameKey, String microserviceName, * @param qualifiedNameKey qualifiedNameKey in {@link #qualifiedNameControllerMap} * @return a qps controller, lower level controllers with valid qpsLimit have priority. */ - protected QpsController searchQpsController(String qualifiedNameKey) { - QpsController qpsController = configQpsControllerMap.get(qualifiedNameKey); - if (isValidQpsController(qpsController)) { - return qpsController; + private AbstractQpsStrategy searchQpsController(String qualifiedNameKey) { + AbstractQpsStrategy qpsStrategy = configQpsControllerMap.get(qualifiedNameKey); + if (isValidQpsController(qpsStrategy)) { + return qpsStrategy; } int index = qualifiedNameKey.lastIndexOf(SEPARATOR); while (index > 0) { - qpsController = configQpsControllerMap.get(qualifiedNameKey.substring(0, index)); - if (isValidQpsController(qpsController)) { - return qpsController; + qpsStrategy = configQpsControllerMap.get(qualifiedNameKey.substring(0, index)); + if (isValidQpsController(qpsStrategy)) { + return qpsStrategy; } index = qualifiedNameKey.lastIndexOf(SEPARATOR, index - 1); } - if (isValidQpsController(qpsController)) { - return qpsController; - } - - if (null != globalQpsController) { - return globalQpsController; + if (isValidQpsController(qpsStrategy)) { + return qpsStrategy; } - // if null is returned, maybe the operation qps controller is not initiated correctly. - // getOrCreateQpsController() should be invoked before. - return qpsController; + return null; } - private boolean keyMatch(String configKey, Entry controllerEntry) { - return controllerEntry.getKey().equals(configKey) - || controllerEntry.getKey().startsWith(configKey + SEPARATOR); - } - - private boolean isValidQpsController(QpsController qpsController) { - return null != qpsController && null != qpsController.getQpsLimit(); + private boolean isValidQpsController(AbstractQpsStrategy qpsStrategy) { + return null != qpsStrategy && null != qpsStrategy.getQpsLimit(); } private void createQpsControllerIfNotExist(String configKey) { - if (configQpsControllerMap.keySet().contains(configKey)) { + if (configQpsControllerMap.containsKey(configKey)) { return; } LOGGER.info("Create qpsController, configKey = [{}]", configKey); - DynamicProperty property = getDynamicProperty(configKey); - QpsController qpsController = new QpsController(configKey, property.getInteger()); + AbstractQpsStrategy qpsStrategy = chooseStrategy(configKey, + environment.getProperty(limitKeyPrefix + configKey, Long.class), + environment.getProperty(bucketKeyPrefix + configKey, Long.class), + environment.getProperty(Config.STRATEGY_KEY)); - configQpsControllerMap.put(configKey, qpsController); + configQpsControllerMap.put(configKey, qpsStrategy); + } - property.addCallback(() -> { - qpsController.setQpsLimit(property.getInteger()); - LOGGER.info("Qps limit updated, configKey = [{}], value = [{}]", configKey, property.getString()); - updateObjMap(configKey); - }); + private void initGlobalQpsController() { + globalQpsStrategy = chooseStrategy(globalLimitKey, + environment.getProperty(globalLimitKey, Long.class, (long) Integer.MAX_VALUE), + environment.getProperty(globalBucketKey, Long.class), + environment.getProperty(Config.STRATEGY_KEY)); } - protected void updateObjMap(String configKey) { - for (Entry controllerEntry : qualifiedNameControllerMap.entrySet()) { - if (keyMatch(configKey, controllerEntry)) { - QpsController qpsController = searchQpsController(controllerEntry.getKey()); - controllerEntry.setValue(qpsController); - LOGGER.info("QpsController updated, operationId = [{}], configKey = [{}], qpsLimit = [{}]", - controllerEntry.getKey(), qpsController.getKey(), qpsController.getQpsLimit()); + private AbstractQpsStrategy chooseStrategy(String configKey, Long limit, Long bucket, + String strategyName) { + if (StringUtils.isEmpty(strategyName)) { + strategyName = "FixedWindow"; + } + AbstractQpsStrategy strategy = null; + List strategyFactories = SPIServiceUtils + .getOrLoadSortedService(IStrategyFactory.class); + for (IStrategyFactory strategyFactory : strategyFactories) { + strategy = strategyFactory.createStrategy(strategyName); + if (strategy != null) { + break; } } - } - - public QpsControllerManager setConfigKeyPrefix(String configKeyPrefix) { - this.configKeyPrefix = configKeyPrefix; - return this; - } - - public QpsControllerManager setGlobalQpsController(String globalConfigKey) { - DynamicProperty globalQpsProperty = DynamicProperty.getInstance(globalConfigKey); - QpsController qpsController = new QpsController(globalConfigKey, globalQpsProperty.getInteger()); - - globalQpsProperty.addCallback(() -> { - qpsController.setQpsLimit(globalQpsProperty.getInteger()); - LOGGER.info("Global qps limit update, value = [{}]", globalQpsProperty.getInteger()); - }); - - this.globalQpsController = qpsController; - return this; - } - - public QpsController getGlobalQpsController() { - return globalQpsController; - } - - protected DynamicProperty getDynamicProperty(String configKey) { - return DynamicProperty.getInstance(configKeyPrefix + configKey); + if (strategy == null) { + throw new ServiceCombException( + "the qps strategy name " + strategyName + " is not exist , please check."); + } + strategy.setKey(configKey); + strategy.setQpsLimit(limit); + strategy.setBucketLimit(bucket); + return strategy; } } diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsStrategy.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsStrategy.java new file mode 100644 index 00000000000..8a712e3e07d --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsStrategy.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps; + +public interface QpsStrategy { + + boolean isLimitNewRequest(); + + String name(); +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/AbstractQpsStrategy.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/AbstractQpsStrategy.java new file mode 100644 index 00000000000..65d36aa3444 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/AbstractQpsStrategy.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps.strategy; + +import org.apache.servicecomb.qps.QpsStrategy; + + +public abstract class AbstractQpsStrategy implements QpsStrategy { + + private Long qpsLimit; + + private Long bucketLimit; + + private String key; + + public Long getBucketLimit() { + return bucketLimit; + } + + public void setBucketLimit(Long bucketLimit) { + this.bucketLimit = bucketLimit; + } + + @Override + public abstract boolean isLimitNewRequest(); + + @Override + public abstract String name(); + + public void setQpsLimit(Long qpsLimit) { + this.qpsLimit = qpsLimit; + } + + public Long getQpsLimit() { + return qpsLimit; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/DefaultStrategyFactory.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/DefaultStrategyFactory.java new file mode 100644 index 00000000000..79037f791a4 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/DefaultStrategyFactory.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.qps.strategy; + +public class DefaultStrategyFactory implements IStrategyFactory { + + public AbstractQpsStrategy createStrategy(String strategyName) { + switch (strategyName) { + case "TokenBucket": + return new TokenBucketStrategy(); + case "LeakyBucket": + return new LeakyBucketStrategy(); + case "FixedWindow": + return new FixedWindowStrategy(); + default: + return null; + } + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/FixedWindowStrategy.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/FixedWindowStrategy.java new file mode 100644 index 00000000000..c95c1ab2cba --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/FixedWindowStrategy.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.qps.strategy; + +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FixedWindowStrategy extends AbstractQpsStrategy { + + private static final Logger LOGGER = LoggerFactory.getLogger(FixedWindowStrategy.class); + + // Interval begin time + private volatile long msCycleBegin; + + // Request count between Interval begin and now in one interval + private final AtomicLong requestCount = new AtomicLong(); + + // request count before an interval + private volatile long lastRequestCount = 1; + + private static final int CYCLE_LENGTH = 1000; + + private static final String STRATEGY_NAME = "FixedWindow"; + + // return true means new request need to be rejected + public boolean isLimitNewRequest() { + if (this.getQpsLimit() == null) { + throw new IllegalStateException("should not happen"); + } + long newCount = requestCount.incrementAndGet(); + long msNow = System.currentTimeMillis(); + //Time jump cause the new request injected + if (msNow - msCycleBegin > CYCLE_LENGTH || msNow < msCycleBegin) { + //no need worry about concurrency problem + lastRequestCount = newCount; + msCycleBegin = msNow; + } + + // Configuration update and use is at the situation of multi-thread concurrency + // It is possible that operation level updated to null,but schema level or microservice level does not updated + boolean isLimitRequest = newCount - lastRequestCount >= this.getQpsLimit(); + if (isLimitRequest){ + LOGGER.warn("qps flowcontrol open, qpsLimit is {} and tps is {}", this.getQpsLimit(), newCount - lastRequestCount + 1); + } + return isLimitRequest; + } + + @Override + public String name() { + return STRATEGY_NAME; + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/IStrategyFactory.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/IStrategyFactory.java new file mode 100644 index 00000000000..bebe8ce90b0 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/IStrategyFactory.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps.strategy; + +public interface IStrategyFactory { + + AbstractQpsStrategy createStrategy(String strategyName); +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/LeakyBucketStrategy.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/LeakyBucketStrategy.java new file mode 100644 index 00000000000..b8bf65c5e7e --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/LeakyBucketStrategy.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps.strategy; + +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * leaky bucket algorithm include 2 implementation : + * 1. as a meter : it's same as the token bucket. + * 2. as a queue : the bucket size equal to qpsLimit. + * + **/ +public class LeakyBucketStrategy extends AbstractQpsStrategy { + + private static final Logger LOGGER = LoggerFactory.getLogger(LeakyBucketStrategy.class); + + // Request count between Interval begin and now in one interval + private final AtomicLong requestCount = new AtomicLong(); + + private volatile long lastTime; + + private long remainder = 0; + + private static final String STRATEGY_NAME = "LeakyBucket"; + + @Override + public boolean isLimitNewRequest() { + if (this.getQpsLimit() == null) { + throw new IllegalStateException("should not happen"); + } + if (this.getBucketLimit() == null) { + this.setBucketLimit(Math.min(2 * this.getQpsLimit(), Integer.MAX_VALUE)); + } + long nowTime = System.currentTimeMillis(); + //get the num of te period time + long leakCount = ((nowTime - lastTime + remainder) / 1000) * this.getQpsLimit(); + remainder = (nowTime - lastTime + remainder) % 1000; + // leak the request + if (requestCount.longValue() > leakCount) { + requestCount.addAndGet(-leakCount); + } else { + requestCount.set(0); + } + lastTime = nowTime; + //compute this time + if (requestCount.longValue() < this.getBucketLimit()) { + requestCount.incrementAndGet(); + return false; + } + LOGGER.warn("qps flowcontrol open, qpsLimit is {} and tps is {}", this.getQpsLimit(), requestCount.longValue() + 1); + return true; + } + + @Override + public String name() { + return STRATEGY_NAME; + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/TokenBucketStrategy.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/TokenBucketStrategy.java new file mode 100644 index 00000000000..082906ffa87 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/strategy/TokenBucketStrategy.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps.strategy; + +public class TokenBucketStrategy extends LeakyBucketStrategy { + + private static final String STRATEGY_NAME = "TokenBucket"; + + @Override + public String name() { + return STRATEGY_NAME; + } +} diff --git a/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory b/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory new file mode 100644 index 00000000000..32f53faffb7 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/services/org.apache.servicecomb.qps.strategy.IStrategyFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.qps.strategy.DefaultStrategyFactory diff --git a/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..731cf581a05 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.qps.FlowControlQpsConfiguration diff --git a/handlers/handler-flowcontrol-qps/src/main/resources/config/cse.handler.xml b/handlers/handler-flowcontrol-qps/src/main/resources/config/cse.handler.xml deleted file mode 100644 index c8f3ebb0370..00000000000 --- a/handlers/handler-flowcontrol-qps/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java index 44b86b267d2..e2b5f79fa69 100644 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java +++ b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java @@ -17,369 +17,288 @@ package org.apache.servicecomb.qps; -import java.util.Map; +import java.util.HashMap; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.config.InMemoryDynamicPropertiesSource; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.qps.strategy.AbstractQpsStrategy; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; +import org.springframework.core.env.Environment; public class QpsControllerManagerTest { + static Environment environment = Mockito.mock(Environment.class); - @Before + @BeforeEach public void beforeTest() { - ArchaiusUtils.resetConfig(); + Mockito.when(environment.getProperty(Config.PROVIDER_LIMIT_KEY_GLOBAL, Long.class, (long) Integer.MAX_VALUE)) + .thenReturn((long) Integer.MAX_VALUE); + Mockito.when(environment.getProperty(Config.CONSUMER_LIMIT_KEY_GLOBAL, Long.class, (long) Integer.MAX_VALUE)) + .thenReturn((long) Integer.MAX_VALUE); } - @After + @AfterEach public void afterTest() { - ArchaiusUtils.resetConfig(); + } @Test - public void testGetOrCreate(@Mocked Invocation invocation, @Mocked OperationMeta operationMeta) { - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - QpsControllerManager testQpsControllerManager = new QpsControllerManager() - .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); - initTestQpsControllerManager(testQpsControllerManager, invocation, operationMeta); + public void testGetOrCreate() { + Invocation invocation = Mockito.mock(Invocation.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + + QpsControllerManager testQpsControllerManager = new QpsControllerManager(false, environment); + initTestQpsControllerManager(false, testQpsControllerManager, invocation, operationMeta); // pojo - setConfigWithDefaultPrefix("pojo", 100); - QpsController qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo", qpsController.getKey()); - Assert.assertTrue(100 == qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("pojo2", invocation); - Assert.assertEquals("pojo2", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals("poj", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - - ArchaiusUtils.setProperty("servicecomb.flowcontrol.Consumer.qps.limit.poj.server", 10000); - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals("poj.server", qpsController.getKey()); - Assert.assertEquals(qpsController.getQpsLimit(), (Integer) 10000); - - ArchaiusUtils.setProperty("servicecomb.flowcontrol.Consumer.qps.limit.poj.server.test", 20000); - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals("poj.server.test", qpsController.getKey()); - Assert.assertEquals(qpsController.getQpsLimit(), (Integer) 20000); - - testGetOrCreateCommon(testQpsControllerManager, invocation, operationMeta); + setConfigWithDefaultPrefix(false, "pojo", 100); + QpsStrategy qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(100, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo2", invocation); + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + Mockito.when(environment.getProperty("servicecomb.flowcontrol.Consumer.qps.limit.poj.server", + Long.class)).thenReturn(Long.valueOf(10000)); + HashMap updated = new HashMap<>(); + updated.put("servicecomb.flowcontrol.Consumer.qps.limit.poj.server", Long.valueOf(10000)); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + Assertions.assertEquals("poj.server", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(((AbstractQpsStrategy) qpsStrategy).getQpsLimit(), (Long) 10000L); + + InMemoryDynamicPropertiesSource.update("servicecomb.flowcontrol.Consumer.qps.limit.poj.server.test", 20000); + Mockito.when(environment.getProperty("servicecomb.flowcontrol.Consumer.qps.limit.poj.server.test", + Long.class)).thenReturn(Long.valueOf(20000)); + updated = new HashMap<>(); + updated.put("servicecomb.flowcontrol.Consumer.qps.limit.poj.server.test", Long.valueOf(20000)); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + Assertions.assertEquals("poj.server.test", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(((AbstractQpsStrategy) qpsStrategy).getQpsLimit(), (Long) 20000L); + + testGetOrCreateCommon(false, testQpsControllerManager, invocation, operationMeta); } @Test - public void testGetOrCreateWithGlobalConfig(@Mocked Invocation invocation, @Mocked OperationMeta operationMeta) { - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - - QpsControllerManager testQpsControllerManager = new QpsControllerManager() - .setGlobalQpsController(Config.PROVIDER_LIMIT_KEY_GLOBAL) - .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); + public void testGetOrCreateWithGlobalConfig() { + Invocation invocation = Mockito.mock(Invocation.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + + QpsControllerManager testQpsControllerManager = new QpsControllerManager(true, environment); // global - setConfig(Config.PROVIDER_LIMIT_KEY_GLOBAL, 50); - QpsController qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); - Assert.assertTrue(50 == qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("pojo2", invocation); - Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); - Assert.assertTrue(50 == qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); - Assert.assertTrue(50 == qpsController.getQpsLimit()); + Mockito.when(environment.getProperty(Config.PROVIDER_LIMIT_KEY_GLOBAL, Long.class, + (long) Integer.MAX_VALUE)).thenReturn(50L); + HashMap updated = new HashMap<>(); + updated.put(Config.PROVIDER_LIMIT_KEY_GLOBAL, 50L); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); + + QpsStrategy qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(50, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo2", invocation); + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(50, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(50, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); // pojo - setConfigWithDefaultPrefix("pojo", 100); - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo", qpsController.getKey()); - Assert.assertTrue(100 == qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("pojo2", invocation); - Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); - Assert.assertTrue(50 == qpsController.getQpsLimit()); - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); - Assert.assertTrue(50 == qpsController.getQpsLimit()); - - testGetOrCreateCommon(testQpsControllerManager, invocation, operationMeta); + setConfigWithDefaultPrefix(true, "pojo", 100); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(100, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo2", invocation); + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(50, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(50, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + + testGetOrCreateCommon(true, testQpsControllerManager, invocation, operationMeta); } @Test - public void testQualifiedNameKey(@Mocked Invocation invocation, @Mocked OperationMeta operationMeta) { - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "schema"; - operationMeta.getSchemaQualifiedName(); - result = "schema.opr"; - } - }; - QpsControllerManager qpsControllerManager = new QpsControllerManager(); - QpsController qpsController = qpsControllerManager.getOrCreate("service", invocation); - Assert.assertEquals("service", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "test_schema"; - operationMeta.getSchemaQualifiedName(); - result = "test_schema.test_opr"; - } - }; - qpsController = qpsControllerManager.getOrCreate("test_service", invocation); - Assert.assertEquals("test_service", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "test_schema"; - operationMeta.getSchemaQualifiedName(); - result = "test-schema.test-opr"; - } - }; - qpsController = qpsControllerManager.getOrCreate("test-service", invocation); - Assert.assertEquals("test-service", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "schema"; - operationMeta.getSchemaQualifiedName(); - result = "schema.opr.tail"; - } - }; - qpsController = qpsControllerManager.getOrCreate("svc", invocation); - Assert.assertEquals("svc", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); - - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "schema.opr2"; - operationMeta.getSchemaQualifiedName(); - result = "schema.opr2.tail"; - } - }; - qpsController = qpsControllerManager.getOrCreate("svc", invocation); - Assert.assertEquals("svc", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); + public void testQualifiedNameKey() { + Invocation invocation = Mockito.mock(Invocation.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getSchemaId()).thenReturn("schema"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("schema.opr"); + QpsControllerManager qpsControllerManager = new QpsControllerManager(true, environment); + QpsStrategy qpsStrategy = qpsControllerManager.getOrCreate("service", invocation); + Assertions.assertEquals("servicecomb.flowcontrol.Provider.qps.global.limit", + ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + Mockito.when(invocation.getSchemaId()).thenReturn("test_schema"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("test_schema.test_opr"); + qpsStrategy = qpsControllerManager.getOrCreate("test_service", invocation); + Assertions.assertEquals("servicecomb.flowcontrol.Provider.qps.global.limit", + ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + Mockito.when(invocation.getSchemaId()).thenReturn("test_schema"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("test-schema.test-opr"); + qpsStrategy = qpsControllerManager.getOrCreate("test-service", invocation); + Assertions.assertEquals("servicecomb.flowcontrol.Provider.qps.global.limit", + ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + Mockito.when(invocation.getSchemaId()).thenReturn("schema"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("schema.opr.tail"); + qpsStrategy = qpsControllerManager.getOrCreate("svc", invocation); + Assertions.assertEquals("servicecomb.flowcontrol.Provider.qps.global.limit", + ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); + + Mockito.when(invocation.getSchemaId()).thenReturn("schema.opr2"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("schema.opr2.tail"); + qpsStrategy = qpsControllerManager.getOrCreate("svc", invocation); + Assertions.assertEquals("servicecomb.flowcontrol.Provider.qps.global.limit", + ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); } - private void testGetOrCreateCommon(QpsControllerManager testQpsControllerManager, Invocation invocation, + private void testGetOrCreateCommon(boolean isProvider, QpsControllerManager testQpsControllerManager, + Invocation invocation, OperationMeta operationMeta) { - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - setConfigWithDefaultPrefix("pojo.server", 200); - QpsController qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo.server", qpsController.getKey()); - Assert.assertTrue(200 == qpsController.getQpsLimit()); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getSchemaQualifiedName(); - result = "server2.test"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo", qpsController.getKey()); - Assert.assertTrue(100 == qpsController.getQpsLimit()); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getSchemaQualifiedName(); - result = "serve.test"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo", qpsController.getKey()); - Assert.assertTrue(100 == qpsController.getQpsLimit()); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + + setConfigWithDefaultPrefix(isProvider, "pojo.server", 200); + QpsStrategy qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo.server", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(200, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server2.test"); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(100, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("serve.test"); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(100, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); // pojo.server.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - setConfigWithDefaultPrefix("pojo.server.test", 300); - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo.server.test", qpsController.getKey()); - Assert.assertTrue(300 == qpsController.getQpsLimit()); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getSchemaQualifiedName(); - result = "server.test2"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo.server", qpsController.getKey()); - Assert.assertTrue(200 == qpsController.getQpsLimit()); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - - operationMeta.getSchemaQualifiedName(); - result = "server.tes"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo.server", qpsController.getKey()); - Assert.assertTrue(200 == qpsController.getQpsLimit()); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + setConfigWithDefaultPrefix(isProvider, "pojo.server.test", 300); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo.server.test", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(300, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test2"); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo.server", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(200, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.tes"); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + Assertions.assertEquals("pojo.server", ((AbstractQpsStrategy) qpsStrategy).getKey()); + Assertions.assertEquals(200, (long) ((AbstractQpsStrategy) qpsStrategy).getQpsLimit()); } /** * Init testQpsControllerManager to test search function. */ - private void initTestQpsControllerManager(QpsControllerManager testQpsControllerManager, Invocation invocation, + private void initTestQpsControllerManager(boolean isProvider, QpsControllerManager testQpsControllerManager, + Invocation invocation, OperationMeta operationMeta) { // pojo.server.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - QpsController qpsController = testQpsControllerManager.getOrCreate("pojo", invocation); - Assert.assertEquals("pojo", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + QpsStrategy qpsStrategy = testQpsControllerManager.getOrCreate("pojo", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // pojo.server.test2 - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test2"; - } - }; + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test2"); testQpsControllerManager.getOrCreate("pojo", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // pojo.server.tes - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.tes"; - } - }; + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.tes"); testQpsControllerManager.getOrCreate("pojo", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // pojo.server2.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server2"; - operationMeta.getSchemaQualifiedName(); - result = "server2.test"; - } - }; + Mockito.when(invocation.getSchemaId()).thenReturn("server2"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server2.test"); testQpsControllerManager.getOrCreate("pojo", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // pojo.serve.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "serve"; - operationMeta.getSchemaQualifiedName(); - result = "serve.test"; - } - }; + Mockito.when(invocation.getSchemaId()).thenReturn("serve"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("serve.test"); testQpsControllerManager.getOrCreate("pojo", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // pojo2.server.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("pojo2", invocation); - Assert.assertEquals("pojo2", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + qpsStrategy = testQpsControllerManager.getOrCreate("pojo2", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); // poj.server.test - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - invocation.getSchemaId(); - result = "server"; - operationMeta.getSchemaQualifiedName(); - result = "server.test"; - } - }; - qpsController = testQpsControllerManager.getOrCreate("poj", invocation); - Assert.assertEquals("poj", qpsController.getKey()); - Assert.assertNull(qpsController.getQpsLimit()); + Mockito.when(invocation.getSchemaId()).thenReturn("server"); + Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("server.test"); + qpsStrategy = testQpsControllerManager.getOrCreate("poj", invocation); + if (isProvider) { + Assertions.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } else { + Assertions.assertEquals(Config.CONSUMER_LIMIT_KEY_GLOBAL, ((AbstractQpsStrategy) qpsStrategy).getKey()); + } + Assertions.assertEquals(Integer.MAX_VALUE, ((AbstractQpsStrategy) qpsStrategy).getQpsLimit().intValue()); } @Test @@ -388,10 +307,10 @@ public void testMock() { OperationMeta operationMeta = invocation.getOperationMeta(); SchemaMeta schemaMeta = operationMeta.getSchemaMeta(); - Assert.assertEquals("service", operationMeta.getMicroserviceName()); - Assert.assertEquals("service.schema.oper", operationMeta.getMicroserviceQualifiedName()); - Assert.assertEquals("schema.oper", operationMeta.getSchemaQualifiedName()); - Assert.assertEquals("schema", schemaMeta.getSchemaId()); + Assertions.assertEquals("service", operationMeta.getMicroserviceName()); + Assertions.assertEquals("service.schema.oper", operationMeta.getMicroserviceQualifiedName()); + Assertions.assertEquals("schema.oper", operationMeta.getSchemaQualifiedName()); + Assertions.assertEquals("schema", schemaMeta.getSchemaId()); } public static Invocation getMockInvocation(String microserviceName, String schemaId, String operationId) { @@ -421,20 +340,52 @@ public static OperationMeta getMockOperationMeta(String microserviceName, String return operationMeta; } - public static void setConfig(String key, int value) { - ArchaiusUtils.setProperty(key, value); + private static void setConfigWithDefaultPrefix(boolean isProvider, String key, int value) { + String configKey = Config.CONSUMER_LIMIT_KEY_PREFIX + key; + if (isProvider) { + configKey = Config.PROVIDER_LIMIT_KEY_PREFIX + key; + } + + Mockito.when(environment.getProperty(configKey, Long.class)).thenReturn(Long.valueOf(value)); + HashMap updated = new HashMap<>(); + updated.put(configKey, value); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); } - public static void setConfigWithDefaultPrefix(String key, int value) { + private static void deleteConfigWithDefaultPrefix(boolean isProvider, String key) { String configKey = Config.CONSUMER_LIMIT_KEY_PREFIX + key; - ArchaiusUtils.setProperty(configKey, value); + if (isProvider) { + configKey = Config.PROVIDER_LIMIT_KEY_PREFIX + key; + } + + Mockito.when(environment.getProperty(configKey, Long.class)).thenReturn(null); + HashMap updated = new HashMap<>(); + updated.put(configKey, null); + EventManager.post(ConfigurationChangedEvent.createIncremental(updated)); } - public static void clearState(QpsControllerManager qpsControllerManager) { - Map objMap = Deencapsulation.getField(qpsControllerManager, "qualifiedNameControllerMap"); - objMap.clear(); - Map configQpsControllerMap = Deencapsulation - .getField(qpsControllerManager, "configQpsControllerMap"); - configQpsControllerMap.clear(); + @Test + public void testDeleteQpsController() { + + final String microserviceName = "springmvcClient"; + final String schemaId = "controller"; + final String operationId = "add"; + final String configKey = "springmvcClient.controller.add"; + + QpsControllerManager testManager = new QpsControllerManager(true, environment); + Invocation testInvocation = getMockInvocation(microserviceName, schemaId, operationId); + Mockito.when(testInvocation.getSchemaId()).thenReturn(schemaId); + + QpsStrategy strategy1 = testManager.getOrCreate(microserviceName, testInvocation); + + setConfigWithDefaultPrefix(true, configKey, 1); + + deleteConfigWithDefaultPrefix(true, configKey); + + QpsStrategy strategy2 = testManager.getOrCreate(microserviceName, testInvocation); + + Assertions.assertEquals(((AbstractQpsStrategy) strategy1).getQpsLimit(), + ((AbstractQpsStrategy) strategy2).getQpsLimit()); + Assertions.assertEquals(((AbstractQpsStrategy) strategy1).getQpsLimit(), Long.valueOf(Integer.MAX_VALUE)); } } diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConfig.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConfig.java deleted file mode 100644 index 3f1a7f6fa04..00000000000 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * - * - */ -public class TestConfig { - @BeforeClass - public static void classSetup() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testEnabled() { - Config.INSTANCE = new Config(); - - Assert.assertEquals(true, Config.INSTANCE.isProviderEnabled()); - ArchaiusUtils.updateProperty(Config.PROVIDER_ENABLED, false); - Assert.assertEquals(false, Config.INSTANCE.isProviderEnabled()); - - ArchaiusUtils.updateProperty(Config.PROVIDER_ENABLED, null); - Assert.assertEquals(true, Config.INSTANCE.isProviderEnabled()); - - Assert.assertEquals(true, Config.INSTANCE.isConsumerEnabled()); - ArchaiusUtils.updateProperty(Config.CONSUMER_ENABLED, false); - Assert.assertEquals(false, Config.INSTANCE.isConsumerEnabled()); - - ArchaiusUtils.updateProperty(Config.CONSUMER_ENABLED, null); - Assert.assertEquals(true, Config.INSTANCE.isConsumerEnabled()); - } -} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java deleted file mode 100644 index 3e6bbbaf822..00000000000 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import static org.junit.Assert.assertEquals; - -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class TestConsumerQpsFlowControlHandler { - - ConsumerQpsFlowControlHandler handler = new ConsumerQpsFlowControlHandler(); - - Invocation invocation = Mockito.mock(Invocation.class); - - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setUP() { - ArchaiusUtils.resetConfig(); - QpsControllerManagerTest.clearState(ConsumerQpsFlowControlHandler.qpsControllerMgr); - } - - - @After - public void afterTest() { - ArchaiusUtils.resetConfig(); - QpsControllerManagerTest.clearState(ConsumerQpsFlowControlHandler.qpsControllerMgr); - } - - @Test - public void testQpsController() { - // to avoid time influence on QpsController - new MockUp() { - @Mock - long currentTimeMillis() { - return 1L; - } - }; - QpsController qpsController = new QpsController("abc", 100); - Assert.assertEquals(false, qpsController.isLimitNewRequest()); - - qpsController.setQpsLimit(1); - Assert.assertEquals(true, qpsController.isLimitNewRequest()); - } - - @Test - public void testHandle() throws Exception { - String key = "svc.schema.opr"; - QpsController qpsController = new QpsController("key", 12); - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("schema.opr"); - Mockito.when(invocation.getSchemaId()).thenReturn("schema"); - Mockito.when(invocation.getMicroserviceName()).thenReturn("svc"); - setQpsController(key, qpsController); - new MockUp() { - @Mock - public boolean isLimitNewRequest() { - return true; - } - }; - - new MockUp() { - @Mock - protected QpsController create(String qualifiedNameKey) { - return qpsController; - } - }; - - handler.handle(invocation, asyncResp); - - ArgumentCaptor captor = ArgumentCaptor.forClass(InvocationException.class); - Mockito.verify(asyncResp).consumerFail(captor.capture()); - InvocationException invocationException = captor.getValue(); - assertEquals(QpsConst.TOO_MANY_REQUESTS_STATUS, invocationException.getStatus()); - assertEquals("rejected by qps flowcontrol", - ((CommonExceptionData) invocationException.getErrorData()).getMessage()); - } - - @Test - public void testHandleIsLimitNewRequestAsFalse() throws Exception { - String key = "service.schema.id"; - QpsController qpsController = new QpsController("service", 12); - Mockito.when(invocation.getMicroserviceName()).thenReturn("service"); - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - - Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("schema.id"); - setQpsController(key, qpsController); - - new MockUp() { - @Mock - public boolean isLimitNewRequest() { - return false; - } - }; - - new MockUp() { - - @Mock - protected QpsController create(String qualifiedNameKey) { - return qpsController; - } - }; - handler.handle(invocation, asyncResp); - - Mockito.verify(invocation).next(asyncResp); - } - - private void setQpsController(String key, QpsController qpsController) { - QpsControllerManager qpsControllerManager = Deencapsulation.getField(handler, "qpsControllerMgr"); - ConcurrentHashMap objMap = Deencapsulation - .getField(qpsControllerManager, "qualifiedNameControllerMap"); - objMap.put(key, qpsController); - } -} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java deleted file mode 100644 index 9f731552465..00000000000 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.qps; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.times; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; - -public class TestProviderQpsFlowControlHandler { - ProviderQpsFlowControlHandler handler = new ProviderQpsFlowControlHandler(); - - Invocation invocation = Mockito.mock(Invocation.class); - - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setUP() { - ArchaiusUtils.resetConfig(); - QpsControllerManagerTest.clearState(ProviderQpsFlowControlHandler.qpsControllerMgr); - ArchaiusUtils.setProperty(Config.PROVIDER_LIMIT_KEY_PREFIX + "test", 1); - } - - @After - public void afterTest() { - ArchaiusUtils.resetConfig(); - QpsControllerManagerTest.clearState(ProviderQpsFlowControlHandler.qpsControllerMgr); - } - - @Test - public void testGlobalQpsControl(final @Injectable Invocation invocation, - final @Injectable AsyncResponse asyncResp) throws Exception { - new Expectations() { - { - invocation.getHandlerIndex(); - result = 0; - invocation.getContext(Const.SRC_MICROSERVICE); - result = "test"; - invocation.getOperationMeta(); - result = QpsControllerManagerTest.getMockOperationMeta("pojo", "server", "opr"); - invocation.getSchemaId(); - result = "server"; - asyncResp.producerFail((Throwable) any); - result = new RuntimeException("test error"); - } - }; - mockUpSystemTime(); - - ProviderQpsFlowControlHandler gHandler = new ProviderQpsFlowControlHandler(); - gHandler.handle(invocation, asyncResp); - - ArchaiusUtils.setProperty(Config.PROVIDER_LIMIT_KEY_GLOBAL, 3); - - expectedException.expect(RuntimeException.class); - expectedException.expectMessage("test error"); - - gHandler.handle(invocation, asyncResp); - gHandler.handle(invocation, asyncResp); - } - - @Test - public void testQpsController() { - mockUpSystemTime(); - QpsController qpsController = new QpsController("abc", 100); - assertFalse(qpsController.isLimitNewRequest()); - - qpsController.setQpsLimit(1); - assertTrue(qpsController.isLimitNewRequest()); - } - - @Test - public void testHandleOnSourceMicroserviceNameIsNull() throws Exception { - Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn(null); - // only when handler index <= 0, the qps logic works - Mockito.when(invocation.getHandlerIndex()).thenReturn(0); - ArchaiusUtils.setProperty("servicecomb.flowcontrol.Provider.qps.global.limit", 1); - ProviderQpsFlowControlHandler.qpsControllerMgr - .setGlobalQpsController("servicecomb.flowcontrol.Provider.qps.global.limit"); - - handler.handle(invocation, asyncResp); - handler.handle(invocation, asyncResp); - - // Invocation#getContext(String) is only invoked when the qps logic works - Mockito.verify(invocation, times(2)).getContext(Const.SRC_MICROSERVICE); - Mockito.verify(asyncResp, times(1)).producerFail(Mockito.any(Exception.class)); - } - - @Test - public void testHandleOnSourceOnHandlerIndexIsGreaterThan0() throws Exception { - Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn(null); - - Mockito.when(invocation.getHandlerIndex()).thenReturn(1); - handler.handle(invocation, asyncResp); - handler.handle(invocation, asyncResp); - - Mockito.verify(invocation, times(0)).getContext(Mockito.anyString()); - } - - @Test - public void testHandle() throws Exception { - Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn("test"); - OperationMeta mockOperationMeta = QpsControllerManagerTest.getMockOperationMeta("pojo", "server", "opr"); - Mockito.when(invocation.getOperationMeta()).thenReturn(mockOperationMeta); - Mockito.when(invocation.getSchemaId()).thenReturn("server"); - - new MockUp() { - @Mock - protected QpsController create(String qualifiedNameKey) { - return new QpsController(qualifiedNameKey, 1); - } - }; - - handler.handle(invocation, asyncResp); - handler.handle(invocation, asyncResp); - - ArgumentCaptor captor = ArgumentCaptor.forClass(InvocationException.class); - Mockito.verify(asyncResp, times(1)).producerFail(captor.capture()); - - InvocationException invocationException = captor.getValue(); - assertEquals(QpsConst.TOO_MANY_REQUESTS_STATUS, invocationException.getStatus()); - assertEquals("rejected by qps flowcontrol", - ((CommonExceptionData) invocationException.getErrorData()).getMessage()); - } - - @Test - public void testHandleIsLimitNewRequestAsFalse() throws Exception { - Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn("test"); - OperationMeta mockOperationMeta = QpsControllerManagerTest - .getMockOperationMeta("pojo", "server", "opr"); - Mockito.when(invocation.getOperationMeta()).thenReturn(mockOperationMeta); - Mockito.when(invocation.getSchemaId()).thenReturn("server"); - - new MockUp() { - @Mock - protected QpsController create(String qualifiedNameKey) { - return new QpsController(qualifiedNameKey, 1); - } - }; - handler.handle(invocation, asyncResp); - - Mockito.verify(invocation, times(0)).next(asyncResp); - Mockito.verify(asyncResp, times(0)).producerFail(Mockito.any(Exception.class)); - } - - private void mockUpSystemTime() { - // to avoid time influence on QpsController - new MockUp() { - @Mock - long currentTimeMillis() { - return 1L; - } - }; - } -} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestQpsStrategy.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestQpsStrategy.java new file mode 100644 index 00000000000..f34b6c5a261 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestQpsStrategy.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.qps; + +import org.apache.servicecomb.qps.strategy.AbstractQpsStrategy; +import org.apache.servicecomb.qps.strategy.FixedWindowStrategy; +import org.apache.servicecomb.qps.strategy.LeakyBucketStrategy; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author GuoYl123 + * @since 2020/7/16 + **/ +public class TestQpsStrategy { + + @Test + public void testFixedWindowStrategy() { + AbstractQpsStrategy qpsStrategy = new FixedWindowStrategy(); + qpsStrategy.setKey("abc"); + qpsStrategy.setQpsLimit(100L); + Assertions.assertFalse(qpsStrategy.isLimitNewRequest()); + + qpsStrategy.setQpsLimit(1L); + Assertions.assertTrue(qpsStrategy.isLimitNewRequest()); + } + + + @Test + public void testLeakyBucketStrategy() { + LeakyBucketStrategy qpsStrategy = new LeakyBucketStrategy(); + qpsStrategy.setKey("abc"); + qpsStrategy.setQpsLimit(100L); + Assertions.assertFalse(qpsStrategy.isLimitNewRequest()); + + qpsStrategy.setQpsLimit(1L); + qpsStrategy.setBucketLimit(1L); + Assertions.assertTrue(qpsStrategy.isLimitNewRequest()); + } + +} diff --git a/handlers/handler-flowcontrol-qps/src/test/resources/log4j.properties b/handlers/handler-flowcontrol-qps/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/handlers/handler-flowcontrol-qps/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/handlers/handler-governance/README.md b/handlers/handler-governance/README.md new file mode 100644 index 00000000000..b6a237f6510 --- /dev/null +++ b/handlers/handler-governance/README.md @@ -0,0 +1,3 @@ +Enable governance features by handler. + +Governance can be enabled in any different process layer, enable it in handler is most portable way. diff --git a/handlers/handler-governance/pom.xml b/handlers/handler-governance/pom.xml new file mode 100644 index 00000000000..7db533e562e --- /dev/null +++ b/handlers/handler-governance/pom.xml @@ -0,0 +1,65 @@ + + + + 4.0.0 + + org.apache.servicecomb + handlers + 3.4.0-SNAPSHOT + + + handler-governance + Java Chassis::Handlers::Governance + + + UTF-8 + + + + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + servicecomb-governance + + + org.apache.servicecomb + registry-local + test + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + + diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceBulkheadFilter.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceBulkheadFilter.java new file mode 100644 index 00000000000..1b007e111ad --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceBulkheadFilter.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.handler.governance; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.InstanceBulkheadHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadFullException; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; +import jakarta.ws.rs.core.Response.Status; + +public class ConsumerInstanceBulkheadFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerInstanceBulkheadFilter.class); + + private final InstanceBulkheadHandler instanceBulkheadHandler; + + @Autowired + public ConsumerInstanceBulkheadFilter(InstanceBulkheadHandler instanceBulkheadHandler) { + this.instanceBulkheadHandler = instanceBulkheadHandler; + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1060; + } + + @Override + public String getName() { + return "instance-bulkhead"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (invocation.getEndpoint() == null) { + return CompletableFuture.failedFuture(new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData("instance bulkhead should work after load balancer."))); + } + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + + addBulkhead(dcs, request); + + CompletableFuture future = new CompletableFuture<>(); + + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + if (e instanceof BulkheadFullException) { + // return 503 so that consumer can retry + future.completeExceptionally(new InvocationException(503, "bulkhead is full and does not permit further calls.", + new CommonExceptionData("bulkhead is full and does not permit further calls."))); + LOGGER.warn("bulkhead is full and does not permit further calls by policy : {}", e.getMessage()); + } else { + future.completeExceptionally(e); + } + }); + + return future; + } + + private void addBulkhead(DecorateCompletionStage dcs, GovernanceRequestExtractor request) { + Bulkhead bulkhead = instanceBulkheadHandler.getActuator(request); + if (bulkhead != null) { + dcs.withBulkhead(bulkhead); + } + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceIsolationFilter.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceIsolationFilter.java new file mode 100644 index 00000000000..e60d52fab18 --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ConsumerInstanceIsolationFilter.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.handler.governance; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.InstanceIsolationHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.circuitbreaker.CallNotPermittedException; +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; +import jakarta.ws.rs.core.Response.Status; + +public class ConsumerInstanceIsolationFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerInstanceIsolationFilter.class); + + private final InstanceIsolationHandler instanceIsolationHandler; + + private DiscoveryManager discoveryManager; + + @Autowired + public ConsumerInstanceIsolationFilter(InstanceIsolationHandler instanceIsolationHandler) { + this.instanceIsolationHandler = instanceIsolationHandler; + } + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1050; + } + + @Override + public String getName() { + return "instance-isolation"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + if (invocation.getEndpoint() == null) { + return CompletableFuture.failedFuture(new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData("instance isolation should work after load balancer."))); + } + + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + CircuitBreakerPolicy circuitBreakerPolicy = instanceIsolationHandler.matchPolicy(request); + if (circuitBreakerPolicy != null && circuitBreakerPolicy.isForceOpen()) { + return CompletableFuture.failedFuture(new InvocationException(Status.SERVICE_UNAVAILABLE, + new CommonExceptionData("Policy \" + circuitBreakerPolicy.getName() + \" forced open and deny requests\""))); + } + + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + + addCircuitBreaker(dcs, request); + + CompletableFuture future = new CompletableFuture<>(); + + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + if (e instanceof CallNotPermittedException) { + LOGGER.warn("instance isolation circuitBreaker is open by policy : {}", e.getMessage()); + discoveryManager.onInstanceIsolated(invocation.getEndpoint().getMicroserviceInstance(), + Duration.parse(circuitBreakerPolicy.getWaitDurationInOpenState()).toMillis()); + // return 503 so that consumer can retry + future.complete(Response.failResp(new InvocationException(Status.SERVICE_UNAVAILABLE, + new CommonExceptionData("instance isolation circuitBreaker is open.")))); + } else { + future.completeExceptionally(e); + } + }); + + return future; + } + + private void addCircuitBreaker(DecorateCompletionStage dcs, GovernanceRequestExtractor request) { + CircuitBreaker circuitBreaker = instanceIsolationHandler.getActuator(request); + if (circuitBreaker != null) { + dcs.withCircuitBreaker(circuitBreaker); + } + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/HandlerGovernanceConfiguration.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/HandlerGovernanceConfiguration.java new file mode 100644 index 00000000000..9223146a759 --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/HandlerGovernanceConfiguration.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.handler.governance; + +import org.apache.servicecomb.governance.handler.BulkheadHandler; +import org.apache.servicecomb.governance.handler.CircuitBreakerHandler; +import org.apache.servicecomb.governance.handler.InstanceBulkheadHandler; +import org.apache.servicecomb.governance.handler.InstanceIsolationHandler; +import org.apache.servicecomb.governance.handler.RateLimitingHandler; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = HandlerGovernanceConfiguration.GOVERNANCE_ENABLED, + havingValue = "true", matchIfMissing = true) +public class HandlerGovernanceConfiguration { + public static final String GOVERNANCE_PREFIX = "servicecomb.governance"; + + public static final String GOVERNANCE_ENABLED = GOVERNANCE_PREFIX + ".enabled"; + + @Bean + public ConsumerInstanceBulkheadFilter scbConsumerInstanceBulkheadFilter( + InstanceBulkheadHandler instanceBulkheadHandler) { + return new ConsumerInstanceBulkheadFilter(instanceBulkheadHandler); + } + + @Bean + public ConsumerInstanceIsolationFilter scbConsumerInstanceIsolationFilter( + InstanceIsolationHandler instanceIsolationHandler) { + return new ConsumerInstanceIsolationFilter(instanceIsolationHandler); + } + + @Bean + public ProviderBulkheadFilter scbProviderBulkheadFilter(BulkheadHandler bulkheadHandler) { + return new ProviderBulkheadFilter(bulkheadHandler); + } + + @Bean + public ProviderCircuitBreakerFilter scbProviderCircuitBreakerFilter(CircuitBreakerHandler circuitBreakerHandler) { + return new ProviderCircuitBreakerFilter(circuitBreakerHandler); + } + + @Bean + public ProviderRateLimitingFilter scbProviderRateLimitingFilter(RateLimitingHandler rateLimitingHandler) { + return new ProviderRateLimitingFilter(rateLimitingHandler); + } +} diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderBulkheadFilter.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderBulkheadFilter.java new file mode 100644 index 00000000000..a68ebf08fb1 --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderBulkheadFilter.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.handler.governance; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.BulkheadHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.bulkhead.Bulkhead; +import io.github.resilience4j.bulkhead.BulkheadFullException; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; + +public class ProviderBulkheadFilter extends AbstractFilter implements ProviderFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderBulkheadFilter.class); + + private final BulkheadHandler bulkheadHandler; + + @Autowired + public ProviderBulkheadFilter(BulkheadHandler bulkheadHandler) { + this.bulkheadHandler = bulkheadHandler; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 1880; + } + + @Override + public String getName() { + return "provider-bulkhead"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + + addBulkhead(dcs, request); + + CompletableFuture future = new CompletableFuture<>(); + + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + if (e instanceof BulkheadFullException) { + future.completeExceptionally( + new InvocationException(429, "bulkhead is full and does not permit further calls.", + new CommonExceptionData("bulkhead is full and does not permit further calls."))); + LOGGER.warn("bulkhead is full and does not permit further calls by policy : {}", e.getMessage()); + } else { + future.completeExceptionally(e); + } + }); + + return future; + } + + private void addBulkhead(DecorateCompletionStage dcs, GovernanceRequestExtractor request) { + Bulkhead bulkhead = bulkheadHandler.getActuator(request); + if (bulkhead != null) { + dcs.withBulkhead(bulkhead); + } + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderCircuitBreakerFilter.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderCircuitBreakerFilter.java new file mode 100644 index 00000000000..dbc0b8978c6 --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderCircuitBreakerFilter.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.handler.governance; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.CircuitBreakerHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.circuitbreaker.CallNotPermittedException; +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; + +public class ProviderCircuitBreakerFilter extends AbstractFilter implements ProviderFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderCircuitBreakerFilter.class); + + private final CircuitBreakerHandler circuitBreakerHandler; + + @Autowired + public ProviderCircuitBreakerFilter(CircuitBreakerHandler circuitBreakerHandler) { + this.circuitBreakerHandler = circuitBreakerHandler; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 1890; + } + + @Override + public String getName() { + return "provider-circuit-breaker"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + + addCircuitBreaker(dcs, request); + + CompletableFuture future = new CompletableFuture<>(); + + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + if (e instanceof CallNotPermittedException) { + future.completeExceptionally(new InvocationException(429, "circuitBreaker is open.", + new CommonExceptionData("circuitBreaker is open."))); + LOGGER.warn("circuitBreaker is open by policy : {}", e.getMessage()); + } else { + future.completeExceptionally(e); + } + }); + + return future; + } + + private void addCircuitBreaker(DecorateCompletionStage dcs, GovernanceRequestExtractor request) { + CircuitBreaker circuitBreaker = circuitBreakerHandler.getActuator(request); + if (circuitBreaker != null) { + dcs.withCircuitBreaker(circuitBreaker); + } + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderRateLimitingFilter.java b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderRateLimitingFilter.java new file mode 100644 index 00000000000..732fcf48ab5 --- /dev/null +++ b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderRateLimitingFilter.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.handler.governance; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.governance.handler.RateLimitingHandler; +import org.apache.servicecomb.governance.marker.GovernanceRequestExtractor; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage; +import io.github.resilience4j.ratelimiter.RateLimiter; +import io.github.resilience4j.ratelimiter.RequestNotPermitted; + +public class ProviderRateLimitingFilter extends AbstractFilter implements ProviderFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderRateLimitingFilter.class); + + private final RateLimitingHandler rateLimitingHandler; + + @Autowired + public ProviderRateLimitingFilter(RateLimitingHandler rateLimitingHandler) { + this.rateLimitingHandler = rateLimitingHandler; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 1900; + } + + @Override + public String getName() { + return "rate-limiting"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + + Supplier> next = createBusinessCompletionStageSupplier(invocation, nextNode); + DecorateCompletionStage dcs = Decorators.ofCompletionStage(next); + GovernanceRequestExtractor request = MatchType.createGovHttpRequest(invocation); + + addRateLimiting(dcs, request); + + CompletableFuture future = new CompletableFuture<>(); + + dcs.get().whenComplete((r, e) -> { + if (e == null) { + future.complete(r); + return; + } + + if (e instanceof RequestNotPermitted) { + future.completeExceptionally( + new InvocationException(429, "rate limited.", new CommonExceptionData("rate limited."))); + LOGGER.warn("the request is rate limit by policy : {}", e.getMessage()); + } else { + future.completeExceptionally(e); + } + }); + + return future; + } + + private void addRateLimiting(DecorateCompletionStage dcs, GovernanceRequestExtractor request) { + RateLimiter rateLimiter = rateLimitingHandler.getActuator(request); + if (rateLimiter != null) { + dcs.withRateLimiter(rateLimiter); + } + } + + private Supplier> createBusinessCompletionStageSupplier(Invocation invocation, + FilterNode nextNode) { + return () -> nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..1e25fbf7679 --- /dev/null +++ b/handlers/handler-governance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.handler.governance.HandlerGovernanceConfiguration diff --git a/handlers/handler-loadbalance/pom.xml b/handlers/handler-loadbalance/pom.xml index 2fff5c6db1b..0fd42dce838 100644 --- a/handlers/handler-loadbalance/pom.xml +++ b/handlers/handler-loadbalance/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb handlers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT handler-loadbalance @@ -37,54 +37,36 @@ java-chassis-core - com.netflix.ribbon - ribbon + org.apache.commons + commons-lang3 - com.netflix.ribbon - ribbon-loadbalancer + io.github.resilience4j + resilience4j-all - com.netflix.ribbon - ribbon-core - - - com.netflix.archaius - archaius-core - - - io.reactivex - rxjava - - - commons-lang - commons-lang - - - - com.netflix.servo - servo-core - provided - - - com.google.code.findbugs - annotations - provided + org.apache.servicecomb + registry-local + test - org.apache.servicecomb foundation-test-scaffolding test - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core test - log4j - log4j + org.jmockit + jmockit test diff --git a/handlers/handler-loadbalance/readme.MD b/handlers/handler-loadbalance/readme.MD index 335e494ba88..53b4ef30d91 100644 --- a/handlers/handler-loadbalance/readme.MD +++ b/handlers/handler-loadbalance/readme.MD @@ -1,6 +1,6 @@ 参考: https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers LoadBalancer -Rule -Ping +Rule +Ping ServerList ServerListFilter diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java deleted file mode 100644 index d70bfb279d2..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.loadbalance; - -import java.util.List; - -import javax.inject.Inject; - -import org.springframework.stereotype.Component; - -@Component -public class BeansHolder { - @Inject - private List extentionsFactories; - - public void init() { - for (ExtensionsFactory extension : this.extentionsFactories) { - ExtensionsManager.addExtentionsFactory(extension); - } - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/Configuration.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/Configuration.java index fd3190f6b4c..87a527c9aff 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/Configuration.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/Configuration.java @@ -19,201 +19,103 @@ import java.util.Map; -import org.apache.servicecomb.serviceregistry.config.ConfigurePropertyUtils; - -import com.netflix.config.DynamicPropertyFactory; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; /** * configuration items - * */ public final class Configuration { //// 2.1 configuration items - public static final String PROP_ROOT = "servicecomb.loadbalance."; - - public static final String RPOP_SERVER_EXPIRED_IN_SECONDS = "servicecomb.loadbalance.stats.serverExpiredInSeconds"; + public static final String ROOT = "servicecomb.loadbalance."; - public static final String RPOP_TIMER_INTERVAL_IN_MINIS = "servicecomb.loadbalance.stats.timerIntervalInMilis"; + public static final String RULE_STRATEGY_GLOBAL = "servicecomb.loadbalance.strategy.name"; - public static final String PROP_RULE_STRATEGY_NAME = "strategy.name"; + public static final String RULE_STRATEGY_NAME = "strategy.name"; // 2.0 configuration items - public static final String PROP_ROOT_20 = "ribbon."; - - // retry configurations - public static final String PROP_RETRY_HANDLER = "retryHandler"; - - public static final String PROP_RETRY_ENABLED = "retryEnabled"; - - public static final String PROP_RETRY_ONNEXT = "retryOnNext"; + public static final String ROOT_20 = "ribbon."; - public static final String PROP_RETRY_ONSAME = "retryOnSame"; - - // SessionStickinessRule configruation + // SessionStickinessRule configuration public static final String SESSION_TIMEOUT_IN_SECONDS = "SessionStickinessRule.sessionTimeoutInSeconds"; public static final String SUCCESSIVE_FAILED_TIMES = "SessionStickinessRule.successiveFailedTimes"; - private static final double PERCENT = 100; - public static final String FILTER_ISOLATION = "isolation."; - public static final String FILTER_OPEN = "enabled"; - - public static final String FILTER_ERROR_PERCENTAGE = "errorThresholdPercentage"; - - public static final String FILTER_ENABLE_REQUEST = "enableRequestThreshold"; - - public static final String FILTER_SINGLE_TEST = "singleTestTime"; - - public static final String FILTER_MIN_ISOLATION_TIME = "minIsolationTime"; - - public static final String FILTER_CONTINUOUS_FAILURE_THRESHOLD = "continuousFailureThreshold"; + public static final String FILTER_MAX_SINGLE_TEST_WINDOW = "maxSingleTestWindow"; public static final String TRANSACTIONCONTROL_OPTIONS_PREFIX_PATTERN = "servicecomb.loadbalance.%s.transactionControl.options"; public static final Configuration INSTANCE = new Configuration(); - private Configuration() { - } + public record RuleType(int type, String value) { + public static final int TYPE_SCHEMA = 1; - public String getRuleStrategyName(String microservice) { - return getStringProperty(null, - PROP_ROOT + microservice + "." + PROP_RULE_STRATEGY_NAME, - PROP_ROOT + PROP_RULE_STRATEGY_NAME); - } + public static final int TYPE_OPERATION = 2; - public int getSessionTimeoutInSeconds(String microservice) { - final int defaultValue = 30; - String p = getStringProperty("30", - PROP_ROOT + microservice + "." + SESSION_TIMEOUT_IN_SECONDS, - PROP_ROOT + SESSION_TIMEOUT_IN_SECONDS); - try { - return Integer.parseInt(p); // can be negative - } catch (NumberFormatException e) { - return defaultValue; + public String getValue() { + return value; } - } - public int getSuccessiveFailedTimes(String microservice) { - final int defaultValue = 5; - String p = getStringProperty("5", - PROP_ROOT + microservice + "." + SUCCESSIVE_FAILED_TIMES, - PROP_ROOT + SUCCESSIVE_FAILED_TIMES); - try { - return Integer.parseInt(p); // can be negative - } catch (NumberFormatException e) { - return defaultValue; + public int getType() { + return type; } } - public String getRetryHandler(String microservice) { - return getStringProperty("default", - PROP_ROOT + microservice + "." + PROP_RETRY_HANDLER, - PROP_ROOT + PROP_RETRY_HANDLER); - } - - public boolean isRetryEnabled(String microservice) { - String p = getStringProperty("false", - PROP_ROOT + microservice + "." + PROP_RETRY_ENABLED, - PROP_ROOT + PROP_RETRY_ENABLED); - return Boolean.parseBoolean(p); + private Configuration() { } - public int getRetryOnNext(String microservice) { - final int defaultValue = 0; - String p = getStringProperty("0", - PROP_ROOT + microservice + "." + PROP_RETRY_ONNEXT, - PROP_ROOT + PROP_RETRY_ONNEXT); - try { - int result = Integer.parseInt(p); - if (result > 0) { - return result; - } - return defaultValue; - } catch (NumberFormatException e) { - return defaultValue; + public RuleType getRuleStrategyName(Invocation invocation) { + String value = getStringProperty(null, ROOT + invocation.getMicroserviceName() + "." + + invocation.getSchemaId() + "." + invocation.getOperationName() + "." + RULE_STRATEGY_NAME); + if (value != null) { + return new RuleType(RuleType.TYPE_OPERATION, value); } - } - - public int getRetryOnSame(String microservice) { - final int defaultValue = 0; - String p = getStringProperty("0", - PROP_ROOT + microservice + "." + PROP_RETRY_ONSAME, - PROP_ROOT + PROP_RETRY_ONSAME); - try { - int result = Integer.parseInt(p); - if (result > 0) { - return result; - } - return defaultValue; - } catch (NumberFormatException e) { - return defaultValue; + value = getStringProperty(null, ROOT + invocation.getMicroserviceName() + "." + + invocation.getSchemaId() + "." + RULE_STRATEGY_NAME); + if (value != null) { + return new RuleType(RuleType.TYPE_SCHEMA, value); } + value = getStringProperty(null, ROOT + invocation.getMicroserviceName() + "." + + RULE_STRATEGY_NAME); + if (value != null) { + return new RuleType(RuleType.TYPE_SCHEMA, value); + } + return new RuleType(RuleType.TYPE_SCHEMA, + getStringProperty("RoundRobin", RULE_STRATEGY_GLOBAL)); } - public boolean isIsolationFilterOpen(String microservice) { - String p = getStringProperty("true", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_OPEN, - PROP_ROOT + FILTER_ISOLATION + FILTER_OPEN); - return Boolean.parseBoolean(p); - } - - public int getErrorThresholdPercentage(String microservice) { - final int defaultValue = 0; - String p = getStringProperty("0", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_ERROR_PERCENTAGE, - PROP_ROOT + FILTER_ISOLATION + FILTER_ERROR_PERCENTAGE); + public int getSessionTimeoutInSeconds(String microservice) { + final int defaultValue = 30; + String p = getStringProperty("30", + ROOT + microservice + "." + SESSION_TIMEOUT_IN_SECONDS, + ROOT + SESSION_TIMEOUT_IN_SECONDS); try { - int result = Integer.parseInt(p); - if (result <= PERCENT && result > 0) { - return result; - } - return defaultValue; + return Integer.parseInt(p); // can be negative } catch (NumberFormatException e) { return defaultValue; } } - public int getEnableRequestThreshold(String microservice) { + public int getSuccessiveFailedTimes(String microservice) { final int defaultValue = 5; String p = getStringProperty("5", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_ENABLE_REQUEST, - PROP_ROOT + FILTER_ISOLATION + FILTER_ENABLE_REQUEST); + ROOT + microservice + "." + SUCCESSIVE_FAILED_TIMES, + ROOT + SUCCESSIVE_FAILED_TIMES); try { - int result = Integer.parseInt(p); - if (result > 0) { - return result; - } - return defaultValue; + return Integer.parseInt(p); // can be negative } catch (NumberFormatException e) { return defaultValue; } } - public int getSingleTestTime(String microservice) { + public int getMaxSingleTestWindow() { final int defaultValue = 60000; - String p = getStringProperty("60000", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_SINGLE_TEST, - PROP_ROOT + FILTER_ISOLATION + FILTER_SINGLE_TEST); - try { - int result = Integer.parseInt(p); - if (result >= 0) { - return result; - } - return defaultValue; - - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public int getMinIsolationTime(String microservice) { - final int defaultValue = 3000; // 3 seconds - String p = getStringProperty("3000", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_MIN_ISOLATION_TIME, - PROP_ROOT + FILTER_ISOLATION + FILTER_MIN_ISOLATION_TIME); + String p = getStringProperty(Integer.toString(defaultValue), + ROOT + FILTER_ISOLATION + FILTER_MAX_SINGLE_TEST_WINDOW); try { int result = Integer.parseInt(p); if (result >= 0) { @@ -227,34 +129,17 @@ public int getMinIsolationTime(String microservice) { public Map getFlowsplitFilterOptions(String microservice) { String keyPrefix = String.format(TRANSACTIONCONTROL_OPTIONS_PREFIX_PATTERN, microservice); - return ConfigurePropertyUtils.getPropertiesWithPrefix(keyPrefix); + return ConfigUtil.stringPropertiesWithPrefix(LegacyPropertyFactory.getEnvironment(), keyPrefix); } public static String getStringProperty(String defaultValue, String... keys) { - String property = null; + String property; for (String key : keys) { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); + property = LegacyPropertyFactory.getStringProperty(key); if (property != null) { return property; } } - return defaultValue; } - - public int getContinuousFailureThreshold(String microservice) { - final int defaultValue = 5; - String p = getStringProperty("5", - PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_CONTINUOUS_FAILURE_THRESHOLD, - PROP_ROOT + FILTER_ISOLATION + FILTER_CONTINUOUS_FAILURE_THRESHOLD); - try { - int result = Integer.parseInt(p); - if (result > 0) { - return result; - } - return defaultValue; - } catch (NumberFormatException e) { - return defaultValue; - } - } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java deleted file mode 100644 index f8ab374ab16..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/DefaultRetryExtensionsFactory.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.loadbalance; - -import java.io.IOException; -import java.net.ConnectException; -import java.net.NoRouteToHostException; -import java.net.SocketTimeoutException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.springframework.stereotype.Component; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.netflix.client.DefaultLoadBalancerRetryHandler; -import com.netflix.client.RetryHandler; - -import io.vertx.core.VertxException; - -@Component -public class DefaultRetryExtensionsFactory implements ExtensionsFactory { - private static final Collection ACCEPT_KEYS = Lists.newArrayList( - Configuration.PROP_RETRY_HANDLER); - - private static final String RETRY_DEFAULT = "default"; - - private static final Collection ACCEPT_VALUES = Lists.newArrayList( - RETRY_DEFAULT); - - private static final Map, List> strictRetriable = - ImmutableMap., List>builder() - .put(ConnectException.class, Arrays.asList()) - .put(SocketTimeoutException.class, Arrays.asList()) - /* - * deal with some special exceptions caused by the server side close the connection - */ - .put(IOException.class, Arrays.asList(new String[] {"Connection reset by peer"})) - .put(VertxException.class, Arrays.asList(new String[] {"Connection was closed"})) - .put(NoRouteToHostException.class, Arrays.asList(new String[]{"Host is unreachable"})) - .build(); - - @Override - public boolean isSupport(String key, String value) { - return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value); - } - - public RetryHandler createRetryHandler(String retryName, String microservice) { - return new DefaultLoadBalancerRetryHandler( - Configuration.INSTANCE.getRetryOnSame(microservice), - Configuration.INSTANCE.getRetryOnNext(microservice), true) { - - @Override - public boolean isRetriableException(Throwable e, boolean sameServer) { - boolean retriable = isPresentAsCause(e); - if (!retriable) { - if (e instanceof InvocationException) { - if (((InvocationException) e).getStatusCode() == 503) { - return true; - } - } - } - return retriable; - } - - public boolean isPresentAsCause(Throwable throwableToSearchIn) { - int infiniteLoopPreventionCounter = 10; - while (throwableToSearchIn != null && infiniteLoopPreventionCounter > 0) { - infiniteLoopPreventionCounter--; - for (Entry, List> c : strictRetriable.entrySet()) { - Class key = c.getKey(); - if (key.isAssignableFrom(throwableToSearchIn.getClass())) { - if (c.getValue() == null || c.getValue().isEmpty()) { - return true; - } else { - String msg = throwableToSearchIn.getMessage(); - for (String val : c.getValue()) { - if (val.equals(msg)) { - return true; - } - } - } - } - } - throwableToSearchIn = throwableToSearchIn.getCause(); - } - return false; - } - }; - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsFactory.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsFactory.java index ce3dca449ab..dc4cd6b6082 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsFactory.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsFactory.java @@ -16,8 +16,6 @@ */ package org.apache.servicecomb.loadbalance; -import com.netflix.client.RetryHandler; - /** * By implements ExtensionsFactory, users can add new extends for rules, filters, etc. */ @@ -27,12 +25,4 @@ public interface ExtensionsFactory { default RuleExt createLoadBalancerRule(String ruleName) { return null; } - - default ServerListFilterExt createServerListFilter(String key, String value, Object... args) { - return null; - } - - default RetryHandler createRetryHandler(String retryName, String microservice) { - return null; - } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsManager.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsManager.java index 2df039560b4..2187f59e789 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsManager.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ExtensionsManager.java @@ -16,31 +16,21 @@ */ package org.apache.servicecomb.loadbalance; -import java.util.ArrayList; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.client.RetryHandler; - public class ExtensionsManager { - private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionsManager.class); - - private static List extentionFactories = new ArrayList<>(); + private final List extensionsFactories; - public static void addExtentionsFactory(ExtensionsFactory factory) { - extentionFactories.add(factory); + public ExtensionsManager(List extensionsFactories) { + this.extensionsFactories = extensionsFactories; } - public static RuleExt createLoadBalancerRule(String microservice) { + public RuleExt createLoadBalancerRule(String ruleStrategyName) { RuleExt rule = null; - for (ExtensionsFactory factory : extentionFactories) { - if (factory.isSupport(Configuration.PROP_RULE_STRATEGY_NAME, - Configuration.INSTANCE.getRuleStrategyName(microservice))) { - rule = factory.createLoadBalancerRule( - Configuration.INSTANCE.getRuleStrategyName(microservice)); + for (ExtensionsFactory factory : extensionsFactories) { + if (factory.isSupport(Configuration.RULE_STRATEGY_NAME, ruleStrategyName)) { + rule = factory.createLoadBalancerRule(ruleStrategyName); break; } } @@ -49,21 +39,6 @@ public static RuleExt createLoadBalancerRule(String microservice) { rule = new RoundRobinRuleExt(); } - LOGGER.info("Using load balance rule {} for microservice {}.", rule.getClass().getName(), microservice); return rule; } - - public static RetryHandler createRetryHandler(String microservice) { - RetryHandler handler = null; - for (ExtensionsFactory factory : extentionFactories) { - if (factory.isSupport(Configuration.PROP_RETRY_HANDLER, Configuration.INSTANCE.getRetryHandler(microservice))) { - handler = factory.createRetryHandler(Configuration.INSTANCE.getRetryHandler(microservice), microservice); - break; - } - } - - // handler can not be null. handler will be created for each invocation. - LOGGER.debug("Using retry handler {} for microservice {}.", handler.getClass().getName(), microservice); - return handler; - } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceConfiguration.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceConfiguration.java new file mode 100644 index 00000000000..d65726e0ada --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceConfiguration.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.loadbalance; + +import java.util.List; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.loadbalance.filter.InstancePropertyDiscoveryFilter; +import org.apache.servicecomb.loadbalance.filter.PriorityInstancePropertyDiscoveryFilter; +import org.apache.servicecomb.loadbalance.filter.ServerDiscoveryFilter; +import org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = LoadBalanceConfiguration.LOAD_BALANCE_ENABLED, + havingValue = "true", matchIfMissing = true) +public class LoadBalanceConfiguration { + public static final String LOAD_BALANCE_PREFIX = "servicecomb.loadbalance"; + + public static final String LOAD_BALANCE_ENABLED = LOAD_BALANCE_PREFIX + ".enabled"; + + @Bean + public LoadBalanceFilter scbLoadBalanceFilter(ExtensionsManager extensionsManager, DiscoveryTree discoveryTree, + SCBEngine scbEngine) { + return new LoadBalanceFilter(extensionsManager, discoveryTree, scbEngine); + } + + @Bean + public RuleNameExtensionsFactory scbRuleNameExtensionsFactory() { + return new RuleNameExtensionsFactory(); + } + + @Bean + public ExtensionsManager scbExtensionsManager(List extensionsFactories) { + return new ExtensionsManager(extensionsFactories); + } + + @Bean + public PriorityInstancePropertyDiscoveryFilter scbPriorityInstancePropertyDiscoveryFilter() { + return new PriorityInstancePropertyDiscoveryFilter(); + } + + @Bean + public InstancePropertyDiscoveryFilter scbInstancePropertyDiscoveryFilter() { + return new InstancePropertyDiscoveryFilter(); + } + + @Bean + public ServerDiscoveryFilter scbServerDiscoveryFilter() { + return new ServerDiscoveryFilter(); + } + + @Bean + public ZoneAwareDiscoveryFilter scbZoneAwareDiscoveryFilter() { + return new ZoneAwareDiscoveryFilter(); + } +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceFilter.java new file mode 100644 index 00000000000..e97263ac465 --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalanceFilter.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.loadbalance; + +import java.net.URI; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.governance.RetryContext; +import org.apache.servicecomb.foundation.common.cache.VersionedCache; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.loadbalance.Configuration.RuleType; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.eventbus.Subscribe; + +import io.github.resilience4j.core.metrics.Metrics.Outcome; +import jakarta.ws.rs.core.Response.Status; + +public class LoadBalanceFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + public static final String CONTEXT_KEY_LAST_SERVER = "x-context-last-server"; + + // Enough times to make sure to choose a different server in high volume. + private static final int COUNT = 17; + + public static final String CONTEXT_KEY_SERVER_LIST = "x-context-server-list"; + + public static final String SERVICECOMB_SERVER_ENDPOINT = "scb-endpoint"; + + private static final Logger LOGGER = LoggerFactory.getLogger(LoadBalanceFilter.class); + + private final DiscoveryTree discoveryTree; + + // key为grouping filter qualified name + private final Map loadBalancerMap = new ConcurrentHashMapEx<>(); + + private final Object lock = new Object(); + + private final ExtensionsManager extensionsManager; + + private final SCBEngine scbEngine; + + // set endpoint in invocation.localContext + // ignore logic of loadBalance + public boolean supportDefinedEndpoint; + + @Autowired + public LoadBalanceFilter(ExtensionsManager extensionsManager, + DiscoveryTree discoveryTree, SCBEngine scbEngine) { + preCheck(scbEngine); + this.scbEngine = scbEngine; + this.supportDefinedEndpoint = this.scbEngine.getEnvironment() + .getProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled", + boolean.class, false); + this.extensionsManager = extensionsManager; + this.discoveryTree = discoveryTree; + EventManager.register(this); + } + + @Subscribe + @SuppressWarnings("unused") + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + Set changedKeys = event.getChanged(); + for (String key : changedKeys) { + if (key.startsWith(Configuration.ROOT)) { + synchronized (lock) { + clearLoadBalancer(); + } + LOGGER.info("clear load balance rule for configuration changed, {}", key); + break; + } + } + } + + private void preCheck(SCBEngine scbEngine) { + // Old configurations check.Just print an error, because configurations may given in dynamic and fail on runtime. + String policyName = scbEngine.getEnvironment() + .getProperty("servicecomb.loadbalance.NFLoadBalancerRuleClassName"); + if (!StringUtils.isEmpty(policyName)) { + LOGGER.error("[servicecomb.loadbalance.NFLoadBalancerRuleClassName] is not supported anymore." + + "use [servicecomb.loadbalance.strategy.name] instead."); + } + + String filterNames = scbEngine.getEnvironment() + .getProperty("servicecomb.loadbalance.serverListFilters"); + if (!StringUtils.isEmpty(filterNames)) { + LOGGER.error( + "Server list implementation changed to SPI. Configuration [servicecomb.loadbalance.serverListFilters]" + + " is not used any more. For ServiceComb defined filters, you do not need config and can " + + "remove this configuration safely. If you define your own filter, need to change it to SPI to make it work."); + } + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER; + } + + @Override + public String getName() { + return "load-balance"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + try { + if (handleSuppliedEndpoint(invocation)) { + invocation.addLocalContext(RetryContext.RETRY_LOAD_BALANCE, false); + return nextNode.onFilter(invocation); + } + } catch (Exception e) { + return CompletableFuture.failedFuture(e); + } + + invocation.addLocalContext(RetryContext.RETRY_LOAD_BALANCE, true); + + LoadBalancer loadBalancer = getOrCreateLoadBalancer(invocation); + + return send(invocation, nextNode, loadBalancer); + } + + // user's can invoke a service by supplying target Endpoint. + // in this case, do not use load balancer, and no stats of server calculated, no retrying. + private boolean handleSuppliedEndpoint(Invocation invocation) throws Exception { + if (invocation.isEdge()) { + return false; + } + if (invocation.getEndpoint() != null) { + return true; + } + + if (supportDefinedEndpoint) { + return defineEndpointAndHandle(invocation); + } + + return false; + } + + private Endpoint parseEndpoint(String endpointUri) throws Exception { + URI formatUri = new URI(endpointUri); + Transport transport = scbEngine.getTransportManager().findTransport(formatUri.getScheme()); + if (transport == null) { + LOGGER.error("not deployed transport {}, ignore {}.", formatUri.getScheme(), endpointUri); + throw new InvocationException(Status.BAD_REQUEST, + "the endpoint's transport is not found."); + } + return new Endpoint(transport, endpointUri); + } + + private boolean defineEndpointAndHandle(Invocation invocation) throws Exception { + Object endpoint = invocation.getLocalContext(SERVICECOMB_SERVER_ENDPOINT); + if (endpoint == null) { + return false; + } + if (endpoint instanceof String) { + // compatible to old usage + endpoint = parseEndpoint((String) endpoint); + } + + invocation.setEndpoint((Endpoint) endpoint); + return true; + } + + private void clearLoadBalancer() { + loadBalancerMap.clear(); + } + + @VisibleForTesting + CompletableFuture send(Invocation invocation, FilterNode filterNode, LoadBalancer chosenLB) { + long time = System.currentTimeMillis(); + ServiceCombServer server = chooseServer(invocation, chosenLB); + if (null == server) { + return CompletableFuture.failedFuture( + new InvocationException(Status.INTERNAL_SERVER_ERROR, + String.format("No available address found for %s/%s.", invocation.getAppId(), + invocation.getMicroserviceName()))); + } + invocation.setEndpoint(server.getEndpoint()); + return filterNode.onFilter(invocation).whenComplete((r, e) -> { + if (e != null || isFailedResponse(r)) { + server.getServerMetrics().record((System.currentTimeMillis() - time), TimeUnit.MILLISECONDS, Outcome.ERROR); + } else { + server.getServerMetrics().record((System.currentTimeMillis() - time), TimeUnit.MILLISECONDS, Outcome.SUCCESS); + } + }); + } + + private ServiceCombServer chooseServer(Invocation invocation, LoadBalancer chosenLB) { + RetryContext retryContext = invocation.getLocalContext(RetryContext.RETRY_CONTEXT); + if (retryContext == null) { + return chosenLB.chooseServer(invocation); + } + + if (!retryContext.isRetry()) { + ServiceCombServer server = chosenLB.chooseServer(invocation); + invocation.addLocalContext(CONTEXT_KEY_LAST_SERVER, server); + return server; + } + + ServiceCombServer lastServer = invocation.getLocalContext(CONTEXT_KEY_LAST_SERVER); + ServiceCombServer nextServer = lastServer; + if (!retryContext.trySameServer()) { + for (int i = 0; i < COUNT; i++) { + ServiceCombServer s = chosenLB.chooseServer(invocation); + if (s == null) { + break; + } + if (!s.equals(nextServer)) { + nextServer = s; + break; + } + } + } + + LOGGER.warn("operation failed {}, retry to instance [{}], last instance [{}], trace id {}", + invocation.getMicroserviceQualifiedName(), + nextServer == null ? "" : nextServer.getEndpoint().getEndpoint(), + lastServer == null ? "" : nextServer.getEndpoint().getEndpoint(), + invocation.getTraceId()); + invocation.addLocalContext(CONTEXT_KEY_LAST_SERVER, nextServer); + return nextServer; + } + + protected boolean isFailedResponse(Response resp) { + if (resp.isFailed()) { + if (resp.getResult() instanceof InvocationException) { + InvocationException e = resp.getResult(); + return e.getStatusCode() == ExceptionFactory.CONSUMER_INNER_STATUS_CODE + || e.getStatusCode() == Status.SERVICE_UNAVAILABLE.getStatusCode() + || e.getStatusCode() == Status.REQUEST_TIMEOUT.getStatusCode(); + } else { + return true; + } + } else { + return false; + } + } + + protected LoadBalancer getOrCreateLoadBalancer(Invocation invocation) { + DiscoveryContext context = new DiscoveryContext(); + context.setInputParameters(invocation); + VersionedCache serversVersionedCache = discoveryTree.discovery(context, + invocation.getAppId(), + invocation.getMicroserviceName()); + invocation.addLocalContext(CONTEXT_KEY_SERVER_LIST, serversVersionedCache.data()); + + RuleType ruleType = Configuration.INSTANCE.getRuleStrategyName(invocation); + String cacheKey; + if (ruleType.getType() == RuleType.TYPE_SCHEMA) { + cacheKey = invocation.getAppId() + "-" + + invocation.getMicroserviceName() + "-" + invocation.getSchemaId(); + } else { + cacheKey = invocation.getAppId() + "-" + + invocation.getMicroserviceName() + "-" + invocation.getSchemaId() + "-" + invocation.getOperationName(); + } + return loadBalancerMap.computeIfAbsent(cacheKey, + key -> createLoadBalancer(ruleType, key, invocation.getMicroserviceName())); + } + + private LoadBalancer createLoadBalancer(RuleType ruleType, String cacheKey, String microserviceName) { + RuleExt rule = extensionsManager.createLoadBalancerRule(ruleType.getValue()); + LOGGER.info("Using load balance rule {} for microservice {}.", rule.getClass().getName(), cacheKey); + return new LoadBalancer(rule, microserviceName); + } +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java index bcc9fea7b40..d60581ff5f0 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java @@ -22,28 +22,28 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; -import com.netflix.loadbalancer.LoadBalancerStats; /** * A load balancer with RuleExt and ServerListFilterExt */ public class LoadBalancer { - private static AtomicInteger id = new AtomicInteger(0); + private static final Logger LOGGER = LoggerFactory.getLogger(LoadBalancer.class); - private RuleExt rule; + private static final AtomicInteger id = new AtomicInteger(0); - private LoadBalancerStats lbStats; + private final RuleExt rule; - private String microServiceName; + private final String microServiceName; private List filters; public LoadBalancer(RuleExt rule, String microServiceName) { this.microServiceName = microServiceName; this.rule = rule; - this.lbStats = new LoadBalancerStats(microServiceName + id.getAndDecrement()); // load new instances, because filters work on service information this.filters = SPIServiceUtils.loadSortedService(ServerListFilterExt.class); this.rule.setLoadBalancer(this); @@ -51,15 +51,23 @@ public LoadBalancer(RuleExt rule, String microServiceName) { } public ServiceCombServer chooseServer(Invocation invocation) { - List servers = invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST); + List servers = invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST); + int serversCount = servers.size(); for (ServerListFilterExt filterExt : filters) { + if (!filterExt.enabled()) { + continue; + } servers = filterExt.getFilteredListOfServers(servers, invocation); + if (servers.isEmpty() && serversCount > 0) { + LOGGER.warn("There are not servers exist after filtered by {}.", filterExt.getClass()); + break; + } } - return rule.choose(servers, invocation); - } - - public LoadBalancerStats getLoadBalancerStats() { - return lbStats; + ServiceCombServer server = rule.choose(servers, invocation); + if (null == server) { + return null; + } + return server; } public String getMicroServiceName() { diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceClientConfig.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceClientConfig.java deleted file mode 100644 index ce55008ca34..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceClientConfig.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import com.netflix.client.config.DefaultClientConfigImpl; - -/** - * 配置转换(暂时没有配置项,待新增) - * - */ -public class LoadbalanceClientConfig extends DefaultClientConfigImpl { - private static final String PREFIX = "servicecomb.loadbalance"; - - public LoadbalanceClientConfig(String namespace) { - super(namespace); - loadProperties(PREFIX); - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java deleted file mode 100644 index 20d31a4522b..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.ws.rs.core.Response.Status; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.provider.consumer.SyncResponseExecutor; -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; -import org.apache.servicecomb.loadbalance.filter.ServerDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.loadbalancer.ILoadBalancer; -import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.reactive.ExecutionContext; -import com.netflix.loadbalancer.reactive.ExecutionInfo; -import com.netflix.loadbalancer.reactive.ExecutionListener; -import com.netflix.loadbalancer.reactive.LoadBalancerCommand; -import com.netflix.loadbalancer.reactive.ServerOperation; - -import rx.Observable; - -/** - * Load balance handler. - */ -public class LoadbalanceHandler implements Handler { - public static final String CONTEXT_KEY_SERVER_LIST = "x-context-server-list"; - - public static final String SERVICECOMB_SERVER_ENDPOINT = "scb-endpoint"; - - public static final boolean supportDefinedEndpoint = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled", false).get(); - - // just a wrapper to make sure in retry mode to choose a different server. - class RetryLoadBalancer implements ILoadBalancer { - // Enough times to make sure to choose a different server in high volume. - static final int COUNT = 17; - - Server lastServer = null; - - LoadBalancer delegate; - - RetryLoadBalancer(LoadBalancer delegate) { - this.delegate = delegate; - } - - @Override - public void addServers(List newServers) { - throw new UnsupportedOperationException("Not implemented."); - } - - @Override - public Server chooseServer(Object key) { - for (int i = 0; i < COUNT; i++) { - Server s = delegate.chooseServer((Invocation) key); - if (s != null && !s.equals(lastServer)) { - lastServer = s; - break; - } - } - - return lastServer; - } - - - @Override - public void markServerDown(Server server) { - throw new UnsupportedOperationException("Not implemented."); - } - - @Override - @Deprecated - public List getServerList(boolean availableOnly) { - throw new UnsupportedOperationException("Not implemented."); - } - - @Override - public List getReachableServers() { - throw new UnsupportedOperationException("Not implemented."); - } - - @Override - public List getAllServers() { - throw new UnsupportedOperationException("Not implemented."); - } - } - - private static final Logger LOGGER = LoggerFactory.getLogger(LoadbalanceHandler.class); - - private static final ExecutorService RETRY_POOL = Executors.newCachedThreadPool(new ThreadFactory() { - private AtomicInteger count = new AtomicInteger(0); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "retry-pool-thread-" + count.getAndIncrement()); - // avoid block shutdown - thread.setDaemon(true); - return thread; - } - }); - - private DiscoveryTree discoveryTree = new DiscoveryTree(); - - // key为grouping filter qualified name - private volatile Map loadBalancerMap = new ConcurrentHashMapEx<>(); - - private final Object lock = new Object(); - - private String strategy = null; - - public LoadbalanceHandler(DiscoveryTree discoveryTree) { - this.discoveryTree = discoveryTree; - } - - public LoadbalanceHandler() { - preCheck(); - discoveryTree.loadFromSPI(DiscoveryFilter.class); - discoveryTree.addFilter(new ServerDiscoveryFilter()); - discoveryTree.sort(); - } - - private void preCheck() { - // Old configurations check.Just print an error, because configurations may given in dynamic and fail on runtime. - - String policyName = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.loadbalance.NFLoadBalancerRuleClassName", null) - .get(); - if (!StringUtils.isEmpty(policyName)) { - LOGGER.error("[servicecomb.loadbalance.NFLoadBalancerRuleClassName] is not supported anymore." + - "use [servicecomb.loadbalance.strategy.name] instead."); - } - - String filterNames = Configuration.getStringProperty(null, "servicecomb.loadbalance.serverListFilters"); - if (!StringUtils.isEmpty(filterNames)) { - LOGGER.error( - "Server list implementation changed to SPI. Configuration [servicecomb.loadbalance.serverListFilters]" + - " is not used any more. For ServiceComb defined filters, you do not need config and can " - + "remove this configuration safely. If you define your own filter, need to change it to SPI to make it work."); - } - } - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - if (supportDefinedEndpoint) { - if (defineEndpointAndHandle(invocation, asyncResp)) { - return; - } - } - - String strategy = Configuration.INSTANCE.getRuleStrategyName(invocation.getMicroserviceName()); - if (!isEqual(strategy, this.strategy)) { - //配置变化,需要重新生成所有的lb实例 - synchronized (lock) { - clearLoadBalancer(); - } - } - this.strategy = strategy; - - LoadBalancer loadBalancer = getOrCreateLoadBalancer(invocation); - - if (!Configuration.INSTANCE.isRetryEnabled(invocation.getMicroserviceName())) { - send(invocation, asyncResp, loadBalancer); - } else { - sendWithRetry(invocation, asyncResp, loadBalancer); - } - } - - private boolean defineEndpointAndHandle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - String endpointUri = invocation.getLocalContext(SERVICECOMB_SERVER_ENDPOINT); - if (endpointUri == null) { - return false; - } - URI formatUri = new URI(endpointUri); - Transport transport = SCBEngine.getInstance().getTransportManager().findTransport(formatUri.getScheme()); - if (transport == null) { - LOGGER.error("not deployed transport {}, ignore {}.", formatUri.getScheme(), endpointUri); - throw new InvocationException(Status.BAD_REQUEST, - "the endpoint's transport is not found."); - } - Endpoint endpoint = new Endpoint(transport, endpointUri); - invocation.setEndpoint(endpoint); - invocation.next(resp -> { - asyncResp.handle(resp); - }); - return true; - } - - private void clearLoadBalancer() { - loadBalancerMap.clear(); - } - - private void send(Invocation invocation, AsyncResponse asyncResp, final LoadBalancer chosenLB) throws Exception { - long time = System.currentTimeMillis(); - ServiceCombServer server = chosenLB.chooseServer(invocation); - if (null == server) { - asyncResp.consumerFail(new InvocationException(Status.INTERNAL_SERVER_ERROR, "No available address found.")); - return; - } - chosenLB.getLoadBalancerStats().incrementNumRequests(server); - invocation.setEndpoint(server.getEndpoint()); - invocation.next(resp -> { - // this stats is for WeightedResponseTimeRule - chosenLB.getLoadBalancerStats().noteResponseTime(server, (System.currentTimeMillis() - time)); - if (isFailedResponse(resp)) { - chosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(server); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server); - } else { - chosenLB.getLoadBalancerStats().incrementActiveRequestsCount(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - } - asyncResp.handle(resp); - }); - } - - private void sendWithRetry(Invocation invocation, AsyncResponse asyncResp, - final LoadBalancer chosenLB) throws Exception { - long time = System.currentTimeMillis(); - // retry in loadbalance, 2.0 feature - final int currentHandler = invocation.getHandlerIndex(); - - final SyncResponseExecutor orginExecutor; - final Executor newExecutor; - if (invocation.getResponseExecutor() instanceof SyncResponseExecutor) { - orginExecutor = (SyncResponseExecutor) invocation.getResponseExecutor(); - newExecutor = new Executor() { - @Override - public void execute(Runnable command) { - // retry的场景,对于同步调用, 同步调用的主线程已经被挂起,无法再主线程中进行重试; - // 重试也不能在网络线程(event-loop)中进行,未被保护的阻塞操作会导致网络线程挂起 - RETRY_POOL.submit(command); - } - }; - invocation.setResponseExecutor(newExecutor); - } else { - orginExecutor = null; - newExecutor = null; - } - - ExecutionListener listener = new ExecutionListener() { - @Override - public void onExecutionStart(ExecutionContext context) throws AbortExecutionException { - } - - @Override - public void onStartWithServer(ExecutionContext context, - ExecutionInfo info) throws AbortExecutionException { - } - - @Override - public void onExceptionWithServer(ExecutionContext context, Throwable exception, - ExecutionInfo info) { - LOGGER.error("Invoke server failed. Operation {}; server {}; {}-{} msg {}", - context.getRequest().getInvocationQualifiedName(), - context.getRequest().getEndpoint(), - info.getNumberOfPastServersAttempted(), - info.getNumberOfPastAttemptsOnServer(), - ExceptionUtils.getExceptionMessageWithoutTrace(exception)); - } - - @Override - public void onExecutionSuccess(ExecutionContext context, Response response, - ExecutionInfo info) { - if (info.getNumberOfPastServersAttempted() > 0 || info.getNumberOfPastAttemptsOnServer() > 0) { - LOGGER.error("Invoke server success. Operation {}; server {}", - context.getRequest().getInvocationQualifiedName(), - context.getRequest().getEndpoint()); - } - if (orginExecutor != null) { - orginExecutor.execute(() -> { - asyncResp.complete(response); - }); - } else { - asyncResp.complete(response); - } - } - - @Override - public void onExecutionFailed(ExecutionContext context, Throwable finalException, - ExecutionInfo info) { - LOGGER.error("Invoke all server failed. Operation {}, e={}", - context.getRequest().getInvocationQualifiedName(), - ExceptionUtils.getExceptionMessageWithoutTrace(finalException)); - if (orginExecutor != null) { - orginExecutor.execute(() -> { - fail(finalException); - }); - } else { - fail(finalException); - } - } - - private void fail(Throwable finalException) { - int depth = 10; - Throwable t = finalException; - while (depth-- > 0) { - if (t instanceof InvocationException) { - asyncResp.consumerFail(t); - return; - } - t = finalException.getCause(); - } - asyncResp.consumerFail(finalException); - } - }; - List> listeners = new ArrayList<>(0); - listeners.add(listener); - ExecutionContext context = new ExecutionContext<>(invocation, null, null, null); - - LoadBalancerCommand command = LoadBalancerCommand.builder() - .withLoadBalancer(new RetryLoadBalancer(chosenLB)) - .withServerLocator(invocation) - .withRetryHandler(ExtensionsManager.createRetryHandler(invocation.getMicroserviceName())) - .withListeners(listeners) - .withExecutionContext(context) - .build(); - - Observable observable = command.submit(new ServerOperation() { - public Observable call(Server s) { - return Observable.create(f -> { - try { - ServiceCombServer server = (ServiceCombServer) s; - chosenLB.getLoadBalancerStats().incrementNumRequests(s); - invocation.setHandlerIndex(currentHandler); // for retry - invocation.setEndpoint(server.getEndpoint()); - invocation.next(resp -> { - if (isFailedResponse(resp)) { - LOGGER.error("service {}, call error, msg is {}, server is {} ", - invocation.getInvocationQualifiedName(), - ExceptionUtils.getExceptionMessageWithoutTrace((Throwable) resp.getResult()), - s); - chosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server); - f.onError(resp.getResult()); - } else { - chosenLB.getLoadBalancerStats().incrementActiveRequestsCount(s); - chosenLB.getLoadBalancerStats().noteResponseTime(s, - (System.currentTimeMillis() - time)); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - f.onNext(resp); - f.onCompleted(); - } - }); - } catch (Exception e) { - LOGGER.error("execution error, msg is {}", ExceptionUtils.getExceptionMessageWithoutTrace(e)); - f.onError(e); - } - }); - } - }); - - observable.subscribe(response -> { - }, error -> { - }, () -> { - }); - } - - protected boolean isFailedResponse(Response resp) { - if (resp.isFailed()) { - if (InvocationException.class.isInstance(resp.getResult())) { - InvocationException e = (InvocationException) resp.getResult(); - return e.getStatusCode() == ExceptionFactory.CONSUMER_INNER_STATUS_CODE - || e.getStatusCode() == 503; - } else { - return true; - } - } else { - return false; - } - } - - protected LoadBalancer getOrCreateLoadBalancer(Invocation invocation) { - DiscoveryContext context = new DiscoveryContext(); - context.setInputParameters(invocation); - VersionedCache serversVersionedCache = discoveryTree.discovery(context, - invocation.getAppId(), - invocation.getMicroserviceName(), - invocation.getMicroserviceVersionRule()); - invocation.addLocalContext(CONTEXT_KEY_SERVER_LIST, serversVersionedCache.data()); - - return loadBalancerMap - .computeIfAbsent(serversVersionedCache.name(), name -> { - return createLoadBalancer(invocation.getMicroserviceName()); - }); - } - - private LoadBalancer createLoadBalancer(String microserviceName) { - RuleExt rule = ExtensionsManager.createLoadBalancerRule(microserviceName); - return new LoadBalancer(rule, microserviceName); - } - - public boolean isEqual(String str1, String str2) { - return (str1 == null ? str2 == null : str1.equals(str2)); - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java index 60eedac529e..318b45f3839 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java @@ -18,7 +18,7 @@ package org.apache.servicecomb.loadbalance; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import org.apache.servicecomb.core.Invocation; @@ -26,14 +26,12 @@ * A random rule. */ public class RandomRuleExt implements RuleExt { - private Random random = new Random(); - @Override public ServiceCombServer choose(List servers, Invocation invocation) { - if (servers.size() == 0) { + if (servers.isEmpty()) { return null; } - int index = Math.abs(random.nextInt()) % servers.size(); + int index = ThreadLocalRandom.current().nextInt(servers.size()); return servers.get(index); } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java index c3a887d2034..70d467843f3 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java @@ -26,11 +26,11 @@ * A round robin rule */ public class RoundRobinRuleExt implements RuleExt { - private AtomicInteger counter = new AtomicInteger(0); + private final AtomicInteger counter = new AtomicInteger(0); @Override public ServiceCombServer choose(List servers, Invocation invocation) { - if (servers.size() == 0) { + if (servers.isEmpty()) { return null; } int index = Math.abs(counter.getAndIncrement()) % servers.size(); diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtensionsFactory.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtensionsFactory.java new file mode 100644 index 00000000000..9d9b0e0da1b --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtensionsFactory.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.loadbalance; + +import java.util.Collection; + +import com.google.common.collect.Lists; + +public class RuleNameExtensionsFactory implements ExtensionsFactory { + private static final Collection ACCEPT_KEYS = Lists.newArrayList( + Configuration.RULE_STRATEGY_NAME); + + private static final String RULE_RoundRobin = "RoundRobin"; + + private static final String RULE_Random = "Random"; + + private static final String RULE_WeightedResponse = "WeightedResponse"; + + private static final String RULE_SessionStickiness = "SessionStickiness"; + + private static final Collection ACCEPT_VALUES = Lists.newArrayList( + RULE_RoundRobin, + RULE_Random, + RULE_WeightedResponse, + RULE_SessionStickiness); + + @Override + public boolean isSupport(String key, String value) { + return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value); + } + + @Override + public RuleExt createLoadBalancerRule(String ruleName) { + if (RULE_RoundRobin.equals(ruleName)) { + return new RoundRobinRuleExt(); + } else if (RULE_Random.equals(ruleName)) { + return new RandomRuleExt(); + } else if (RULE_WeightedResponse.equals(ruleName)) { + return new WeightedResponseTimeRuleExt(); + } else if (RULE_SessionStickiness.equals(ruleName)) { + return new SessionStickinessRule(); + } else { + throw new IllegalStateException("unexpected code to reach here, value is " + ruleName); + } + } +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtentionsFactory.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtentionsFactory.java deleted file mode 100644 index 5ab7cfb959d..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RuleNameExtentionsFactory.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.loadbalance; - -import java.util.Collection; - -import org.springframework.stereotype.Component; - -import com.google.common.collect.Lists; - -@Component -public class RuleNameExtentionsFactory implements ExtensionsFactory { - private static final Collection ACCEPT_KEYS = Lists.newArrayList( - Configuration.PROP_RULE_STRATEGY_NAME); - - private static final String RULE_RoundRobin = "RoundRobin"; - - private static final String RULE_Random = "Random"; - - private static final String RULE_WeightedResponse = "WeightedResponse"; - - private static final String RULE_SessionStickiness = "SessionStickiness"; - - private static final Collection ACCEPT_VALUES = Lists.newArrayList( - RULE_RoundRobin, - RULE_Random, - RULE_WeightedResponse, - RULE_SessionStickiness); - - @Override - public boolean isSupport(String key, String value) { - return ACCEPT_KEYS.contains(key) && ACCEPT_VALUES.contains(value); - } - - @Override - public RuleExt createLoadBalancerRule(String ruleName) { - if (RULE_RoundRobin.equals(ruleName)) { - return new RoundRobinRuleExt(); - } else if (RULE_Random.equals(ruleName)) { - return new RandomRuleExt(); - } else if (RULE_WeightedResponse.equals(ruleName)) { - return new WeightedResponseTimeRuleExt(); - } else if (RULE_SessionStickiness.equals(ruleName)) { - return new SessionStickinessRule(); - } else { - throw new IllegalStateException("unexpected code to reach here, value is " + ruleName); - } - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java index 9dba0046dd8..9d2d07ceb5f 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java @@ -28,8 +28,10 @@ * support this. */ public interface ServerListFilterExt { + int ORDER_NORMAL = 0; + default int getOrder() { - return 0; + return ORDER_NORMAL; } default boolean enabled() { diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerMetrics.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerMetrics.java new file mode 100644 index 00000000000..d756ff40300 --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerMetrics.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance; + +import java.util.concurrent.TimeUnit; + +import io.github.resilience4j.core.metrics.FixedSizeSlidingWindowMetrics; +import io.github.resilience4j.core.metrics.Metrics.Outcome; +import io.github.resilience4j.core.metrics.Snapshot; + +/** + * ServiceCombServer states + */ +public class ServerMetrics { + private final FixedSizeSlidingWindowMetrics metrics = new FixedSizeSlidingWindowMetrics(50); + + public Snapshot record(long duration, TimeUnit durationUnit, Outcome outcome) { + return metrics.record(duration, durationUnit, outcome); + } + + public Snapshot getSnapshot() { + return metrics.getSnapshot(); + } +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java deleted file mode 100644 index ffde2d7eed1..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.util.Iterator; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; -import com.netflix.config.DynamicPropertyFactory; - -/** - * Add special stats that com.netflix.loadbalancer.LoadBalancerStats not provided - */ -public class ServiceCombLoadBalancerStats { - private final static Logger LOGGER = LoggerFactory.getLogger(ServiceCombLoadBalancerStats.class); - - private final Map pingView = new ConcurrentHashMap<>(); - - private int serverExpireInSeconds = DynamicPropertyFactory.getInstance() - .getIntProperty(Configuration.RPOP_SERVER_EXPIRED_IN_SECONDS, 300).get(); - - private long timerIntervalInMilis = DynamicPropertyFactory.getInstance() - .getLongProperty(Configuration.RPOP_TIMER_INTERVAL_IN_MINIS, 10000).get(); - - private LoadingCache serverStatsCache; - - public static final ServiceCombLoadBalancerStats INSTANCE; - - private Timer timer; - - static { - INSTANCE = new ServiceCombLoadBalancerStats(); - INSTANCE.init(); - } - - /** - * Should be singleton, use it only for testing - */ - ServiceCombLoadBalancerStats() { - } - - public void markIsolated(ServiceCombServer server, boolean isolated) { - try { - serverStatsCache.get(server).markIsolated(isolated); - } catch (ExecutionException e) { - LOGGER.error("Not expected to happen, maybe a bug.", e); - } - } - - public void markSuccess(ServiceCombServer server) { - try { - serverStatsCache.get(server).markSuccess(); - } catch (ExecutionException e) { - LOGGER.error("Not expected to happen, maybe a bug.", e); - } - } - - public void markFailure(ServiceCombServer server) { - try { - serverStatsCache.get(server).markFailure(); - } catch (ExecutionException e) { - LOGGER.error("Not expected to happen, maybe a bug.", e); - } - } - - public ServiceCombServerStats getServiceCombServerStats(ServiceCombServer server) { - try { - return serverStatsCache.get(server); - } catch (ExecutionException e) { - LOGGER.error("Not expected to happen, maybe a bug.", e); - return null; - } - } - - public ServiceCombServer getServiceCombServer(MicroserviceInstance instance) { - for (ServiceCombServer server : serverStatsCache.asMap().keySet()) { - if (server.getInstance().equals(instance)) { - return server; - } - } - return null; - } - - @VisibleForTesting - void setServerExpireInSeconds(int sec) { - this.serverExpireInSeconds = sec; - } - - @VisibleForTesting - void setTimerIntervalInMilis(int milis) { - this.timerIntervalInMilis = milis; - } - - @VisibleForTesting - Map getPingView() { - return this.pingView; - } - - void init() { - // for testing - if (timer != null) { - timer.cancel(); - } - if (serverStatsCache != null) { - serverStatsCache.cleanUp(); - } - - serverStatsCache = - CacheBuilder.newBuilder() - .expireAfterAccess(serverExpireInSeconds, TimeUnit.SECONDS) - .removalListener(new RemovalListener() { - @Override - public void onRemoval(RemovalNotification notification) { - LOGGER.info("stats of instance {} removed.", notification.getKey().getInstance().getInstanceId()); - pingView.remove(notification.getKey()); - } - }) - .build( - new CacheLoader() { - public ServiceCombServerStats load(ServiceCombServer server) { - ServiceCombServerStats stats = new ServiceCombServerStats(); - pingView.put(server, stats); - return stats; - } - }); - - timer = new Timer("LoadBalancerStatsTimer", true); - timer.schedule(new TimerTask() { - private MicroserviceInstancePing ping = SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class); - - @Override - public void run() { - try { - Map allServers = pingView; - Iterator instances = allServers.keySet().iterator(); - while (instances.hasNext()) { - ServiceCombServer server = instances.next(); - ServiceCombServerStats stats = allServers.get(server); - if ((System.currentTimeMillis() - stats.getLastVisitTime() > timerIntervalInMilis) && !ping - .ping(server.getInstance())) { - LOGGER.info("ping mark server {} failure.", server.getInstance().getInstanceId()); - stats.markFailure(); - } - } - serverStatsCache.cleanUp(); - } catch (Throwable e) { - LOGGER.warn("LoadBalancerStatsTimer error.", e); - } - } - }, timerIntervalInMilis, timerIntervalInMilis); - } -} - diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java index 800e2aebe26..edfdf322f6e 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java @@ -17,82 +17,67 @@ package org.apache.servicecomb.loadbalance; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; +import java.util.Objects; -import com.google.common.annotations.VisibleForTesting; -import com.netflix.loadbalancer.Server; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.registry.api.DiscoveryInstance; /** - * 服务器抽象,address只有transport识别, LB模块不识别 - * LB模块不提供服务器状态监测,这块功能是由注册中心进行处理的。 + * Server object used for transports and load balancer. * */ -public class ServiceCombServer extends Server { +public class ServiceCombServer { private final Endpoint endpoint; - // 所属服务实例 - private final MicroserviceInstance instance; + private final String microserviceName; - @VisibleForTesting - ServiceCombServer(Endpoint endpoint, MicroserviceInstance instance) { - super(null); - this.endpoint = endpoint; - this.instance = instance; + private final ServerMetrics serverMetrics; - // Different types of Robin Component Rule have different usages for server status and list. - // e.g. RoundRobinRule using getAllServers & alive & readyToServe - // RandomRule using getReachableServers & alive - // WeightedResponseTimeRule using getAllServers & alive - // To make all rules work only on "how to choose a server from alive servers", we do not rely on Robbin defined status - this.setAlive(true); - this.setReadyToServe(true); + public ServiceCombServer(String microserviceName, Endpoint endpoint) { + this.microserviceName = microserviceName; + this.endpoint = endpoint; + this.serverMetrics = new ServerMetrics(); } - public ServiceCombServer(Transport transport, CacheEndpoint cacheEndpoint) { - super(null); - - endpoint = new Endpoint(transport, cacheEndpoint.getEndpoint(), cacheEndpoint.getInstance()); - instance = cacheEndpoint.getInstance(); - - // Different types of Robin Component Rule have different usages for server status and list. - // e.g. RoundRobinRule using getAllServers & alive & readyToServe - // RandomRule using getReachableServers & alive - // WeightedResponseTimeRule using getAllServers & alive - // To make all rules work only on "how to choose a server from alive servers", we do not rely on Robbin defined status - this.setAlive(true); - this.setReadyToServe(true); + public String getMicroserviceName() { + return this.microserviceName; } public Endpoint getEndpoint() { return endpoint; } - public MicroserviceInstance getInstance() { - return instance; + public DiscoveryInstance getInstance() { + return endpoint.getMicroserviceInstance(); } + @Override public String toString() { return endpoint.getEndpoint(); } - // used in LoadBalancerContext public String getHost() { return endpoint.getEndpoint(); } - // take endpoints that belongs to same instance as same server + public ServerMetrics getServerMetrics() { + return serverMetrics; + } + + @Override public boolean equals(Object o) { if (o instanceof ServiceCombServer) { - return this.instance.getInstanceId().equals(((ServiceCombServer) o).instance.getInstanceId()); + return this.getInstance().getInstanceId() + .equals(((ServiceCombServer) o).getInstance().getInstanceId()) + && StringUtils.equals(endpoint.getEndpoint(), ((ServiceCombServer) o).getEndpoint().getEndpoint()); } else { return false; } } + @Override public int hashCode() { - return this.instance.getInstanceId().hashCode(); + return Objects.hash(this.getInstance().getInstanceId(), this.endpoint); } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java deleted file mode 100644 index b33771bba5b..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * Special stats that com.netflix.loadbalancer.ServerStats not provided. - * - * In concurrent scenarios, we can't count statistics accurately, but it's fine. - */ -public class ServiceCombServerStats { - private static final long TIME_WINDOW_IN_MILLISECONDS = 60000; - - private long lastWindow = System.currentTimeMillis(); - - private Object lock = new Object(); - - private AtomicLong continuousFailureCount = new AtomicLong(0); - - private long lastVisitTime = System.currentTimeMillis(); - - private long lastActiveTime = System.currentTimeMillis(); - - private AtomicLong totalRequests = new AtomicLong(0L); - - private AtomicLong successRequests = new AtomicLong(0L); - - private AtomicLong failedRequests = new AtomicLong(0L); - - private boolean isolated = false; - - public void markIsolated(boolean isolated) { - this.isolated = isolated; - } - - public void markSuccess() { - long time = System.currentTimeMillis(); - ensureWindow(time); - lastVisitTime = time; - lastActiveTime = time; - totalRequests.incrementAndGet(); - successRequests.incrementAndGet(); - continuousFailureCount.set(0); - } - - public void markFailure() { - long time = System.currentTimeMillis(); - ensureWindow(time); - lastVisitTime = time; - - // when isolated, do not update any failure statistics, or we can not recover from failure very quickly - if (!isolated) { - totalRequests.incrementAndGet(); - failedRequests.incrementAndGet(); - continuousFailureCount.incrementAndGet(); - } - } - - private void ensureWindow(long time) { - if (time - lastWindow > TIME_WINDOW_IN_MILLISECONDS) { - synchronized (lock) { - if (time - lastWindow > TIME_WINDOW_IN_MILLISECONDS) { - if (!isolated) { - continuousFailureCount.set(0); - totalRequests.set(0); - successRequests.set(0); - failedRequests.set(0); - } - lastWindow = time; - } - } - } - } - - public long getLastVisitTime() { - return lastVisitTime; - } - - public long getLastActiveTime() { - return lastActiveTime; - } - - public long getCountinuousFailureCount() { - return continuousFailureCount.get(); - } - - public long getTotalRequests() { - return totalRequests.get(); - } - - public long getSuccessRequests() { - return successRequests.get(); - } - - public long getFailedRequests() { - return failedRequests.get(); - } - - public int getSuccessRate() { - if (totalRequests.get() == 0L) { - return 0; - } - return (int) (successRequests.get() * 100 / totalRequests.get()); - } - - public int getFailedRate() { - if (totalRequests.get() == 0L) { - return 0; - } - return (int) (failedRequests.get() * 100 / totalRequests.get()); - } - - public boolean isIsolated() { - return isolated; - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java index a854a831a38..37d94bc0fa1 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java @@ -23,8 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.netflix.loadbalancer.LoadBalancerStats; -import com.netflix.loadbalancer.ServerStats; +import com.google.common.annotations.VisibleForTesting; /** * 会话保持策略:优先选择上一次选中的服务器,保证请求都发送到同一个服务器上去。 @@ -36,14 +35,12 @@ public class SessionStickinessRule implements RuleExt { private final Object lock = new Object(); - private LoadBalancer loadBalancer; - // use random rule as the trigger rule, to prevent consumer instance select the same producer instance. - private RuleExt triggerRule; + private final RuleExt triggerRule; private volatile ServiceCombServer lastServer = null; - private long lastAccessedTime = 0; + private volatile long lastAccessedTime = 0; private volatile boolean errorThresholdMet = false; @@ -55,9 +52,9 @@ public SessionStickinessRule() { triggerRule = new RoundRobinRuleExt(); } + @Override public void setLoadBalancer(LoadBalancer loadBalancer) { this.microserviceName = loadBalancer.getMicroServiceName(); - this.loadBalancer = loadBalancer; } private ServiceCombServer chooseNextServer(List servers, Invocation invocation) { @@ -75,7 +72,8 @@ private ServiceCombServer chooseInitialServer(List servers, I return lastServer; } - private ServiceCombServer chooseServerWhenTimeout(List servers, Invocation invocation) { + @VisibleForTesting + ServiceCombServer chooseServerWhenTimeout(List servers, Invocation invocation) { synchronized (lock) { if (isTimeOut()) { chooseNextServer(servers, invocation); @@ -101,19 +99,10 @@ private boolean isTimeOut() { * MILLI_COUNT_IN_SECOND); } - private boolean isErrorThresholdMet() { - LoadBalancerStats stats = loadBalancer.getLoadBalancerStats(); - - if (stats != null && stats.getServerStats() != null && stats.getServerStats().size() > 0) { - ServerStats serverStats = stats.getSingleServerStat(lastServer); - int successiveFaildCount = serverStats.getSuccessiveConnectionFailureCount(); - if (Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName) > 0 - && successiveFaildCount >= Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName)) { - serverStats.clearSuccessiveConnectionFailureCount(); - return true; - } - } - return false; + private boolean isErrorThresholdMet(ServiceCombServer server) { + int successiveFailedCount = server.getServerMetrics().getSnapshot().getNumberOfFailedCalls(); + return Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName) > 0 + && successiveFailedCount >= Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName); } @Override @@ -129,7 +118,7 @@ public ServiceCombServer choose(List servers, Invocation invo this.lastAccessedTime = System.currentTimeMillis(); } - if (isErrorThresholdMet()) { + if (isErrorThresholdMet(lastServer)) { LOG.warn("reached max error. choose another server."); errorThresholdMet = true; return chooseServerErrorThresholdMet(servers, invocation); diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java index 529c0a35dcc..a6462876e93 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java @@ -19,43 +19,48 @@ import java.util.ArrayList; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.servicecomb.core.Invocation; -import com.netflix.loadbalancer.ServerStats; - /** * Rule based on response time. */ public class WeightedResponseTimeRuleExt extends RoundRobinRuleExt { - // 10ms + // when all servers are very fast(less than MIN_GAP), use round-robin rule. private static final double MIN_GAP = 10d; - private static final int RANDOM_PERCENT = 10; + // calculate stats once per RANDOM_PERCENT requests. + private static final int RANDOM_PERCENT = 1000; - private Random random = new Random(); + private final Object lock = new Object(); - private LoadBalancer loadBalancer; + private final AtomicInteger counter = new AtomicInteger(0); - private double totalWeightsCache = 0d; + // notices: rule will always use as a fixed group of instance, see LoadBalancer for details. + private volatile int size = -1; - @Override - public void setLoadBalancer(LoadBalancer loadBalancer) { - this.loadBalancer = loadBalancer; - } + private volatile List cacheStates = new ArrayList<>(); @Override public ServiceCombServer choose(List servers, Invocation invocation) { - List stats = calculateTotalWeights(servers); + int count = counter.getAndIncrement(); + if (count % RANDOM_PERCENT == 0 || size != servers.size()) { + synchronized (lock) { + this.cacheStates = doCalculateTotalWeights(servers); + this.size = servers.size(); + } + } + List stats = this.cacheStates; if (stats.size() > 0) { double finalTotal = stats.get(stats.size() - 1); List weights = new ArrayList<>(servers.size()); for (int i = 0; i < stats.size() - 1; i++) { weights.add(finalTotal - stats.get(i)); } - double ran = random.nextDouble() * finalTotal * (servers.size() - 1); + double ran = ThreadLocalRandom.current().nextDouble() * finalTotal * (servers.size() - 1); for (int i = 0; i < weights.size(); i++) { ran -= weights.get(i); if (ran < 0) { @@ -67,25 +72,13 @@ public ServiceCombServer choose(List servers, Invocation invo return super.choose(servers, invocation); } - private List calculateTotalWeights(List servers) { - if (totalWeightsCache > MIN_GAP * servers.size()) { - return doCalculateTotalWeights(servers); - } - // 10% possibilities to use weighed response rule when the normal access is very fast. - if (random.nextInt(RANDOM_PERCENT) == 0) { - return doCalculateTotalWeights(servers); - } else { - return new ArrayList<>(); - } - } - - private List doCalculateTotalWeights(List servers) { + private static List doCalculateTotalWeights(List servers) { List stats = new ArrayList<>(servers.size() + 1); double totalWeights = 0; boolean needRandom = false; for (ServiceCombServer server : servers) { - ServerStats serverStats = loadBalancer.getLoadBalancerStats().getSingleServerStat(server); - double avgTime = serverStats.getResponseTimeAvg(); + // this method will create new instance, so we cache the states. + double avgTime = server.getServerMetrics().getSnapshot().getAverageDuration().toMillis(); if (!needRandom && avgTime > MIN_GAP) { needRandom = true; } @@ -93,7 +86,6 @@ private List doCalculateTotalWeights(List servers) { stats.add(avgTime); } stats.add(totalWeights); - totalWeightsCache = totalWeights; if (needRandom) { return stats; } else { diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java deleted file mode 100644 index 1714e0b7136..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.loadbalance.event; - -import org.apache.servicecomb.foundation.common.event.AlarmEvent; -import org.apache.servicecomb.loadbalance.ServiceCombServerStats; -import org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -public class IsolationServerEvent extends AlarmEvent { - - private String microserviceName; - - private MicroserviceInstance instance; - - //当前实例总请求数 - private long currentTotalRequest; - - //当前实例连续出错次数 - private long currentCountinuousFailureCount; - - //当前实例出错百分比 - private double currentErrorPercentage; - - private int minIsolationTime; - - private long enableRequestThreshold; - - private int continuousFailureThreshold; - - private int errorThresholdPercentage; - - private long singleTestTime; - - public IsolationServerEvent(String microserviceName, MicroserviceInstance instance, - ServiceCombServerStats serverStats, - IsolationDiscoveryFilter.Settings settings, Type type) { - super(type); - this.microserviceName = microserviceName; - this.currentTotalRequest = serverStats.getTotalRequests(); - this.currentCountinuousFailureCount = serverStats.getCountinuousFailureCount(); - this.currentErrorPercentage = serverStats.getFailedRate(); - this.minIsolationTime = settings.minIsolationTime; - this.enableRequestThreshold = settings.enableRequestThreshold; - this.continuousFailureThreshold = settings.continuousFailureThreshold; - this.errorThresholdPercentage = settings.errorThresholdPercentage; - this.singleTestTime = settings.singleTestTime; - this.instance = instance; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public long getCurrentTotalRequest() { - return currentTotalRequest; - } - - public long getCurrentCountinuousFailureCount() { - return currentCountinuousFailureCount; - } - - public double getCurrentErrorPercentage() { - return currentErrorPercentage; - } - - public long getEnableRequestThreshold() { - return enableRequestThreshold; - } - - public int getContinuousFailureThreshold() { - return continuousFailureThreshold; - } - - public int getErrorThresholdPercentage() { - return errorThresholdPercentage; - } - - public long getSingleTestTime() { - return singleTestTime; - } - - public MicroserviceInstance getInstance() { - return instance; - } - - public int getMinIsolationTime() { - return minIsolationTime; - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java index 62c2db42583..3a4bde530c3 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java @@ -30,7 +30,6 @@ public class LoadbalanceExceptionUtils extends ExceptionUtils { public static CseException createLoadbalanceException(String code, Throwable cause, Object... args) { String msg = String.format(ERROR_DESC_MGR.ensureFindValue(code), args); - CseException exception = new CseException(code, msg, cause); - return exception; + return new CseException(code, msg, cause); } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java index 07adcd9d3ba..2b4c3eb6b20 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java @@ -17,25 +17,27 @@ package org.apache.servicecomb.loadbalance.filter; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.loadbalance.Configuration; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.AbstractDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; - -import com.netflix.config.DynamicPropertyFactory; +import org.apache.servicecomb.registry.discovery.AbstractDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; /** - * Instance property based filter + * Instance property based filter */ public class InstancePropertyDiscoveryFilter extends AbstractDiscoveryFilter { + private static final String MATCHED = "matched"; + public static final String SERVICECOMB_LOADBALANCE_FILTER_INSTANCE_PROPERTY_ENABLED = "servicecomb.loadbalance.filter.instanceProperty.enabled"; + @Override public int getOrder() { return 400; @@ -43,8 +45,13 @@ public int getOrder() { @Override public boolean enabled() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.loadbalance.filter.instanceProperty.enabled", true).get(); + + if (enabled == null) { + enabled = dynamicProperties.getBooleanProperty(SERVICECOMB_LOADBALANCE_FILTER_INSTANCE_PROPERTY_ENABLED, + value -> enabled = value, + true); + } + return enabled; } @Override @@ -54,17 +61,16 @@ public boolean isGroupingFilter() { @Override protected void init(DiscoveryContext context, DiscoveryTreeNode parent) { - Map matchedInstance = new HashMap<>(); + List matchedInstance = new ArrayList<>(); Invocation invocation = context.getInputParameters(); - Map instances = parent.data(); + List instances = parent.data(); Map filterOptions = Configuration.INSTANCE.getFlowsplitFilterOptions(invocation.getMicroserviceName()); - for (String id : instances.keySet()) { - MicroserviceInstance target = instances.get(id); + instances.forEach((target) -> { if (allowVisit(target, filterOptions)) { - matchedInstance.put(id, target); + matchedInstance.add(target); } - } + }); parent.child(MATCHED, new DiscoveryTreeNode() .subName(parent, MATCHED) .data(matchedInstance)); @@ -75,7 +81,7 @@ protected String findChildName(DiscoveryContext context, DiscoveryTreeNode paren return MATCHED; } - protected boolean allowVisit(MicroserviceInstance instance, Map filterOptions) { + protected boolean allowVisit(StatefulDiscoveryInstance instance, Map filterOptions) { Map propertiesMap = instance.getProperties(); for (Entry entry : filterOptions.entrySet()) { if (!entry.getValue().equals(propertiesMap.get(entry.getKey()))) { diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java deleted file mode 100644 index 2856434c0e5..00000000000 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance.filter; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.loadbalance.Configuration; -import org.apache.servicecomb.loadbalance.ServiceCombLoadBalancerStats; -import org.apache.servicecomb.loadbalance.ServiceCombServer; -import org.apache.servicecomb.loadbalance.ServiceCombServerStats; -import org.apache.servicecomb.loadbalance.event.IsolationServerEvent; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.netflix.config.DynamicPropertyFactory; - -/** - * Isolate instances by error metrics - */ -public class IsolationDiscoveryFilter implements DiscoveryFilter { - - private static final Logger LOGGER = LoggerFactory.getLogger(IsolationDiscoveryFilter.class); - - public class Settings { - public int errorThresholdPercentage; - - public long singleTestTime; - - public long enableRequestThreshold; - - public int continuousFailureThreshold; - - public int minIsolationTime; // to avoid isolation recover too fast due to no concurrent control in concurrent scenario - } - - public EventBus eventBus = EventManager.getEventBus(); - - @Override - public int getOrder() { - return 500; - } - - @Override - public boolean enabled() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.loadbalance.filter.isolation.enabled", true).get(); - } - - @Override - public boolean isGroupingFilter() { - return false; - } - - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - Map instances = parent.data(); - Invocation invocation = context.getInputParameters(); - if (!Configuration.INSTANCE.isIsolationFilterOpen(invocation.getMicroserviceName())) { - return parent; - } - - Map filteredServers = new HashMap<>(); - for (String key : instances.keySet()) { - MicroserviceInstance instance = instances.get(key); - if (allowVisit(invocation, instance)) { - filteredServers.put(key, instance); - } - } - DiscoveryTreeNode child = new DiscoveryTreeNode().data(filteredServers); - parent.child("filterred", child); - return child; - } - - private Settings createSettings(Invocation invocation) { - Settings settings = new Settings(); - settings.errorThresholdPercentage = Configuration.INSTANCE - .getErrorThresholdPercentage(invocation.getMicroserviceName()); - settings.singleTestTime = Configuration.INSTANCE.getSingleTestTime(invocation.getMicroserviceName()); - settings.enableRequestThreshold = Configuration.INSTANCE - .getEnableRequestThreshold(invocation.getMicroserviceName()); - settings.continuousFailureThreshold = Configuration.INSTANCE - .getContinuousFailureThreshold(invocation.getMicroserviceName()); - settings.minIsolationTime = Configuration.INSTANCE - .getMinIsolationTime(invocation.getMicroserviceName()); - return settings; - } - - private boolean allowVisit(Invocation invocation, MicroserviceInstance instance) { - ServiceCombServer server = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(instance); - if (server == null) { - // first time accessed. - return true; - } - ServiceCombServerStats serverStats = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server); - Settings settings = createSettings(invocation); - if (!checkThresholdAllowed(settings, serverStats)) { - if (serverStats.isIsolated() - && (System.currentTimeMillis() - serverStats.getLastVisitTime()) > settings.singleTestTime) { - // [1]we can implement better recovery based on several attempts, but here we do not know if this attempt is success - LOGGER.info("The Service {}'s instance {} has been isolated for a while, give a single test opportunity.", - invocation.getMicroserviceName(), - instance.getInstanceId()); - return true; - } - if (!serverStats.isIsolated()) { - ServiceCombLoadBalancerStats.INSTANCE.markIsolated(server, true); - eventBus.post( - new IsolationServerEvent(invocation.getMicroserviceName(), instance, serverStats, - settings, Type.OPEN)); - LOGGER.warn("Isolate service {}'s instance {}.", invocation.getMicroserviceName(), - instance.getInstanceId()); - } - return false; - } - if (serverStats.isIsolated()) { - // [2] so that we add a feature to isolate for at least a minimal time, and we can avoid - // high volume of concurrent requests with a percentage of error(e.g. 50%) scenario with no isolation - if ((System.currentTimeMillis() - serverStats.getLastVisitTime()) <= settings.minIsolationTime) { - return false; - } - ServiceCombLoadBalancerStats.INSTANCE.markIsolated(server, false); - eventBus.post(new IsolationServerEvent(invocation.getMicroserviceName(), instance, serverStats, - settings, Type.CLOSE)); - LOGGER.warn("Recover service {}'s instance {} from isolation.", invocation.getMicroserviceName(), - instance.getInstanceId()); - } - return true; - } - - private boolean checkThresholdAllowed(Settings settings, ServiceCombServerStats serverStats) { - if (serverStats.getTotalRequests() < settings.enableRequestThreshold) { - return true; - } - - if (settings.continuousFailureThreshold > 0) { - // continuousFailureThreshold has higher priority to decide the result - if (serverStats.getCountinuousFailureCount() >= settings.continuousFailureThreshold) { - return false; - } - } - - if (settings.errorThresholdPercentage == 0) { - return true; - } - if (serverStats.getFailedRate() >= settings.errorThresholdPercentage) { - return false; - } - return true; - } -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java new file mode 100644 index 00000000000..d890b7ea229 --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance.filter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.registry.discovery.AbstractDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import jakarta.validation.constraints.NotNull; + +/** + * Instance property with priority filter + */ +public class PriorityInstancePropertyDiscoveryFilter extends AbstractDiscoveryFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(PriorityInstancePropertyDiscoveryFilter.class); + + private static final String ALL_INSTANCE = "allInstance"; + + public static final String SERVICECOMB_LOADBALANCE_FILTER_PRIORITY_INSTANCE_PROPERTY_KEY = "servicecomb.loadbalance.filter.priorityInstanceProperty.key"; + + private String propertyKey; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + protected void init(DiscoveryContext context, DiscoveryTreeNode parent) { + + propertyKey = dynamicProperties.getStringProperty(SERVICECOMB_LOADBALANCE_FILTER_PRIORITY_INSTANCE_PROPERTY_KEY, + value -> propertyKey = value, + "environment"); + + // group all instance by property + List instances = parent.data(); + Map> groupByProperty = new HashMap<>(); + for (StatefulDiscoveryInstance microserviceInstance : instances) { + String propertyValue = new PriorityInstanceProperty(propertyKey, microserviceInstance).getPropertyValue(); + groupByProperty.computeIfAbsent(propertyValue, key -> new ArrayList<>()) + .add(microserviceInstance); + } + Map children = new HashMap<>(); + for (Map.Entry> entry : groupByProperty.entrySet()) { + children.put(entry.getKey(), + new DiscoveryTreeNode().subName(parent, entry.getKey()).data(entry.getValue())); + } + children.put(ALL_INSTANCE, new DiscoveryTreeNode().subName(parent, ALL_INSTANCE).data(instances)); + parent.children(children); + } + + @Override + protected String findChildName(DiscoveryContext context, DiscoveryTreeNode parent) { + Invocation invocation = context.getInputParameters(); + + // context property has precedence over instance property + String initPropertyValue = invocation.getContext() + .computeIfAbsent("x-" + propertyKey, + key -> new PriorityInstanceProperty(propertyKey, + BootStrapProperties.readServiceProperties(environment).get(propertyKey)) + .getPropertyValue()); + + PriorityInstanceProperty currentProperty = context.getContextParameter(propertyKey); + // start with initial value, then search with priority + if (Objects.isNull(currentProperty)) { + currentProperty = new PriorityInstanceProperty(propertyKey, initPropertyValue); + while (!parent.children().containsKey(currentProperty.getPropertyValue()) + && currentProperty.hasChildren()) { + currentProperty = currentProperty.child(); + } + } else { + if (currentProperty.hasChildren()) { + currentProperty = currentProperty.child(); + } + } + LOGGER.debug("Discovery instance filter by {}", currentProperty); + context.putContextParameter(propertyKey, currentProperty); + + // stop push filter stack if property is empty + if (currentProperty.isEmpty()) { + return currentProperty.getPropertyValue(); + } + context.pushRerunFilter(); + return currentProperty.getPropertyValue(); + } + + @Override + public boolean enabled() { + + if (enabled == null) { + enabled = dynamicProperties.getBooleanProperty("servicecomb.loadbalance.filter.priorityInstanceProperty.enabled", + value -> enabled = value, + false); + } + return enabled; + } + + @Override + public int getOrder() { + return new InstancePropertyDiscoveryFilter().getOrder() + 1; + } + + static class PriorityInstanceProperty { + private static final int MAX_LENGTH = 10000; + + private static final String SEPARATOR = "."; + + private final String propertyKey; + + private final String propertyVal; + + /** + * Constructor + * + * @param key property key + * @param value property value + */ + public PriorityInstanceProperty(@NotNull String key, String value) { + propertyKey = key; + if (Objects.isNull(value)) { + value = StringUtils.EMPTY; + } + if (value.length() > MAX_LENGTH) { + throw new IllegalArgumentException("property value exceed max length"); + } + propertyVal = value; + } + + /** + * Constructor + * + * @param key property key + * @param microserviceInstance instance + */ + public PriorityInstanceProperty(@NotNull String key, @NotNull StatefulDiscoveryInstance microserviceInstance) { + this(key, Optional.ofNullable(microserviceInstance.getProperties().get(key)) + .orElse(StringUtils.EMPTY)); + } + + /** + * whether property is empty + * + * @return result + */ + public boolean isEmpty() { + return StringUtils.isEmpty(propertyVal); + } + + /** + * does property have lower priority children + * + * @return result + */ + public boolean hasChildren() { + return StringUtils.isNotEmpty(propertyVal); + } + + /** + * get lower priority child + * + * @return result + */ + public PriorityInstanceProperty child() { + if (propertyVal.contains(SEPARATOR)) { + return new PriorityInstanceProperty(propertyKey, StringUtils.substringBeforeLast(propertyVal, SEPARATOR)); + } + return new PriorityInstanceProperty(propertyKey, StringUtils.EMPTY); + } + + /** + * get property value + * + * @return propertyVal + */ + public String getPropertyValue() { + return propertyVal; + } + + @Override + public String toString() { + return "PriorityInstanceProperty{key=" + propertyKey + ", value=" + propertyVal + '}'; + } + } +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ServerDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ServerDiscoveryFilter.java index 3f959155251..50baab772fb 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ServerDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ServerDiscoveryFilter.java @@ -17,26 +17,32 @@ package org.apache.servicecomb.loadbalance.filter; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.filter.EndpointDiscoveryFilter; +import org.apache.servicecomb.core.registry.discovery.EndpointDiscoveryFilter; import org.apache.servicecomb.loadbalance.ServiceCombServer; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServerDiscoveryFilter extends EndpointDiscoveryFilter { private static final Logger LOGGER = LoggerFactory.getLogger(ServerDiscoveryFilter.class); + public ServerDiscoveryFilter() { + } + @Override - protected Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance) { - Transport transport = CseContext.getInstance().getTransportManager().findTransport(transportName); + protected Object createEndpoint(DiscoveryContext context, String transportName, String endpoint, + StatefulDiscoveryInstance instance) { + Transport transport = scbEngine.getTransportManager().findTransport(transportName); if (transport == null) { LOGGER.info("not deployed transport {}, ignore {}.", transportName, endpoint); return null; } - - return new ServiceCombServer(transport, new CacheEndpoint(endpoint, instance)); + Invocation invocation = context.getInputParameters(); + return new ServiceCombServer(invocation.getMicroserviceName(), + new Endpoint(transport, endpoint, instance)); } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java index 379851940b7..0e521397f13 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java @@ -17,108 +17,160 @@ package org.apache.servicecomb.loadbalance.filter; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.AbstractDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.registry.discovery.AbstractGroupDiscoveryFilter; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.springframework.beans.factory.annotation.Autowired; -import com.netflix.config.DynamicPropertyFactory; +public class ZoneAwareDiscoveryFilter extends AbstractGroupDiscoveryFilter { + public static final String PARAMETER = "zone_aware_level"; + public static final String GROUP_PREFIX = "zone_aware_group_"; -public class ZoneAwareDiscoveryFilter extends AbstractDiscoveryFilter { - private static final String KEY_ZONE_AWARE_STEP = "_KEY_ZONE_AWARE_STEP"; + public static final String GROUP_SIZE = "zone_aware_group_size"; - private static final String GROUP_RegionAndAZMatch = "instancesRegionAndAZMatch"; + public static final String CONFIG_ENABLED = "servicecomb.loadbalance.filter.zoneaware.enabled"; - private static final String GROUP_instancesAZMatch = "instancesAZMatch"; + public static final String CONFIG_RATIO = "servicecomb.loadbalance.filter.zoneaware.ratio"; - private static final String GROUP_instancesNoMatch = "instancesNoMatch"; + public static final String CONFIG_RATIO_CEILING = "servicecomb.loadbalance.filter.zoneaware.ratioCeiling"; + + private DataCenterProperties dataCenterProperties; + + private Integer ratio; + + private Integer ratioCeiling; + + + @Autowired + @SuppressWarnings("unused") + public void setDataCenterProperties(DataCenterProperties dataCenterProperties) { + this.dataCenterProperties = dataCenterProperties; + } @Override public int getOrder() { - return 300; + return -9000; } @Override public boolean enabled() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.loadbalance.filter.zoneaware.enabled", true).get(); + + if (enabled == null) { + enabled = dynamicProperties.getBooleanProperty(CONFIG_ENABLED, + value -> enabled = value, + true); + } + return enabled; + } + + private int getRatio() { + + if (ratio == null) { + ratio = dynamicProperties.getIntProperty(CONFIG_RATIO, + value -> ratio = value, + 30); + } + return ratio; + } + + private int getRatioCeiling(int defaultValue) { + + if (ratioCeiling == null) { + ratioCeiling = dynamicProperties.getIntProperty(CONFIG_RATIO_CEILING, + value -> ratioCeiling = value, + defaultValue); + } + return ratioCeiling; } @Override - public boolean isGroupingFilter() { - return true; + protected String contextParameter() { + return PARAMETER; } @Override - protected void init(DiscoveryContext context, DiscoveryTreeNode parent) { - MicroserviceInstance myself = RegistryUtils.getMicroserviceInstance(); - - Map instancesRegionAndAZMatch = new HashMap<>(); - Map instancesAZMatch = new HashMap<>(); - Map instancesNoMatch = new HashMap<>(); - Map instances = parent.data(); - for (String id : instances.keySet()) { - MicroserviceInstance target = instances.get(id); - if (regionAndAZMatch(myself, target)) { - instancesRegionAndAZMatch.put(id, target); - } else if (regionMatch(myself, target)) { - instancesAZMatch.put(id, target); + protected String groupsSizeParameter() { + return GROUP_SIZE; + } + + @Override + protected String groupPrefix() { + return GROUP_PREFIX; + } + + @Override + public void init(DiscoveryContext context, DiscoveryTreeNode parent) { + List instances = parent.data(); + List instancesRegionAndAZMatch = new ArrayList<>(); + List instancesAZMatch = new ArrayList<>(); + List instancesNoMatch = new ArrayList<>(); + + int groups = 1; + + for (StatefulDiscoveryInstance server : instances) { + if (regionAndAZMatch(server)) { + instancesRegionAndAZMatch.add(server); + } else if (regionMatch(server)) { + instancesAZMatch.add(server); } else { - instancesNoMatch.put(id, target); + instancesNoMatch.add(server); } } - Map children = new HashMap<>(); - children.put(GROUP_RegionAndAZMatch, new DiscoveryTreeNode() - .subName(parent, GROUP_RegionAndAZMatch) - .data(instancesRegionAndAZMatch)); - children.put(GROUP_instancesAZMatch, new DiscoveryTreeNode() - .subName(parent, GROUP_instancesAZMatch) - .data(instancesAZMatch)); - children.put(GROUP_instancesNoMatch, new DiscoveryTreeNode() - .subName(parent, GROUP_instancesNoMatch) - .data(instancesNoMatch)); - parent.children(children); - } - @Override - protected String findChildName(DiscoveryContext context, DiscoveryTreeNode parent) { - String key = context.getContextParameter(KEY_ZONE_AWARE_STEP); - if (key == null) { - key = GROUP_RegionAndAZMatch; - context.pushRerunFilter(); - } else if (GROUP_RegionAndAZMatch.equals(key)) { - key = GROUP_instancesAZMatch; - context.pushRerunFilter(); - } else if (GROUP_instancesAZMatch.equals(key)) { - key = GROUP_instancesNoMatch; + int ratio = getRatio(); + int ratioCeiling = getRatioCeiling(100 - ratio); + + if (hasEnoughMembers(instances.size(), instancesRegionAndAZMatch.size(), ratio, ratioCeiling)) { + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(instancesRegionAndAZMatch)); + groups++; + } else { + instancesAZMatch.addAll(instancesRegionAndAZMatch); + } + + if (hasEnoughMembers(instances.size(), instancesAZMatch.size(), ratio, ratioCeiling)) { + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(instancesAZMatch)); + groups++; } else { - throw new ServiceCombException("not possible happen, maybe a bug."); + instancesNoMatch.addAll(instancesAZMatch); } - context.putContextParameter(KEY_ZONE_AWARE_STEP, key); - return key; + + parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode() + .subName(parent, GROUP_PREFIX + groups).data(instancesNoMatch)); + + parent.attribute(GROUP_SIZE, groups); } - private boolean regionAndAZMatch(MicroserviceInstance myself, MicroserviceInstance target) { - if (myself.getDataCenterInfo() == null) { - // when instance have no datacenter info, it will match all other datacenters - return true; + private boolean hasEnoughMembers(int totalSize, int groupSize, int ratio, int ratioCeiling) { + if (totalSize == 0 || groupSize == 0) { + return false; } - if (target.getDataCenterInfo() != null) { - return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion()) && - myself.getDataCenterInfo().getAvailableZone().equals(target.getDataCenterInfo().getAvailableZone()); + int actual = Math.floorDiv(groupSize * 100, totalSize); + return actual >= ratio && actual <= ratioCeiling; + } + + private boolean regionAndAZMatch(StatefulDiscoveryInstance target) { + if (dataCenterProperties.getRegion() != null + && dataCenterProperties.getAvailableZone() != null && target.getDataCenterInfo() != null) { + return dataCenterProperties.getRegion() + .equals(target.getDataCenterInfo().getRegion()) && + dataCenterProperties.getAvailableZone() + .equals(target.getDataCenterInfo().getAvailableZone()); } return false; } - private boolean regionMatch(MicroserviceInstance myself, MicroserviceInstance target) { - if (target.getDataCenterInfo() != null) { - return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion()); + private boolean regionMatch(StatefulDiscoveryInstance target) { + if (dataCenterProperties.getRegion() != null && target.getDataCenterInfo() != null) { + return dataCenterProperties.getRegion() + .equals(target.getDataCenterInfo().getRegion()); } return false; } diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter deleted file mode 100644 index c191ce881fa..00000000000 --- a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter -org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter -org.apache.servicecomb.loadbalance.filter.InstancePropertyDiscoveryFilter \ No newline at end of file diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/spring/cse.bean.xml b/handlers/handler-loadbalance/src/main/resources/META-INF/spring/cse.bean.xml deleted file mode 100644 index 7953580741a..00000000000 --- a/handlers/handler-loadbalance/src/main/resources/META-INF/spring/cse.bean.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-loadbalance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..995d86d443a --- /dev/null +++ b/handlers/handler-loadbalance/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.loadbalance.LoadBalanceConfiguration diff --git a/handlers/handler-loadbalance/src/main/resources/config/cse.handler.xml b/handlers/handler-loadbalance/src/main/resources/config/cse.handler.xml deleted file mode 100644 index ab5181156b5..00000000000 --- a/handlers/handler-loadbalance/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestConfiguration.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestConfiguration.java index 01dd6bcf92d..81f24cd8b60 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestConfiguration.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestConfiguration.java @@ -17,137 +17,60 @@ package org.apache.servicecomb.loadbalance; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.After; +import org.junit.Before; import org.junit.Test; - -import mockit.Mock; -import mockit.MockUp; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; /** * */ public class TestConfiguration { + Environment environment = Mockito.mock(Environment.class); - @Test - public void testConstants() { - - assertEquals("servicecomb.loadbalance.", Configuration.PROP_ROOT); - assertEquals("ribbon.", Configuration.PROP_ROOT_20); - assertEquals("retryEnabled", Configuration.PROP_RETRY_ENABLED); - assertEquals("retryOnNext", Configuration.PROP_RETRY_ONNEXT); - assertEquals("retryOnSame", Configuration.PROP_RETRY_ONSAME); - assertEquals("SessionStickinessRule.successiveFailedTimes", Configuration.SUCCESSIVE_FAILED_TIMES); - - assertNotNull(Configuration.INSTANCE); - } - - @Test - public void testFullConfigurationWithArgsString() { - assertNotNull(Configuration.INSTANCE.getRetryOnNext("test")); - assertNotNull(Configuration.INSTANCE.getRetryOnSame("test")); - assertNotNull(Configuration.INSTANCE.isRetryEnabled("test")); - assertNotNull(Configuration.INSTANCE.getSuccessiveFailedTimes("test")); - assertNotNull(Configuration.INSTANCE.getSessionTimeoutInSeconds("test")); - } - - @Test - public void testConfigurationWithGetpropertyReturnsStringChar() { - - new MockUp() { - @Mock - private String getProperty(String defaultValue, String... keys) { - return "tyt"; - } - }; - - Configuration.INSTANCE.getRetryOnNext("test"); - - assertNotNull(Configuration.INSTANCE.getRetryOnNext("test")); - } - - @Test - public void testConfigurationWithGetpropertyReturnsStringNum() { - - new MockUp() { - - @Mock - private String getProperty(String defaultValue, String... keys) { - return "1234"; - } - }; - - Configuration.INSTANCE.getRetryOnNext("test"); - - assertNotNull(Configuration.INSTANCE.getRetryOnNext("test")); + @Before + public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); } - @Test - public void testGetRetryOnSameWithGetpropertyReturnsStringChar() { - - new MockUp() { - @Mock - private String getProperty(String defaultValue, String... keys) { - return "tyt"; - } - }; - - Configuration.INSTANCE.getRetryOnSame("test"); - assertNotNull(Configuration.INSTANCE.getRetryOnSame("test")); + @After + public void after() { } @Test - public void testGetRetryOnSameWithGetpropertyReturnsStringNum() { - - new MockUp() { + public void testConstants() { - @Mock - private String getProperty(String defaultValue, String... keys) { - return "1234"; - } - }; + Assertions.assertEquals("servicecomb.loadbalance.", Configuration.ROOT); + Assertions.assertEquals("ribbon.", Configuration.ROOT_20); + Assertions.assertEquals("SessionStickinessRule.successiveFailedTimes", Configuration.SUCCESSIVE_FAILED_TIMES); + Assertions.assertEquals("maxSingleTestWindow", Configuration.FILTER_MAX_SINGLE_TEST_WINDOW); - Configuration.INSTANCE.getRetryOnSame("test"); - assertNotNull(Configuration.INSTANCE.getRetryOnSame("test")); + Assertions.assertNotNull(Configuration.INSTANCE); } @Test - public void testIsRetryEnabledWithGetpropertyReturnsStringChar() { - - new MockUp() { - @Mock - private String getProperty(String defaultValue, String... keys) { - return "tyt"; - } - }; - - Configuration.INSTANCE.isRetryEnabled("test"); - assertNotNull(Configuration.INSTANCE.isRetryEnabled("test")); + public void testFullConfigurationWithArgsString() { + Assertions.assertNotNull(Configuration.INSTANCE.getSuccessiveFailedTimes("test")); + Assertions.assertNotNull(Configuration.INSTANCE.getSessionTimeoutInSeconds("test")); } @Test - public void testIsRetryEnabledWithGetpropertyReturnsStringNum() { - - new MockUp() { - - @Mock - private String getProperty(String defaultValue, String... keys) { - return "1234"; - } - }; - - Configuration.INSTANCE.isRetryEnabled("test"); - assertNotNull(Configuration.INSTANCE.isRetryEnabled("test")); + public void testGetSuccessiveFailedTimes() { + Assertions.assertNotNull(Configuration.INSTANCE.getSuccessiveFailedTimes("test")); } @Test - public void testGetSuccessiveFailedTimes() { - assertNotNull(Configuration.INSTANCE.getSuccessiveFailedTimes("test")); + public void testGetSessionTimeoutInSeconds() { + Assertions.assertNotNull(Configuration.INSTANCE.getSessionTimeoutInSeconds("test")); } @Test - public void testGetSessionTimeoutInSeconds() { - assertNotNull(Configuration.INSTANCE.getSessionTimeoutInSeconds("test")); + public void testGetMaxSingleTestWindow() { + Assertions.assertEquals(60000, Configuration.INSTANCE.getMaxSingleTestWindow()); + Mockito.when(environment.getProperty("servicecomb.loadbalance.isolation.maxSingleTestWindow")).thenReturn("5000"); + Assertions.assertEquals(5000, Configuration.INSTANCE.getMaxSingleTestWindow()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java deleted file mode 100644 index 99faf1e6abf..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestDefaultRetryhandler.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.io.IOException; -import java.net.ConnectException; -import java.net.NoRouteToHostException; -import java.net.SocketTimeoutException; - -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.netflix.client.RetryHandler; - -import io.vertx.core.VertxException; - -public class TestDefaultRetryhandler { - - private static final String RETYR_NAME = "default"; - - private static final String MICROSERVICE_NAME = "servicename"; - - private RetryHandler retryHandler; - - @Before - public void setup() { - DefaultRetryExtensionsFactory factory = new DefaultRetryExtensionsFactory(); - retryHandler = factory.createRetryHandler(RETYR_NAME, MICROSERVICE_NAME); - } - - @Test - public void testRetryWithConnectionException() { - Exception target = new ConnectException("connectin refused"); - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - } - - @Test - public void testRetryWithSocketTimeout() { - Exception target = new SocketTimeoutException("Read timed out"); - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - } - - @Test - public void testRetryWithIOException() { - Exception target = new IOException("Connection reset by peer"); - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - - target = new IOException("Target not exist"); - root = new Exception(target); - retriable = retryHandler.isRetriableException(root, false); - Assert.assertFalse(retriable); - } - - @Test - public void testRetryVertxException() { - Exception target = new VertxException("Connection was closed"); - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - - target = new IOException(""); - root = new Exception(target); - retriable = retryHandler.isRetriableException(root, false); - Assert.assertFalse(retriable); - } - - @Test - public void testRetryNoRouteToHostException() { - Exception target = new NoRouteToHostException("Host is unreachable"); - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - - target = new NoRouteToHostException("Cannot assign requested address"); - root = new Exception(target); - retriable = retryHandler.isRetriableException(root, false); - Assert.assertFalse(retriable); - } - - @Test - public void testRetryInvocation503() { - Exception root = new InvocationException(503, "Service Unavailable", "Error"); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - } - - @Test - public void testRetryEqualTen() { - Exception target = new ConnectException("connectin refused"); - for (int i = 0; i < 8; i++) { - target = new Exception("Level" + i, target); - } - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertTrue(retriable); - } - - @Test - public void testRetryOverTen() { - Exception target = new ConnectException("connectin refused"); - for (int i = 0; i < 9; i++) { - target = new Exception("Level" + i, target); - } - Exception root = new Exception(target); - boolean retriable = retryHandler.isRetriableException(root, false); - Assert.assertFalse(retriable); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestExtensionsManager.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestExtensionsManager.java index 3b1faacc8e5..2b159d38339 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestExtensionsManager.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestExtensionsManager.java @@ -16,85 +16,40 @@ */ package org.apache.servicecomb.loadbalance; -import java.io.IOException; -import java.net.ConnectException; -import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.netflix.client.DefaultLoadBalancerRetryHandler; -import com.netflix.client.RetryHandler; - -import mockit.Deencapsulation; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestExtensionsManager { - @Before + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach public void setUp() { - ConfigUtil.createLocalConfig(); - Deencapsulation.setField(ExtensionsManager.class, "extentionFactories", new ArrayList<>()); + LegacyPropertyFactory.setEnvironment(environment); } - @After + @AfterEach public void tearDown() { - Deencapsulation.setField(ExtensionsManager.class, "extentionFactories", new ArrayList<>()); - ArchaiusUtils.resetConfig(); } @Test public void testRuleName() { - System.setProperty("servicecomb.loadbalance.mytest1.strategy.name", "RoundRobin"); - System.setProperty("servicecomb.loadbalance.mytest2.strategy.name", "Random"); - System.setProperty("servicecomb.loadbalance.mytest3.strategy.name", "WeightedResponse"); - System.setProperty("servicecomb.loadbalance.mytest4.strategy.name", "SessionStickiness"); - - BeansHolder holder = new BeansHolder(); - List extensionsFactories = new ArrayList<>(); - extensionsFactories.add(new RuleNameExtentionsFactory()); - extensionsFactories.add(new DefaultRetryExtensionsFactory()); - Deencapsulation.setField(holder, "extentionsFactories", extensionsFactories); - holder.init(); - - Assert.assertEquals(RoundRobinRuleExt.class.getName(), - ExtensionsManager.createLoadBalancerRule("mytest1").getClass().getName()); - Assert.assertEquals(RandomRuleExt.class.getName(), - ExtensionsManager.createLoadBalancerRule("mytest2").getClass().getName()); - Assert.assertEquals(WeightedResponseTimeRuleExt.class.getName(), - ExtensionsManager.createLoadBalancerRule("mytest3").getClass().getName()); - Assert.assertEquals(SessionStickinessRule.class.getName(), - ExtensionsManager.createLoadBalancerRule("mytest4").getClass().getName()); - - System.getProperties().remove("servicecomb.loadbalance.mytest1.strategy.name"); - System.getProperties().remove("servicecomb.loadbalance.mytest2.strategy.name"); - System.getProperties().remove("servicecomb.loadbalance.mytest3.strategy.name"); - System.getProperties().remove("servicecomb.loadbalance.mytest4.strategy.name"); - } - - - @Test - public void testRuleClassName() { - BeansHolder holder = new BeansHolder(); List extensionsFactories = new ArrayList<>(); - extensionsFactories.add(new RuleNameExtentionsFactory()); - extensionsFactories.add(new DefaultRetryExtensionsFactory()); - Deencapsulation.setField(holder, "extentionsFactories", extensionsFactories); - holder.init(); - RetryHandler retryHandler = ExtensionsManager.createRetryHandler("mytest1"); - Assert.assertTrue(DefaultLoadBalancerRetryHandler.class.isInstance(retryHandler)); - Assert.assertFalse(retryHandler.isRetriableException(new InvocationException(400, "", ""), false)); - Assert.assertFalse(retryHandler.isRetriableException(new InvocationException(400, "", ""), true)); - Assert.assertTrue(retryHandler.isRetriableException(new InvocationException(503, "", ""), true)); - Assert.assertTrue(retryHandler.isRetriableException(new ConnectException(), false)); - Assert.assertTrue(retryHandler.isRetriableException(new ConnectException(), true)); - Assert.assertTrue(retryHandler.isRetriableException(new SocketTimeoutException(), false)); - Assert.assertTrue(retryHandler.isRetriableException(new SocketTimeoutException(), true)); - Assert.assertFalse(retryHandler.isRetriableException(new IOException(), true)); + extensionsFactories.add(new RuleNameExtensionsFactory()); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionsFactories); + + Assertions.assertEquals(RoundRobinRuleExt.class.getName(), + extensionsManager.createLoadBalancerRule("RoundRobin").getClass().getName()); + Assertions.assertEquals(RandomRuleExt.class.getName(), + extensionsManager.createLoadBalancerRule("Random").getClass().getName()); + Assertions.assertEquals(WeightedResponseTimeRuleExt.class.getName(), + extensionsManager.createLoadBalancerRule("WeightedResponse").getClass().getName()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceCreator.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceCreator.java index e0019b7a156..1ee1824c6d6 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceCreator.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceCreator.java @@ -23,14 +23,12 @@ import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; -import com.netflix.loadbalancer.Server; - -import mockit.Deencapsulation; import mockit.Expectations; import mockit.Injectable; @@ -41,15 +39,18 @@ public void testLoadBalanceWithRoundRobinRuleAndFilter(@Injectable Invocation in // Robin components implementations require getReachableServers & getServerList have the same size, we add a test case for this. RoundRobinRuleExt rule = new RoundRobinRuleExt(); List servers = new ArrayList<>(); - Endpoint host1 = new Endpoint(transport, "host1"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("instance1"); - ServiceCombServer server = new ServiceCombServer(host1, instance1); - Endpoint host2 = new Endpoint(transport, "host2"); - MicroserviceInstance instance2 = new MicroserviceInstance(); - instance2.setInstanceId("instance2"); - ServiceCombServer server2 = new ServiceCombServer(host2, instance2); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance1 = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("instance1"); + Endpoint host1 = new Endpoint(transport, "host1", instance1); + ServiceCombServer server = new ServiceCombServer(null, host1); + + DiscoveryInstance discoveryInstance2 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = new StatefulDiscoveryInstance(discoveryInstance2); + Mockito.when(discoveryInstance2.getInstanceId()).thenReturn("instance2"); + Endpoint host2 = new Endpoint(transport, "host2", instance2); + ServiceCombServer server2 = new ServiceCombServer(null, host2); servers.add(server); servers.add(server2); @@ -57,34 +58,30 @@ public void testLoadBalanceWithRoundRobinRuleAndFilter(@Injectable Invocation in List filters = new ArrayList<>(); - filters.add(new ServerListFilterExt() { - @Override - public List getFilteredListOfServers(List serverList, - Invocation invocation) { - List filteredServers = new ArrayList<>(); - for (ServiceCombServer server : servers) { - if (server.getHost().equals("host1")) { - continue; - } - filteredServers.add(server); + filters.add((serverList, invocation1) -> { + List filteredServers = new ArrayList<>(); + for (ServiceCombServer server1 : servers) { + if (server1.getHost().equals("host1")) { + continue; } - return filteredServers; + filteredServers.add(server1); } + return filteredServers; }); lb.setFilters(filters); new Expectations() { { - invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST); + invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST); result = servers; } }; - Server s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + ServiceCombServer s = lb.chooseServer(invocation); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + Assertions.assertEquals(server2, s); } @Test @@ -95,47 +92,46 @@ public void testLoadBalanceWithRandomRuleAndFilter(@Injectable Invocation invoca LoadBalancer lb = new LoadBalancer(rule, "service"); List servers = new ArrayList<>(); - Endpoint host1 = new Endpoint(transport, "host1"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("instance1"); - ServiceCombServer server = new ServiceCombServer(host1, instance1); - Endpoint host2 = new Endpoint(transport, "host2"); - MicroserviceInstance instance2 = new MicroserviceInstance(); - instance2.setInstanceId("instance2"); - ServiceCombServer server2 = new ServiceCombServer(host2, instance2); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance1 = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("instance1"); + Endpoint host1 = new Endpoint(transport, "host1", instance1); + ServiceCombServer server = new ServiceCombServer(null, host1); + + DiscoveryInstance discoveryInstance2 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = new StatefulDiscoveryInstance(discoveryInstance2); + Mockito.when(discoveryInstance2.getInstanceId()).thenReturn("instance2"); + Endpoint host2 = new Endpoint(transport, "host2", instance2); + ServiceCombServer server2 = new ServiceCombServer(null, host2); servers.add(server); servers.add(server2); List filters = new ArrayList<>(); - filters.add(new ServerListFilterExt() { - @Override - public List getFilteredListOfServers(List serverList, - Invocation invocation) { - List filteredServers = new ArrayList<>(); - for (ServiceCombServer server : servers) { - if (server.getHost().equals("host1")) { - continue; - } - filteredServers.add(server); + filters.add((serverList, invocation1) -> { + List filteredServers = new ArrayList<>(); + for (ServiceCombServer server1 : servers) { + if (server1.getHost().equals("host1")) { + continue; } - return filteredServers; + filteredServers.add(server1); } + return filteredServers; }); lb.setFilters(filters); new Expectations() { { - invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST); + invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST); result = servers; } }; - Server s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + ServiceCombServer s = lb.chooseServer(invocation); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); + Assertions.assertEquals(server2, s); } @Test @@ -146,100 +142,56 @@ public void testLoadBalanceWithWeightedResponseTimeRuleAndFilter(@Injectable End LoadBalancer lb = new LoadBalancer(rule, "service"); List servers = new ArrayList<>(); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("ii01"); - MicroserviceInstance instance2 = new MicroserviceInstance(); - instance2.setInstanceId("ii02"); - ServiceCombServer server = new ServiceCombServer(endpoint1, instance1); - ServiceCombServer server2 = new ServiceCombServer(endpoint2, instance2); + + DiscoveryInstance discoveryInstance1 = Mockito.mock(DiscoveryInstance.class); +// StatefulDiscoveryInstance instance1 = new StatefulDiscoveryInstance(discoveryInstance1); + Mockito.when(discoveryInstance1.getInstanceId()).thenReturn("ii01"); + + DiscoveryInstance discoveryInstance2 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = new StatefulDiscoveryInstance(discoveryInstance2); + Mockito.when(discoveryInstance2.getInstanceId()).thenReturn("ii02"); new Expectations() { { endpoint1.getEndpoint(); result = "host1"; +// endpoint1.getMicroserviceInstance(); +// result = instance1; endpoint2.getEndpoint(); result = "host2"; + endpoint2.getMicroserviceInstance(); + result = instance2; } }; + ServiceCombServer server = new ServiceCombServer(null, endpoint1); + ServiceCombServer server2 = new ServiceCombServer(null, endpoint2); + servers.add(server); servers.add(server2); List filters = new ArrayList<>(); - filters.add(new ServerListFilterExt() { - @Override - public List getFilteredListOfServers(List serverList, - Invocation invocation) { - List filteredServers = new ArrayList<>(); - for (ServiceCombServer server : servers) { - if (server.getHost().equals("host1")) { - continue; - } - filteredServers.add(server); + filters.add((serverList, invocation1) -> { + List filteredServers = new ArrayList<>(); + for (ServiceCombServer server1 : servers) { + if (server1.getHost().equals("host1")) { + continue; } - return filteredServers; + filteredServers.add(server1); } + return filteredServers; }); lb.setFilters(filters); new Expectations() { { - invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST); - result = servers; - } - }; - Server s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); - s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); - s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); - } - - @Test - public void testLoadBalanceWithSessionSticknessRule(@Injectable Invocation invocation, - @Injectable Transport transport) { - SessionStickinessRule rule = new SessionStickinessRule(); - LoadBalancer lb = new LoadBalancer(rule, "service"); - - List servers = new ArrayList<>(); - Endpoint host1 = new Endpoint(transport, "host1"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - ServiceCombServer server = new ServiceCombServer(host1, instance1); - instance1.setInstanceId("instance1"); - - Endpoint host2 = new Endpoint(transport, "host2"); - MicroserviceInstance instance2 = new MicroserviceInstance(); - ServiceCombServer server2 = new ServiceCombServer(host2, instance2); - instance2.setInstanceId("instance2"); - - servers.add(server); - servers.add(server2); - - lb.setFilters(new ArrayList<>()); - new Expectations() { - { - invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST); + invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST); result = servers; } }; - - Server s = lb.chooseServer(invocation); - Assert.assertEquals(server, s); - s = lb.chooseServer(invocation); - Assert.assertEquals(server, s); - - long time = Deencapsulation.getField(rule, "lastAccessedTime"); - Deencapsulation.setField(rule, "lastAccessedTime", time - 1000 * 300); - ArchaiusUtils.setProperty("cse.loadbalance.service.SessionStickinessRule.sessionTimeoutInSeconds", 9); + ServiceCombServer s = lb.chooseServer(invocation); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server2, s); - - ArchaiusUtils.setProperty("cse.loadbalance.service.SessionStickinessRule.successiveFailedTimes", 5); - lb.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); - lb.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); - lb.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); - lb.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); - lb.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s); + Assertions.assertEquals(server2, s); s = lb.chooseServer(invocation); - Assert.assertEquals(server, s); + Assertions.assertEquals(server2, s); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter.java new file mode 100644 index 00000000000..123f23ac514 --- /dev/null +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance; + +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.registry.discovery.TelnetInstancePing; +import org.apache.servicecomb.swagger.invocation.AsyncResponse; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import mockit.Deencapsulation; +import mockit.Injectable; +import mockit.Mock; +import mockit.MockUp; +import mockit.Mocked; + +/** + * + * + */ +public class TestLoadBalanceFilter { + static SCBEngine scbEngine; + + static TransportManager transportManager; + + String microserviceName = "ms"; + + LoadBalanceFilter handler; + + Map loadBalancerMap; + + @Injectable + Invocation invocation; + + @Mocked + Transport restTransport; + + Response sendResponse; + + @Before + public void setUp() { + Environment environment = Mockito.mock(Environment.class); + scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_NAME); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled", + boolean.class, false)).thenReturn(false); + scbEngine.run(); + transportManager = scbEngine.getTransportManager(); + + new MockUp(invocation) { + @Mock + String getMicroserviceName() { + return microserviceName; + } + + @Mock + void next(AsyncResponse asyncResp) throws Exception { + asyncResp.handle(sendResponse); + } + + @Mock + public T getLocalContext(String key) { + return (T) null; + } + }; + + new MockUp(transportManager) { + @Mock + Transport findTransport(String transportName) { + return restTransport; + } + }; + + List extensionsFactories = new ArrayList<>(); + extensionsFactories.add(new RuleNameExtensionsFactory()); + ExtensionsManager extensionsManager = new ExtensionsManager(extensionsFactories); + + DiscoveryTree discoveryTree = new DiscoveryTree( + new DiscoveryManager(Collections.emptyList(), List.of(new TelnetInstancePing()))); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), + discoveryTree, scbEngine); + loadBalancerMap = Deencapsulation.getField(handler, "loadBalancerMap"); + } + + @After + public void teardown() { + scbEngine.destroy(); + } + + @Test + public void testIsFailedResponse() { + Assertions.assertFalse(handler.isFailedResponse(Response.create(400, "", ""))); + Assertions.assertFalse(handler.isFailedResponse(Response.create(500, "", ""))); + Assertions.assertTrue(handler.isFailedResponse(Response.create(490, "", ""))); + Assertions.assertTrue(handler.isFailedResponse(Response.consumerFailResp(new NullPointerException()))); + } +} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java new file mode 100644 index 00000000000..4c2fb5f5b45 --- /dev/null +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java @@ -0,0 +1,581 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance; + +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.config.DynamicProperties; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.NonSwaggerInvocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.loadbalance.filter.ServerDiscoveryFilter; +import org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.discovery.DiscoveryTree; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; + +public class TestLoadBalanceFilter2 { + DynamicProperties dynamicProperties = Mockito.mock(DynamicProperties.class); + + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + + Mockito.when(environment.getProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled", + boolean.class, false)).thenReturn(false); + + Mockito.when(dynamicProperties.getBooleanProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.enabled"), + Mockito.any(), + Mockito.eq(true))) + .thenReturn(true); + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratio"), + Mockito.any(), + Mockito.eq(30))) + .thenReturn(0); + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratioCeiling"), + Mockito.any(), + Mockito.eq(100))) + .thenReturn(100); + + LegacyPropertyFactory.setEnvironment(environment); + } + + @Test + public void testZoneAwareFilterWorks() { + ReferenceConfig referenceConfig = Mockito.mock(ReferenceConfig.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + InvocationRuntimeType invocationRuntimeType = Mockito.mock(InvocationRuntimeType.class); + SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Operation operation = Mockito.mock(Operation.class); + when(operationMeta.getSwaggerOperation()).thenReturn(operation); + when(operation.getExtensions()).thenReturn(null); + OpenAPI openAPI = Mockito.mock(OpenAPI.class); + when(schemaMeta.getSwagger()).thenReturn(openAPI); + when(openAPI.getExtensions()).thenReturn(null); + MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + when(schemaMeta.getMicroserviceName()).thenReturn("testMicroserviceName"); + when(microserviceMeta.getAppId()).thenReturn("testApp"); + when(referenceConfig.getTransport()).thenReturn("rest"); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, new HashMap<>()); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Transport transport = Mockito.mock(Transport.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getEnvironment()).thenReturn(environment); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:9090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:9091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:9092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + List data = new ArrayList<>(); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + when(transportManager.findTransport("rest")).thenReturn(transport); + + LoadBalanceFilter handler; + LoadBalancer loadBalancer; + ServiceCombServer server; + + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("testApp", "testMicroserviceName")) + .thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new ZoneAwareDiscoveryFilter(); + zoneAwareDiscoveryFilter.setDynamicProperties(dynamicProperties); + zoneAwareDiscoveryFilter.setDataCenterProperties(myself); + ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter(); + serverDiscoveryFilter.setScbEngine(scbEngine); + discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter, + serverDiscoveryFilter)); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), + discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertNull(server); + + data.add(noneMatchInstance); + parent.cacheVersion(1); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), + discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9092", server.getEndpoint().getEndpoint()); + + data.add(regionMatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9091", server.getEndpoint().getEndpoint()); + + data.add(allmatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9090", server.getEndpoint().getEndpoint()); + } + + + @Test + public void testIsolationEventWithEndpoint() { + ReferenceConfig referenceConfig = Mockito.mock(ReferenceConfig.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + InvocationRuntimeType invocationRuntimeType = Mockito.mock(InvocationRuntimeType.class); + SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Operation operation = Mockito.mock(Operation.class); + when(operationMeta.getSwaggerOperation()).thenReturn(operation); + when(operation.getExtensions()).thenReturn(null); + OpenAPI openAPI = Mockito.mock(OpenAPI.class); + when(schemaMeta.getSwagger()).thenReturn(openAPI); + when(openAPI.getExtensions()).thenReturn(null); + MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + when(schemaMeta.getMicroserviceName()).thenReturn("testMicroserviceName"); + when(microserviceMeta.getAppId()).thenReturn("testApp"); + when(referenceConfig.getTransport()).thenReturn("rest"); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, new HashMap<>()); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Transport transport = Mockito.mock(Transport.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getEnvironment()).thenReturn(environment); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test"); + myself.setAvailableZone("test"); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test"); + info.setAvailableZone("test"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:9090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("instance"); + + List data = new ArrayList<>(); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + + when(transportManager.findTransport("rest")).thenReturn(transport); + + LoadBalanceFilter handler; + LoadBalancer loadBalancer; + ServiceCombServer server; + + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("testApp", "testMicroserviceName")) + .thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new ZoneAwareDiscoveryFilter(); + zoneAwareDiscoveryFilter.setDynamicProperties(dynamicProperties); + zoneAwareDiscoveryFilter.setDataCenterProperties(myself); + ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter(); + serverDiscoveryFilter.setScbEngine(scbEngine); + discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter, + serverDiscoveryFilter)); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), + discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertNull(server); + + data.add(instance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9090", server.getEndpoint().getEndpoint()); + } + + @Test + public void testZoneAwareFilterWorksEmptyInstanceProtectionEnabled() { + ReferenceConfig referenceConfig = Mockito.mock(ReferenceConfig.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + InvocationRuntimeType invocationRuntimeType = Mockito.mock(InvocationRuntimeType.class); + SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); + when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); + when(schemaMeta.getMicroserviceName()).thenReturn("testMicroserviceName"); + Operation operation = Mockito.mock(Operation.class); + when(operationMeta.getSwaggerOperation()).thenReturn(operation); + when(operation.getExtensions()).thenReturn(null); + OpenAPI openAPI = Mockito.mock(OpenAPI.class); + when(schemaMeta.getSwagger()).thenReturn(openAPI); + when(openAPI.getExtensions()).thenReturn(null); + when(microserviceMeta.getAppId()).thenReturn("testApp"); + when(referenceConfig.getTransport()).thenReturn("rest"); + Invocation invocation = new Invocation(referenceConfig, operationMeta, invocationRuntimeType, new HashMap<>()); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Transport transport = Mockito.mock(Transport.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Mockito.when(scbEngine.getEnvironment()).thenReturn(environment); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:9090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:9091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:9092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + List data = new ArrayList<>(); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + + when(transportManager.findTransport("rest")).thenReturn(transport); + + LoadBalanceFilter handler; + LoadBalancer loadBalancer; + ServiceCombServer server; + + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("testApp", "testMicroserviceName")) + .thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new ZoneAwareDiscoveryFilter(); + zoneAwareDiscoveryFilter.setDynamicProperties(dynamicProperties); + zoneAwareDiscoveryFilter.setDataCenterProperties(myself); + ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter(); + serverDiscoveryFilter.setScbEngine(scbEngine); + discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter, + serverDiscoveryFilter)); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertNull(server); + + data.add(noneMatchInstance); + parent.cacheVersion(1); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9092", server.getEndpoint().getEndpoint()); + + data.add(regionMatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9091", server.getEndpoint().getEndpoint()); + + data.add(allmatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:9090", server.getEndpoint().getEndpoint()); + } + + @Test + public void testZoneAwareFilterUsingMockedInvocationWorks() { + Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName"); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Transport transport = Mockito.mock(Transport.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Mockito.when(scbEngine.getEnvironment()).thenReturn(environment); + Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.operation.enabled", + boolean.class, true)).thenReturn(false); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:7090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:7091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:7092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + List data = new ArrayList<>(); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + + when(transportManager.findTransport("rest")).thenReturn(transport); + + LoadBalanceFilter handler; + LoadBalancer loadBalancer; + ServiceCombServer server; + + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("testApp", "testMicroserviceName")) + .thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new ZoneAwareDiscoveryFilter(); + zoneAwareDiscoveryFilter.setDynamicProperties(dynamicProperties); + zoneAwareDiscoveryFilter.setDataCenterProperties(myself); + ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter(); + serverDiscoveryFilter.setScbEngine(scbEngine); + discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter, + serverDiscoveryFilter)); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertNull(server); + + data.add(noneMatchInstance); + parent.cacheVersion(1); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7092", server.getEndpoint().getEndpoint()); + + data.add(regionMatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7091", server.getEndpoint().getEndpoint()); + + data.add(allmatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7090", server.getEndpoint().getEndpoint()); + } + + @Test + public void testStatusFilterUsingMockedInvocationWorks() { + Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName"); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Transport transport = Mockito.mock(Transport.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Mockito.when(scbEngine.getEnvironment()).thenReturn(environment); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:7090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + Mockito.when(discoveryInstance.getStatus()).thenReturn(MicroserviceInstanceStatus.TESTING); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:7091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:7092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + List data = new ArrayList<>(); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + + when(transportManager.findTransport("rest")).thenReturn(transport); + + LoadBalanceFilter handler; + LoadBalancer loadBalancer; + ServiceCombServer server; + + DiscoveryManager discoveryManager = Mockito.mock(DiscoveryManager.class); + Mockito.when(discoveryManager.getOrCreateVersionedCache("testApp", "testMicroserviceName")) + .thenReturn(parent); + DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager); + ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new ZoneAwareDiscoveryFilter(); + zoneAwareDiscoveryFilter.setDynamicProperties(dynamicProperties); + zoneAwareDiscoveryFilter.setDataCenterProperties(myself); + ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter(); + serverDiscoveryFilter.setScbEngine(scbEngine); + discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter, + serverDiscoveryFilter)); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertNull(server); + + data.add(noneMatchInstance); + parent.cacheVersion(1); + handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()), discoveryTree, scbEngine); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7092", server.getEndpoint().getEndpoint()); + + data.add(regionMatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7091", server.getEndpoint().getEndpoint()); + + data.add(allmatchInstance); + parent.cacheVersion(parent.cacheVersion() + 1); + loadBalancer = handler.getOrCreateLoadBalancer(invocation); + server = loadBalancer.chooseServer(invocation); + Assertions.assertEquals("rest://localhost:7090", server.getEndpoint().getEndpoint()); + } +} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java deleted file mode 100644 index d98d672a32c..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.NonSwaggerInvocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter; -import org.apache.servicecomb.loadbalance.filter.ServerDiscoveryFilter; -import org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.DataCenterInfo; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -/** - * - * - */ -public class TestLoadBalanceHandler2 { - @BeforeClass - public static void beforeClass() { - //prepare for defineEndpointAndHandle - ArchaiusUtils.setProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled", "true"); - // avoid mock - - } - - @Before - public void setUp() { - // clear up load balance stats - ServiceCombLoadBalancerStats.INSTANCE.init(); - } - - @After - public void teardown() { - CseContext.getInstance().setTransportManager(null); - ArchaiusUtils.resetConfig(); - } - - @Test - public void testZoneAwareAndIsolationFilterWorks() throws Exception { - ReferenceConfig referenceConfig = Mockito.mock(ReferenceConfig.class); - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); - when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); - MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); - when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); - when(schemaMeta.getMicroserviceName()).thenReturn("testMicroserviceName"); - when(microserviceMeta.getAppId()).thenReturn("testApp"); - when(referenceConfig.getVersionRule()).thenReturn("0.0.0+"); - when(referenceConfig.getTransport()).thenReturn("rest"); - Invocation invocation = new Invocation(referenceConfig, operationMeta, new Object[0]); - - InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); - TransportManager transportManager = Mockito.mock(TransportManager.class); - Transport transport = Mockito.mock(Transport.class); - ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); - - // set up data - MicroserviceInstance myself = new MicroserviceInstance(); - DataCenterInfo info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone"); - myself.setDataCenterInfo(info); - - MicroserviceInstance allmatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone"); - List allMatchEndpoint = new ArrayList<>(); - allMatchEndpoint.add("rest://localhost:9090"); - allmatchInstance.setEndpoints(allMatchEndpoint); - allmatchInstance.setDataCenterInfo(info); - allmatchInstance.setInstanceId("allmatchInstance"); - - MicroserviceInstance regionMatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone2"); - List regionMatchEndpoint = new ArrayList<>(); - regionMatchEndpoint.add("rest://localhost:9091"); - regionMatchInstance.setEndpoints(regionMatchEndpoint); - regionMatchInstance.setDataCenterInfo(info); - regionMatchInstance.setInstanceId("regionMatchInstance"); - - MicroserviceInstance noneMatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region2"); - info.setAvailableZone("test-zone2"); - List noMatchEndpoint = new ArrayList<>(); - noMatchEndpoint.add("rest://localhost:9092"); - noneMatchInstance.setEndpoints(noMatchEndpoint); - noneMatchInstance.setDataCenterInfo(info); - noneMatchInstance.setInstanceId("noneMatchInstance"); - - Map data = new HashMap<>(); - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); - CseContext.getInstance().setTransportManager(transportManager); - - RegistryUtils.setServiceRegistry(serviceRegistry); - - when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); - when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) - .thenReturn(parent); - when(transportManager.findTransport("rest")).thenReturn(transport); - - LoadbalanceHandler handler = null; - LoadBalancer loadBalancer = null; - ServiceCombServer server = null; - - handler = new LoadbalanceHandler(); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server, null); - - data.put("noneMatchInstance", noneMatchInstance); - parent.cacheVersion(1); - handler = new LoadbalanceHandler(); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9092"); - - data.put("regionMatchInstance", regionMatchInstance); - parent.cacheVersion(parent.cacheVersion() + 1); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9091"); - - data.put("allmatchInstance", allmatchInstance); - parent.cacheVersion(parent.cacheVersion() + 1); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9090"); - - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server); - - //if errorThresholdPercentage is 0,that means errorThresholdPercentage is not active. - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.errorThresholdPercentage", "0"); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9090"); - - //if errorThresholdPercentage greater than 0, it will activate. - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.errorThresholdPercentage", "20"); - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.minIsolationTime", "10"); - ServiceCombServer server2 = server; - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9091"); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server2); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9091"); - TimeUnit.MILLISECONDS.sleep(20); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9090"); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:9091"); - } - - @Test - public void testZoneAwareAndIsolationFilterUsingMockedInvocationWorks() throws Exception { - Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName", "0.0.0+", (inv, aysnc) -> { - aysnc.success("OK"); - }); - - InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); - TransportManager transportManager = Mockito.mock(TransportManager.class); - Transport transport = Mockito.mock(Transport.class); - ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); - - // set up data - MicroserviceInstance myself = new MicroserviceInstance(); - DataCenterInfo info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone"); - myself.setDataCenterInfo(info); - - MicroserviceInstance allmatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone"); - List allMatchEndpoint = new ArrayList<>(); - allMatchEndpoint.add("rest://localhost:7090"); - allmatchInstance.setEndpoints(allMatchEndpoint); - allmatchInstance.setDataCenterInfo(info); - allmatchInstance.setInstanceId("allmatchInstance"); - - MicroserviceInstance regionMatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region"); - info.setAvailableZone("test-zone2"); - List regionMatchEndpoint = new ArrayList<>(); - regionMatchEndpoint.add("rest://localhost:7091"); - regionMatchInstance.setEndpoints(regionMatchEndpoint); - regionMatchInstance.setDataCenterInfo(info); - regionMatchInstance.setInstanceId("regionMatchInstance"); - - MicroserviceInstance noneMatchInstance = new MicroserviceInstance(); - info = new DataCenterInfo(); - info.setName("test"); - info.setRegion("test-Region2"); - info.setAvailableZone("test-zone2"); - List noMatchEndpoint = new ArrayList<>(); - noMatchEndpoint.add("rest://localhost:7092"); - noneMatchInstance.setEndpoints(noMatchEndpoint); - noneMatchInstance.setDataCenterInfo(info); - noneMatchInstance.setInstanceId("noneMatchInstance"); - - Map data = new HashMap<>(); - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); - CseContext.getInstance().setTransportManager(transportManager); - - RegistryUtils.setServiceRegistry(serviceRegistry); - - when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); - when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) - .thenReturn(parent); - when(transportManager.findTransport("rest")).thenReturn(transport); - - LoadbalanceHandler handler = null; - LoadBalancer loadBalancer = null; - ServiceCombServer server = null; - - DiscoveryTree discoveryTree = new DiscoveryTree(); - discoveryTree.addFilter(new IsolationDiscoveryFilter()); - discoveryTree.addFilter(new ZoneAwareDiscoveryFilter()); - discoveryTree.addFilter(new ServerDiscoveryFilter()); - discoveryTree.sort(); - handler = new LoadbalanceHandler(discoveryTree); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server, null); - - data.put("noneMatchInstance", noneMatchInstance); - parent.cacheVersion(1); - handler = new LoadbalanceHandler(); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7092"); - handler.handle(invocation, (response) -> { - Assert.assertEquals(response.getResult(), "OK"); - }); - - data.put("regionMatchInstance", regionMatchInstance); - parent.cacheVersion(parent.cacheVersion() + 1); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7091"); - handler.handle(invocation, (response) -> { - Assert.assertEquals(response.getResult(), "OK"); - }); - - data.put("allmatchInstance", allmatchInstance); - parent.cacheVersion(parent.cacheVersion() + 1); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7090"); - - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server); - - //if errorThresholdPercentage is 0,that means errorThresholdPercentage is not active. - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.errorThresholdPercentage", "0"); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7090"); - - //if errorThresholdPercentage greater than 0, it will activate. - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.errorThresholdPercentage", "20"); - ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.minIsolationTime", "10"); - ServiceCombServer server2 = server; - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7091"); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server2); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7091"); - TimeUnit.MILLISECONDS.sleep(20); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7090"); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2); - loadBalancer = handler.getOrCreateLoadBalancer(invocation); - server = loadBalancer.chooseServer(invocation); - Assert.assertEquals(server.getEndpoint().getEndpoint(), "rest://localhost:7091"); - handler.handle(invocation, (response) -> { - Assert.assertEquals(response.getResult(), "OK"); - }); - } - - @Test - public void testConfigEndpoint() { - ReferenceConfig referenceConfig = Mockito.mock(ReferenceConfig.class); - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); - when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); - MicroserviceMeta microserviceMeta = Mockito.mock(MicroserviceMeta.class); - when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta); - when(schemaMeta.getMicroserviceName()).thenReturn("testMicroserviceName"); - when(microserviceMeta.getAppId()).thenReturn("testApp"); - when(referenceConfig.getVersionRule()).thenReturn("0.0.0+"); - when(referenceConfig.getTransport()).thenReturn("rest"); - Invocation invocation = new Invocation(referenceConfig, operationMeta, new Object[0]); - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - - InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); - TransportManager transportManager = Mockito.mock(TransportManager.class); - Transport transport = Mockito.mock(Transport.class); - ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); - - // set up data - MicroserviceInstance myself = new MicroserviceInstance(); - - MicroserviceInstance findInstance = new MicroserviceInstance(); - List findEndpoint = new ArrayList<>(); - findEndpoint.add("rest://localhost:9092"); - findInstance.setEndpoints(findEndpoint); - findInstance.setInstanceId("findInstance"); - - Map data = new HashMap<>(); - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); - CseContext.getInstance().setTransportManager(transportManager); - SCBEngine.getInstance().setTransportManager(transportManager); - - RegistryUtils.setServiceRegistry(serviceRegistry); - - when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); - when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) - .thenReturn(parent); - when(transportManager.findTransport("rest")).thenReturn(transport); - - LoadbalanceHandler handler = null; - - handler = new LoadbalanceHandler(); - data.put("findInstance", findInstance); - parent.cacheVersion(1); - handler = new LoadbalanceHandler(); - try { - handler.handle(invocation, asyncResp); - } catch (Exception e) { - - } - Assert.assertEquals("rest://localhost:9092", invocation.getEndpoint().getEndpoint()); - - //success - invocation.addLocalContext("scb-endpoint", "rest://127.0.0.1:8080?sslEnabled=true&protocol=http2"); - try { - handler.handle(invocation, asyncResp); - } catch (Exception e) { - - } - Assert.assertEquals("rest://127.0.0.1:8080?sslEnabled=true&protocol=http2", invocation.getEndpoint().getEndpoint()); - - //endpoint format is not correct - invocation.addLocalContext("scb-endpoint", "127.0.0.1:8080"); - try { - handler.handle(invocation, asyncResp); - Assert.assertEquals("endpoint's format is not correct, throw exception", " but not throw exception"); - } catch (Exception e) { - Assert.assertTrue(e.getMessage() - .contains("Illegal character in scheme name")); - } - - //transport is not find - invocation.addLocalContext("scb-endpoint", "my://127.0.0.1:8080?sslEnabled=true&protocol=http2"); - try { - handler.handle(invocation, asyncResp); - Assert.assertEquals("endpoint's transport not found, throw exception", "but not throw exception"); - } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("the endpoint's transport is not found.")); - } - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalancer.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalancer.java index 761c23cbefa..ba17976e0ba 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalancer.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalancer.java @@ -17,33 +17,36 @@ package org.apache.servicecomb.loadbalance; -import static org.mockito.Mockito.when; - import java.util.ArrayList; import java.util.List; import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestLoadBalancer { - private RuleExt rule = Mockito.mock(RuleExt.class); + private final RuleExt rule = Mockito.mock(RuleExt.class); @Test public void testLoadBalancerFullOperationWithoutException() { List newServers = new ArrayList<>(); ServiceCombServer server = Mockito.mock(ServiceCombServer.class); Invocation invocation = Mockito.mock(Invocation.class); + StatefulDiscoveryInstance microserviceInstance = Mockito.mock(StatefulDiscoveryInstance.class); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); newServers.add(server); - when(invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST)).thenReturn(newServers); + Mockito.when(invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST)).thenReturn(newServers); + Mockito.when(server.getInstance()).thenReturn(microserviceInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("123456"); LoadBalancer loadBalancer = new LoadBalancer(rule, "test"); loadBalancer.chooseServer(invocation); - when(rule.choose(newServers, invocation)).thenReturn(server); + Mockito.when(rule.choose(newServers, invocation)).thenReturn(server); - Assert.assertEquals(server, loadBalancer.chooseServer(invocation)); - Assert.assertNotNull(loadBalancer.getLoadBalancerStats()); - Assert.assertEquals("test", loadBalancer.getMicroServiceName()); + Assertions.assertEquals(server, loadBalancer.chooseServer(invocation)); + Assertions.assertEquals("test", loadBalancer.getMicroServiceName()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceClientConfig.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceClientConfig.java deleted file mode 100644 index b2c57a21b6d..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceClientConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import static org.junit.Assert.assertNotNull; - -import org.junit.Test; - -/** - * - * - */ -public class TestLoadbalanceClientConfig { - - @Test - public void testLoadbalanceConstructor() { - - LoadbalanceClientConfig lbc = new LoadbalanceClientConfig("test"); - - assertNotNull(lbc); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java deleted file mode 100644 index b20530dd494..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; - -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import com.netflix.loadbalancer.IRule; -import com.netflix.loadbalancer.LoadBalancerStats; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -/** - * - * - */ -public class TestLoadbalanceHandler { - String microserviceName = "ms"; - - IRule rule = Mockito.mock(IRule.class); - - LoadbalanceHandler handler; - - Map loadBalancerMap; - - @Injectable - Invocation invocation; - - @Mocked - ServiceRegistry serviceRegistry; - - @Mocked - InstanceCacheManager instanceCacheManager; - - @Mocked - TransportManager transportManager; - - @Mocked - Transport restTransport; - - Response sendResponse; - - List results = new ArrayList<>(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setUp() { - new MockUp(invocation) { - @Mock - String getMicroserviceName() { - return microserviceName; - } - - @Mock - void next(AsyncResponse asyncResp) throws Exception { - asyncResp.handle(sendResponse); - } - }; - - CseContext.getInstance().setTransportManager(transportManager); - new MockUp(transportManager) { - @Mock - Transport findTransport(String transportName) { - return restTransport; - } - }; - - RegistryUtils.setServiceRegistry(serviceRegistry); - new MockUp(serviceRegistry) { - @Mock - InstanceCacheManager getInstanceCacheManager() { - return instanceCacheManager; - } - }; - - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(DiscoveryFilter.class); - result = Collections.emptyList(); - } - }; - - BeansHolder holder = new BeansHolder(); - List extensionsFactories = new ArrayList<>(); - extensionsFactories.add(new RuleNameExtentionsFactory()); - extensionsFactories.add(new DefaultRetryExtensionsFactory()); - Deencapsulation.setField(holder, "extentionsFactories", extensionsFactories); - holder.init(); - - handler = new LoadbalanceHandler(); - loadBalancerMap = Deencapsulation.getField(handler, "loadBalancerMap"); - } - - @After - public void teardown() { - CseContext.getInstance().setTransportManager(null); - RegistryUtils.setServiceRegistry(null); - ArchaiusUtils.resetConfig(); - } - - @Test - public void send_noEndPoint(@Injectable LoadBalancer loadBalancer) { - new Expectations(loadBalancer) { - { - loadBalancer.chooseServer(invocation); - result = null; - } - }; - - Holder result = new Holder<>(); - Deencapsulation.invoke(handler, "send", invocation, (AsyncResponse) resp -> { - result.value = (Throwable) resp.getResult(); - }, loadBalancer); - - Assert.assertEquals("InvocationException: code=500;msg=CommonExceptionData [message=No available address found.]", - result.value.getMessage()); - } - - @Test - public void send_failed2(@Injectable LoadBalancer loadBalancer) { - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - CacheEndpoint cacheEndpoint = new CacheEndpoint("rest://localhost:8080", instance1); - ServiceCombServer server = new ServiceCombServer(restTransport, cacheEndpoint); - LoadBalancerStats stats = new LoadBalancerStats("test"); - new Expectations(loadBalancer) { - { - loadBalancer.chooseServer(invocation); - result = server; - loadBalancer.getLoadBalancerStats(); - result = stats; - } - }; - sendResponse = Response.create(Status.BAD_REQUEST, "send failed"); - - Holder result = new Holder<>(); - Deencapsulation.invoke(handler, "send", invocation, (AsyncResponse) resp -> { - result.value = (Throwable) resp.getResult(); - }, loadBalancer); - - // InvocationException is not taken as a failure - Assert.assertEquals(0, - loadBalancer.getLoadBalancerStats().getSingleServerStat(server).getSuccessiveConnectionFailureCount()); - Assert.assertEquals("InvocationException: code=400;msg=send failed", - result.value.getMessage()); - } - - @Test - public void send_failed(@Injectable LoadBalancer loadBalancer) { - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - CacheEndpoint cacheEndpoint = new CacheEndpoint("rest://localhost:8080", instance1); - ServiceCombServer server = new ServiceCombServer(restTransport, cacheEndpoint); - LoadBalancerStats stats = new LoadBalancerStats("test"); - new Expectations(loadBalancer) { - { - loadBalancer.chooseServer(invocation); - result = server; - loadBalancer.getLoadBalancerStats(); - result = stats; - } - }; - sendResponse = Response.consumerFailResp(new SocketException()); - - Holder result = new Holder<>(); - Deencapsulation.invoke(handler, "send", invocation, (AsyncResponse) resp -> { - result.value = (Throwable) resp.getResult(); - }, loadBalancer); - - Assert.assertEquals(1, - loadBalancer.getLoadBalancerStats().getSingleServerStat(server).getSuccessiveConnectionFailureCount()); - Assert.assertEquals("InvocationException: code=490;msg=CommonExceptionData [message=Cse Internal Bad Request]", - result.value.getMessage()); - } - - @Test - public void send_success(@Injectable LoadBalancer loadBalancer) { - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - CacheEndpoint cacheEndpoint = new CacheEndpoint("rest://localhost:8080", instance1); - ServiceCombServer server = new ServiceCombServer(restTransport, cacheEndpoint); - LoadBalancerStats stats = new LoadBalancerStats("test"); - new Expectations(loadBalancer) { - { - loadBalancer.chooseServer(invocation); - result = server; - loadBalancer.getLoadBalancerStats(); - result = stats; - } - }; - sendResponse = Response.ok("success"); - - Holder result = new Holder<>(); - Deencapsulation.invoke(handler, "send", invocation, (AsyncResponse) resp -> { - result.value = resp.getResult(); - }, loadBalancer); - - Assert.assertEquals(1, - loadBalancer.getLoadBalancerStats().getSingleServerStat(server).getActiveRequestsCount()); - Assert.assertEquals("success", result.value); - } - - @Test - public void sendWithRetry(@Injectable LoadBalancer loadBalancer) { - Holder result = new Holder<>(); - Deencapsulation.invoke(handler, "sendWithRetry", invocation, (AsyncResponse) resp -> { - result.value = resp.getResult(); - }, loadBalancer); - - // no exception - } - - @Test - public void testIsEqual() { - boolean nullResult = handler.isEqual(null, null); - Assert.assertEquals(true, nullResult); - boolean bothNotNullResult = - handler.isEqual("com.netflix.loadbalancer.RandomRule", "com.netflix.loadbalancer.RandomRule"); - Assert.assertEquals(true, bothNotNullResult); - boolean globalNotNull = handler.isEqual(null, "com.netflix.loadbalancer.RandomRule"); - Assert.assertEquals(false, globalNotNull); - boolean localNotNull = handler.isEqual("com.netflix.loadbalancer.RandomRule", null); - Assert.assertEquals(false, localNotNull); - } - - @Test - public void testIsFailedResponse() { - Assert.assertFalse(handler.isFailedResponse(Response.create(400, "", ""))); - Assert.assertFalse(handler.isFailedResponse(Response.create(500, "", ""))); - Assert.assertTrue(handler.isFailedResponse(Response.create(490, "", ""))); - Assert.assertTrue(handler.isFailedResponse(Response.consumerFailResp(new NullPointerException()))); - } - - @Test - public void retryPoolDaemon() throws ExecutionException, InterruptedException { - ExecutorService RETRY_POOL = Deencapsulation.getField(handler, "RETRY_POOL"); - - Holder nameHolder = new Holder<>(); - - RETRY_POOL.submit(() -> { - nameHolder.value = Thread.currentThread(); - }).get(); - - Assert.assertThat(nameHolder.value.getName(), Matchers.startsWith("retry-pool-thread-")); - Assert.assertTrue(nameHolder.value.isDaemon()); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java index ce78b503e7f..d381703f445 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java @@ -22,22 +22,20 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestRoundRobinRuleExt { @Test public void testRoundRobin() { RoundRobinRuleExt rule = new RoundRobinRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); for (int i = 0; i < 2; i++) { ServiceCombServer server = Mockito.mock(ServiceCombServer.class); Mockito.when(server.toString()).thenReturn("server " + i); servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, 1); } AtomicInteger server1 = new AtomicInteger(0); @@ -49,21 +47,19 @@ public void testRoundRobin() { server2.incrementAndGet(); } } - Assert.assertEquals(server1.get(), server2.get()); + Assertions.assertEquals(server1.get(), server2.get()); } @Test public void testBenchmarkRobin() { // less than 0.001ms RoundRobinRuleExt rule = new RoundRobinRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); for (int i = 0; i < 100; i++) { ServiceCombServer server = Mockito.mock(ServiceCombServer.class); Mockito.when(server.toString()).thenReturn("server " + i); servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, 2); } long begin = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { @@ -71,6 +67,6 @@ public void testBenchmarkRobin() { } long taken = System.currentTimeMillis() - begin; System.out.println("taken " + taken); - Assert.assertEquals("actual token " + taken, taken < 10 * 5, true); // 5 * times make slow machine happy + Assertions.assertTrue(taken < 10 * 5, "actual token " + taken); // 5 * times make slow machine happy } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java deleted file mode 100644 index fb884529cf9..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import static org.awaitility.Awaitility.await; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; - -public class TestServiceCombLoadBalancerStats { - @BeforeClass - public static void beforeClass() { - // avoid mock - ServiceCombLoadBalancerStats.INSTANCE.init(); - } - - @Test - public void testServiceExpire(@Injectable Transport transport, @Mocked SPIServiceUtils utils, @Injectable - MicroserviceInstancePing ping) throws Exception { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("instance1"); - - new Expectations() { - { - SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class); - result = ping; - ping.ping(instance); - result = false; - } - }; - - ServiceCombLoadBalancerStats serviceCombLoadBalancerStats = new ServiceCombLoadBalancerStats(); - serviceCombLoadBalancerStats.setServerExpireInSeconds(2); - serviceCombLoadBalancerStats.setTimerIntervalInMilis(500); - serviceCombLoadBalancerStats.init(); - - ServiceCombServer serviceCombServer = new ServiceCombServer(transport, - new CacheEndpoint("rest://localhost:8080", instance)); - serviceCombLoadBalancerStats.markSuccess(serviceCombServer); - ServiceCombServerStats stats = serviceCombLoadBalancerStats.getServiceCombServerStats(serviceCombServer); - Assert.assertEquals(serviceCombLoadBalancerStats.getPingView().size(), 1); - await().atMost(5, TimeUnit.SECONDS) - .until(() -> { - return serviceCombLoadBalancerStats.getPingView().size() <= 0; - }); - Assert.assertEquals(serviceCombLoadBalancerStats.getPingView().size(), 0); - System.out.print(stats.getFailedRequests()); - Assert.assertTrue(stats.getFailedRequests() >= 1); - } - - @Test - public void testSimpleThread(@Injectable Transport transport) { - long time = System.currentTimeMillis(); - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("instance1"); - ServiceCombServer serviceCombServer = new ServiceCombServer(transport, - new CacheEndpoint("rest://localhost:8080", instance)); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getCountinuousFailureCount(), - 2); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getCountinuousFailureCount(), - 0); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer); - Assert - .assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getTotalRequests(), 4); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRate(), 50); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getSuccessRate(), 50); - Assert.assertTrue( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime() <= System - .currentTimeMillis() - && ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime() - >= time); - } - - @Test - public void testMiltiThread(@Injectable Transport transport) throws Exception { - long time = System.currentTimeMillis(); - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("instance2"); - ServiceCombServer serviceCombServer = new ServiceCombServer(transport, - new CacheEndpoint("rest://localhost:8080", instance)); - - CountDownLatch latch = new CountDownLatch(10); - for (int i = 0; i < 10; i++) { - new Thread() { - public void run() { - ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer); - ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer); - ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer); - latch.countDown(); - } - }.start(); - } - latch.await(30, TimeUnit.SECONDS); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getTotalRequests(), - 4 * 10); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRate(), 50); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getSuccessRate(), 50); - Assert.assertEquals( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getSuccessRequests(), 20); - Assert.assertTrue( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime() <= System - .currentTimeMillis() - && ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime() - >= time); - - // time consuming test for timers, taking about 20 seconds. ping timer will update instance status to failure - Assert.assertTrue( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRate() <= 50); - long beginTime = System.currentTimeMillis(); - long rate = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests(); - while (rate <= 20 && - System.currentTimeMillis() - beginTime <= 30000) { - Thread.sleep(2000); - rate = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests(); - System.out.println("XXXTTTTT1" + rate); - } - - Assert.assertTrue(System.currentTimeMillis() - beginTime < 30000); - Assert - .assertTrue( - ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests() - > 20); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServer.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServer.java index 1b2e599c7a9..e914ae20c6a 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServer.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServer.java @@ -17,14 +17,13 @@ package org.apache.servicecomb.loadbalance; -import static org.junit.Assert.assertNotNull; - +import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.junit.Assert; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; /** @@ -33,58 +32,61 @@ */ public class TestServiceCombServer { - private Transport transport = Mockito.mock(Transport.class); + private final Transport transport = Mockito.mock(Transport.class); private ServiceCombServer cs; @Before public void setUp() { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("123456"); - cs = new ServiceCombServer(transport, new CacheEndpoint("abcd", instance)); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("123456"); + cs = new ServiceCombServer(null, new Endpoint(transport, "abcd", instance)); } @Test public void testCseServerObj() { - assertNotNull(cs); + Assertions.assertNotNull(cs); } @Test public void testGetEndpoint() { cs.getEndpoint(); - assertNotNull(cs.getEndpoint()); + Assertions.assertNotNull(cs.getEndpoint()); } @Test public void testEqualsMethod() { - Assert.assertFalse(cs.equals((Object) "abcd")); + Assertions.assertNotEquals(cs, (Object) "abcd"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - ServiceCombServer other = new ServiceCombServer(transport, new CacheEndpoint("1234", instance1)); - Assert.assertFalse(cs.equals(other)); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance1 = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("1234"); + ServiceCombServer other = new ServiceCombServer(null, new Endpoint(transport, "1234", instance1)); + Assertions.assertNotEquals(cs, other); - MicroserviceInstance instance2 = new MicroserviceInstance(); - instance2.setInstanceId("123456"); - other = new ServiceCombServer(transport, new CacheEndpoint("abcd", instance2)); - Assert.assertTrue(cs.equals(other)); + DiscoveryInstance discoveryInstance2 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = new StatefulDiscoveryInstance(discoveryInstance2); + Mockito.when(discoveryInstance2.getInstanceId()).thenReturn("123456"); + other = new ServiceCombServer(null, new Endpoint(transport, "abcd", instance2)); + Assertions.assertEquals(cs, other); } @Test public void testToStringMethod() { cs.toString(); - assertNotNull(cs.toString()); + Assertions.assertNotNull(cs.toString()); } @Test public void testGetHost() { cs.getHost(); - assertNotNull(cs.getHost()); + Assertions.assertNotNull(cs.getHost()); } @Test public void testHashCodeMethod() { cs.hashCode(); - assertNotNull(cs.hashCode()); + Assertions.assertNotNull(cs.hashCode()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java deleted file mode 100644 index 30103687299..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mock; -import mockit.MockUp; - -public class TestServiceCombServerStats { - @Test - public void testSimpleThread() { - long time = System.currentTimeMillis(); - ServiceCombServerStats stats = new ServiceCombServerStats(); - stats.markFailure(); - stats.markFailure(); - Assert.assertEquals(stats.getCountinuousFailureCount(), 2); - stats.markSuccess(); - Assert.assertEquals(stats.getCountinuousFailureCount(), 0); - stats.markSuccess(); - Assert.assertEquals(stats.getTotalRequests(), 4); - Assert.assertEquals(stats.getFailedRate(), 50); - Assert.assertEquals(stats.getSuccessRate(), 50); - Assert.assertTrue(stats.getLastVisitTime() <= System.currentTimeMillis() && stats.getLastVisitTime() >= time); - Assert.assertTrue(stats.getLastActiveTime() <= System.currentTimeMillis() && stats.getLastActiveTime() >= time); - } - - @Test - public void testMiltiThread() throws Exception { - long time = System.currentTimeMillis(); - ServiceCombServerStats stats = new ServiceCombServerStats(); - CountDownLatch latch = new CountDownLatch(10); - for (int i = 0; i < 10; i++) { - new Thread() { - public void run() { - stats.markFailure(); - stats.markFailure(); - stats.markSuccess(); - stats.markSuccess(); - latch.countDown(); - } - }.start(); - } - latch.await(30, TimeUnit.SECONDS); - Assert.assertEquals(stats.getTotalRequests(), 4 * 10); - Assert.assertEquals(stats.getFailedRate(), 50); - Assert.assertEquals(stats.getSuccessRate(), 50); - Assert.assertTrue(stats.getLastVisitTime() <= System.currentTimeMillis() && stats.getLastVisitTime() >= time); - Assert.assertTrue(stats.getLastActiveTime() <= System.currentTimeMillis() && stats.getLastActiveTime() >= time); - } - - @Test - public void testTimeWindow() { - new MockUp() { - @Mock - long currentTimeMillis() { - return 1000; - } - }; - ServiceCombServerStats stats = new ServiceCombServerStats(); - Assert.assertEquals(stats.getLastVisitTime(), 1000); - stats.markSuccess(); - stats.markFailure(); - Assert.assertEquals(stats.getTotalRequests(), 2); - Assert.assertEquals(stats.getFailedRate(), 50); - Assert.assertEquals(stats.getSuccessRate(), 50); - new MockUp() { - @Mock - long currentTimeMillis() { - return 60000 + 2000; - } - }; - stats.markSuccess(); - Assert.assertEquals(stats.getTotalRequests(), 1); - Assert.assertEquals(stats.getFailedRate(), 0); - Assert.assertEquals(stats.getSuccessRate(), 100); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionStickinessRule.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionStickinessRule.java new file mode 100644 index 00000000000..9a60b18657c --- /dev/null +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionStickinessRule.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; + +import mockit.Deencapsulation; +import mockit.Mock; +import mockit.MockUp; + +public class TestSessionStickinessRule { + @Test + public void testServerWithoutTimeoutAndWithThreshold() { + + boolean status = true; + + SessionStickinessRule ss = new SessionStickinessRule(); + + Invocation invocation = mock(Invocation.class); + ServiceCombServer server = mock(ServiceCombServer.class); + List servers = new ArrayList<>(); + servers.add(server); + + Deencapsulation.setField(ss, "lastServer", server); + + ServerMetrics serverMetrics = new ServerMetrics(); + Mockito.when(server.getServerMetrics()).thenReturn(serverMetrics); + + new MockUp() { + + @Mock + private boolean isTimeOut() { + return false; + } + }; + + new MockUp() { + + @Mock + private boolean isErrorThresholdMet(ServiceCombServer server) { + return true; + } + }; + + try { + ss.choose(servers, invocation); + } catch (Exception e) { + e.printStackTrace(); + status = false; + } + Assertions.assertTrue(status); + } + + @Test + public void testServerWithTimeout() { + + boolean status = true; + + SessionStickinessRule ss = new SessionStickinessRule(); + + Invocation invocation = mock(Invocation.class); + ServiceCombServer server = mock(ServiceCombServer.class); + List servers = new ArrayList<>(); + servers.add(server); + + Deencapsulation.setField(ss, "lastServer", server); + + new MockUp() { + + @Mock + private boolean isTimeOut() { + return true; + } + }; + + try { + ss.choose(servers, invocation); + } catch (Exception e) { + status = false; + } + + Assertions.assertTrue(status); + } + + @Test + public void testServerWithoutTimeoutException() { + + boolean status = true; + + SessionStickinessRule ss = new SessionStickinessRule(); + + Invocation invocation = mock(Invocation.class); + ServiceCombServer server = mock(ServiceCombServer.class); + List servers = new ArrayList<>(); + servers.add(server); + + Deencapsulation.setField(ss, "lastServer", server); + + new MockUp() { + + @Mock + private boolean isTimeOut() { + return false; + } + }; + + try { + ss.choose(servers, invocation); + } catch (Exception e) { + status = false; + } + Assertions.assertFalse(status); + } + + @Test + public void testServerWithoutTimeoutAndThreshold() { + + boolean status = true; + + SessionStickinessRule ss = new SessionStickinessRule(); + + Invocation invocation = mock(Invocation.class); + ServiceCombServer server = mock(ServiceCombServer.class); + List servers = new ArrayList<>(); + servers.add(server); + + Deencapsulation.setField(ss, "lastServer", server); + + new MockUp() { + + @Mock + private boolean isTimeOut() { + return false; + } + }; + + new MockUp() { + + @Mock + private boolean isErrorThresholdMet(ServiceCombServer server) { + return false; + } + }; + + new MockUp() { + + @Mock + private boolean isLastServerExists(ServiceCombServer server) { + return true; + } + }; + + try { + ss.choose(servers, invocation); + } catch (Exception e) { + status = false; + } + Assertions.assertTrue(status); + } + + @Test + public void testLastServerNotExist() { + SessionStickinessRule rule = new SessionStickinessRule(); + + Transport transport = mock(Transport.class); + Invocation invocation = mock(Invocation.class); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance1 = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("1234"); + ServiceCombServer mockedServer = + new ServiceCombServer(null, new Endpoint(transport, "rest:127.0.0.1:8890", instance1)); + List allServers = Arrays.asList(mockedServer); + LoadBalancer lb = new LoadBalancer(rule, "mockedServer"); + when(invocation.getLocalContext(LoadBalanceFilter.CONTEXT_KEY_SERVER_LIST)).thenReturn(allServers); + rule.setLoadBalancer(lb); + ServiceCombServer server = new ServiceCombServer(null, + new Endpoint(transport, "rest:127.0.0.1:8890", instance1)); + Deencapsulation.setField(rule, "lastServer", server); + + new MockUp(rule) { + @Mock + private boolean isTimeOut() { + return false; + } + + @Mock + private boolean isErrorThresholdMet(ServiceCombServer server) { + return false; + } + }; + ServiceCombServer s = rule.choose(allServers, invocation); + Assertions.assertEquals(mockedServer, s); + } +} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionSticknessRule.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionSticknessRule.java deleted file mode 100644 index 228e973e02c..00000000000 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestSessionSticknessRule.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.loadbalance; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.loadbalancer.LoadBalancerStats; -import com.netflix.loadbalancer.Server; - -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class TestSessionSticknessRule { - - @Test - public void testRuleFullOperation() { - SessionStickinessRule rule = new SessionStickinessRule(); - - LoadBalancer mockedLb = mock(LoadBalancer.class); - Transport transport = mock(Transport.class); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - ServiceCombServer mockedServer = - new ServiceCombServer(transport, new CacheEndpoint("rest:127.0.0.1:8889", instance1)); - Invocation invocation = mock(Invocation.class); - LoadBalancerStats stats = mock(LoadBalancerStats.class); - Mockito.when(mockedLb.getLoadBalancerStats()).thenReturn(stats); - Deencapsulation.invoke(rule, "chooseServerWhenTimeout", Arrays.asList(mockedServer), invocation); - mockedServer.setAlive(true); - mockedServer.setReadyToServe(true); - List allServers = Arrays.asList(mockedServer); - rule.setLoadBalancer(mockedLb); - - - Server s = rule.choose(allServers, invocation); - Assert.assertEquals(s, mockedServer); - - s = rule.choose(allServers, invocation); - Assert.assertEquals(s, mockedServer); - } - - @Test - public void testServerWithoutTimeoutAndWithThreshold() { - - boolean status = true; - - SessionStickinessRule ss = new SessionStickinessRule(); - - Invocation invocation = mock(Invocation.class); - ServiceCombServer server = mock(ServiceCombServer.class); - List servers = new ArrayList<>(); - servers.add(server); - - Deencapsulation.setField(ss, "lastServer", server); - - new MockUp() { - - @Mock - private boolean isTimeOut() { - return false; - } - }; - - new MockUp() { - - @Mock - private boolean isErrorThresholdMet() { - return true; - } - }; - - try { - ss.choose(servers, invocation); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testServerWithTimeout() { - - boolean status = true; - - SessionStickinessRule ss = new SessionStickinessRule(); - - Invocation invocation = mock(Invocation.class); - ServiceCombServer server = mock(ServiceCombServer.class); - List servers = new ArrayList<>(); - servers.add(server); - - Deencapsulation.setField(ss, "lastServer", server); - - new MockUp() { - - @Mock - private boolean isTimeOut() { - return true; - } - }; - - try { - ss.choose(servers, invocation); - } catch (Exception e) { - status = false; - } - - Assert.assertTrue(status); - } - - @Test - public void testServerWithoutTimeoutException() { - - boolean status = true; - - SessionStickinessRule ss = new SessionStickinessRule(); - - Invocation invocation = mock(Invocation.class); - ServiceCombServer server = mock(ServiceCombServer.class); - List servers = new ArrayList<>(); - servers.add(server); - - Deencapsulation.setField(ss, "lastServer", server); - - new MockUp() { - - @Mock - private boolean isTimeOut() { - return false; - } - }; - - try { - ss.choose(servers, invocation); - } catch (Exception e) { - status = false; - } - Assert.assertFalse(status); - } - - @Test - public void testServerWithoutTimeoutAndThreshold() { - - boolean status = true; - - SessionStickinessRule ss = new SessionStickinessRule(); - - Invocation invocation = mock(Invocation.class); - ServiceCombServer server = mock(ServiceCombServer.class); - List servers = new ArrayList<>(); - servers.add(server); - - Deencapsulation.setField(ss, "lastServer", server); - - new MockUp() { - - @Mock - private boolean isTimeOut() { - return false; - } - }; - - new MockUp() { - - @Mock - private boolean isErrorThresholdMet() { - return false; - } - }; - - new MockUp() { - - @Mock - private boolean isLastServerExists(Server server) { - return true; - } - }; - - try { - ss.choose(servers, invocation); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testServerWithActualServerObj() { - - boolean status = true; - SessionStickinessRule ss = new SessionStickinessRule(); - - Invocation invocation = mock(Invocation.class); - ServiceCombServer server = mock(ServiceCombServer.class); - List servers = new ArrayList<>(); - servers.add(server); - - Deencapsulation.setField(ss, "lastServer", server); - try { - ss.choose(servers, invocation); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testLastServerNotExist() { - SessionStickinessRule rule = new SessionStickinessRule(); - - Transport transport = mock(Transport.class); - Invocation invocation = mock(Invocation.class); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setInstanceId("1234"); - ServiceCombServer mockedServer = - new ServiceCombServer(transport, new CacheEndpoint("rest:127.0.0.1:8890", instance1)); - mockedServer.setAlive(true); - mockedServer.setReadyToServe(true); - mockedServer.setId("mockedServer"); - List allServers = Arrays.asList(mockedServer); - LoadBalancer lb = new LoadBalancer(rule, "mockedServer"); - when(invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST)).thenReturn(allServers); - rule.setLoadBalancer(lb); - ServiceCombServer server = new ServiceCombServer(transport, new CacheEndpoint("rest:127.0.0.1:8890", instance1)); - Deencapsulation.setField(rule, "lastServer", server); - - new MockUp(rule) { - @Mock - private boolean isTimeOut() { - return false; - } - - @Mock - private boolean isErrorThresholdMet() { - return false; - } - }; - Server s = rule.choose(allServers, invocation); - Assert.assertEquals(mockedServer, s); - } -} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java index 0d4e0031fe9..e3d20d2eea2 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java @@ -19,25 +19,29 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import io.github.resilience4j.core.metrics.Metrics.Outcome; + public class TestWeightedResponseTimeRuleExt { @Test public void testRoundRobin() { WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); for (int i = 0; i < 2; i++) { ServiceCombServer server = Mockito.mock(ServiceCombServer.class); + ServerMetrics serverMetrics = new ServerMetrics(); + Mockito.when(server.getServerMetrics()).thenReturn(serverMetrics); Mockito.when(server.toString()).thenReturn("server " + i); servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, 1); + serverMetrics.record(1, TimeUnit.MILLISECONDS, Outcome.SUCCESS); } AtomicInteger server1 = new AtomicInteger(0); @@ -49,34 +53,60 @@ public void testRoundRobin() { server2.incrementAndGet(); } } - Assert.assertEquals(server1.get(), server2.get()); + Assertions.assertEquals(server1.get(), server2.get()); } @Test public void testWeighed() { WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); - for (int i = 0; i < 2; i++) { - ServiceCombServer server = Mockito.mock(ServiceCombServer.class); - Mockito.when(server.toString()).thenReturn("server " + i); - servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, 20 * Math.pow(4, i + 1)); + + ServiceCombServer server1 = Mockito.mock(ServiceCombServer.class); + Mockito.when(server1.toString()).thenReturn("server " + 0); + servers.add(server1); + ServerMetrics serverMetrics1 = new ServerMetrics(); + Mockito.when(server1.getServerMetrics()).thenReturn(serverMetrics1); + + ServiceCombServer server2 = Mockito.mock(ServiceCombServer.class); + Mockito.when(server2.toString()).thenReturn("server " + 1); + servers.add(server2); + ServerMetrics serverMetrics2 = new ServerMetrics(); + Mockito.when(server2.getServerMetrics()).thenReturn(serverMetrics2); + + AtomicInteger serverCounter1 = new AtomicInteger(0); + AtomicInteger serverCounter2 = new AtomicInteger(0); + for (int i = 0; i < 100; i++) { + serverMetrics1.record(200, TimeUnit.MILLISECONDS, Outcome.SUCCESS); + serverMetrics2.record(400, TimeUnit.MILLISECONDS, Outcome.SUCCESS); } + for (int i = 0; i < 2000; i++) { + if (rule.choose(servers, invocation).toString().equals("server 0")) { + serverCounter1.incrementAndGet(); + } else { + serverCounter2.incrementAndGet(); + } + } + double percent = (double) serverCounter1.get() / (serverCounter2.get() + serverCounter1.get()); + System.out.println("percent" + percent); + Assertions.assertEquals(0.67d, percent, 0.1); + serverCounter1.set(0); + serverCounter2.set(0); - AtomicInteger server1 = new AtomicInteger(0); - AtomicInteger server2 = new AtomicInteger(0); + for (int i = 0; i < 100; i++) { + serverMetrics1.record(20, TimeUnit.MILLISECONDS, Outcome.SUCCESS); + serverMetrics2.record(20, TimeUnit.MILLISECONDS, Outcome.SUCCESS); + } for (int i = 0; i < 2000; i++) { if (rule.choose(servers, invocation).toString().equals("server 0")) { - server1.incrementAndGet(); + serverCounter1.incrementAndGet(); } else { - server2.incrementAndGet(); + serverCounter2.incrementAndGet(); } } - double percent = (double) server1.get() / (server2.get() + server1.get()); + percent = (double) serverCounter1.get() / (serverCounter2.get() + serverCounter1.get()); System.out.println("percent" + percent); - Assert.assertEquals("actually percent: " + percent, 0.70d < percent, percent < 0.90d); + Assertions.assertEquals(0.50d, percent, 0.1); } @Test @@ -84,43 +114,45 @@ public void testBenchmark() { // 100 instances will taken less than 0.1ms. Because we use weighed rule when response time more than 10ms, // This only taken 1/1000 time. WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); for (int i = 0; i < 100; i++) { ServiceCombServer server = Mockito.mock(ServiceCombServer.class); + ServerMetrics serverMetrics = new ServerMetrics(); Mockito.when(server.toString()).thenReturn("server " + i); + Mockito.when(server.getServerMetrics()).thenReturn(serverMetrics); servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, i); + serverMetrics.record(i, TimeUnit.MILLISECONDS, Outcome.SUCCESS); } long begin = System.currentTimeMillis(); - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100000; i++) { rule.choose(servers, invocation); } long taken = System.currentTimeMillis() - begin; System.out.println("taken " + taken); - Assert.assertEquals("actually taken: " + taken, taken < 1000 * 5, true); // 5 * times make slow machine happy + Assertions.assertTrue(taken < 1000 * 5, "actually taken: " + taken); // 5 * times make slow machine happy } @Test public void testBenchmarkRobin() { // 100 instances will taken less than 0.02ms. Not as good as RoundRobinRule, which taken less than 0.001ms WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt(); - LoadBalancer loadBalancer = new LoadBalancer(rule, "testService"); List servers = new ArrayList<>(); Invocation invocation = Mockito.mock(Invocation.class); for (int i = 0; i < 100; i++) { ServiceCombServer server = Mockito.mock(ServiceCombServer.class); + ServerMetrics serverMetrics = new ServerMetrics(); Mockito.when(server.toString()).thenReturn("server " + i); + Mockito.when(server.getServerMetrics()).thenReturn(serverMetrics); servers.add(server); - loadBalancer.getLoadBalancerStats().noteResponseTime(server, 2); + serverMetrics.record(2, TimeUnit.MILLISECONDS, Outcome.SUCCESS); } long begin = System.currentTimeMillis(); - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100000; i++) { rule.choose(servers, invocation); } long taken = System.currentTimeMillis() - begin; System.out.println("taken " + taken); - Assert.assertEquals("actually taken: " + taken, taken < 200 * 2, true); // 5 * times make slow machine happy + Assertions.assertTrue(taken < 200 * 5, "actually taken: " + taken); // 5 * times make slow machine happy } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/exception/TestLoadbalanceExceptionUtils.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/exception/TestLoadbalanceExceptionUtils.java index 390f6de07c5..71b929af53e 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/exception/TestLoadbalanceExceptionUtils.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/exception/TestLoadbalanceExceptionUtils.java @@ -17,25 +17,19 @@ package org.apache.servicecomb.loadbalance.exception; -import static org.junit.Assert.assertEquals; - import org.apache.servicecomb.core.exception.CseException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -/** - * - * - */ public class TestLoadbalanceExceptionUtils { @Test public void testLoadbalanceExceptionUtils() { - assertEquals("servicecomb.handler.lb.wrong.rule", LoadbalanceExceptionUtils.CSE_HANDLER_LB_WRONG_RULE); + Assertions.assertEquals("servicecomb.handler.lb.wrong.rule", LoadbalanceExceptionUtils.CSE_HANDLER_LB_WRONG_RULE); CseException cseException = LoadbalanceExceptionUtils.createLoadbalanceException("servicecomb.handler.lb.wrong.rule", new Throwable(), "ARGS"); - Assert.assertNotNull(cseException); + Assertions.assertNotNull(cseException); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilterTest.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilterTest.java new file mode 100644 index 00000000000..7c78388dcdc --- /dev/null +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilterTest.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.loadbalance.filter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.servicecomb.config.DynamicProperties; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; + +import com.google.common.collect.Sets; + +/** + * Test for PriorityInstancePropertyDiscoveryFilter + */ +public class PriorityInstancePropertyDiscoveryFilterTest { + + public static final String PROPERTY_KEY = "environment"; + + private PriorityInstancePropertyDiscoveryFilter filter; + + private List instances; + + StatefulDiscoveryInstance instance1; + + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + + EnumerablePropertySource propertySource; + + DynamicProperties dynamicProperties = Mockito.mock(DynamicProperties.class); + + @Before + public void setUp() { + propertySource = Mockito.mock(EnumerablePropertySource.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.service.properties." + PROPERTY_KEY + }); + + filter = new PriorityInstancePropertyDiscoveryFilter(); + filter.setEnvironment(environment); + filter.setDynamicProperties(dynamicProperties); + Mockito.when(dynamicProperties.getStringProperty(Mockito.eq("servicecomb.loadbalance.filter.priorityInstanceProperty.key"), + Mockito.any(), + Mockito.eq("environment"))).thenReturn("environment"); + instances = new ArrayList<>(); + filter.setEnvironment(environment); + DiscoveryInstance discoveryInstance1 = Mockito.mock(DiscoveryInstance.class); + instance1 = new StatefulDiscoveryInstance(discoveryInstance1); + Mockito.when(discoveryInstance1.getInstanceId()).thenReturn("instance.empty"); + + DiscoveryInstance discoveryInstance2 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance2 = new StatefulDiscoveryInstance(discoveryInstance2); + Mockito.when(discoveryInstance2.getInstanceId()).thenReturn("instance.local"); + Map properties = new HashMap<>(); + properties.put(PROPERTY_KEY, "local"); + Mockito.when(discoveryInstance2.getProperties()).thenReturn(properties); + + DiscoveryInstance discoveryInstance3 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance3 = new StatefulDiscoveryInstance(discoveryInstance3); + Mockito.when(discoveryInstance3.getInstanceId()).thenReturn("instance.local.feature1"); + Map properties3 = new HashMap<>(); + properties3.put(PROPERTY_KEY, "local.feature1"); + Mockito.when(discoveryInstance3.getProperties()).thenReturn(properties3); + + DiscoveryInstance discoveryInstance4 = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance4 = new StatefulDiscoveryInstance(discoveryInstance4); + Mockito.when(discoveryInstance4.getInstanceId()).thenReturn("instance.local.feature1.sprint1"); + Map properties4 = new HashMap<>(); + properties4.put(PROPERTY_KEY, "local.feature1.sprint1"); + Mockito.when(discoveryInstance4.getProperties()).thenReturn(properties4); + + instances.add(instance1); + instances.add(instance2); + instances.add(instance3); + instances.add(instance4); + } + + @After + public void cleanup() { + } + + @Test + public void testGetFilteredListOfServers() { + + //complete match + executeTest("", Sets.newHashSet("instance.empty")); + executeTest("local", Sets.newHashSet("instance.local")); + executeTest("local.feature1", Sets.newHashSet("instance.local.feature1")); + executeTest("local.feature1.sprint1", Sets.newHashSet("instance.local.feature1.sprint1")); + + //priority match + executeTest("test", Sets.newHashSet("instance.empty")); + executeTest("local.feature2", Sets.newHashSet("instance.local")); + executeTest("local.feature1.sprint2", Sets.newHashSet("instance.local.feature1")); + executeTest("local.feature2.sprint1", Sets.newHashSet("instance.local")); + executeTest("local.feature1.sprint2.temp", Sets.newHashSet("instance.local.feature1")); + + //none match + instances.remove(instance1); + executeTest("", Collections.emptySet()); + executeTest("foo", Collections.emptySet()); + instances.add(instance1); + } + + + private void executeTest(String selfProperty, Set expectedMatchedKeys) { + Mockito.when(environment.getProperty("servicecomb.service.properties." + PROPERTY_KEY)).thenReturn(selfProperty); + + Invocation invocation = new Invocation(); + DiscoveryContext discoveryContext = new DiscoveryContext(); + discoveryContext.setInputParameters(invocation); + + DiscoveryTreeNode parent = new DiscoveryTreeNode(); + parent.name("parent"); + parent.data(instances); + + DiscoveryTreeNode node = filter.discovery(discoveryContext, parent); + List filterInstance = node.data(); + assertThat(filterInstance.stream().map(instance -> instance.getInstanceId()).collect( + Collectors.toList())).containsAnyElementsOf(expectedMatchedKeys); + } +} diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestInstancePropertyDiscoveryFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestInstancePropertyDiscoveryFilter.java index 12222ae99da..0c498d25de2 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestInstancePropertyDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestInstancePropertyDiscoveryFilter.java @@ -17,81 +17,93 @@ package org.apache.servicecomb.loadbalance.filter; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.commons.configuration.BaseConfiguration; import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; public class TestInstancePropertyDiscoveryFilter { private InstancePropertyDiscoveryFilter filter; - MicroserviceInstance instance = new MicroserviceInstance(); + StatefulDiscoveryInstance instance; - @BeforeClass - public static void beforeCls() { - AbstractConfiguration configuration = new BaseConfiguration(); - configuration.addProperty("servicecomb.loadbalance.test.flowsplitFilter.policy", - "org.apache.servicecomb.loadbalance.filter.SimpleFlowsplitFilter"); - configuration.addProperty("servicecomb.loadbalance.test.flowsplitFilter.options.tag0", "value0"); - } + ConfigurableEnvironment environment; + + EnumerablePropertySource propertySource; - @Before + @BeforeEach public void setUp() { + environment = Mockito.mock(ConfigurableEnvironment.class); + LegacyPropertyFactory.setEnvironment(environment); + propertySource = Mockito.mock(EnumerablePropertySource.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.loadbalance.test.flowsplitFilter.policy", + "servicecomb.loadbalance.test.flowsplitFilter.options.tag0" + }); + Mockito.when(environment.getProperty("servicecomb.loadbalance.test.flowsplitFilter.policy")) + .thenReturn("org.apache.servicecomb.loadbalance.filter.SimpleFlowsplitFilter"); + Mockito.when(environment.getProperty("servicecomb.loadbalance.test.flowsplitFilter.options.tag0")) + .thenReturn("value0"); + filter = new InstancePropertyDiscoveryFilter(); Map properties = new HashMap<>(); properties.put("tag0", "value0"); properties.put("tag1", "value1"); - instance.setInstanceId("instance111"); - instance.setProperties(properties); + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + instance = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("instance111"); + Mockito.when(discoveryInstance.getProperties()).thenReturn(properties); } @Test public void testAllowVisit() { Map filterOptions = new HashMap<>(); - Assert.assertTrue(filter.allowVisit(instance, filterOptions)); + Assertions.assertTrue(filter.allowVisit(instance, filterOptions)); filterOptions.put("tag0", "value0"); - Assert.assertTrue(filter.allowVisit(instance, filterOptions)); + Assertions.assertTrue(filter.allowVisit(instance, filterOptions)); filterOptions.put("tag2", "value2"); - Assert.assertFalse(filter.allowVisit(instance, filterOptions)); + Assertions.assertFalse(filter.allowVisit(instance, filterOptions)); filterOptions.clear(); filterOptions.put("tag0", "value1"); - Assert.assertFalse(filter.allowVisit(instance, filterOptions)); + Assertions.assertFalse(filter.allowVisit(instance, filterOptions)); } @Test @SuppressWarnings("unchecked") - public void testGetFilteredListOfServers(@Injectable DiscoveryContext context, @Injectable DiscoveryTreeNode parent, - @Injectable Invocation invocation) { - Map instances = new HashMap<>(); - instances.put(instance.getInstanceId(), instance); - new Expectations() { - { - context.getInputParameters(); - result = invocation; - parent.data(); - result = instances; - parent.name(); - result = "parent"; - } - }; + public void testGetFilteredListOfServers() { + DiscoveryContext context = new DiscoveryContext(); + DiscoveryTreeNode parent = new DiscoveryTreeNode(); + + Invocation invocation = Mockito.mock(Invocation.class); + context.setInputParameters(invocation); + + List instances = new ArrayList<>(); + instances.add(instance); + parent.data(instances); + parent.name("parent"); DiscoveryTreeNode node = filter.discovery(context, parent); - Assert.assertEquals(1, ((Map) node.data()).keySet().size()); + Assertions.assertEquals(1, ((List) node.data()).size()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestServerDiscoveryFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestServerDiscoveryFilter.java index 5dbd6a45cfb..a4aa3a5191a 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestServerDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestServerDiscoveryFilter.java @@ -17,66 +17,57 @@ package org.apache.servicecomb.loadbalance.filter; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; +import static org.mockito.ArgumentMatchers.any; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.core.transport.TransportManager; import org.apache.servicecomb.loadbalance.ServiceCombServer; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestServerDiscoveryFilter { ServerDiscoveryFilter filter = new ServerDiscoveryFilter(); - @Mocked - TransportManager transportManager; - - @Mocked - Transport trasport; - - @Before - public void setup() { - CseContext.getInstance().setTransportManager(transportManager); - } - - @After - public void teardown() { - CseContext.getInstance().setTransportManager(null); - } - @Test public void createEndpoint_TransportNotExist() { - new Expectations() { - { - transportManager.findTransport(anyString); - result = null; - } - }; - - ServiceCombServer server = (ServiceCombServer) filter.createEndpoint(Const.RESTFUL, null, null); - Assert.assertNull(server); + TransportManager transportManager = Mockito.mock(TransportManager.class); + Mockito.when(transportManager.findTransport(any(String.class))).thenReturn(null); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + filter.setScbEngine(scbEngine); + ServiceCombServer server = (ServiceCombServer) filter.createEndpoint(null, CoreConst.RESTFUL, null, null); + Assertions.assertNull(server); } @Test public void createEndpointNormal() { - new Expectations() { - { - transportManager.findTransport(anyString); - result = trasport; - } - }; - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("0000001"); + TransportManager transportManager = Mockito.mock(TransportManager.class); + SCBEngine scbEngine = Mockito.mock(SCBEngine.class); + Mockito.when(scbEngine.getTransportManager()).thenReturn(transportManager); + Transport transport = Mockito.mock(Transport.class); + Invocation invocation = Mockito.mock(Invocation.class); + Mockito.when(transportManager.findTransport(any(String.class))).thenReturn(transport); + Mockito.when(invocation.getConfigTransportName()).thenReturn(CoreConst.RESTFUL); + Mockito.when(invocation.getMicroserviceName()).thenReturn("test"); + DiscoveryContext context = new DiscoveryContext(); + context.setInputParameters(invocation); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance instance = new StatefulDiscoveryInstance(discoveryInstance); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("0000001"); + filter.setScbEngine(scbEngine); - ServiceCombServer server = (ServiceCombServer) filter.createEndpoint(Const.RESTFUL, "rest://localhost:8080", instance); - Assert.assertSame(instance, server.getInstance()); - Assert.assertSame(trasport, server.getEndpoint().getTransport()); - Assert.assertEquals("rest://localhost:8080", server.getEndpoint().getEndpoint()); + ServiceCombServer server = (ServiceCombServer) filter + .createEndpoint(context, CoreConst.RESTFUL, "rest://localhost:8080", instance); + Assertions.assertSame(instance, server.getInstance()); + Assertions.assertSame(transport, server.getEndpoint().getTransport()); + Assertions.assertEquals("rest://localhost:8080", server.getEndpoint().getEndpoint()); } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java new file mode 100644 index 00000000000..05b6d5432ca --- /dev/null +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.loadbalance.filter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.config.DynamicProperties; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.discovery.DiscoveryContext; +import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class TestZoneAwareDiscoveryFilter { + DynamicProperties dynamicProperties = Mockito.mock(DynamicProperties.class); + + @BeforeEach + public void setUp() { + + Mockito.when(dynamicProperties.getBooleanProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.enabled"), + Mockito.any(), + Mockito.eq(true))) + .thenReturn(true); + } + + @Test + public void test_not_enough_instance() { + + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratio"), + Mockito.any(), + Mockito.eq(30))) + .thenReturn(50); + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratioCeiling"), + Mockito.any(), + Mockito.eq(50))) + .thenReturn(70); + + ZoneAwareDiscoveryFilter filter = new ZoneAwareDiscoveryFilter(); + filter.setDynamicProperties(dynamicProperties); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + filter.setDataCenterProperties(myself); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:9090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:9091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:9092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + // run test + List data = Arrays.asList(allmatchInstance, regionMatchInstance, noneMatchInstance); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + DiscoveryContext context = new DiscoveryContext(); + DiscoveryTreeNode result = filter.discovery(context, parent); + + // check result + Integer level = context.getContextParameter(filter.contextParameter()); + Integer groups = parent.attribute(filter.groupsSizeParameter()); + List resultData = result.data(); + Assertions.assertEquals(1, level); + Assertions.assertEquals(2, groups); + Assertions.assertEquals(2, resultData.size()); + Assertions.assertEquals("regionMatchInstance", resultData.get(0).getInstanceId()); + Assertions.assertEquals("allmatchInstance", resultData.get(1).getInstanceId()); + } + + @Test + public void test_not_enough_instance_both_ceiling_floor() { + + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratio"), + Mockito.any(), + Mockito.eq(30))) + .thenReturn(40); + Mockito.when(dynamicProperties.getIntProperty(Mockito.eq("servicecomb.loadbalance.filter.zoneaware.ratioCeiling"), + Mockito.any(), + Mockito.eq(60))) + .thenReturn(60); + + ZoneAwareDiscoveryFilter filter = new ZoneAwareDiscoveryFilter(); + filter.setDynamicProperties(dynamicProperties); + + // set up data + DataCenterProperties myself = new DataCenterProperties(); + myself.setName("test"); + myself.setRegion("test-Region"); + myself.setAvailableZone("test-zone"); + filter.setDataCenterProperties(myself); + + DiscoveryInstance discoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance allmatchInstance = new StatefulDiscoveryInstance(discoveryInstance); + DataCenterInfo info = new DataCenterInfo(); + info.setName("test"); + info.setRegion("test-Region"); + info.setAvailableZone("test-zone"); + List allMatchEndpoint = new ArrayList<>(); + allMatchEndpoint.add("rest://localhost:9090"); + Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint); + Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info); + Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance"); + + DiscoveryInstance regionMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance regionMatchInstance = new StatefulDiscoveryInstance(regionMatchDiscoveryInstance); + DataCenterInfo regionMatchInfo = new DataCenterInfo(); + regionMatchInfo.setName("test"); + regionMatchInfo.setRegion("test-Region"); + regionMatchInfo.setAvailableZone("test-zone2"); + List regionMatchEndpoint = new ArrayList<>(); + regionMatchEndpoint.add("rest://localhost:9091"); + Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint); + Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo); + Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance"); + + DiscoveryInstance noneMatchDiscoveryInstance = Mockito.mock(DiscoveryInstance.class); + StatefulDiscoveryInstance noneMatchInstance = new StatefulDiscoveryInstance(noneMatchDiscoveryInstance); + DataCenterInfo noneMatchInfo = new DataCenterInfo(); + noneMatchInfo.setName("test"); + noneMatchInfo.setRegion("test-Region2"); + noneMatchInfo.setAvailableZone("test-zone2"); + List noMatchEndpoint = new ArrayList<>(); + noMatchEndpoint.add("rest://localhost:9092"); + Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint); + Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo); + Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance"); + + // run test + List data = Arrays.asList(allmatchInstance, regionMatchInstance, noneMatchInstance); + DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); + DiscoveryContext context = new DiscoveryContext(); + DiscoveryTreeNode result = filter.discovery(context, parent); + + // check result + Integer level = context.getContextParameter(filter.contextParameter()); + Integer groups = parent.attribute(filter.groupsSizeParameter()); + List resultData = result.data(); + Assertions.assertEquals(null, level); + Assertions.assertEquals(1, groups); + Assertions.assertEquals(3, resultData.size()); + Assertions.assertEquals("noneMatchInstance", resultData.get(0).getInstanceId()); + Assertions.assertEquals("regionMatchInstance", resultData.get(1).getInstanceId()); + Assertions.assertEquals("allmatchInstance", resultData.get(2).getInstanceId()); + } +} diff --git a/handlers/handler-loadbalance/src/test/resources/log4j.properties b/handlers/handler-loadbalance/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/handlers/handler-loadbalance/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/handlers/handler-loadbalance/src/test/resources/microservice.yaml b/handlers/handler-loadbalance/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..5ff7ed9ae41 --- /dev/null +++ b/handlers/handler-loadbalance/src/test/resources/microservice.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + filter-chains: + consumer: + default: empty + producer: + default: empty diff --git a/handlers/handler-publickey-auth/pom.xml b/handlers/handler-publickey-auth/pom.xml index adbff180db3..9f13b26f232 100644 --- a/handlers/handler-publickey-auth/pom.xml +++ b/handlers/handler-publickey-auth/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb handlers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT handler-publickey-auth @@ -37,13 +37,18 @@ java-chassis-core - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + registry-local + test + + + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test @@ -51,7 +56,11 @@ foundation-test-scaffolding test - + + org.mockito + mockito-inline + test + diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/AuthHandlerBoot.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/AuthHandlerBoot.java deleted file mode 100644 index 897e0900e8d..00000000000 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/AuthHandlerBoot.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb; - -import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.foundation.common.utils.RSAKeyPairEntry; -import org.apache.servicecomb.foundation.common.utils.RSAUtils; -import org.apache.servicecomb.foundation.token.RSAKeypair4Auth; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.springframework.stereotype.Component; - -/** - * - * initialize public and private key pair when system boot before registry instance to service center - * - * - */ -@Component -public class AuthHandlerBoot implements BootListener { - - - @Override - public void onBootEvent(BootEvent event) { - if (EventType.BEFORE_REGISTRY.equals(event.getEventType())) { - RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair(); - RSAKeypair4Auth.INSTANCE.setPrivateKey(rsaKeyPairEntry.getPrivateKey()); - RSAKeypair4Auth.INSTANCE.setPublicKey(rsaKeyPairEntry.getPublicKey()); - RSAKeypair4Auth.INSTANCE.setPublicKeyEncoded(rsaKeyPairEntry.getPublicKeyEncoded()); - RegistryUtils.getMicroserviceInstance().getProperties().put(Const.INSTANCE_PUBKEY_PRO, - rsaKeyPairEntry.getPublicKeyEncoded()); - } - } -} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationBootListener.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationBootListener.java new file mode 100644 index 00000000000..71fd4e500fb --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationBootListener.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.foundation.common.utils.KeyPairEntry; +import org.apache.servicecomb.foundation.common.utils.KeyPairUtils; +import org.apache.servicecomb.foundation.token.Keypair4Auth; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * initialize public and private key pair when system boot before registry instance to service center + */ +public class AuthenticationBootListener implements BootListener { + private RegistrationManager registrationManager; + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Override + public void onBootEvent(BootEvent event) { + if (!EventType.BEFORE_REGISTRY.equals(event.getEventType())) { + return; + } + KeyPairEntry rsaKeyPairEntry = KeyPairUtils.generateALGKeyPair(); + Keypair4Auth.INSTANCE.setPrivateKey(rsaKeyPairEntry.getPrivateKey()); + Keypair4Auth.INSTANCE.setPublicKey(rsaKeyPairEntry.getPublicKey()); + Keypair4Auth.INSTANCE.setPublicKeyEncoded(rsaKeyPairEntry.getPublicKeyEncoded()); + this.registrationManager.addProperty(DefinitionConst.INSTANCE_PUBKEY_PRO, + rsaKeyPairEntry.getPublicKeyEncoded()); + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java new file mode 100644 index 00000000000..a7f8ea308ee --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication; + +import org.apache.servicecomb.authentication.consumer.ConsumerAuthFilter; +import org.apache.servicecomb.authentication.consumer.ConsumerTokenManager; +import org.apache.servicecomb.authentication.provider.AccessController; +import org.apache.servicecomb.authentication.provider.ProviderAuthFilter; +import org.apache.servicecomb.authentication.provider.ProviderTokenManager; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@ConditionalOnProperty(value = AuthenticationConfiguration.ACCESS_CONTROL_ENABLED, + havingValue = "true") +public class AuthenticationConfiguration { + public static final String ACCESS_CONTROL_PREFIX = "servicecomb.publicKey.accessControl"; + + public static final String ACCESS_CONTROL_ENABLED = ACCESS_CONTROL_PREFIX + ".enabled"; + + @Bean + public ConsumerAuthFilter scbConsumerAuthFilter() { + return new ConsumerAuthFilter(); + } + + @Bean + public ProviderAuthFilter scbProviderAuthFilter() { + return new ProviderAuthFilter(); + } + + @Bean + public AuthenticationBootListener scbAuthenticationBootListener() { + return new AuthenticationBootListener(); + } + + @Bean + public ConsumerTokenManager scbConsumerTokenManager() { + return new ConsumerTokenManager(); + } + + @Bean + public ProviderTokenManager scbProviderTokenManager() { + return new ProviderTokenManager(); + } + + @Bean + public AccessController scbAccessController(Environment environment) { + return new AccessController(environment); + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/RSAAuthenticationToken.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/RSAAuthenticationToken.java index b70f783a178..aa88091b70e 100644 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/RSAAuthenticationToken.java +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/RSAAuthenticationToken.java @@ -24,19 +24,21 @@ */ public class RSAAuthenticationToken { - public final static long TOKEN_ACTIVE_TIME = 24 * 60 * 60 * 1000; + public static final long TOKEN_ACTIVE_TIME = 24 * 60 * 60 * 1000; - private String instanceId; + private final String instanceId; - private String serviceId; + private final String serviceId; - private long generateTime; + private final long generateTime; - private String randomCode; + private final String randomCode; - private String sign; + private final String sign; - private String tokenFormat; + private final String tokenFormat; + + private final String plainToken; public RSAAuthenticationToken(String instanceId, String serviceId, long generateTime, String randomCode, String sign) { @@ -51,13 +53,13 @@ public RSAAuthenticationToken(String instanceId, String serviceId, long generate generateTime, randomCode, sign); + this.plainToken = String.format("%s@%s@%s@%s", this.instanceId, this.serviceId, this.generateTime, this.randomCode); } public String plainToken() { - return String.format("%s@%s@%s@%s", this.instanceId, this.serviceId, this.generateTime, this.randomCode); + return this.plainToken; } - public String getInstanceId() { return instanceId; } @@ -83,17 +85,13 @@ public static RSAAuthenticationToken fromStr(String token) { return null; } return new RSAAuthenticationToken(tokenArr[0], tokenArr[1], - Long.valueOf(tokenArr[2]), tokenArr[3], tokenArr[4]); + Long.parseLong(tokenArr[2]), tokenArr[3], tokenArr[4]); } public String getServiceId() { return serviceId; } - public void setServiceId(String serviceId) { - this.serviceId = serviceId; - } - @Override public boolean equals(Object obj) { if (!(obj instanceof RSAAuthenticationToken)) { @@ -103,10 +101,7 @@ public boolean equals(Object obj) { if (!token.plainToken().equals(this.plainToken())) { return false; } - if (!token.getSign().equals(this.sign)) { - return false; - } - return true; + return token.getSign().equals(this.sign); } public int hashCode() { diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthFilter.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthFilter.java new file mode 100644 index 00000000000..e26f24d936a --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthFilter.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.consumer; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; + +import jakarta.ws.rs.core.Response.Status; + +public class ConsumerAuthFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private ConsumerTokenManager authenticationTokenManager; + + @Autowired + public void setConsumerTokenManager(ConsumerTokenManager consumerTokenManager) { + this.authenticationTokenManager = consumerTokenManager; + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1010; + } + + @Override + public String getName() { + return "consumer-public-key"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + Optional token = Optional.ofNullable(authenticationTokenManager.getToken()); + if (!token.isPresent()) { + return CompletableFuture.failedFuture( + new InvocationException(Status.SERVICE_UNAVAILABLE, "auth token is not properly configured yet.")); + } + invocation.addContext(CoreConst.AUTH_TOKEN, token.get()); + return nextNode.onFilter(invocation); + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthHandler.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthHandler.java deleted file mode 100644 index 715b043c375..00000000000 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerAuthHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication.consumer; - -import java.util.Optional; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; - -/** - * - * add token to context - * Provider will get token for authentication - * - */ -public class ConsumerAuthHandler implements Handler { - - private RSAConsumerTokenManager athenticationTokenManager = new RSAConsumerTokenManager(); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - - Optional token = Optional.ofNullable(athenticationTokenManager.getToken()); - if (!token.isPresent()) { - asyncResp.consumerFail( - new IllegalStateException("rejected by consumer authentication handler")); - return; - } - invocation.addContext(Const.AUTH_TOKEN, token.get()); - invocation.next(asyncResp); - } - - public void setAuthenticationTokenManager(RSAConsumerTokenManager authenticationTokenManager) { - this.athenticationTokenManager = authenticationTokenManager; - } -} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerTokenManager.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerTokenManager.java new file mode 100644 index 00000000000..8da889abc02 --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/ConsumerTokenManager.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.consumer; + +import java.security.PrivateKey; + +import org.apache.servicecomb.authentication.RSAAuthenticationToken; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.foundation.common.utils.KeyPairUtils; +import org.apache.servicecomb.foundation.token.Keypair4Auth; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class ConsumerTokenManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerTokenManager.class); + + private final Object lock = new Object(); + + private RSAAuthenticationToken token; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + public String getToken() { + + if (isExpired(token)) { + synchronized (lock) { + if (isExpired(token)) { + return createToken(); + } + } + } + return token.format(); + } + + public String createToken() { + PrivateKey privateKey = Keypair4Auth.INSTANCE.getPrivateKey(); + String instanceId = BootStrapProperties.readServiceName(environment); + String serviceId = BootStrapProperties.readApplication(environment); + + if (instanceId == null || serviceId == null) { + LOGGER.error("service not ready when create token."); + return null; + } + + @SuppressWarnings("deprecation") + String randomCode = org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(128); + long generateTime = System.currentTimeMillis(); + try { + String plain = String.format("%s@%s@%s@%s", instanceId, serviceId, generateTime, randomCode); + String sign = KeyPairUtils.sign(plain, privateKey); + token = RSAAuthenticationToken.fromStr(String.format("%s@%s", plain, sign)); + } catch (Exception e) { + LOGGER.error("create token error", e); + return null; + } + return token.format(); + } + + /** + * the TTL of Token is 24 hours + * client token will expired 15 minutes early + */ + public boolean isExpired(RSAAuthenticationToken token) { + if (null == token) { + return true; + } + long generateTime = token.getGenerateTime(); + long expiredDate = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME - 15 * 60 * 1000; + long now = System.currentTimeMillis(); + return now > expiredDate; + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/RSAConsumerTokenManager.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/RSAConsumerTokenManager.java deleted file mode 100644 index d3c610ccac7..00000000000 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/consumer/RSAConsumerTokenManager.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication.consumer; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; - -import org.apache.servicecomb.authentication.RSAAuthenticationToken; -import org.apache.servicecomb.foundation.common.utils.RSAUtils; -import org.apache.servicecomb.foundation.token.RSAKeypair4Auth; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RSAConsumerTokenManager { - - private static final Logger logger = LoggerFactory.getLogger(RSAConsumerTokenManager.class); - - private Object lock = new Object(); - - private RSAAuthenticationToken token; - - public String getToken() { - - if (isExpired(token)) { - synchronized (lock) { - if (isExpired(token)) { - return createToken(); - } - } - } - return token.format(); - } - - public String createToken() { - PrivateKey privateKey = RSAKeypair4Auth.INSTANCE.getPrivateKey(); - String instanceId = RegistryUtils.getMicroserviceInstance().getInstanceId(); - String serviceId = RegistryUtils.getMicroservice().getServiceId(); - @SuppressWarnings("deprecation") - String randomCode = org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(128); - long generateTime = System.currentTimeMillis(); - try { - String plain = String.format("%s@%s@%s@%s", instanceId, serviceId, generateTime, randomCode); - String sign = RSAUtils.sign(plain, privateKey); - token = RSAAuthenticationToken.fromStr(String.format("%s@%s", plain, sign)); - } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException e) { - logger.error("create token error", e); - throw new IllegalStateException("create token error"); - } - return token.format(); - } - - /** - * the TTL of Token is 24 hours - * client token will expired 15 minutes early - */ - public boolean isExpired(RSAAuthenticationToken token) { - if (null == token) { - return true; - } - long generateTime = token.getGenerateTime(); - long expiredDate = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME - 15 * 60 * 1000; - long now = System.currentTimeMillis(); - return now > expiredDate; - } -} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/AccessController.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/AccessController.java index e609e9f0b13..b923b2939d7 100644 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/AccessController.java +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/AccessController.java @@ -16,25 +16,28 @@ */ package org.apache.servicecomb.authentication.provider; -import java.beans.PropertyDescriptor; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.DynamicPropertyFactory; +import com.google.common.eventbus.Subscribe; /** * Add black / white list control to service access */ public class AccessController { - class ConfigurationItem { + static class ConfigurationItem { static final String CATEGORY_PROPERTY = "property"; String category; @@ -56,66 +59,71 @@ class ConfigurationItem { private static final String KEY_RULE_POSTFIX = ".rule"; + private final Environment environment; + private Map whiteList = new HashMap<>(); private Map blackList = new HashMap<>(); - public AccessController() { + public AccessController(Environment environment) { + this.environment = environment; loadConfigurations(KEY_BLACK_LIST_PREFIX); loadConfigurations(KEY_WHITE_LIST_PREFIX); + EventManager.register(this); } - public boolean isAllowed(Microservice microservice) { + public boolean isAllowed(DiscoveryInstance microservice) { return whiteAllowed(microservice) && !blackDenied(microservice); } - private boolean whiteAllowed(Microservice microservice) { - if(whiteList.isEmpty()) { + private boolean whiteAllowed(DiscoveryInstance microservice) { + if (whiteList.isEmpty()) { return true; } return matchFound(microservice, whiteList); } - private boolean blackDenied(Microservice microservice) { - if(blackList.isEmpty()) { + private boolean blackDenied(DiscoveryInstance microservice) { + if (blackList.isEmpty()) { return false; } return matchFound(microservice, blackList); } - private boolean matchFound(Microservice microservice, Map ruleList) { + private boolean matchFound(DiscoveryInstance microservice, Map ruleList) { boolean matched = false; for (ConfigurationItem item : ruleList.values()) { if (ConfigurationItem.CATEGORY_PROPERTY.equals(item.category)) { // we support to configure properties, e.g. serviceName, appId, environment, alias, version and so on, also support key in properties. - if (matchMicroserviceField(microservice, item) || matchMicroserviceProperties(microservice, item)) + if (matchMicroserviceField(microservice, item) || matchMicroserviceProperties(microservice, item)) { return true; + } } } return matched; } - private boolean matchMicroserviceProperties(Microservice microservice, ConfigurationItem item) { + private boolean matchMicroserviceProperties(DiscoveryInstance microservice, ConfigurationItem item) { Map properties = microservice.getProperties(); for (Entry entry : properties.entrySet()) { - if (!entry.getKey().equals(item.propertyName)) + if (!entry.getKey().equals(item.propertyName)) { continue; + } return isPatternMatch(entry.getValue(), item.rule); } return false; } - private boolean matchMicroserviceField(Microservice microservice, ConfigurationItem item) { - Object fieldValue = null; - try { - fieldValue = new PropertyDescriptor(item.propertyName, Microservice.class).getReadMethod().invoke(microservice); - } catch (Exception e) { - LOG.warn("can't find propertyname: {} in microservice field, will search in microservice properties.", item.propertyName); - return false; + private boolean matchMicroserviceField(DiscoveryInstance microservice, ConfigurationItem item) { + String fieldValue; + if ("version".equals(item.propertyName)) { + fieldValue = microservice.getVersion(); + } else if ("serviceName".equals(item.propertyName)) { + fieldValue = microservice.getServiceName(); + } else { + fieldValue = microservice.getProperties().get(item.propertyName); } - if (fieldValue.getClass().getName().equals(String.class.getName())) - return isPatternMatch((String) fieldValue, item.rule); - return false; + return isPatternMatch(fieldValue, item.rule); } private boolean isPatternMatch(String value, String pattern) { @@ -128,40 +136,40 @@ private boolean isPatternMatch(String value, String pattern) { return value.equals(pattern); } - private void loadConfigurations(String prefix) { - ConcurrentCompositeConfiguration config = (ConcurrentCompositeConfiguration) DynamicPropertyFactory - .getBackingConfigurationSource(); - loadConfigurations(config, prefix); - config.addConfigurationListener(event -> { - if (event.getPropertyName().startsWith(prefix)) { - LOG.info("Access rule have been changed. Reload configurations. Event=" + event.getType()); - loadConfigurations(config, prefix); + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(KEY_WHITE_LIST_PREFIX)) { + loadConfigurations(KEY_WHITE_LIST_PREFIX); + break; + } + } + for (String changed : event.getChanged()) { + if (changed.startsWith(KEY_BLACK_LIST_PREFIX)) { + loadConfigurations(KEY_BLACK_LIST_PREFIX); + break; } - }); + } } - private void loadConfigurations(ConcurrentCompositeConfiguration config, String prefix) { + private void loadConfigurations(String prefix) { Map configurations = new HashMap<>(); - Iterator configsItems = config.getKeys(prefix); - while (configsItems.hasNext()) { - String pathKey = configsItems.next(); + Set configsItems = ConfigUtil.propertiesWithPrefix((ConfigurableEnvironment) environment, prefix); + for (String pathKey : configsItems) { if (pathKey.endsWith(KEY_RULE_POSTFIX)) { ConfigurationItem configurationItem = new ConfigurationItem(); - String rule = DynamicPropertyFactory.getInstance() - .getStringProperty(pathKey, null).get(); + String rule = environment.getProperty(pathKey); if (StringUtils.isEmpty(rule)) { continue; } configurationItem.rule = rule; String pathKeyItem = pathKey .substring(prefix.length() + 1, pathKey.length() - KEY_RULE_POSTFIX.length()); - configurationItem.propertyName = DynamicPropertyFactory.getInstance() - .getStringProperty(String.format(KEY_PROPERTY_NAME, prefix, pathKeyItem), null).get(); + configurationItem.propertyName = environment.getProperty(String.format(KEY_PROPERTY_NAME, prefix, pathKeyItem)); if (StringUtils.isEmpty(configurationItem.propertyName)) { continue; } - configurationItem.category = DynamicPropertyFactory.getInstance() - .getStringProperty(String.format(KEY_CATEGORY, prefix, pathKeyItem), null).get(); + configurationItem.category = environment.getProperty(String.format(KEY_CATEGORY, prefix, pathKeyItem)); if (StringUtils.isEmpty(configurationItem.category)) { continue; } @@ -171,19 +179,17 @@ private void loadConfigurations(ConcurrentCompositeConfiguration config, String if (KEY_WHITE_LIST_PREFIX.equals(prefix)) { this.whiteList = configurations; - logConfigurations(prefix, configurations, true); + logConfigurations(configurations, true); } else { this.blackList = configurations; - logConfigurations(prefix, configurations, false); + logConfigurations(configurations, false); } } - private void logConfigurations(String prefix, Map configurations, boolean isWhite) { - for (String key : configurations.keySet()) { - ConfigurationItem item = configurations.get(key); - LOG.info((isWhite ? "White list " : "Black list ") + "config item: key=" + key + ";category=" + item.category - + ";propertyName=" + item.propertyName - + ";rule=" + item.rule); - } + private void logConfigurations(Map configurations, boolean isWhite) { + configurations.forEach((key, item) -> LOG.info((isWhite ? "White list " : "Black list ") + "config item: key=" + key + + ";category=" + item.category + + ";propertyName=" + item.propertyName + + ";rule=" + item.rule)); } } diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java new file mode 100644 index 00000000000..c587195d238 --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.authentication.provider; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.env.Environment; + +public class PathCheckUtils { + private static final String KEY_INCLUDE_PATH = "servicecomb.publicKey.accessControl.includePathPatterns"; + + private static final String KEY_EXCLUDE_PATH = "servicecomb.publicKey.accessControl.excludePathPatterns"; + + /** + * first determine configured non-authentication path is matched requestPath, if match not needed auth. + * second determine whether of configured authentication path, if not configured, default all path need auth; + * if configured, then check whether of matched requestPath, if match needed auth, otherwise not needed auth. + * + * @param requestPath path + * @param env environment + * @return notRequiredAuth + */ + public static boolean isNotRequiredAuth(String requestPath, Environment env) { + if (excludePathMatchPath(requestPath, env)) { + return true; + } + return includePathMatchPath(requestPath, env); + } + + private static boolean excludePathMatchPath(String requestPath, Environment env) { + String excludePathPattern = env.getProperty(KEY_EXCLUDE_PATH, ""); + if (StringUtils.isEmpty(excludePathPattern)) { + return false; + } + return isPathMather(requestPath, excludePathPattern); + } + + private static boolean includePathMatchPath(String requestPath, Environment env) { + String includePathPattern = env.getProperty(KEY_INCLUDE_PATH, ""); + if (StringUtils.isEmpty(includePathPattern)) { + return false; + } + return !isPathMather(requestPath, includePathPattern); + } + + private static boolean isPathMather(String requestPath, String pathPattern) { + for (String pattern : pathPattern.split(",")) { + if (!pattern.isEmpty() && isPatternMatch(requestPath, pattern)) { + return true; + } + } + return false; + } + + public static boolean isPatternMatch(String value, String pattern) { + if (pattern.startsWith("*") || pattern.startsWith("/*")) { + int index = 0; + for (int i = 0; i < pattern.length(); i++) { + if (pattern.charAt(i) != '*' && pattern.charAt(i) != '/') { + break; + } + index++; + } + return value.endsWith(pattern.substring(index)); + } + if (pattern.endsWith("*")) { + int index = pattern.length() - 1; + for (int i = pattern.length() - 1; i >= 0; i--) { + if (pattern.charAt(i) != '*' && pattern.charAt(i) != '/') { + break; + } + index--; + } + return value.startsWith(pattern.substring(0, index + 1)); + } + return value.equals(pattern); + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java new file mode 100644 index 00000000000..f525ae88cf8 --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.provider; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import jakarta.ws.rs.core.Response.Status; + +public class ProviderAuthFilter extends AbstractFilter implements ProviderFilter { + private ProviderTokenManager authenticationTokenManager; + + private Environment env; + + @Autowired + public void setProviderTokenManager(ProviderTokenManager providerTokenManager, Environment env) { + this.authenticationTokenManager = providerTokenManager; + this.env = env; + } + + @Override + public int getOrder() { + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER + 1010; + } + + @Override + public String getName() { + return "provider-public-key"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + String requestFullPath = SwaggerUtils.concatAbsolutePath(invocation.getSchemaMeta().getSwagger(), + invocation.getOperationMeta().getOperationPath()); + if (PathCheckUtils.isNotRequiredAuth(requestFullPath, env)) { + return nextNode.onFilter(invocation); + } + String token = invocation.getContext(CoreConst.AUTH_TOKEN); + if (null != token && authenticationTokenManager.valid(token)) { + return nextNode.onFilter(invocation); + } + return CompletableFuture.failedFuture( + new InvocationException(Status.UNAUTHORIZED, "public key authorization failed.")); + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthHanlder.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthHanlder.java deleted file mode 100644 index a871ece33cf..00000000000 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthHanlder.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication.provider; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.context.HttpStatus; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class ProviderAuthHanlder implements Handler { - - private RSAProviderTokenManager authenticationTokenManager = new RSAProviderTokenManager(); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - - String token = invocation.getContext(Const.AUTH_TOKEN); - if (null != token && authenticationTokenManager.valid(token)) { - invocation.next(asyncResp); - } else { - asyncResp.producerFail(new InvocationException(new HttpStatus(401, "UNAUTHORIZED"), "UNAUTHORIZED")); - } - } -} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderTokenManager.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderTokenManager.java new file mode 100644 index 00000000000..ebedacb7bf2 --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderTokenManager.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.provider; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.authentication.RSAAuthenticationToken; +import org.apache.servicecomb.foundation.common.utils.KeyPairUtils; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.apache.servicecomb.registry.discovery.MicroserviceInstanceCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +public class ProviderTokenManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProviderTokenManager.class); + + private final Cache validatedToken = CacheBuilder.newBuilder() + .expireAfterAccess(getExpiredTime(), TimeUnit.MILLISECONDS) + .build(); + + private AccessController accessController; + + private MicroserviceInstanceCache microserviceInstanceCache; + + @Autowired + public void setMicroserviceInstanceCache(MicroserviceInstanceCache microserviceInstanceCache) { + this.microserviceInstanceCache = microserviceInstanceCache; + } + + @Autowired + public void setAccessController(AccessController accessController) { + this.accessController = accessController; + } + + public boolean valid(String token) { + try { + RSAAuthenticationToken rsaToken = RSAAuthenticationToken.fromStr(token); + if (null == rsaToken) { + LOGGER.error("token format is error, perhaps you need to set auth handler at consumer"); + return false; + } + if (tokenExpired(rsaToken)) { + LOGGER.error("token is expired"); + return false; + } + + if (validatedToken.asMap().containsKey(rsaToken)) { + return accessController.isAllowed(microserviceInstanceCache.getOrCreate( + rsaToken.getServiceId(), rsaToken.getInstanceId())); + } + + if (isValidToken(rsaToken) && !tokenExpired(rsaToken)) { + validatedToken.put(rsaToken, true); + return accessController.isAllowed(microserviceInstanceCache.getOrCreate( + rsaToken.getServiceId(), rsaToken.getInstanceId())); + } + return false; + } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException e) { + LOGGER.error("verify error", e); + return false; + } + } + + public boolean isValidToken(RSAAuthenticationToken rsaToken) + throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { + String sign = rsaToken.getSign(); + String content = rsaToken.plainToken(); + String publicKey = getPublicKeyFromInstance(rsaToken.getInstanceId(), rsaToken.getServiceId()); + return KeyPairUtils.verify(publicKey, sign, content); + } + + protected int getExpiredTime() { + return 60 * 60 * 1000; + } + + private boolean tokenExpired(RSAAuthenticationToken rsaToken) { + long generateTime = rsaToken.getGenerateTime(); + long expired = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME + 15 * 60 * 1000; + long now = System.currentTimeMillis(); + return now > expired; + } + + private String getPublicKeyFromInstance(String instanceId, String serviceId) { + DiscoveryInstance instances = microserviceInstanceCache.getOrCreate(serviceId, instanceId); + if (instances != null) { + return instances.getProperties().get(DefinitionConst.INSTANCE_PUBKEY_PRO); + } else { + LOGGER.error("not instance found {}-{}, maybe attack", instanceId, serviceId); + return ""; + } + } + + @VisibleForTesting + Cache getValidatedToken() { + return validatedToken; + } +} diff --git a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/RSAProviderTokenManager.java b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/RSAProviderTokenManager.java deleted file mode 100644 index e0add994144..00000000000 --- a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/RSAProviderTokenManager.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication.provider; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.authentication.RSAAuthenticationToken; -import org.apache.servicecomb.foundation.common.utils.RSAUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.MicroserviceInstanceCache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RSAProviderTokenManager { - - private final static Logger LOGGER = LoggerFactory.getLogger(RSAProviderTokenManager.class); - - private Set validatedToken = ConcurrentHashMap.newKeySet(1000); - - private AccessController accessController = new AccessController(); - - public boolean valid(String token) { - try { - RSAAuthenticationToken rsaToken = RSAAuthenticationToken.fromStr(token); - if (null == rsaToken) { - LOGGER.error("token format is error, perhaps you need to set auth handler at consumer"); - return false; - } - if (tokenExprired(rsaToken)) { - LOGGER.error("token is expired"); - return false; - } - if (validatedToken.contains(rsaToken)) { - return accessController.isAllowed(MicroserviceInstanceCache.getOrCreate(rsaToken.getServiceId())); - } - - String sign = rsaToken.getSign(); - String content = rsaToken.plainToken(); - String publicKey = getPublicKey(rsaToken.getInstanceId(), rsaToken.getServiceId()); - boolean verify = RSAUtils.verify(publicKey, sign, content); - if (verify && !tokenExprired(rsaToken)) { - validatedToken.add(rsaToken); - return accessController.isAllowed(MicroserviceInstanceCache.getOrCreate(rsaToken.getServiceId())); - } - return false; - } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException e) { - LOGGER.error("verfiy error", e); - return false; - } - } - - private boolean tokenExprired(RSAAuthenticationToken rsaToken) { - long generateTime = rsaToken.getGenerateTime(); - long expired = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME + 15 * 60 * 1000; - long now = System.currentTimeMillis(); - return now > expired; - } - - private String getPublicKey(String instanceId, String serviceId) { - MicroserviceInstance instances = MicroserviceInstanceCache.getOrCreate(serviceId, instanceId); - if (instances != null) { - return instances.getProperties().get(Const.INSTANCE_PUBKEY_PRO); - } else { - LOGGER.error("not instance found {}-{}, maybe attack", instanceId, serviceId); - return ""; - } - } -} diff --git a/handlers/handler-publickey-auth/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-publickey-auth/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..23589733acf --- /dev/null +++ b/handlers/handler-publickey-auth/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.authentication.AuthenticationConfiguration diff --git a/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml b/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 4ca3eecacf1..00000000000 --- a/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAccessController.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAccessController.java index 892aceaac31..0c6c6afd346 100644 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAccessController.java +++ b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAccessController.java @@ -20,145 +20,260 @@ import java.util.Map; import org.apache.servicecomb.authentication.provider.AccessController; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; public class TestAccessController { - @After + ConfigurableEnvironment environment; + + EnumerablePropertySource propertySource; + + @BeforeEach public void tearDown() { - ArchaiusUtils.resetConfig(); + environment = Mockito.mock(ConfigurableEnvironment.class); + propertySource = Mockito.mock(EnumerablePropertySource.class); } @Test public void testIsValidOfWhiteByServiceName() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.propertyName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "trust*"); - AccessController controller = new AccessController(); - Microservice service = new Microservice(); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.white.list1.propertyName", + "servicecomb.publicKey.accessControl.white.list1.category", + "servicecomb.publicKey.accessControl.white.list1.rule" + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.propertyName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("trust*"); + + AccessController controller = new AccessController(environment); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trustCustomer"); + Assertions.assertTrue(controller.isAllowed(service)); - service.setServiceName("trustCustomer"); - Assert.assertTrue(controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("nottrustCustomer"); + Assertions.assertFalse(controller.isAllowed(service)); - service.setServiceName("nottrustCustomer"); - Assert.assertTrue(!controller.isAllowed(service)); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("*trust"); + Map latest = new HashMap<>(); + latest.put("servicecomb.publicKey.accessControl.white.list1.rule", "*trust"); + controller.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust"); + Assertions.assertTrue(controller.isAllowed(service)); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "*trust"); - service.setServiceName("Customer_trust"); - Assert.assertTrue(controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust_not"); + Assertions.assertFalse(controller.isAllowed(service)); - service.setServiceName("Customer_trust_not"); - Assert.assertTrue(!controller.isAllowed(service)); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("trust"); + latest.put("servicecomb.publicKey.accessControl.white.list1.rule", "trust"); + controller.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "trust"); - service.setServiceName("trust"); - Assert.assertTrue(controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trust"); + Assertions.assertTrue(controller.isAllowed(service)); - service.setServiceName("Customer_trust"); - Assert.assertTrue(!controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust"); + Assertions.assertFalse(controller.isAllowed(service)); } @Test public void testIsValidOfBlackByServiceName() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.propertyName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "trust*"); - AccessController controller = new AccessController(); - Microservice service = new Microservice(); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.black.list1.propertyName", + "servicecomb.publicKey.accessControl.black.list1.category", + "servicecomb.publicKey.accessControl.black.list1.rule" + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.propertyName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("trust*"); - service.setServiceName("trustCustomer"); - Assert.assertTrue(!controller.isAllowed(service)); + AccessController controller = new AccessController(environment); - service.setServiceName("nottrustCustomer"); - Assert.assertTrue(controller.isAllowed(service)); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trustCustomer"); + Assertions.assertFalse(controller.isAllowed(service)); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "*trust"); - service.setServiceName("Customer_trust"); - Assert.assertTrue(!controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("nottrustCustomer"); + Assertions.assertTrue(controller.isAllowed(service)); - service.setServiceName("Customer_trust_not"); - Assert.assertTrue(controller.isAllowed(service)); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("*trust"); + Map latest = new HashMap<>(); + latest.put("servicecomb.publicKey.accessControl.black.list1.rule", "*trust"); + controller.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust"); + Assertions.assertFalse(controller.isAllowed(service)); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "trust"); - service.setServiceName("trust"); - Assert.assertTrue(!controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust_not"); + Assertions.assertTrue(controller.isAllowed(service)); - service.setServiceName("Customer_trust"); - Assert.assertTrue(controller.isAllowed(service)); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("trust"); + latest = new HashMap<>(); + latest.put("servicecomb.publicKey.accessControl.black.list1.rule", "trust"); + controller.onConfigurationChangedEvent(ConfigurationChangedEvent.createIncremental(latest, new HashMap<>())); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trust"); + Assertions.assertFalse(controller.isAllowed(service)); + + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("Customer_trust"); + Assertions.assertTrue(controller.isAllowed(service)); } @Test public void testIsValidOfBlackAndWhiteByServiceName() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.propertyName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "trust*"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.propertyName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "*hacker"); - - AccessController controller = new AccessController(); - Microservice service = new Microservice(); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.black.list1.propertyName", + "servicecomb.publicKey.accessControl.black.list1.category", + "servicecomb.publicKey.accessControl.black.list1.rule", + "servicecomb.publicKey.accessControl.white.list1.propertyName", + "servicecomb.publicKey.accessControl.white.list1.category", + "servicecomb.publicKey.accessControl.white.list1.rule" + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.propertyName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("trust*"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.propertyName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("*hacker"); - service.setServiceName("trustCustomer"); - Assert.assertTrue(controller.isAllowed(service)); + AccessController controller = new AccessController(environment); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trustCustomer"); + Assertions.assertTrue(controller.isAllowed(service)); - service.setServiceName("trustCustomerhacker"); - Assert.assertTrue(!controller.isAllowed(service)); + service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trustCustomerhacker"); + Assertions.assertFalse(controller.isAllowed(service)); } @Test public void testIsValidOfBlackByProperties() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.propertyName", "tag"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "test"); - AccessController controller = new AccessController(); - Microservice service = new Microservice(); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.black.list1.propertyName", + "servicecomb.publicKey.accessControl.black.list1.category", + "servicecomb.publicKey.accessControl.black.list1.rule", + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.propertyName")) + .thenReturn("tag"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("test"); + + AccessController controller = new AccessController(environment); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); Map map = new HashMap<>(); map.put("tag", "test"); + Mockito.when(service.getProperties()).thenReturn(map); - service.setProperties(map); - Assert.assertTrue(!controller.isAllowed(service)); + Assertions.assertFalse(controller.isAllowed(service)); map.put("tag", "testa"); - service.setProperties(map); - Assert.assertTrue(controller.isAllowed(service)); + Mockito.when(service.getProperties()).thenReturn(map); + Assertions.assertTrue(controller.isAllowed(service)); } @Test public void testIsValidOfWhiteByProperties() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.propertyName", "tag"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "test"); - AccessController controller = new AccessController(); - Microservice service = new Microservice(); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.white.list1.propertyName", + "servicecomb.publicKey.accessControl.white.list1.category", + "servicecomb.publicKey.accessControl.white.list1.rule", + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.propertyName")) + .thenReturn("tag"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("test"); + + AccessController controller = new AccessController(environment); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); Map map = new HashMap<>(); map.put("tag", "test"); - - service.setProperties(map); - Assert.assertTrue(controller.isAllowed(service)); + Mockito.when(service.getProperties()).thenReturn(map); + Assertions.assertTrue(controller.isAllowed(service)); map.put("tag", "testa"); - service.setProperties(map); - Assert.assertTrue(!controller.isAllowed(service)); + Mockito.when(service.getProperties()).thenReturn(map); + Assertions.assertFalse(controller.isAllowed(service)); } @Test public void testIsValidOfBlackAndWhiteByServiceNameAndVersion() { - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.propertyName", "serviceName"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.white.list1.rule", "trust*"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.propertyName", "version"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.category", "property"); - ArchaiusUtils.setProperty("servicecomb.publicKey.accessControl.black.list1.rule", "0.0.1"); - - AccessController controller = new AccessController(); - Microservice service = new Microservice(); - service.setServiceName("trustCustomer"); - service.setVersion("0.0.1"); - - Assert.assertTrue(!controller.isAllowed(service)); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] { + "servicecomb.publicKey.accessControl.black.list1.propertyName", + "servicecomb.publicKey.accessControl.black.list1.category", + "servicecomb.publicKey.accessControl.black.list1.rule", + "servicecomb.publicKey.accessControl.white.list1.propertyName", + "servicecomb.publicKey.accessControl.white.list1.category", + "servicecomb.publicKey.accessControl.white.list1.rule" + }); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.propertyName")) + .thenReturn("serviceName"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.white.list1.rule")) + .thenReturn("trust*"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.propertyName")) + .thenReturn("version"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.category")) + .thenReturn("property"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.black.list1.rule")) + .thenReturn("0.0.1"); + + AccessController controller = new AccessController(environment); + DiscoveryInstance service = Mockito.mock(DiscoveryInstance.class); + Mockito.when(service.getServiceName()).thenReturn("trustCustomer"); + Mockito.when(service.getVersion()).thenReturn("0.0.1"); + + Assertions.assertFalse(controller.isAllowed(service)); } } diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthHandlerBoot.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthHandlerBoot.java deleted file mode 100644 index ffec08744bc..00000000000 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthHandlerBoot.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication; - -import org.apache.servicecomb.AuthHandlerBoot; -import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.core.BootListener.BootEvent; -import org.apache.servicecomb.foundation.token.RSAKeypair4Auth; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; - -public class TestAuthHandlerBoot { - - - @Test - public void testGenerateRSAKey() { - MicroserviceInstance microserviceInstance = new MicroserviceInstance(); - Microservice microservice = new Microservice(); - microservice.setInstance(microserviceInstance); - new Expectations(RegistryUtils.class) { - { - - RegistryUtils.getMicroserviceInstance(); - result = microserviceInstance; - } - }; - - AuthHandlerBoot authHandlerBoot = new AuthHandlerBoot(); - BootEvent bootEvent = new BootEvent(); - bootEvent.setEventType(BootListener.EventType.BEFORE_REGISTRY); - authHandlerBoot.onBootEvent(bootEvent); - Assert.assertNotNull(RSAKeypair4Auth.INSTANCE.getPrivateKey()); - Assert.assertNotNull(RSAKeypair4Auth.INSTANCE.getPublicKey()); - } -} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthenticationBootListener.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthenticationBootListener.java new file mode 100644 index 00000000000..28cb8d48d2d --- /dev/null +++ b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestAuthenticationBootListener.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication; + +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.core.BootListener.BootEvent; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.token.Keypair4Auth; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestAuthenticationBootListener { + private SCBEngine engine; + + private Environment environment; + + @BeforeEach + public void setUp() { + environment = Mockito.mock(Environment.class); + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keyGeneratorAlgorithm", "RSA")) + .thenReturn("RSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.signAlgorithm", "SHA256withRSA")) + .thenReturn("SHA256withRSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keySize", int.class, 2048)) + .thenReturn(2048); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)) + .thenReturn(BootStrapProperties.DEFAULT_APPLICATION); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_NAME); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_ENVIRONMENT)) + .thenReturn(BootStrapProperties.DEFAULT_MICROSERVICE_ENVIRONMENT); + + engine = SCBBootstrap.createSCBEngineForTest(environment); + engine.run(); + } + + @AfterEach + public void teardown() { + engine.destroy(); + } + + @Test + public void testGenerateRSAKey() { + RegistrationManager registrationManager = Mockito.mock(RegistrationManager.class); + AuthenticationBootListener authenticationBootListener = new AuthenticationBootListener(); + authenticationBootListener.setRegistrationManager(registrationManager); + BootEvent bootEvent = new BootEvent(); + bootEvent.setEventType(BootListener.EventType.BEFORE_REGISTRY); + authenticationBootListener.onBootEvent(bootEvent); + Assertions.assertNotNull(Keypair4Auth.INSTANCE.getPrivateKey()); + Assertions.assertNotNull(Keypair4Auth.INSTANCE.getPublicKey()); + } + + @Test + public void testMicroserviceInstancePublicKey() { + RegistrationManager registrationManager = Mockito.mock(RegistrationManager.class); + AuthenticationBootListener authenticationBootListener = new AuthenticationBootListener(); + authenticationBootListener.setRegistrationManager(registrationManager); + BootEvent bootEvent = new BootEvent(); + bootEvent.setEventType(BootListener.EventType.BEFORE_REGISTRY); + + authenticationBootListener.onBootEvent(bootEvent); + + Mockito.verify(registrationManager, times(1)) + .addProperty(eq(DefinitionConst.INSTANCE_PUBKEY_PRO), any(String.class)); + } +} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestConsumerAuthHandler.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestConsumerAuthHandler.java deleted file mode 100644 index 9855e8e9c7d..00000000000 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestConsumerAuthHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication; - -import org.apache.servicecomb.authentication.consumer.ConsumerAuthHandler; -import org.apache.servicecomb.authentication.consumer.RSAConsumerTokenManager; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestConsumerAuthHandler { - - Invocation invocation = null; - - AsyncResponse asyncResp = null; - - RSAConsumerTokenManager tokenManager = null; - - @Test - public void testHandler() throws Exception { - tokenManager = Mockito.mock(RSAConsumerTokenManager.class); - Mockito.when(tokenManager.getToken()).thenReturn("testtoken"); - ConsumerAuthHandler consumerAuthHandler = new ConsumerAuthHandler(); - consumerAuthHandler.setAuthenticationTokenManager(tokenManager); - consumerAuthHandler.handle(invocation, asyncResp); - Assert.assertTrue(true); - } - - - @Test - public void testHandlerException() throws Exception { - tokenManager = Mockito.mock(RSAConsumerTokenManager.class); - Mockito.when(tokenManager.getToken()).thenReturn(null); - ConsumerAuthHandler consumerAuthHandler = new ConsumerAuthHandler(); - consumerAuthHandler.setAuthenticationTokenManager(tokenManager); - consumerAuthHandler.handle(invocation, asyncResp); - } - - @Before - public void setUp() throws Exception { - invocation = Mockito.mock(Invocation.class); - asyncResp = Mockito.mock(AsyncResponse.class); - } -} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestProviderAuthHanlder.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestProviderAuthHanlder.java deleted file mode 100644 index 27b496a8cc8..00000000000 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestProviderAuthHanlder.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication; - -import org.apache.servicecomb.authentication.provider.ProviderAuthHanlder; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestProviderAuthHanlder { - Invocation invocation = null; - - AsyncResponse asyncResp = null; - - @Before - public void setUp() throws Exception { - ConfigUtil.installDynamicConfig(); - invocation = Mockito.mock(Invocation.class); - asyncResp = Mockito.mock(AsyncResponse.class); - Mockito.when(invocation.getContext(Const.AUTH_TOKEN)).thenReturn("testtoken"); - } - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - @Test - public void testHandle() throws Exception { - ProviderAuthHanlder providerAuthHanlder = new ProviderAuthHanlder(); - providerAuthHanlder.handle(invocation, asyncResp); - Assert.assertTrue(true); - } -} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAAuthenticationToken.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAAuthenticationToken.java index 58ee7a3aca7..e9ec7e2b2a9 100644 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAAuthenticationToken.java +++ b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAAuthenticationToken.java @@ -16,18 +16,38 @@ */ package org.apache.servicecomb.authentication; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; + import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; -import org.apache.servicecomb.foundation.common.utils.RSAUtils; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.KeyPairUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestRSAAuthenticationToken { + static Environment environment = Mockito.mock(Environment.class); + @BeforeAll + public static void setUpClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keyGeneratorAlgorithm", "RSA")) + .thenReturn("RSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.signAlgorithm", "SHA256withRSA")) + .thenReturn("SHA256withRSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keySize", int.class, 2048)) + .thenReturn(2048); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + } @Test public void testRSAAuthenticationToken() @@ -36,16 +56,16 @@ public void testRSAAuthenticationToken() "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr); String contents = token.plainToken(); - Assert.assertEquals( + Assertions.assertEquals( "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ", contents); String sign = token.getSign(); - Assert.assertEquals( + Assertions.assertEquals( "WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=", sign); String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB"; - Assert.assertTrue(RSAUtils.verify(pubKey, sign, contents)); + Assertions.assertTrue(KeyPairUtils.verify(pubKey, sign, contents)); } @@ -54,7 +74,7 @@ public void testRSAAuthenticationTokenError() { String tokenstr = "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr); - Assert.assertNull(token); + Assertions.assertNull(token); } @@ -63,17 +83,17 @@ public void testEqual() { String tokenstr = "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr); - Assert.assertNotEquals(token, null); + Assertions.assertNotEquals(token, null); RSAAuthenticationToken token2 = RSAAuthenticationToken.fromStr( "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk"); - Assert.assertNotEquals(token2, token); + Assertions.assertNotEquals(token2, token); RSAAuthenticationToken token3 = RSAAuthenticationToken.fromStr( "e8a0a4b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk"); - Assert.assertNotEquals(token3, token); + Assertions.assertNotEquals(token3, token); RSAAuthenticationToken token4 = RSAAuthenticationToken.fromStr( "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="); - Assert.assertEquals(token4, token); + Assertions.assertEquals(token4, token); } } diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAProviderTokenManager.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAProviderTokenManager.java deleted file mode 100644 index 6efbaf92c70..00000000000 --- a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/TestRSAProviderTokenManager.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.authentication; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.authentication.consumer.RSAConsumerTokenManager; -import org.apache.servicecomb.authentication.provider.RSAProviderTokenManager; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.utils.RSAKeyPairEntry; -import org.apache.servicecomb.foundation.common.utils.RSAUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.token.RSAKeypair4Auth; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.MicroserviceInstanceCache; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Expectations; - -public class TestRSAProviderTokenManager { - - - @Before - public void setUp() throws Exception { - ConfigUtil.installDynamicConfig(); - } - - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testTokenExpried() { - String tokenStr = - "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; - RSAProviderTokenManager tokenManager = new RSAProviderTokenManager(); - MicroserviceInstance microserviceInstance = new MicroserviceInstance(); - Map properties = new HashMap<>(); - microserviceInstance.setProperties(properties); - properties.put(Const.INSTANCE_PUBKEY_PRO, - "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB"); - Assert.assertFalse(tokenManager.valid(tokenStr)); - } - - @Test - public void testTokenFromVaidatePool() { - RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair(); - RSAKeypair4Auth.INSTANCE.setPrivateKey(rsaKeyPairEntry.getPrivateKey()); - RSAKeypair4Auth.INSTANCE.setPublicKey(rsaKeyPairEntry.getPublicKey()); - RSAKeypair4Auth.INSTANCE.setPublicKeyEncoded(rsaKeyPairEntry.getPublicKeyEncoded()); - String serviceId = "c8636e5acf1f11e7b701286ed488fc20"; - String instanceId = "e8a04b54cf2711e7b701286ed488fc20"; - RSAConsumerTokenManager rsaCoumserTokenManager = new RSAConsumerTokenManager(); - MicroserviceInstance microserviceInstance = new MicroserviceInstance(); - microserviceInstance.setInstanceId(instanceId); - Map properties = new HashMap<>(); - microserviceInstance.setProperties(properties); - properties.put(Const.INSTANCE_PUBKEY_PRO, rsaKeyPairEntry.getPublicKeyEncoded()); - Microservice microservice = new Microservice(); - microservice.setServiceId(serviceId); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getMicroservice(); - result = microservice; - RegistryUtils.getMicroserviceInstance(); - result = microserviceInstance; - } - }; - - //Test Consumer first create token - String token = rsaCoumserTokenManager.getToken(); - Assert.assertNotNull(token); - // use cache token - Assert.assertEquals(token, rsaCoumserTokenManager.getToken()); - new Expectations(MicroserviceInstanceCache.class) { - { - MicroserviceInstanceCache.getOrCreate(serviceId, instanceId); - result = microserviceInstance; - MicroserviceInstanceCache.getOrCreate(serviceId); - result = microservice; - } - }; - RSAProviderTokenManager rsaProviderTokenManager = new RSAProviderTokenManager(); - //first validate need to verify use RSA - Assert.assertTrue(rsaProviderTokenManager.valid(token)); - // second validate use validated pool - Assert.assertTrue(rsaProviderTokenManager.valid(token)); - } -} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestPathCheckUtils.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestPathCheckUtils.java new file mode 100644 index 00000000000..b8ff4623081 --- /dev/null +++ b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestPathCheckUtils.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.provider; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.when; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.servers.Server; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class TestPathCheckUtils { + private static final String KEY_INCLUDE_PATH = "servicecomb.publicKey.accessControl.includePathPatterns"; + + private static final String KEY_EXCLUDE_PATH = "servicecomb.publicKey.accessControl.excludePathPatterns"; + + private static final String BASE_PATH = "/api/v1"; + + private Environment environment; + + private OpenAPI swagger; + + @BeforeEach + public void setUp() { + environment = Mockito.mock(Environment.class); + swagger = new OpenAPI(); + swagger.setServers(new ArrayList<>()); + swagger.getServers().add(new Server().url(BASE_PATH)); + } + + @Test + public void testExcludePathWithBasePathAndExactMatch() { + String operationPath = "/public"; + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(BASE_PATH + operationPath); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, operationPath); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for excluded path with exact match"); + } + + @Test + public void testExcludePathWithBasePathAndWildcard() { + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(BASE_PATH + "/public/*"); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/public/test"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for excluded path with wildcard"); + + fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/public/nested/path"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for excluded nested path with wildcard"); + } + + @Test + public void testIncludePathWithBasePath() { + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(""); + when(environment.getProperty(KEY_INCLUDE_PATH, "")).thenReturn(BASE_PATH + "/private/*"); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/private/resource"); + assertFalse(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should require auth for included path"); + + fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/public/resource"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for non-included path"); + } + + @Test + public void testExcludeOverrideIncludePath() { + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(BASE_PATH + "/resource"); + when(environment.getProperty(KEY_INCLUDE_PATH, "")).thenReturn(BASE_PATH + "/*"); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/resource"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Exclude patterns should override include patterns"); + } + + @Test + public void testMultipleExcludePaths() { + List operationPaths = List.of("/public", "/health", "/metrics/*"); + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(concatPath(BASE_PATH, operationPaths)); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/public"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for first exclude path"); + + fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/health"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for second exclude path"); + + fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/metrics/jvm"); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth for wildcard exclude path"); + } + + @Test + public void testDifferentBasePath() { + String basePath = "/different/base"; + String publicOperationPath = "/public"; + String privateOperationPath = "/private"; + swagger.getServers().clear(); + swagger.getServers().add(new Server().url(basePath)); + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(basePath + publicOperationPath); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, publicOperationPath); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth with different base path"); + + fullPath = SwaggerUtils.concatAbsolutePath(swagger, privateOperationPath); + assertFalse(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should require auth for non-excluded path with different base path"); + } + + @Test + public void testNoBasePath() { + String operationPath = "/public"; + swagger.setServers(null); + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(operationPath); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, operationPath); + assertTrue(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should not require auth when no base path is set"); + } + + @Test + public void testEmptyConfiguration() { + when(environment.getProperty(KEY_EXCLUDE_PATH, "")).thenReturn(""); + when(environment.getProperty(KEY_INCLUDE_PATH, "")).thenReturn(""); + + String fullPath = SwaggerUtils.concatAbsolutePath(swagger, "/any/path"); + assertFalse(PathCheckUtils.isNotRequiredAuth(fullPath, environment), + "Should require auth by default when no patterns are configured"); + } + + private String concatPath(String basePath, List paths) { + return paths.stream().map(path -> basePath + path).collect(Collectors.joining(",")); + } +} diff --git a/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestProviderTokenManager.java b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestProviderTokenManager.java new file mode 100644 index 00000000000..801f91e697d --- /dev/null +++ b/handlers/handler-publickey-auth/src/test/java/org/apache/servicecomb/authentication/provider/TestProviderTokenManager.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.authentication.provider; + +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; +import static org.mockito.ArgumentMatchers.any; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.authentication.RSAAuthenticationToken; +import org.apache.servicecomb.authentication.consumer.ConsumerTokenManager; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.KeyPairEntry; +import org.apache.servicecomb.foundation.common.utils.KeyPairUtils; +import org.apache.servicecomb.foundation.token.Keypair4Auth; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.apache.servicecomb.registry.discovery.MicroserviceInstanceCache; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MutablePropertySources; + +import com.google.common.cache.Cache; + +public class TestProviderTokenManager { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void setUpClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keyGeneratorAlgorithm", "RSA")) + .thenReturn("RSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.signAlgorithm", "SHA256withRSA")) + .thenReturn("SHA256withRSA"); + Mockito.when(environment.getProperty("servicecomb.publicKey.accessControl.keySize", int.class, 2048)) + .thenReturn(2048); + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void teardown() { + } + + @Test + public void testTokenExpired() { + String tokenStr = + "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; + ProviderTokenManager tokenManager = new ProviderTokenManager(); + DiscoveryInstance microserviceInstance = Mockito.mock(DiscoveryInstance.class); + Map properties = new HashMap<>(); + Mockito.when(microserviceInstance.getProperties()).thenReturn(properties); + properties.put(DefinitionConst.INSTANCE_PUBKEY_PRO, + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB"); + Assertions.assertFalse(tokenManager.valid(tokenStr)); + } + + @Test + @SuppressWarnings("unchecked") + public void testTokenExpiredRemoveInstance() throws Exception { + + String tokenStr = + "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk="; + RSAAuthenticationToken token = Mockito.spy(RSAAuthenticationToken.fromStr(tokenStr)); + ProviderTokenManager tokenManager = Mockito.spy(new ProviderTokenManager() { + @Override + protected int getExpiredTime() { + return 500; + } + }); + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + tokenManager.setAccessController(new AccessController(environment)); + MicroserviceInstanceCache microserviceInstanceCache = Mockito.mock(MicroserviceInstanceCache.class); + DiscoveryInstance microserviceInstance = Mockito.mock(DiscoveryInstance.class); + Mockito.when(microserviceInstance.getInstanceId()).thenReturn(""); + Map properties = new HashMap<>(); + Mockito.when(microserviceInstance.getProperties()).thenReturn(properties); + Mockito.when(microserviceInstanceCache.getOrCreate(any(String.class), any(String.class))) + .thenReturn(microserviceInstance); + tokenManager.setMicroserviceInstanceCache(microserviceInstanceCache); + try (MockedStatic rsaAuthenticationTokenMockedStatic = Mockito.mockStatic( + RSAAuthenticationToken.class)) { + rsaAuthenticationTokenMockedStatic.when(() -> RSAAuthenticationToken.fromStr(tokenStr)).thenReturn(token); + Mockito.when(token.getGenerateTime()).thenReturn(System.currentTimeMillis()); + Mockito.doReturn(true).when(tokenManager).isValidToken(token); + Assertions.assertTrue(tokenManager.valid(tokenStr)); + + Cache cache = tokenManager + .getValidatedToken(); + Assertions.assertTrue(cache.asMap().containsKey(token)); + + Thread.sleep(1000); + Assertions.assertFalse(cache.asMap().containsKey(token)); + } + } + + @Test + public void testTokenFromValidatePool() { + KeyPairEntry keyPairEntry = KeyPairUtils.generateALGKeyPair(); + Keypair4Auth.INSTANCE.setPrivateKey(keyPairEntry.getPrivateKey()); + Keypair4Auth.INSTANCE.setPublicKey(keyPairEntry.getPublicKey()); + Keypair4Auth.INSTANCE.setPublicKeyEncoded(keyPairEntry.getPublicKeyEncoded()); + String serviceId = "test"; + String instanceId = "test"; + ConsumerTokenManager consumerTokenManager = new ConsumerTokenManager(); + + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_NAME)).thenReturn("test"); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)).thenReturn("test"); + consumerTokenManager.setEnvironment(environment); + DiscoveryInstance microserviceInstance = Mockito.mock(DiscoveryInstance.class); + Mockito.when(microserviceInstance.getInstanceId()).thenReturn(instanceId); + Map properties = new HashMap<>(); + Mockito.when(microserviceInstance.getProperties()).thenReturn(properties); + properties.put(DefinitionConst.INSTANCE_PUBKEY_PRO, keyPairEntry.getPublicKeyEncoded()); + MicroserviceInstanceCache microserviceInstanceCache = Mockito.mock(MicroserviceInstanceCache.class); + Mockito.when(microserviceInstanceCache.getOrCreate(serviceId, instanceId)).thenReturn(microserviceInstance); + //Test Consumer first create token + String token = consumerTokenManager.getToken(); + Assertions.assertNotNull(token); + // use cache token + Assertions.assertEquals(token, consumerTokenManager.getToken()); + ProviderTokenManager rsaProviderTokenManager = new ProviderTokenManager(); + + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + rsaProviderTokenManager.setAccessController(new AccessController(environment)); + + rsaProviderTokenManager.setMicroserviceInstanceCache(microserviceInstanceCache); + //first validate need to verify use RSA + Assertions.assertTrue(rsaProviderTokenManager.valid(token)); + // second validate use validated pool + Assertions.assertTrue(rsaProviderTokenManager.valid(token)); + } +} diff --git a/handlers/handler-publickey-auth/src/test/resources/log4j.properties b/handlers/handler-publickey-auth/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/handlers/handler-publickey-auth/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/handlers/handler-publickey-auth/src/test/resources/microservice.yaml b/handlers/handler-publickey-auth/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..5ff7ed9ae41 --- /dev/null +++ b/handlers/handler-publickey-auth/src/test/resources/microservice.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + filter-chains: + consumer: + default: empty + producer: + default: empty diff --git a/handlers/handler-router/pom.xml b/handlers/handler-router/pom.xml new file mode 100644 index 00000000000..0068002eb7d --- /dev/null +++ b/handlers/handler-router/pom.xml @@ -0,0 +1,62 @@ + + + + + + handlers + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + handler-router + Java Chassis::Handlers::Router + + + + org.springframework + spring-core + + + org.springframework + spring-beans + + + com.google.guava + guava + + + org.yaml + snakeyaml + + + org.apache.servicecomb + common-rest + + + org.apache.servicecomb + servicecomb-governance + + + org.apache.servicecomb + handler-loadbalance + + + diff --git a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterServerListFilter.java b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterServerListFilter.java new file mode 100644 index 00000000000..fdae82e1445 --- /dev/null +++ b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/RouterServerListFilter.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.custom; + +import java.util.List; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.governance.MatchType; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.loadbalance.ServerListFilterExt; +import org.apache.servicecomb.loadbalance.ServiceCombServer; +import org.apache.servicecomb.router.RouterFilter; +import org.apache.servicecomb.router.distribute.RouterDistributor; + +public class RouterServerListFilter implements ServerListFilterExt { + + private static final String ENABLE = "servicecomb.router.type"; + + private static final String TYPE_ROUTER = "router"; + + @SuppressWarnings("unchecked") + private final RouterDistributor routerDistributor = BeanUtils + .getBean(RouterDistributor.class); + + private final RouterFilter routerFilter = BeanUtils.getBean(RouterFilter.class); + + @Override + public boolean enabled() { + return LegacyPropertyFactory.getStringProperty(ENABLE, "") + .equals(TYPE_ROUTER); + } + + @Override + public List getFilteredListOfServers(List list, + Invocation invocation) { + String targetServiceName = invocation.getMicroserviceName(); + return routerFilter.getFilteredListOfServers(list, targetServiceName, + MatchType.createGovHttpRequest(invocation), routerDistributor); + } +} diff --git a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterConfiguration.java b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterConfiguration.java new file mode 100644 index 00000000000..ff6952d24c8 --- /dev/null +++ b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterConfiguration.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.custom; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = ServiceCombRouterConfiguration.ROUTER_ENABLED, + havingValue = "true", matchIfMissing = true) +public class ServiceCombRouterConfiguration { + public static final String ROUTER_PREFIX = "servicecomb.router"; + + public static final String ROUTER_ENABLED = ROUTER_PREFIX + ".enabled"; + + @Bean + public ServiceCombRouterDistributor scbServiceCombRouterDistributor() { + return new ServiceCombRouterDistributor(); + } +} diff --git a/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterDistributor.java b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterDistributor.java new file mode 100644 index 00000000000..709e4598bd8 --- /dev/null +++ b/handlers/handler-router/src/main/java/org/apache/servicecomb/router/custom/ServiceCombRouterDistributor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.router.custom; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.loadbalance.ServiceCombServer; +import org.apache.servicecomb.router.distribute.AbstractRouterDistributor; + +public class ServiceCombRouterDistributor extends + AbstractRouterDistributor { + + public ServiceCombRouterDistributor() { + init( + instance -> instance.getInstance().getVersion(), + instance -> instance.getInstance().getServiceName(), + instance -> { + Map properties = new HashMap<>(); + properties.putAll(instance.getInstance().getProperties()); + return properties; + }); + } +} diff --git a/handlers/handler-router/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt b/handlers/handler-router/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt new file mode 100644 index 00000000000..0e6f5d9a65b --- /dev/null +++ b/handlers/handler-router/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.router.custom.RouterServerListFilter diff --git a/handlers/handler-router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..8bbbb93c1f5 --- /dev/null +++ b/handlers/handler-router/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.router.custom.ServiceCombRouterConfiguration diff --git a/handlers/handler-tracing-zipkin/pom.xml b/handlers/handler-tracing-zipkin/pom.xml index 2cb12075c3a..3644d209bab 100644 --- a/handlers/handler-tracing-zipkin/pom.xml +++ b/handlers/handler-tracing-zipkin/pom.xml @@ -22,7 +22,7 @@ handlers org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -50,24 +50,21 @@ io.zipkin.brave brave - - io.zipkin.reporter2 - zipkin-sender-okhttp3 - io.zipkin.brave - brave-context-log4j12 + brave-context-slf4j - io.zipkin.java + io.zipkin.zipkin2 zipkin - compile - - com.google.code.findbugs - jsr305 + io.zipkin.reporter2 + zipkin-sender-okhttp3 + + + io.zipkin.reporter2 + zipkin-reporter-brave - diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ConsumerInvocationAdapter.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ConsumerInvocationAdapter.java deleted file mode 100644 index 1428fa8f815..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ConsumerInvocationAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import javax.annotation.Nonnull; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -import brave.http.HttpClientAdapter; -import zipkin2.internal.Nullable; - -class ConsumerInvocationAdapter extends HttpClientAdapter { - - @Nullable - @Override - public String method(@Nonnull Invocation invocation) { - return invocation.getOperationMeta().getHttpMethod(); - } - - @Nullable - @Override - public String url(@Nonnull Invocation invocation) { - return invocation.getEndpoint().getEndpoint(); - } - - @Nullable - @Override - public String path(@Nonnull Invocation request) { - return request.getOperationMeta().getOperationPath(); - } - - @Nullable - @Override - public String requestHeader(@Nonnull Invocation invocation, @Nonnull String key) { - return invocation.getContext().get(key); - } - - @Nullable - @Override - public Integer statusCode(@Nonnull Response response) { - return response.getStatusCode(); - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpRequestParser.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpRequestParser.java new file mode 100644 index 00000000000..32fb8752028 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpRequestParser.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; + +import brave.SpanCustomizer; +import brave.http.HttpRequest; +import brave.http.HttpRequestParser; +import brave.http.HttpTags; +import brave.propagation.TraceContext; + +public record CustomHttpRequestParser() implements HttpRequestParser { + @Override + public void parse(HttpRequest req, TraceContext context, SpanCustomizer span) { + Invocation invocation = ((InvocationAware) req).getInvocation(); + span.name(invocation.getInvocationQualifiedName()); + HttpTags.METHOD.tag(req, context, span); + HttpTags.PATH.tag(req, context, span); + if (!invocation.isConsumer()) { // server or edge + HttpTags.ROUTE.tag(req, context, span); + } + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpResponseParser.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpResponseParser.java new file mode 100644 index 00000000000..bb59f7e9371 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/CustomHttpResponseParser.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; + +import brave.SpanCustomizer; +import brave.Tags; +import brave.http.HttpResponse; +import brave.http.HttpResponseParser; +import brave.http.HttpTags; +import brave.propagation.TraceContext; + +public record CustomHttpResponseParser() implements HttpResponseParser { + @Override + public void parse(HttpResponse response, TraceContext context, SpanCustomizer span) { + Invocation invocation = ((InvocationAware) response).getInvocation(); + HttpTags.STATUS_CODE.tag(response, context, span); + if (response.error() != null) { + span.tag(Tags.ERROR.key(), response.error().getMessage()); + } + if (!invocation.isProducer()) { // client or edge + span.tag(HttpTags.ROUTE.key(), response.route()); + } + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientRequestWrapper.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientRequestWrapper.java new file mode 100644 index 00000000000..cc758d68a27 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientRequestWrapper.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; + +import brave.http.HttpClientRequest; + +class HttpClientRequestWrapper extends HttpClientRequest implements InvocationAware { + private final Invocation invocation; + + HttpClientRequestWrapper(Invocation invocation) { + this.invocation = invocation; + } + + @Override + public void header(String name, String value) { + invocation.addContext(name, value); + } + + @Override + public String method() { + return invocation.getOperationMeta().getHttpMethod(); + } + + @Override + public String route() { + return invocation.getEndpoint().getEndpoint(); + } + + @Override + public String path() { + return TracingConfiguration.createRequestPath(invocation); + } + + @Override + public String url() { + return invocation.getInvocationQualifiedName(); + } + + @Override + public String header(String name) { + return invocation.getContext(name); + } + + @Override + public Object unwrap() { + return invocation; + } + + @Override + public Invocation getInvocation() { + return invocation; + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientResponseWrapper.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientResponseWrapper.java new file mode 100644 index 00000000000..b939efaa610 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpClientResponseWrapper.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; + +import brave.http.HttpClientRequest; +import brave.http.HttpClientResponse; + +class HttpClientResponseWrapper extends HttpClientResponse implements InvocationAware { + final HttpClientRequest request; + + final Response response; + + final Invocation invocation; + + HttpClientResponseWrapper(Invocation invocation, Response response, HttpClientRequestWrapper request) { + this.response = response; + this.request = request; + this.invocation = invocation; + } + + @Override + public int statusCode() { + return response.getStatusCode(); + } + + @Override + public Object unwrap() { + return response; + } + + @Override + public HttpClientRequest request() { + return request; + } + + @Override + public Throwable error() { + return response.isFailed() ? response.getResult() : null; + } + + @Override + public Invocation getInvocation() { + return invocation; + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServeRequestWrapper.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServeRequestWrapper.java new file mode 100644 index 00000000000..45725539b46 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServeRequestWrapper.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.Invocation; + +import brave.http.HttpServerRequest; + +class HttpServeRequestWrapper extends HttpServerRequest implements InvocationAware { + private final Invocation invocation; + + HttpServeRequestWrapper(Invocation invocation) { + this.invocation = invocation; + } + + @Override + public String method() { + return invocation.getOperationMeta().getHttpMethod(); + } + + @Override + public String path() { + return TracingConfiguration.createRequestPath(invocation); + } + + @Override + public String url() { + return invocation.getInvocationQualifiedName(); + } + + @Override + public String route() { + return invocation.getRequestEx() != null ? invocation.getRequestEx().getRemoteAddr() : null; + } + + @Override + public String header(String name) { + String result = invocation.getContext(name); + if (StringUtils.isEmpty(result) && invocation.getRequestEx() != null) { + result = invocation.getRequestEx().getHeader(name); + } + return result; + } + + @Override + public Object unwrap() { + return invocation; + } + + @Override + public Invocation getInvocation() { + return invocation; + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServerResponseWrapper.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServerResponseWrapper.java new file mode 100644 index 00000000000..9f384bdfffd --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/HttpServerResponseWrapper.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.swagger.invocation.Response; + +import brave.http.HttpServerRequest; +import brave.http.HttpServerResponse; + +class HttpServerResponseWrapper extends HttpServerResponse implements InvocationAware { + private final Response response; + + private final HttpServerRequest request; + + private final Invocation invocation; + + HttpServerResponseWrapper(Invocation invocation, Response response, HttpServeRequestWrapper request) { + this.response = response; + this.request = request; + this.invocation = invocation; + } + + @Override + public int statusCode() { + return response.getStatusCode(); + } + + @Override + public Object unwrap() { + return response; + } + + @Override + public HttpServerRequest request() { + return request; + } + + @Override + public Throwable error() { + return response.isFailed() ? response.getResult() : null; + } + + @Override + public Invocation getInvocation() { + return invocation; + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/InvocationAware.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/InvocationAware.java new file mode 100644 index 00000000000..ddb4e8365ae --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/InvocationAware.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; + +public interface InvocationAware { + Invocation getInvocation(); +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/LogSpanHandler.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/LogSpanHandler.java new file mode 100644 index 00000000000..93499ec9209 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/LogSpanHandler.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.tracing.zipkin; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brave.handler.MutableSpan; +import brave.handler.SpanHandler; +import brave.propagation.TraceContext; + +public class LogSpanHandler extends SpanHandler { + private static final Logger LOGGER = LoggerFactory.getLogger("scb-trace"); + + public boolean end(TraceContext context, MutableSpan span, Cause cause) { + if (!LOGGER.isInfoEnabled()) { + return false; + } else { + LOGGER.info(span.toString()); + return true; + } + } + + public String toString() { + return "LogSpanHandler{name=scb-trace}"; + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ProviderInvocationAdapter.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ProviderInvocationAdapter.java deleted file mode 100644 index da12ab62c5f..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ProviderInvocationAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import javax.annotation.Nonnull; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -import brave.http.HttpServerAdapter; -import zipkin2.internal.Nullable; - -class ProviderInvocationAdapter extends HttpServerAdapter { - - @Nullable - @Override - public String method(@Nonnull Invocation invocation) { - return invocation.getOperationMeta().getHttpMethod(); - } - - @Nullable - @Override - public String url(@Nonnull Invocation invocation) { - return invocation.getEndpoint().getEndpoint(); - } - - @Nullable - @Override - public String path(@Nonnull Invocation request) { - return request.getOperationMeta().getOperationPath(); - } - - @Nullable - @Override - public String requestHeader(@Nonnull Invocation invocation, @Nonnull String key) { - return invocation.getContext().get(key); - } - - @Nullable - @Override - public Integer statusCode(@Nonnull Response response) { - return response.getStatusCode(); - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/TracingConfiguration.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/TracingConfiguration.java index b144fe5809f..79dbc2857b6 100644 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/TracingConfiguration.java +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/TracingConfiguration.java @@ -17,83 +17,143 @@ package org.apache.servicecomb.tracing.zipkin; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_ADDRESS; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_API_V1; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_API_V2; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_API_VERSION; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_PATH; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_MICROSERVICE_NAME; import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_TRACING_COLLECTOR_ADDRESS; import java.text.MessageFormat; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.config.DynamicProperties; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import brave.Tracing; -import brave.context.log4j12.MDCCurrentTraceContext; +import brave.context.slf4j.MDCScopeDecorator; import brave.http.HttpTracing; import brave.propagation.CurrentTraceContext; +import brave.propagation.ThreadLocalCurrentTraceContext; import zipkin2.Span; -import zipkin2.codec.SpanBytesEncoder; import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.BytesMessageSender; import zipkin2.reporter.Reporter; import zipkin2.reporter.Sender; +import zipkin2.reporter.SpanBytesEncoder; +import zipkin2.reporter.brave.AsyncZipkinSpanHandler; import zipkin2.reporter.okhttp3.OkHttpSender; @Configuration -class TracingConfiguration { - private String apiVersion = CONFIG_TRACING_COLLECTOR_API_V2; +@ConditionalOnProperty(value = TracingConfiguration.TRACING_ENABLED, + havingValue = "true", matchIfMissing = true) +public class TracingConfiguration { + public static final String TRACING_PREFIX = "servicecomb.tracing"; - @Bean - Sender sender(DynamicProperties dynamicProperties) { - apiVersion = dynamicProperties.getStringProperty(CONFIG_TRACING_COLLECTOR_API_VERSION, - CONFIG_TRACING_COLLECTOR_API_V2).toLowerCase(); - // use default value if the user set value is invalid - if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) != 0) { - apiVersion = CONFIG_TRACING_COLLECTOR_API_V2; - } + public static final String TRACING_ENABLED = TRACING_PREFIX + ".enabled"; - String path = MessageFormat.format(CONFIG_TRACING_COLLECTOR_PATH, apiVersion); - return OkHttpSender.create( - dynamicProperties.getStringProperty( - CONFIG_TRACING_COLLECTOR_ADDRESS, - DEFAULT_TRACING_COLLECTOR_ADDRESS) - .trim() - .replaceAll("/+$", "") - .concat(path)); - } + public static final String TRACING_REPORTER_LOG_ENABLED = TRACING_PREFIX + ".reporter.log.enabled"; - @Bean - Reporter zipkinReporter(Sender sender) { - if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) == 0) { - return AsyncReporter.builder(sender).build(SpanBytesEncoder.JSON_V1); + public static final String TRACING_REPORTER_ZIPKIN_ENABLED = TRACING_PREFIX + ".reporter.zipkin.enabled"; + + @Configuration + @ConditionalOnProperty(value = TracingConfiguration.TRACING_REPORTER_ZIPKIN_ENABLED, + havingValue = "true") + static class ZipkinReporterConfiguration { + @Bean + BytesMessageSender scbOkHttpSender(DynamicProperties dynamicProperties) { + String apiVersion = dynamicProperties.getStringProperty(CONFIG_TRACING_COLLECTOR_API_VERSION, + CONFIG_TRACING_COLLECTOR_API_V2).toLowerCase(); + // use default value if the user set value is invalid + if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) != 0) { + apiVersion = CONFIG_TRACING_COLLECTOR_API_V2; + } + + String path = MessageFormat.format(CONFIG_TRACING_COLLECTOR_PATH, apiVersion); + return OkHttpSender.create( + dynamicProperties.getStringProperty( + CONFIG_TRACING_COLLECTOR_ADDRESS, + DEFAULT_TRACING_COLLECTOR_ADDRESS) + .trim() + .replaceAll("/+$", "") + .concat(path)); } - return AsyncReporter.builder(sender).build(); - } + @Bean + Reporter scbZipkinReporter(DynamicProperties dynamicProperties, BytesMessageSender sender) { + String apiVersion = dynamicProperties.getStringProperty(CONFIG_TRACING_COLLECTOR_API_VERSION, + CONFIG_TRACING_COLLECTOR_API_V2).toLowerCase(); + if (apiVersion.compareTo(CONFIG_TRACING_COLLECTOR_API_V1) == 0) { + return AsyncReporter.builder(sender).build(SpanBytesEncoder.JSON_V1); + } + return AsyncReporter.builder(sender).build(); + } + } @Bean - Tracing tracing(Reporter reporter, DynamicProperties dynamicProperties, - CurrentTraceContext currentTraceContext) { - return Tracing.newBuilder() - .localServiceName(dynamicProperties.getStringProperty(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, - DEFAULT_MICROSERVICE_NAME)) - .currentTraceContext(currentTraceContext) // puts trace IDs into logs - .spanReporter(reporter) + CurrentTraceContext scbCurrentTraceContext() { + return ThreadLocalCurrentTraceContext.newBuilder() + .addScopeDecorator(MDCScopeDecorator.newBuilder().build()) .build(); } @Bean - CurrentTraceContext currentTraceContext() { - return MDCCurrentTraceContext.create(); + Tracing scbTracing(@Autowired(required = false) Sender sender, + CurrentTraceContext currentTraceContext, Environment environment, DynamicProperties dynamicProperties) { + Tracing.Builder builder = Tracing.newBuilder() + .localServiceName(BootStrapProperties.readServiceName(environment)) + .currentTraceContext(currentTraceContext); // puts trace IDs into logs + if (dynamicProperties.getBooleanProperty(TRACING_REPORTER_LOG_ENABLED, true)) { + builder.addSpanHandler(new LogSpanHandler()); + } + if (dynamicProperties.getBooleanProperty(TRACING_REPORTER_ZIPKIN_ENABLED, false)) { + builder.addSpanHandler(AsyncZipkinSpanHandler.create(sender)); + } + return builder.build(); + } + + @Bean + HttpTracing scbHttpTracing(Tracing tracing) { + return HttpTracing.newBuilder(tracing) + .clientRequestParser(new CustomHttpRequestParser()) + .clientResponseParser(new CustomHttpResponseParser()) + .serverRequestParser(new CustomHttpRequestParser()) + .serverResponseParser(new CustomHttpResponseParser()).build(); } @Bean - HttpTracing httpTracing(Tracing tracing) { - return HttpTracing.create(tracing); + ZipkinTracingFilter scbZipkinTracingFilter() { + return new ZipkinTracingFilter(); + } + + public static String createRequestPath(Invocation invocation) { + URIEndpointObject address = (URIEndpointObject) invocation.getEndpoint().getAddress(); + String urlPrefix = address.getFirst(DefinitionConst.URL_PREFIX); + RestOperationMeta swaggerRestOperation = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); + String path = (String) invocation.getHandlerContext().get(RestConst.REST_CLIENT_REQUEST_PATH); + if (path == null) { + try { + path = swaggerRestOperation.getPathBuilder().createRequestPath(invocation.getSwaggerArguments()); + } catch (Exception e) { + path = invocation.getOperationMeta().getOperationPath(); + } + } + + if (StringUtils.isEmpty(urlPrefix) || path.startsWith(urlPrefix)) { + return path; + } + + return urlPrefix + path; } } diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerDelegate.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerDelegate.java deleted file mode 100644 index 13ca8feabf6..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerDelegate.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -import brave.Span; -import brave.Tracing; -import brave.http.HttpClientHandler; -import brave.http.HttpTracing; -import brave.propagation.Propagation.Setter; -import brave.propagation.TraceContext.Injector; - -class ZipkinConsumerDelegate implements ZipkinTracingDelegate { - - private final HttpClientHandler handler; - - private final HttpTracing httpTracing; - - private final Injector injector; - - @SuppressWarnings("unchecked") - ZipkinConsumerDelegate(HttpTracing httpTracing) { - this.httpTracing = httpTracing; - this.injector = httpTracing.tracing().propagation().injector(injector()); - this.handler = HttpClientHandler.create(httpTracing, new ConsumerInvocationAdapter()); - } - - @Override - public Span createSpan(Invocation invocation) { - return handler.handleSend(injector, invocation); - } - - @Override - public void onResponse(Span span, Response response, Throwable error) { - handler.handleReceive(response, error, span); - } - - @Override - public String name() { - return "Zipkin consumer"; - } - - @Override - public Tracing tracer() { - return httpTracing.tracing(); - } - - private Setter injector() { - return (invocation, key, value) -> invocation.getContext().put(key, value); - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerTracingHandler.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerTracingHandler.java deleted file mode 100644 index 7883134131a..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinConsumerTracingHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -import brave.http.HttpTracing; - -public class ZipkinConsumerTracingHandler extends ZipkinTracingHandler { - - public ZipkinConsumerTracingHandler() { - this(new ZipkinConsumerDelegate(BeanUtils.getContext().getBean(HttpTracing.class))); - } - - private ZipkinConsumerTracingHandler(ZipkinTracingDelegate tracingHandler) { - super(tracingHandler); - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegate.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegate.java deleted file mode 100644 index 60b83bf859c..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegate.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import brave.Span; -import brave.Tracing; -import brave.http.HttpServerHandler; -import brave.http.HttpTracing; -import brave.propagation.Propagation.Getter; -import brave.propagation.TraceContext.Extractor; - -class ZipkinProviderDelegate implements ZipkinTracingDelegate { - private static final Logger LOG = LoggerFactory.getLogger(ZipkinProviderDelegate.class); - - private final HttpServerHandler handler; - - private final HttpTracing httpTracing; - - private final Extractor extractor; - - public static final String SPAN_ID_HEADER_NAME = "X-B3-SpanId"; - - public static final String TRACE_ID_HEADER_NAME = Const.TRACE_ID_NAME; - - private static final Getter INVOCATION_STRING_GETTER = (invocation, key) -> { - String extracted = invocation.getContext().get(key); - if (StringUtils.isEmpty(extracted) && SPAN_ID_HEADER_NAME.equals(key)) { - // use traceId as spanId to avoid brave's recreating traceId - extracted = invocation.getContext().get(TRACE_ID_HEADER_NAME); - LOG.debug("try to extract X-B3-SpanId, but the value is empty, replace with TraceId = [{}]", extracted); - } - return extracted; - }; - - @SuppressWarnings("unchecked") - ZipkinProviderDelegate(HttpTracing httpTracing) { - this.httpTracing = httpTracing; - this.extractor = httpTracing.tracing().propagation().extractor(extractor()); - this.handler = HttpServerHandler.create(httpTracing, new ProviderInvocationAdapter()); - } - - @Override - public Tracing tracer() { - return httpTracing.tracing(); - } - - @Override - public Span createSpan(Invocation invocation) { - return handler.handleReceive(extractor, invocation); - } - - @Override - public void onResponse(Span span, Response response, Throwable error) { - handler.handleSend(response, error, span); - } - - @Override - public String name() { - return "Zipkin provider"; - } - - private Getter extractor() { - return INVOCATION_STRING_GETTER; - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderTracingHandler.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderTracingHandler.java deleted file mode 100644 index abec4f33004..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderTracingHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -import brave.http.HttpTracing; - -public class ZipkinProviderTracingHandler extends ZipkinTracingHandler { - - public ZipkinProviderTracingHandler() { - this(new ZipkinProviderDelegate(BeanUtils.getContext().getBean(HttpTracing.class))); - } - - private ZipkinProviderTracingHandler(ZipkinProviderDelegate tracingHandler) { - super(tracingHandler); - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingDelegate.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingDelegate.java deleted file mode 100644 index 3761a8d8454..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingDelegate.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.Response; - -import brave.Span; -import brave.Tracing; - -interface ZipkinTracingDelegate { - - Tracing tracer(); - - Span createSpan(Invocation invocation); - - void onResponse(Span span, Response response, Throwable error); - - String name(); -} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java new file mode 100644 index 00000000000..f88532adf5e --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingFilter.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.tracing.zipkin; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.event.InvocationStartEvent; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.Subscribe; + +import brave.Span; +import brave.http.HttpClientHandler; +import brave.http.HttpClientRequest; +import brave.http.HttpClientResponse; +import brave.http.HttpServerHandler; +import brave.http.HttpServerRequest; +import brave.http.HttpServerResponse; +import brave.http.HttpTracing; + +public class ZipkinTracingFilter { + public static final String CONTEXT_TRACE_REQUEST = "x-trace-request"; + + public static final String CONTEXT_TRACE_HANDLER = "x-trace-handler"; + + public static final String CONTEXT_TRACE_SPAN = "x-trace-span"; + + public static final String CONTEXT_TRACE_EDGE_REQUEST = "x-trace-edge-request"; + + public static final String CONTEXT_TRACE_EDGE_HANDLER = "x-trace-edge-handler"; + + public static final String CONTEXT_TRACE_EDGE_SPAN = "x-trace-edge-span"; + + private HttpTracing httpTracing; + + public ZipkinTracingFilter() { + EventManager.register(this); + } + + @Autowired + public void setHttpTracing(HttpTracing httpTracing) { + this.httpTracing = httpTracing; + } + + @Subscribe + public void onInvocationStartEvent(InvocationStartEvent event) { + Invocation invocation = event.getInvocation(); + + if (invocation.isProducer()) { + HttpServerHandler handler = HttpServerHandler.create(httpTracing); + HttpServeRequestWrapper request = new HttpServeRequestWrapper(invocation); + Span span = handler.handleReceive(request); + invocation.addLocalContext(CONTEXT_TRACE_SPAN, span); + invocation.addLocalContext(CONTEXT_TRACE_HANDLER, handler); + invocation.addLocalContext(CONTEXT_TRACE_REQUEST, request); + } else if (invocation.isConsumer()) { + Span parentSpan = invocation.getLocalContext(CONTEXT_TRACE_SPAN); + HttpClientHandler handler = HttpClientHandler.create(httpTracing); + HttpClientRequestWrapper request = new HttpClientRequestWrapper(invocation); + Span span = handler.handleSendWithParent(request, parentSpan == null ? null : parentSpan.context()); + invocation.addLocalContext(CONTEXT_TRACE_HANDLER, handler); + invocation.addLocalContext(CONTEXT_TRACE_REQUEST, request); + invocation.addLocalContext(CONTEXT_TRACE_SPAN, span); + } else { + // edge as server + HttpServerHandler serverHandler = HttpServerHandler.create(httpTracing); + HttpServeRequestWrapper serverRequest = new HttpServeRequestWrapper(invocation); + Span serverSpan = serverHandler.handleReceive(serverRequest); + invocation.addLocalContext(CONTEXT_TRACE_EDGE_SPAN, serverSpan); + invocation.addLocalContext(CONTEXT_TRACE_EDGE_HANDLER, serverHandler); + invocation.addLocalContext(CONTEXT_TRACE_EDGE_REQUEST, serverRequest); + + // edge as client + HttpClientHandler clientHandler = HttpClientHandler.create(httpTracing); + HttpClientRequestWrapper clientRequest = new HttpClientRequestWrapper(invocation); + Span clientSpan = clientHandler.handleSendWithParent(clientRequest, serverSpan.context()); + invocation.addLocalContext(CONTEXT_TRACE_HANDLER, clientHandler); + invocation.addLocalContext(CONTEXT_TRACE_REQUEST, clientRequest); + invocation.addLocalContext(CONTEXT_TRACE_SPAN, clientSpan); + } + } + + @Subscribe + public void onInvocationFinishEvent(InvocationFinishEvent event) { + Invocation invocation = event.getInvocation(); + if (invocation.isProducer()) { + HttpServerHandler handler + = invocation.getLocalContext(CONTEXT_TRACE_HANDLER); + Span span = invocation.getLocalContext(CONTEXT_TRACE_SPAN); + handler.handleSend(new HttpServerResponseWrapper(invocation, event.getResponse(), + invocation.getLocalContext(CONTEXT_TRACE_REQUEST)), span); + } else if (invocation.isConsumer()) { + HttpClientHandler handler + = invocation.getLocalContext(CONTEXT_TRACE_HANDLER); + Span span = invocation.getLocalContext(CONTEXT_TRACE_SPAN); + handler.handleReceive(new HttpClientResponseWrapper(invocation, event.getResponse(), + invocation.getLocalContext(CONTEXT_TRACE_REQUEST)), span); + } else { + // edge as client + HttpClientHandler clientHandler + = invocation.getLocalContext(CONTEXT_TRACE_HANDLER); + Span clientSpan = invocation.getLocalContext(CONTEXT_TRACE_SPAN); + clientHandler.handleReceive(new HttpClientResponseWrapper(invocation, event.getResponse(), + invocation.getLocalContext(CONTEXT_TRACE_REQUEST)), clientSpan); + // edge as server + HttpServerHandler serverHandler + = invocation.getLocalContext(CONTEXT_TRACE_EDGE_HANDLER); + Span serverSpan = invocation.getLocalContext(CONTEXT_TRACE_EDGE_SPAN); + serverHandler.handleSend(new HttpServerResponseWrapper(invocation, event.getResponse(), + invocation.getLocalContext(CONTEXT_TRACE_EDGE_REQUEST)), serverSpan); + } + } +} diff --git a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandler.java b/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandler.java deleted file mode 100644 index 7990d0dfa28..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brave.Span; -import brave.Tracer.SpanInScope; -import brave.Tracing; - -class ZipkinTracingHandler implements Handler { - - private static final Logger LOGGER = LoggerFactory.getLogger(ZipkinTracingHandler.class); - - private final Tracing tracer; - - private final ZipkinTracingDelegate tracingDelegate; - - ZipkinTracingHandler(ZipkinTracingDelegate tracingDelegate) { - this.tracer = tracingDelegate.tracer(); - this.tracingDelegate = tracingDelegate; - } - - @SuppressWarnings({"try", "unused"}) - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - Span span = tracingDelegate.createSpan(invocation); - try (SpanInScope scope = tracer.tracer().withSpanInScope(span)) { - LOGGER.debug("{}: Generated tracing span for {}", - tracingDelegate.name(), - invocation.getOperationName()); - - invocation.next(onResponse(invocation, asyncResp, span)); - } catch (Exception e) { - LOGGER.debug("{}: Failed invocation on {}", - tracingDelegate.name(), - invocation.getOperationName(), - e); - - tracingDelegate.onResponse(span, null, e); - throw e; - } - } - - private AsyncResponse onResponse(Invocation invocation, AsyncResponse asyncResp, Span span) { - return response -> { - Throwable error = response.isFailed() ? response.getResult() : null; - tracingDelegate.onResponse(span, response, error); - - LOGGER.debug("{}: Completed invocation on {}", - tracingDelegate.name(), - invocation.getOperationName(), - error); - - asyncResp.handle(response); - }; - } -} diff --git a/handlers/handler-tracing-zipkin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/handlers/handler-tracing-zipkin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..f7edf1bb134 --- /dev/null +++ b/handlers/handler-tracing-zipkin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.tracing.zipkin.TracingConfiguration diff --git a/handlers/handler-tracing-zipkin/src/main/resources/config/cse.handler.xml b/handlers/handler-tracing-zipkin/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 713ce08f65d..00000000000 --- a/handlers/handler-tracing-zipkin/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegateTest.java b/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegateTest.java deleted file mode 100644 index 1ff3f9866ba..00000000000 --- a/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinProviderDelegateTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.core.Invocation; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import brave.propagation.Propagation.Getter; -import mockit.Deencapsulation; - -public class ZipkinProviderDelegateTest { - @Test - public void testGetterOnGetSpanId() { - Getter getter = Deencapsulation - .getField(ZipkinProviderDelegate.class, "INVOCATION_STRING_GETTER"); - - Invocation invocation = Mockito.mock(Invocation.class); - Map context = new HashMap<>(); - - Mockito.when(invocation.getContext()).thenReturn(context); - - // if there is no spanId or traceId, then result is null - String spanId = getter.get(invocation, ZipkinProviderDelegate.SPAN_ID_HEADER_NAME); - Assert.assertNull(spanId); - - // if there is no spanId but traceId, then traceId will be returned as result - final String testTraceId = "testTraceId"; - context.put(ZipkinProviderDelegate.TRACE_ID_HEADER_NAME, testTraceId); - spanId = getter.get(invocation, ZipkinProviderDelegate.SPAN_ID_HEADER_NAME); - Assert.assertEquals(testTraceId, spanId); - - // if there is spanId, then spanId will be returned - final String testSpanId = "testSpanId"; - context.put(ZipkinProviderDelegate.SPAN_ID_HEADER_NAME, testSpanId); - spanId = getter.get(invocation, ZipkinProviderDelegate.SPAN_ID_HEADER_NAME); - Assert.assertEquals(testSpanId, spanId); - } - - @Test - public void testGetterOnGetOtherContent() { - Getter getter = Deencapsulation - .getField(ZipkinProviderDelegate.class, "INVOCATION_STRING_GETTER"); - - Invocation invocation = Mockito.mock(Invocation.class); - Map context = new HashMap<>(); - - Mockito.when(invocation.getContext()).thenReturn(context); - - final String key = "key"; - String value = getter.get(invocation, key); - Assert.assertNull(value); - - final String expectedValue = "value"; - context.put(key, expectedValue); - value = getter.get(invocation, key); - Assert.assertEquals(expectedValue, value); - } -} diff --git a/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandlerTest.java b/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandlerTest.java deleted file mode 100644 index ffe27ce5820..00000000000 --- a/handlers/handler-tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingHandlerTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tracing.zipkin; - -import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import brave.Span; -import brave.Tracing; - -public class ZipkinTracingHandlerTest { - - private final Invocation invocation = Mockito.mock(Invocation.class); - - private final Response response = Mockito.mock(Response.class); - - private final AsyncResponse asyncResponse = Mockito.mock(AsyncResponse.class); - - private final ZipkinTracingDelegate delegate = Mockito.mock(ZipkinTracingDelegate.class); - - private final Tracing tracing = Tracing.newBuilder().build(); - - private final Span span = Mockito.mock(Span.class); - - private final RuntimeException exception = new RuntimeException("oops"); - - private ZipkinTracingHandler tracingHandler; - - @Before - public void setUp() throws Exception { - when(delegate.tracer()).thenReturn(tracing); - when(delegate.createSpan(invocation)).thenReturn(span); - when(delegate.name()).thenReturn("delegate"); - - tracingHandler = new ZipkinTracingHandler(delegate); - } - - @Test - public void delegatesResponseAndHandleResponse() throws Exception { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(AsyncResponse.class); - - tracingHandler.handle(invocation, asyncResponse); - - verify(invocation).next(argumentCaptor.capture()); - - argumentCaptor.getValue().handle(response); - - verify(asyncResponse).handle(response); - verify(delegate).onResponse(span, response, null); - } - - @Test - public void delegatesErrorResponseAndHandleResponse() throws Exception { - when(response.isFailed()).thenReturn(true); - when(response.getResult()).thenReturn(exception); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(AsyncResponse.class); - - tracingHandler.handle(invocation, asyncResponse); - - verify(invocation).next(argumentCaptor.capture()); - - argumentCaptor.getValue().handle(response); - - verify(asyncResponse).handle(response); - verify(delegate).onResponse(span, response, exception); - } - - @Test - public void delegatesErrorOnInvocationFailure() throws Exception { - doThrow(exception).when(invocation).next(any(AsyncResponse.class)); - - try { - tracingHandler.handle(invocation, asyncResponse); - expectFailing(RuntimeException.class); - } catch (Exception e) { - assertThat(e, is(exception)); - } - - verify(delegate).onResponse(span, null, exception); - } -} diff --git a/handlers/pom.xml b/handlers/pom.xml index aeaa00e6c32..e74e2c95134 100644 --- a/handlers/pom.xml +++ b/handlers/pom.xml @@ -22,8 +22,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default 4.0.0 @@ -33,11 +33,12 @@ handler-tracing-zipkin - handler-bizkeeper handler-flowcontrol-qps handler-loadbalance handler-fault-injection handler-publickey-auth + handler-router + handler-governance diff --git a/huawei-cloud/darklaunch/pom.xml b/huawei-cloud/darklaunch/pom.xml new file mode 100644 index 00000000000..b4396f87a64 --- /dev/null +++ b/huawei-cloud/darklaunch/pom.xml @@ -0,0 +1,45 @@ + + + + + huawei-cloud + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + darklaunch + Java Chassis::darklaunch + + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + handler-loadbalance + + + diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRule.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRule.java new file mode 100644 index 00000000000..988cd9e401f --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRule.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.darklaunch.oper.ConditionFactory; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DarklaunchRule { + private static final Logger LOG = LoggerFactory.getLogger(DarklaunchRule.class); + + public static final String PROP_VERSION = "version"; + + public static final String PROP_TAG = "tag"; + + public static final String PROP_PERCENT = "rate"; + + private PolicyType policyType; + + private final List ruleItems = new ArrayList<>(); + + public static DarklaunchRule parse(String ruleStr) { + if (StringUtils.isEmpty(ruleStr)) { + return null; + } + + try { + DarklaunchRuleJson ruleJson = JsonUtils + .readValue(ruleStr.getBytes(StandardCharsets.UTF_8), DarklaunchRuleJson.class); + DarklaunchRule rule = new DarklaunchRule(ruleJson.getPolicyType()); + for (DarklaunchRuleItemJson itemJson : ruleJson.getRuleItems()) { + DarklaunchRuleItem item = new DarklaunchRuleItem(itemJson.getGroupName()); + item.setGroupCondition( + ConditionFactory.buildCondition(itemJson.getGroupCondition(), itemJson.isCaseInsensitive()) + ); + if (rule.getPolicyType().equals(PolicyType.RULE)) { + item.setPolicyCondition( + ConditionFactory.buildCondition(itemJson.getPolicyCondition(), itemJson.isCaseInsensitive())); + } else { + item.setPolicyCondition(ConditionFactory.buildRateCondition(itemJson.getPolicyCondition())); + } + rule.addRuleItem(item); + } + return rule; + } catch (Exception e) { + LOG.warn("Invalid configuration: rule={},message={}", ruleStr, e.getMessage()); + } + return null; + } + + public DarklaunchRule(PolicyType policyType) { + this.policyType = policyType; + } + + public PolicyType getPolicyType() { + return policyType; + } + + public void setPolicyType(PolicyType policyType) { + this.policyType = policyType; + } + + public List getRuleItems() { + return ruleItems; + } + + public void addRuleItem(DarklaunchRuleItem ruleItem) { + this.ruleItems.add(ruleItem); + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItem.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItem.java new file mode 100644 index 00000000000..a6ad1e8ccb1 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItem.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.darklaunch.oper.Condition; +import org.apache.servicecomb.loadbalance.ServiceCombServer; + +public class DarklaunchRuleItem { + private String groupName; + + private Condition groupCondition; + + private Condition policyCondition; + + private final List servers = new ArrayList<>(); + + public DarklaunchRuleItem(String groupName) { + this.groupName = groupName; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public Condition getGroupCondition() { + return groupCondition; + } + + public void setGroupCondition(Condition groupCondition) { + this.groupCondition = groupCondition; + } + + public Condition getPolicyCondition() { + return policyCondition; + } + + public void setPolicyCondition(Condition policyCondition) { + this.policyCondition = policyCondition; + } + + public List getServers() { + return this.servers; + } + + public void addServer(ServiceCombServer server) { + this.servers.add(server); + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItemJson.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItemJson.java new file mode 100644 index 00000000000..47dce445ce9 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleItemJson.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DarklaunchRuleItemJson { + private String groupName; + + private String groupCondition; + + private String policyCondition; + + private boolean caseInsensitive; + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getGroupCondition() { + return groupCondition; + } + + public void setGroupCondition(String groupCondition) { + this.groupCondition = groupCondition; + } + + public String getPolicyCondition() { + return policyCondition; + } + + public void setPolicyCondition(String policyCondition) { + this.policyCondition = policyCondition; + } + + public boolean isCaseInsensitive() { + return caseInsensitive; + } + + public void setCaseInsensitive(boolean caseInsensitive) { + this.caseInsensitive = caseInsensitive; + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleJson.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleJson.java new file mode 100644 index 00000000000..4c1255218e5 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchRuleJson.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DarklaunchRuleJson { + private PolicyType policyType; + + private List ruleItems = new ArrayList<>(); + + public PolicyType getPolicyType() { + return policyType; + } + + public void setPolicyType(PolicyType policyType) { + this.policyType = policyType; + } + + public List getRuleItems() { + return ruleItems; + } + + public void setRuleItems(List ruleItems) { + this.ruleItems = ruleItems; + } + + public void addRuleItem(DarklaunchRuleItemJson ruleItem) { + this.ruleItems.add(ruleItem); + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchServerListFilter.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchServerListFilter.java new file mode 100644 index 00000000000..d380a8f254c --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/DarklaunchServerListFilter.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.loadbalance.ServerListFilterExt; +import org.apache.servicecomb.loadbalance.ServiceCombServer; + +public class DarklaunchServerListFilter implements ServerListFilterExt { + + private static final String POLICY_SERVICE_COMB = "servicecomb.darklaunch.policy.%s"; + + private static final int HUNDRED = 100; + + private final Random random = new Random(); + + public DarklaunchServerListFilter() { + } + + @Override + public int getOrder() { + return HUNDRED; + } + + @Override + public boolean enabled() { + return true; + } + + @Override + public List getFilteredListOfServers(List serverList, Invocation invocation) { + DarklaunchRule rule = DarklaunchRule.parse(LegacyPropertyFactory + .getStringProperty(String.format(POLICY_SERVICE_COMB, invocation.getMicroserviceName()))); + if (rule == null) { + return serverList; + } + List defaultGroup = new ArrayList<>(); + divideServerGroup(serverList, rule, defaultGroup); + + if (rule.getPolicyType() == PolicyType.RULE) { + for (DarklaunchRuleItem item : rule.getRuleItems()) { + List ruleServers = getRuleServers(invocation, item, defaultGroup); + if (ruleServers != null) { + return ruleServers; + } + } + } else { + int rate = random.nextInt(HUNDRED); + for (DarklaunchRuleItem item : rule.getRuleItems()) { + item.getPolicyCondition().setActual(DarklaunchRule.PROP_PERCENT, rate); + if (item.getPolicyCondition().match()) { + if (item.getServers().isEmpty()) { + return defaultGroup; + } + return item.getServers(); + } + rate = rate - Integer.parseInt(item.getPolicyCondition().expected()); + } + } + return defaultGroup; + } + + private List getRuleServers(Invocation invocation, DarklaunchRuleItem item, + List defaultGroup) { + invocation.getSwaggerArguments().forEach((k, v) -> item.getPolicyCondition().setActual(k, v)); + for (String key : invocation.getContext().keySet()) { + item.getPolicyCondition().setActual(key, invocation.getContext(key)); + } + if (item.getPolicyCondition().match()) { + if (item.getServers().isEmpty()) { + return defaultGroup; + } + return item.getServers(); + } + return null; + } + + private void divideServerGroup(List serverList, DarklaunchRule rule, + List defaultGroup) { + for (ServiceCombServer server : serverList) { + boolean hasGroup = false; + for (DarklaunchRuleItem item : rule.getRuleItems()) { + item.getGroupCondition() + .setActual(DarklaunchRule.PROP_VERSION, server.getInstance().getVersion()); + if (item.getGroupCondition().match()) { + item.addServer(server); + hasGroup = true; + } + } + if (!hasGroup) { + defaultGroup.add(server); + } + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/PolicyType.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/PolicyType.java new file mode 100644 index 00000000000..fcabf5b45e6 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/PolicyType.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch; + +public enum PolicyType { + RULE, + RATE +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AbstractCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AbstractCondition.java new file mode 100644 index 00000000000..e257aa76333 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AbstractCondition.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public abstract class AbstractCondition implements Condition { + private final String key; + + private final String expected; + + private Object actual; + + private SupportedType type = SupportedType.UNKNOWN; + + public AbstractCondition(String key, String expected) { + assertValueNotNull(key, expected); + this.key = key; + this.expected = expected; + } + + @Override + public String key() { + return this.key; + } + + @Override + public String expected() { + return this.expected; + } + + @Override + public void setActual(String key, Object actual) { + assertValueNotNull(key, ""); + if (this.key.equals(key)) { + if (actual instanceof String) { + this.type = SupportedType.STRING; + } else if (actual instanceof Number) { + this.type = SupportedType.NUMBER; + } + this.actual = actual; + } + } + + protected void assertValueNotNull(String key, Object value) { + if (key == null) { + throw new IllegalArgumentException("Key can not be null."); + } + if (value == null) { + throw new IllegalArgumentException("Argument can not be null. key = " + key); + } + } + + public static int compareNum(Object num, String anotherNum) { + try { + if (num instanceof Integer) { + return Integer.compare((Integer) num, Integer.parseInt(anotherNum)); + } + if (num instanceof Long) { + return Long.compare((Long) num, Long.parseLong(anotherNum)); + } + if (num instanceof Double) { + return Double.compare((Double) num, Double.parseDouble(anotherNum)); + } + if (num instanceof Float) { + return Float.compare((Float) num, Float.parseFloat(anotherNum)); + } + } catch (NumberFormatException e) { + return 1; + } + return 1; + } + + public Object getActual() { + return actual; + } + + public SupportedType getType() { + return type; + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AndCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AndCondition.java new file mode 100644 index 00000000000..ccb033ef422 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/AndCondition.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class AndCondition extends AbstractCondition { + private final Condition[] conditions; + + public AndCondition(Condition... conditions) { + super("and", "and"); + this.conditions = conditions; + } + + @Override + public void setActual(String key, Object actual) { + for (Condition condition : this.conditions) { + condition.setActual(key, actual); + } + } + + @Override + public boolean match() { + for (Condition condition : this.conditions) { + if (!condition.match()) { + return false; + } + } + return true; + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/CaseInsensitiveCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/CaseInsensitiveCondition.java new file mode 100644 index 00000000000..e47e17241bf --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/CaseInsensitiveCondition.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class CaseInsensitiveCondition extends AbstractCondition { + private final Condition condition; + + public CaseInsensitiveCondition(Condition condition) { + super(condition.key(), condition.expected()); + this.condition = condition; + } + + @Override + public void setActual(String key, Object actual) { + if (null == actual) { + condition.setActual(key, null); + return; + } + actual = actual.toString().toLowerCase(); + condition.setActual(key, actual); + } + + @Override + public boolean match() { + return condition.match(); + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/Condition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/Condition.java new file mode 100644 index 00000000000..bb8489a4828 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/Condition.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + + +public interface Condition { + String key(); + + String expected(); + + void setActual(String key, Object actual); + + boolean match(); +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/ConditionFactory.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/ConditionFactory.java new file mode 100644 index 00000000000..d7b410c35b8 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/ConditionFactory.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.darklaunch.DarklaunchRule; + +public class ConditionFactory { + public static final String OP_AND = "&&"; + + public static final String OP_OR = "||"; + + public static final String OP_OR_ESCAPE = "\\|\\|"; + + private static final String[] OP_LIST = {">=", "<=", "!=", "=", ">", "<", "~"}; + + public static final String SEP_COLON = ","; + + private static String[] split2Part(String str, String sep) { + int index = str.indexOf(sep); + if (index > 0) { + return new String[] { + str.substring(0, index), str.substring(index + sep.length()) + }; + } else { + return new String[] {str}; + } + } + + private static String[] split(String str, String sep) { + return Arrays.stream(str.split(sep)) + .filter(s -> !StringUtils.isEmpty(s)).toArray(String[]::new); + } + + public static Condition buildRateCondition(String strCondition) { + return new LessCondition(DarklaunchRule.PROP_PERCENT, strCondition); + } + + public static Condition buildCondition(String strCondition, boolean caseInsensitive) { + if (strCondition.contains(OP_AND)) { + String[] rules = split(strCondition, OP_AND); + Condition[] conditions = new Condition[rules.length]; + for (int i = 0; i < conditions.length; i++) { + conditions[i] = buildGroupConditionItem(rules[i], caseInsensitive); + } + return new AndCondition(conditions); + } else if (strCondition.contains(OP_OR)) { + String[] rules = split(strCondition, OP_OR_ESCAPE); + Condition[] conditions = new Condition[rules.length]; + for (int i = 0; i < conditions.length; i++) { + conditions[i] = buildGroupConditionItem(rules[i], caseInsensitive); + } + return new OrCondition(conditions); + } else { + return buildGroupConditionItem(strCondition, caseInsensitive); + } + } + + private static Condition buildGroupConditionItem(String groupCondition, boolean caseInsensitive) { + for (int index = 0; index < OP_LIST.length; index++) { + if (groupCondition.contains(OP_LIST[index])) { + String[] pairs = split2Part(groupCondition, OP_LIST[index]); + if (pairs[1].contains(SEP_COLON)) { + String[] values = split(pairs[1], SEP_COLON); + Condition[] conditions = new Condition[values.length]; + for (int i = 0; i < values.length; i++) { + conditions[i] = buildCondition(index, pairs[0], values[i], caseInsensitive); + } + return new OrCondition(conditions); + } else { + return buildCondition(index, pairs[0], pairs[1], caseInsensitive); + } + } + } + throw new IllegalArgumentException(groupCondition); + } + + private static Condition buildCondition(int index, String key, String value, boolean caseInsensitive) { + value = caseInsensitive ? value.toLowerCase() : value; + Condition condition = buildCondition(index, key, value); + if (caseInsensitive) { + return new CaseInsensitiveCondition(condition); + } + return condition; + } + + private static Condition buildCondition(int index, String key, String value) { + switch (index) { + case 0: + return new GreaterOrEqualCondition(key, value); + case 1: + return new LessOrEqualCondition(key, value); + case 2: + return new NotEqualCondition(key, value); + case 3: + return new EqualCondition(key, value); + case 4: + return new GreaterCondition(key, value); + case 5: + return new LessCondition(key, value); + default: + return new LikeCondition(key, value); + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/EqualCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/EqualCondition.java new file mode 100644 index 00000000000..1073c10ff9f --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/EqualCondition.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class EqualCondition extends AbstractCondition { + public EqualCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) == 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) == 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterCondition.java new file mode 100644 index 00000000000..6709c21975c --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterCondition.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class GreaterCondition extends AbstractCondition { + public GreaterCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) > 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) > 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterOrEqualCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterOrEqualCondition.java new file mode 100644 index 00000000000..28139bb5c12 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/GreaterOrEqualCondition.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class GreaterOrEqualCondition extends AbstractCondition { + public GreaterOrEqualCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) >= 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) >= 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessCondition.java new file mode 100644 index 00000000000..6acce8e34c8 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessCondition.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class LessCondition extends AbstractCondition { + public LessCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) < 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) < 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessOrEqualCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessOrEqualCondition.java new file mode 100644 index 00000000000..b7eea4eaaff --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LessOrEqualCondition.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class LessOrEqualCondition extends AbstractCondition { + public LessOrEqualCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) <= 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) <= 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LikeCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LikeCondition.java new file mode 100644 index 00000000000..790ba9a57ad --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/LikeCondition.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +import java.util.regex.Pattern; + +public class LikeCondition extends AbstractCondition { + private final Pattern pattern; + + public LikeCondition(String key, String expected) { + super(key, expected); + + char[] cs = expected.toCharArray(); + StringBuilder regExp = new StringBuilder(); + int lastPos = 0; + for (int i = 0; i < cs.length; i++) { + if ((cs[i]) == '*') { + regExp.append(Pattern.quote(new String(cs, lastPos, i - lastPos))); + regExp.append(".*"); + lastPos = i + 1; + } else if (cs[i] == '?') { + regExp.append(Pattern.quote(new String(cs, lastPos, i - lastPos))); + regExp.append("."); + lastPos = i = 1; + } + } + regExp.append(Pattern.quote(new String(cs, lastPos, cs.length - lastPos))); + pattern = Pattern.compile(regExp.toString()); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.STRING) { + return this.pattern.matcher((String) this.getActual()).matches(); + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/NotEqualCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/NotEqualCondition.java new file mode 100644 index 00000000000..e5cde3724ee --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/NotEqualCondition.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class NotEqualCondition extends AbstractCondition { + + public NotEqualCondition(String key, String expected) { + super(key, expected); + } + + @Override + public boolean match() { + SupportedType type = this.getType(); + if (type == SupportedType.NUMBER) { + return compareNum(this.getActual(), this.expected()) != 0; + } else if (type == SupportedType.STRING) { + return ((String) this.getActual()).compareTo(this.expected()) != 0; + } else { + return false; + } + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/OrCondition.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/OrCondition.java new file mode 100644 index 00000000000..8c1374f8cc9 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/OrCondition.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public class OrCondition extends AbstractCondition { + private final Condition[] conditions; + + public OrCondition(Condition... conditions) { + super("or", "or"); + this.conditions = conditions; + } + + @Override + public void setActual(String key, Object actual) { + for (Condition condition : this.conditions) { + condition.setActual(key, actual); + } + } + + @Override + public boolean match() { + for (Condition condition : this.conditions) { + if (condition.match()) { + return true; + } + } + return false; + } +} diff --git a/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/SupportedType.java b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/SupportedType.java new file mode 100644 index 00000000000..2308ad45921 --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/java/org/apache/servicecomb/darklaunch/oper/SupportedType.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.darklaunch.oper; + +public enum SupportedType { + STRING, + NUMBER, + UNKNOWN +} diff --git a/huawei-cloud/darklaunch/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt b/huawei-cloud/darklaunch/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt new file mode 100644 index 00000000000..1104043c1cc --- /dev/null +++ b/huawei-cloud/darklaunch/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.darklaunch.DarklaunchServerListFilter diff --git a/huawei-cloud/dashboard/pom.xml b/huawei-cloud/dashboard/pom.xml new file mode 100644 index 00000000000..015a43a240a --- /dev/null +++ b/huawei-cloud/dashboard/pom.xml @@ -0,0 +1,55 @@ + + + + + huawei-cloud + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + dashboard + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + dashboard-client + + + + + org.apache.servicecomb + metrics-core + provided + + + + diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DashboardConfiguration.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DashboardConfiguration.java new file mode 100644 index 00000000000..328b6bf6e02 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DashboardConfiguration.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class DashboardConfiguration { + @Bean + public MonitorInformationCollector scbMonitorInformationCollector() { + return new MonitorInformationCollector(); + } + + @Bean + public MonitorConstant scbMonitorConstant(Environment environment) { + return new MonitorConstant(environment); + } + + @Bean + public MonitorBootListener scbMonitorBootListener() { + return new MonitorBootListener(); + } + + @Bean + public DataFactory scbDataFactory() { + return new DataFactory(); + } + + @Bean + public MetricsMonitorDataProvider scbMetricsMonitorDataProvider() { + return new MetricsMonitorDataProvider(); + } + + @Bean + public DefaultMonitorDataPublisher scbDefaultMonitorDataPublisher() { + return new DefaultMonitorDataPublisher(); + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DataFactory.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DataFactory.java new file mode 100644 index 00000000000..4889683c131 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DataFactory.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.model.MonitorDataProvider; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.model.MonitorDataPublisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import io.netty.util.concurrent.DefaultThreadFactory; + +public class DataFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); + + private static final int CORE_SIZE = 1; + + private boolean hasStart = false; + + @Autowired + private List dataProviders; + + @Autowired + private MonitorDataPublisher publisher; + + @Autowired + private MonitorConstant monitorConstant; + + private ScheduledExecutorService executorService = null; + + + public DataFactory() { + ThreadFactory threadFactory = new DefaultThreadFactory("monitor-datafactory"); + executorService = Executors.newScheduledThreadPool(CORE_SIZE, threadFactory); + } + + public void setMonitorDataProviders(List dataProviders) { + this.dataProviders = dataProviders; + } + + public void setMonitorDataPublisher(MonitorDataPublisher publisher) { + this.publisher = publisher; + } + + void start() { + if (!hasStart) { + publisher.init(); + + StringBuilder sb = new StringBuilder(); + sb.append("Monitor data sender started. Configured data providers is {"); + for (MonitorDataProvider provider : dataProviders) { + sb.append(provider.getClass().getName()); + sb.append(","); + } + sb.append("}"); + LOGGER.info(sb.toString()); + + executorService.scheduleWithFixedDelay(() -> { + try { + sendData(); + } catch (Throwable e) { + LOGGER.error("send monitor data error.", e); + } + }, monitorConstant.getInterval(), monitorConstant.getInterval(), TimeUnit.MILLISECONDS); + hasStart = true; + } + } + + void sendData() { + for (MonitorDataProvider provider : this.dataProviders) { + if (provider.enabled()) { + this.publisher.publish(provider); + } + } + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java new file mode 100644 index 00000000000..1209d9d8532 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/DefaultMonitorDataPublisher.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.dashboard.client.DashboardAddressManager; +import org.apache.servicecomb.dashboard.client.DashboardClient; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.model.MonitorDataProvider; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.model.MonitorDataPublisher; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class DefaultMonitorDataPublisher implements MonitorDataPublisher { + private static final String SSL_KEY = "mc.consumer"; + + private DashboardClient dashboardClient; + + private MonitorConstant monitorConstant; + + private Environment environment; + + @Autowired + public void setMonitorConstant(MonitorConstant monitorConstant) { + this.monitorConstant = monitorConstant; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void init() { + DashboardAddressManager addressManager = createDashboardAddressManager(); + + RequestConfig.Builder requestBuilder = HttpTransportFactory.defaultRequestConfig(); + requestBuilder.setConnectionRequestTimeout(1000); + requestBuilder.setSocketTimeout(10000); + + HttpTransport httpTransport = createHttpTransport(addressManager, requestBuilder.build(), + environment); + + dashboardClient = new DashboardClient(addressManager, httpTransport); + } + + @SuppressWarnings("unchecked") + private DashboardAddressManager createDashboardAddressManager() { + List addresses = ConfigUtil.parseArrayValue( + environment.getProperty(MonitorConstant.SYSTEM_KEY_DASHBOARD_SERVICE, "")); + + if (addresses.isEmpty()) { + throw new IllegalStateException("dashboard address is not configured."); + } + String region = environment.getProperty("servicecomb.datacenter.region"); + String availableZone = environment.getProperty("servicecomb.datacenter.availableZone"); + + return new DashboardAddressManager(addresses, EventManager.getEventBus(), region, availableZone); + } + + private HttpTransport createHttpTransport(DashboardAddressManager addressManager, RequestConfig requestConfig, + Environment environment) { + List authHeaderProviders = SPIServiceUtils.getOrLoadSortedService(AuthHeaderProvider.class); + + if (monitorConstant.isProxyEnable()) { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(requestConfig); + HttpHost proxy = new HttpHost(monitorConstant.getProxyHost(), + monitorConstant.getProxyPort(), "http"); // now only support http proxy + httpClientBuilder.setProxy(proxy); + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials(monitorConstant.getProxyUsername(), + monitorConstant.getProxyPasswd())); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(addressManager.sslEnabled(), environment, SSL_KEY), + getRequestAuthHeaderProvider(authHeaderProviders), httpClientBuilder); + } + + return HttpTransportFactory + .createHttpTransport( + TransportUtils + .createSSLProperties(monitorConstant.sslEnabled(), environment, SSL_KEY), + getRequestAuthHeaderProvider(authHeaderProviders), requestConfig); + } + + private static RequestAuthHeaderProvider getRequestAuthHeaderProvider(List authHeaderProviders) { + return signRequest -> { + String host = signRequest != null && signRequest.getEndpoint() != null ? signRequest.getEndpoint().getHost() : ""; + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.authHeaders(host))); + return headers; + }; + } + + @Override + public void publish(MonitorDataProvider provider) { + dashboardClient.sendData(provider.getURL(), provider.getData()); + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProvider.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProvider.java new file mode 100644 index 00000000000..ed54eef341e --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProvider.java @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.dashboard.client.model.InterfaceInfo; +import org.apache.servicecomb.dashboard.client.model.MonitorData; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.metrics.PolledEvent; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.model.MonitorDataProvider; +import org.apache.servicecomb.metrics.core.publish.PublishModelFactory; +import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; +import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf; +import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroup; +import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; +import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo; +import org.apache.servicecomb.registry.sc.SCRegistration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.Subscribe; + +import io.micrometer.core.instrument.Meter; + +/** + * Monitor data based on metrics-core module. + */ +public class MetricsMonitorDataProvider implements MonitorDataProvider { + + public static final String CODE_SUCCESS = "2[0-9]{2}"; + + public static final String CODE_TIMEOUT = "408"; + + public static final String NAME_PROVIDER = "Provider."; + + public static final String NAME_CONSUMER = "Consumer."; + + private volatile List meters = null; + + private SCRegistration scRegistration; + + private Environment environment; + + private MonitorConstant monitorConstant; + + public MetricsMonitorDataProvider() { + EventManager.register(this); + } + + @Autowired + public void setSCRegistration(SCRegistration scRegistration) { + this.scRegistration = scRegistration; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setMonitorConstant(MonitorConstant monitorConstant) { + this.monitorConstant = monitorConstant; + } + + @Override + public boolean enabled() { + return environment.getProperty("servicecomb.monitor.provider.metrics.enabled", boolean.class, true); + } + + @Override + public String getURL() { + return String.format(monitorConstant.getMonitorUri(), scRegistration.getMicroserviceInstance().getServiceName()); + } + + @Override + public void extractServiceInfo(MonitorData monitorData) { + monitorData.setAppId(scRegistration.getMicroserviceInstance().getApplication()); + monitorData.setName(scRegistration.getMicroserviceInstance().getServiceName()); + monitorData.setVersion(scRegistration.getMicroserviceInstance().getVersion()); + monitorData.setServiceId(scRegistration.getMicroserviceInstance().getBackendMicroservice().getServiceId()); + monitorData.setInstance(scRegistration.getMicroserviceInstance().getBackendMicroserviceInstance().getHostName()); + monitorData.setInstanceId(scRegistration.getMicroserviceInstance().getInstanceId()); + monitorData.setEnvironment(scRegistration.getMicroserviceInstance().getEnvironment()); + } + + @Override + public void extractInterfaceInfo(MonitorData monitorData) { + if (meters == null) { + return; + } + PublishModelFactory factory = new PublishModelFactory(meters); + DefaultPublishModel model = factory.createDefaultPublishModel(); + + Map combinedResults = new HashMap<>(); + extractProviderInfo(model, combinedResults); + extractConsumerInfo(model, combinedResults); + extractEdgeInfo(model, combinedResults); + combinedResults.forEach((k, v) -> { + v.setFailureRate(v.getTotal() == 0 ? 0 : v.getFailure() / (double) v.getTotal()); + monitorData.addInterfaceInfo(v); + }); + } + + private void extractProviderInfo(DefaultPublishModel model, Map combinedResults) { + OperationPerfGroups producerPerf = model.getProducer().getOperationPerfGroups(); + if (producerPerf == null) { + return; + } + + for (Map statusMap : producerPerf.getGroups().values()) { + for (OperationPerfGroup perfGroup : statusMap.values()) { + for (int i = 0; i < perfGroup.getOperationPerfs().size(); i++) { + OperationPerf operationPerf = perfGroup.getOperationPerfs().get(i); + PerfInfo stageTotal = operationPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + String name = NAME_PROVIDER + operationPerf.getOperation(); + InterfaceInfo interfaceInfo = combinedResults.computeIfAbsent(name, + k -> { + InterfaceInfo obj = new InterfaceInfo(); + obj.setName(name); + return obj; + }); + // dashboard calculates the latest 10 seconds, different with metrics cycle. + interfaceInfo.setTotal( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().matches(CODE_SUCCESS)) { + interfaceInfo.setQps(stageTotal.getTotalRequests() / 10); + interfaceInfo.setLatency(doubleToInt(stageTotal.calcMsLatency())); + } else { + interfaceInfo.setFailure( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().equals(CODE_TIMEOUT)) { + interfaceInfo.setCountTimeout( + doubleToInt(interfaceInfo.getCountTimeout() + stageTotal.getTotalRequests())); + } + } + } + } + } + } + + private void extractEdgeInfo(DefaultPublishModel model, Map combinedResults) { + OperationPerfGroups edgePerf = model.getEdge().getOperationPerfGroups(); + if (edgePerf == null) { + return; + } + for (Map statusMap : edgePerf.getGroups().values()) { + for (OperationPerfGroup perfGroup : statusMap.values()) { + for (int i = 0; i < perfGroup.getOperationPerfs().size(); i++) { + OperationPerf operationPerf = perfGroup.getOperationPerfs().get(i); + PerfInfo stageTotal = operationPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + String name = NAME_CONSUMER + operationPerf.getOperation(); + InterfaceInfo interfaceInfo = combinedResults.computeIfAbsent(name, + k -> { + InterfaceInfo obj = new InterfaceInfo(); + obj.setName(name); + return obj; + }); + // dashboard calculates the latest 10 seconds, different with metrics cycle. + interfaceInfo.setTotal( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().matches(CODE_SUCCESS)) { + interfaceInfo.setQps(stageTotal.getTotalRequests() / 10); + interfaceInfo.setLatency(doubleToInt(stageTotal.calcMsLatency())); + } else { + interfaceInfo.setFailure( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().equals(CODE_TIMEOUT)) { + interfaceInfo.setCountTimeout( + doubleToInt( + interfaceInfo.getCountTimeout() + stageTotal.getTotalRequests())); + } + } + } + } + } + } + + private void extractConsumerInfo(DefaultPublishModel model, Map combinedResults) { + OperationPerfGroups consumerPerf = model.getConsumer().getOperationPerfGroups(); + if (consumerPerf == null) { + return; + } + for (Map statusMap : consumerPerf.getGroups().values()) { + for (OperationPerfGroup perfGroup : statusMap.values()) { + for (int i = 0; i < perfGroup.getOperationPerfs().size(); i++) { + OperationPerf operationPerf = perfGroup.getOperationPerfs().get(i); + PerfInfo stageTotal = operationPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + String name = NAME_CONSUMER + operationPerf.getOperation(); + InterfaceInfo interfaceInfo = combinedResults.computeIfAbsent(name, + k -> { + InterfaceInfo obj = new InterfaceInfo(); + obj.setName(name); + return obj; + }); + // dashboard calculates the latest 10 seconds, different with metrics cycle. + interfaceInfo.setTotal( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().matches(CODE_SUCCESS)) { + interfaceInfo.setQps(stageTotal.getTotalRequests() / 10); + interfaceInfo.setLatency(doubleToInt(stageTotal.calcMsLatency())); + } else { + interfaceInfo.setFailure( + doubleToInt(interfaceInfo.getTotal() + stageTotal.getTotalRequests())); + if (perfGroup.getStatus().equals(CODE_TIMEOUT)) { + interfaceInfo.setCountTimeout( + doubleToInt( + interfaceInfo.getCountTimeout() + stageTotal.getTotalRequests())); + } + } + } + } + } + } + + private int doubleToInt(Double d) { + return d.intValue(); + } + + @Subscribe + public void onPolledEvent(PolledEvent event) { + this.meters = event.getMeters(); + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorBootListener.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorBootListener.java new file mode 100644 index 00000000000..06dd4aa6d63 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorBootListener.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.springframework.beans.factory.annotation.Autowired; + +public class MonitorBootListener implements BootListener { + + @Autowired + private DataFactory dataFactory; + + @Autowired + private MonitorConstant monitorConstant; + + @Override + public void onBootEvent(BootEvent event) { + if (!monitorConstant.isMonitorEnabled()) { + return; + } + + if (EventType.AFTER_REGISTRY == event.getEventType()) { + dataFactory.start(); + } + } + + public DataFactory getDataFactory() { + return dataFactory; + } + + public void setDataFactory(DataFactory dataFactory) { + this.dataFactory = dataFactory; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorInformationCollector.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorInformationCollector.java new file mode 100644 index 00000000000..ef8b03a1368 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MonitorInformationCollector.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.core.bootup.BootUpInformationCollector; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.MonitorConstant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class MonitorInformationCollector implements BootUpInformationCollector { + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public String collect() { + return "monitor center: " + + ConfigUtil.parseArrayValue( + environment.getProperty(MonitorConstant.SYSTEM_KEY_DASHBOARD_SERVICE, "")); + } + + @Override + public int getOrder() { + return 100; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/TransportUtils.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/TransportUtils.java new file mode 100644 index 00000000000..d58482d23af --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/TransportUtils.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import static org.apache.servicecomb.foundation.ssl.SSLOption.DEFAULT_OPTION; + +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.springframework.core.env.Environment; + +public class TransportUtils { + public static SSLProperties createSSLProperties(boolean sslEnabled, Environment environment, String tag) { + SSLProperties sslProperties = new SSLProperties(); + sslProperties.setEnabled(sslEnabled); + + if (!sslEnabled) { + return sslProperties; + } + + SSLOption option = new SSLOption(); + option.setEngine(getStringProperty(environment, + DEFAULT_OPTION.getEngine(), + "ssl." + tag + ".engine", + "ssl.engine")); + option.setProtocols( + getStringProperty(environment, + DEFAULT_OPTION.getProtocols(), + "ssl." + tag + ".protocols", + "ssl.protocols")); + option.setCiphers( + getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + tag + ".ciphers", "ssl.ciphers")); + option.setAuthPeer( + getBooleanProperty(environment, DEFAULT_OPTION.isAuthPeer(), "ssl." + tag + ".authPeer", "ssl.authPeer")); + option.setCheckCNHost( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNHost(), + "ssl." + tag + ".checkCN.host", + "ssl.checkCN.host")); + option.setCheckCNWhite( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNWhite(), + "ssl." + tag + ".checkCN.white", + "ssl.checkCN.white")); + option.setCheckCNWhiteFile(getStringProperty(environment, + DEFAULT_OPTION.getCiphers(), + "ssl." + tag + ".checkCN.white.file", + "ssl.checkCN.white.file")); + option.setAllowRenegotiate(getBooleanProperty(environment, + DEFAULT_OPTION.isAllowRenegotiate(), + "ssl." + tag + ".allowRenegotiate", + "ssl.allowRenegotiate")); + option.setStorePath( + getStringProperty(environment, + DEFAULT_OPTION.getStorePath(), + "ssl." + tag + ".storePath", + "ssl.storePath")); + option.setClientAuth( + getStringProperty(environment, + DEFAULT_OPTION.getClientAuth(), + "ssl." + tag + ".clientAuth", + "ssl.clientAuth")); + option.setTrustStore( + getStringProperty(environment, + DEFAULT_OPTION.getTrustStore(), + "ssl." + tag + ".trustStore", + "ssl.trustStore")); + option.setTrustStoreType(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreType(), + "ssl." + tag + ".trustStoreType", + "ssl.trustStoreType")); + option.setTrustStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreValue(), + "ssl." + tag + ".trustStoreValue", + "ssl.trustStoreValue")); + option.setKeyStore( + getStringProperty(environment, DEFAULT_OPTION.getKeyStore(), "ssl." + tag + ".keyStore", "ssl.keyStore")); + option.setKeyStoreType( + getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreType(), + "ssl." + tag + ".keyStoreType", + "ssl.keyStoreType")); + option.setKeyStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreValue(), + "ssl." + tag + ".keyStoreValue", + "ssl.keyStoreValue")); + option.setCrl(getStringProperty(environment, DEFAULT_OPTION.getCrl(), "ssl." + tag + ".crl", "ssl.crl")); + option.setSslCustomClass( + getStringProperty(environment, null, "ssl." + tag + ".sslCustomClass", "ssl.sslCustomClass")); + + sslProperties.setSslOption(option); + sslProperties.setSslCustom(SSLCustom.createSSLCustom(option.getSslCustomClass())); + return sslProperties; + } + + private static String getStringProperty(Environment environment, String defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key); + } + } + return defaultValue; + } + + private static boolean getBooleanProperty(Environment environment, boolean defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key, boolean.class, false); + } + } + return defaultValue; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/CPUMonitorCalc.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/CPUMonitorCalc.java new file mode 100644 index 00000000000..6db0a859e47 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/CPUMonitorCalc.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor.data; + + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ThreadMXBean; + +public class CPUMonitorCalc { + private static final int PERCENTAGE = 100; + + private static final CPUMonitorCalc instance = new CPUMonitorCalc(); + + private final OperatingSystemMXBean osMxBean; + + private final ThreadMXBean threadMXBean; + + private long preTime = System.nanoTime(); + + private long preUsedTime = 0; + + private CPUMonitorCalc() { + osMxBean = ManagementFactory.getOperatingSystemMXBean(); + threadMXBean = ManagementFactory.getThreadMXBean(); + } + + public static CPUMonitorCalc getInstance() { + return instance; + } + + public double getProcessCpu() { + long totalTime = 0; + + for (long id : threadMXBean.getAllThreadIds()) { + totalTime += threadMXBean.getThreadCpuTime(id); + } + + long curtime = System.nanoTime(); + long usedTime = totalTime - preUsedTime; + long totalPassedTime = curtime - preTime; + preTime = curtime; + preUsedTime = totalTime; + return (((double) usedTime) / totalPassedTime / osMxBean.getAvailableProcessors()) * PERCENTAGE; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/MonitorConstant.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/MonitorConstant.java new file mode 100644 index 00000000000..19b20787843 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/MonitorConstant.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor.data; + +import org.springframework.core.env.Environment; + +public class MonitorConstant { + public static final String SYSTEM_KEY_DASHBOARD_SERVICE = "DashboardService"; + + public static final String MONITOR_URI = "servicecomb.monitor.client.serverUri"; + + public static final String PROXY_ENABLE = "servicecomb.proxy.enable"; + + public static final String PROXY_HOST = "servicecomb.proxy.host"; + + public static final String PROXY_PORT = "servicecomb.proxy.port"; + + public static final String PROXY_USERNAME = "servicecomb.proxy.username"; + + public static final String PROXY_PASSWD = "servicecomb.proxy.passwd"; + + public static final int MIN_INTERVAL_MILLISECONDS = 5000; + + public static final int DEFAULT_TIMEOUT = 5000; + + public static final int DEFAULT_INTERVAL = 10000; + + private final String DOMAIN_NAME; + + private final String CURRENT_VERSION; + + private final String VERSION_V1; + + private final String PREFIX_V2; + + private final String monitorsUri; + + private Environment environment; + + public MonitorConstant(Environment environment) { + this.environment = environment; + this.VERSION_V1 = "v1"; + this.DOMAIN_NAME = getDomainName(); + this.PREFIX_V2 = String.format("/v2/%s/csemonitor", DOMAIN_NAME); + this.CURRENT_VERSION = getApiVersion(); + + if (VERSION_V1.equals(CURRENT_VERSION)) { + monitorsUri = "/csemonitor/v1/metric?service=%s"; + } else { + monitorsUri = PREFIX_V2 + "/metric?service=%s"; + } + } + + public String getMonitorUri() { + return this.monitorsUri; + } + + public String getDomainName() { + return environment.getProperty("servicecomb.config.client.domainName", "default"); + } + + public String getApiVersion() { + return environment.getProperty("servicecomb.monitor.client.api.version", "v2"); + } + + public String getServerUrl() { + return environment.getProperty("servicecomb.monitor.client.serverUri"); + } + + public boolean sslEnabled() { + return environment.getProperty("servicecomb.monitor.client.sslEnabled", boolean.class, true); + } + + public boolean isMonitorEnabled() { + return environment.getProperty("servicecomb.monitor.client.enabled", boolean.class, false); + } + + public int getConnectionTimeout() { + return environment.getProperty("servicecomb.monitor.client.timeout", int.class, DEFAULT_TIMEOUT); + } + + public int getInterval() { + return Math.max(environment.getProperty("servicecomb.monitor.client.interval", int.class, DEFAULT_INTERVAL), + MIN_INTERVAL_MILLISECONDS); + } + + public Boolean isProxyEnable() { + return Boolean.parseBoolean(getProperty("false", PROXY_ENABLE)); + } + + public String getProxyHost() { + return getProperty("127.0.0.1", PROXY_HOST); + } + + public int getProxyPort() { + return Integer.parseInt(getProperty("8080", PROXY_PORT)); + } + + public String getProxyUsername() { + return getProperty(null, PROXY_USERNAME); + } + + public String getProxyPasswd() { + return getProperty(null, PROXY_PASSWD); + } + + private String getProperty(String defaultValue, String... keys) { + String property = null; + for (String key : keys) { + property = environment.getProperty(key); + if (property != null) { + break; + } + } + + if (property != null) { + return property; + } + return defaultValue; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataProvider.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataProvider.java new file mode 100644 index 00000000000..4f88a5a4492 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataProvider.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor.model; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.RuntimeMXBean; +import java.lang.management.ThreadMXBean; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.dashboard.client.model.MonitorData; +import org.apache.servicecomb.huaweicloud.dashboard.monitor.data.CPUMonitorCalc; + +public interface MonitorDataProvider { + boolean enabled(); + + String getURL(); + + void extractServiceInfo(MonitorData monitorData); + + default void exactProcessInfo(MonitorData monitorData) { + MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + MemoryUsage memoryHeapUsage = memoryMXBean.getHeapMemoryUsage(); + MemoryUsage memoryNonHeapUsage = memoryMXBean.getNonHeapMemoryUsage(); + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + int threadCount = threadMXBean.getThreadCount(); + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + + double cpu = operatingSystemMXBean.getSystemLoadAverage(); + monitorData.setCpu(CPUMonitorCalc.getInstance().getProcessCpu()); + monitorData.setLoadAverage(cpu); + monitorData.setThreadCount(threadCount); + monitorData.setUptime(runtimeMXBean.getUptime()); + + Map memoryInfo = new HashMap<>(); + memoryInfo.put("heapInit", memoryHeapUsage.getInit()); + memoryInfo.put("headMax", memoryHeapUsage.getMax()); + memoryInfo.put("heapCommit", memoryHeapUsage.getCommitted()); + memoryInfo.put("heapUsed", memoryHeapUsage.getUsed()); + memoryInfo.put("nonHeapInit", memoryNonHeapUsage.getInit()); + memoryInfo.put("nonHeapCommit", memoryNonHeapUsage.getCommitted()); + memoryInfo.put("nonHeapUsed", memoryNonHeapUsage.getUsed()); + monitorData.setMemory(memoryInfo); + } + + void extractInterfaceInfo(MonitorData monitorData); + + default MonitorData getData() { + MonitorData monitorData = new MonitorData(); + extractServiceInfo(monitorData); + exactProcessInfo(monitorData); + extractInterfaceInfo(monitorData); + return monitorData; + } +} diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataPublisher.java b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataPublisher.java new file mode 100644 index 00000000000..7876c2e3f64 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/model/MonitorDataPublisher.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.dashboard.monitor.model; + +public interface MonitorDataPublisher { + void publish(MonitorDataProvider provider); + + default void init() { + + } +} diff --git a/huawei-cloud/dashboard/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector b/huawei-cloud/dashboard/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector new file mode 100644 index 00000000000..008bc6a1526 --- /dev/null +++ b/huawei-cloud/dashboard/src/main/resources/META-INF/services/org.apache.servicecomb.core.bootup.BootUpInformationCollector @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.servicecomb.huaweicloud.dashboard.monitor.MonitorInformationCollector diff --git a/huawei-cloud/dashboard/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/huawei-cloud/dashboard/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..54229959fcb --- /dev/null +++ b/huawei-cloud/dashboard/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.huaweicloud.dashboard.monitor.DashboardConfiguration diff --git a/huawei-cloud/dashboard/src/test/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProviderTest.java b/huawei-cloud/dashboard/src/test/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProviderTest.java new file mode 100644 index 00000000000..c5411febdb8 --- /dev/null +++ b/huawei-cloud/dashboard/src/test/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/MetricsMonitorDataProviderTest.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.dashboard.monitor; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MetricsMonitorDataProviderTest { + @Test + public void testCodeMatch() { + Assertions.assertTrue("200".matches(MetricsMonitorDataProvider.CODE_SUCCESS)); + Assertions.assertTrue("202".matches(MetricsMonitorDataProvider.CODE_SUCCESS)); + Assertions.assertFalse("2002".matches(MetricsMonitorDataProvider.CODE_SUCCESS)); + Assertions.assertFalse("400".matches(MetricsMonitorDataProvider.CODE_SUCCESS)); + } +} diff --git a/huawei-cloud/dashboard/src/test/resources/microservice.yaml b/huawei-cloud/dashboard/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..363e3369fa0 --- /dev/null +++ b/huawei-cloud/dashboard/src/test/resources/microservice.yaml @@ -0,0 +1,42 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# spring boot configurations +server: + port: 9093 # should be same with servicecomb.rest.address to use web container + +# override common configurations in common module +servicecomb-config-order: 10 +instance_description: + environment: production + +servicecomb: + service: + environment: development + application: demo-java-chassis-dashboard + name: test-dashboard + version: 0.0.1 + registry: + address: http://127.0.0.1:30100 + instance: + watch: false + kie: + serverUri: http://127.0.0.1:30110 + customLabel: public + + rest: + address: 0.0.0.0:9097 # should be same with server.port to use web container diff --git a/huawei-cloud/pom.xml b/huawei-cloud/pom.xml new file mode 100644 index 00000000000..eb70052ed01 --- /dev/null +++ b/huawei-cloud/pom.xml @@ -0,0 +1,39 @@ + + + + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + + huawei-cloud + Java Chassis::Huawei Cloud + pom + 4.0.0 + + + servicestage + dashboard + darklaunch + + + diff --git a/huawei-cloud/servicestage/pom.xml b/huawei-cloud/servicestage/pom.xml new file mode 100644 index 00000000000..d92064951f9 --- /dev/null +++ b/huawei-cloud/servicestage/pom.xml @@ -0,0 +1,50 @@ + + + + + huawei-cloud + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + servicestage + Java Chassis::Huawei Cloud::ServiceStage + + + + org.apache.servicecomb + java-chassis-core + + + org.apache.servicecomb + registry-service-center + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + + diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/AKSKAuthHeaderProvider.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/AKSKAuthHeaderProvider.java new file mode 100644 index 00000000000..e80e867cab4 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/AKSKAuthHeaderProvider.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.auth.Cipher; +import org.apache.servicecomb.foundation.auth.DefaultCipher; +import org.apache.servicecomb.foundation.auth.ShaAKSKCipher; +import org.apache.servicecomb.foundation.bootstrap.BootStrapService; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +public class AKSKAuthHeaderProvider implements AuthHeaderProvider, BootStrapService { + private static final Logger LOGGER = LoggerFactory.getLogger(AKSKAuthHeaderProvider.class); + + private static final String CONFIG_AKSK_ENABLED = "servicecomb.credentials.akskEnabled"; + + private static final String CONFIG_ACCESS_KEY = "servicecomb.credentials.accessKey"; + + private static final String CONFIG_SECRET_KEY = "servicecomb.credentials.secretKey"; + + private static final String CONFIG_CIPHER = "servicecomb.credentials.akskCustomCipher"; + + private static final String CONFIG_PROJECT = "servicecomb.credentials.project"; + + private static final String VALUE_DEFAULT_PROJECT = "default"; + + private static final String VALUE_DEFAULT_CIPHER = "default"; + + private static final String X_SERVICE_AK = "X-Service-AK"; + + private static final String X_SERVICE_SHAAKSK = "X-Service-ShaAKSK"; + + private static final String X_SERVICE_PROJECT = "X-Service-Project"; + + private static Environment environment; + + private final Map headers = new HashMap<>(); + + private boolean loaded = false; + + public AKSKAuthHeaderProvider() { + } + + public Map authHeaders() { + if (!environment.getProperty(CONFIG_AKSK_ENABLED, boolean.class, true)) { + return Collections.emptyMap(); + } + + if (StringUtils.isEmpty(getAccessKey())) { + LOGGER.warn("ak sk auth enabled but access key is not configured, disable it at runtime. " + + "Config [{}] to false to disable it implicitly.", + CONFIG_AKSK_ENABLED); + return Collections.emptyMap(); + } + + if (!loaded) { + load(); + } + return headers; + } + + private synchronized void load() { + if (!loaded) { + headers.put(X_SERVICE_AK, getAccessKey()); + headers.put(X_SERVICE_SHAAKSK, getSecretKey()); + headers.put(X_SERVICE_PROJECT, getProject()); + loaded = true; + } + } + + private String getAccessKey() { + return environment.getProperty(CONFIG_ACCESS_KEY, ""); + } + + private String getCipher() { + return environment.getProperty(CONFIG_CIPHER, VALUE_DEFAULT_CIPHER); + } + + private String getSecretKey() { + String secretKey = environment.getProperty(CONFIG_SECRET_KEY, ""); + String decodedSecretKey = new String(findCipher().decrypt(secretKey.toCharArray())); + + // ShaAKSKCipher 不解密, 认证的时候不处理;其他算法解密为 plain,需要 encode 为 ShaAKSKCipher 去认证。 + if (ShaAKSKCipher.CIPHER_NAME.equalsIgnoreCase(getCipher())) { + return decodedSecretKey; + } else { + return sha256Encode(decodedSecretKey, getAccessKey()); + } + } + + private String getProject() { + String project = environment.getProperty(CONFIG_PROJECT, VALUE_DEFAULT_PROJECT); + if (StringUtils.isEmpty(project)) { + return project; + } + return URLEncoder.encode(project, StandardCharsets.UTF_8); + } + + private Cipher findCipher() { + if (DefaultCipher.CIPHER_NAME.equals(getCipher())) { + return DefaultCipher.getInstance(); + } + + List ciphers = SPIServiceUtils.getOrLoadSortedService(Cipher.class); + return ciphers.stream().filter(c -> c.name().equals(getCipher())).findFirst() + .orElseThrow(() -> new IllegalArgumentException("failed to find cipher named " + getCipher())); + } + + public static String sha256Encode(String key, String data) { + try { + Mac sha256HMAC = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), + "HmacSHA256"); + sha256HMAC.init(secretKey); + return Hex.encodeHexString(sha256HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + throw new IllegalArgumentException("Can not encode ak sk. Please check the value is correct.", e); + } + } + + @Override + public void startup(Environment environment) { + AKSKAuthHeaderProvider.environment = environment; + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvConfig.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvConfig.java new file mode 100644 index 00000000000..baadb927b40 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvConfig.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.servicestage; + +import static org.apache.commons.lang3.StringUtils.EMPTY; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; + +public class CasEnvConfig { + private static final String APPLICATION_ID = "CAS_APPLICATION_ID"; + + private static final String COMPONENT_NAME = "CAS_COMPONENT_NAME"; + + private static final String INSTANCE_VERSION = "CAS_INSTANCE_VERSION"; + + private static final String INSTANCE_ID = "CAS_INSTANCE_ID"; + + private static final String ENVIRONMENT_ID = "CAS_ENVIRONMENT_ID"; + + private static final String SERVICE_PROPS = "SERVICECOMB_SERVICE_PROPS"; + + private static final String INSTANCE_PROPS = "SERVICECOMB_INSTANCE_PROPS"; + + public static final CasEnvConfig INSTANCE = new CasEnvConfig(); + + private Map parseProps(String value) { + Map rs = new HashMap<>(); + if (StringUtils.isEmpty(value)) { + return rs; + } + return Arrays.stream(value.split(",")).map(v -> v.split(":")) + .filter(v -> v.length == 2) + .collect(Collectors.toMap(v -> v[0], v -> v[1])); + } + + public Map getNonEmptyInstanceProperties() { + Map map = new HashMap<>(); + + map.put(APPLICATION_ID, LegacyPropertyFactory + .getStringProperty(APPLICATION_ID, EMPTY)); + map.put(COMPONENT_NAME, LegacyPropertyFactory + .getStringProperty(COMPONENT_NAME, EMPTY)); + map.put(INSTANCE_VERSION, LegacyPropertyFactory + .getStringProperty(INSTANCE_VERSION, EMPTY)); + map.put(INSTANCE_ID, LegacyPropertyFactory + .getStringProperty(INSTANCE_ID, EMPTY)); + map.put(ENVIRONMENT_ID, LegacyPropertyFactory + .getStringProperty(ENVIRONMENT_ID, EMPTY)); + + Map instanceProps = map.entrySet().stream() + .filter(entry -> StringUtils.isNotEmpty(entry.getValue())) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + + instanceProps.putAll(parseProps(LegacyPropertyFactory + .getStringProperty(INSTANCE_PROPS, EMPTY))); + + return instanceProps; + } + + public Map getNonEmptyServiceProperties() { + return parseProps(LegacyPropertyFactory + .getStringProperty(SERVICE_PROPS, EMPTY)); + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvVariablesAdapter.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvVariablesAdapter.java new file mode 100644 index 00000000000..41cfc848df6 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/CasEnvVariablesAdapter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import java.util.Map; + +import org.apache.servicecomb.registry.RegistrationManager; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +public class CasEnvVariablesAdapter implements InitializingBean { + + private RegistrationManager registrationManager; + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Override + public void afterPropertiesSet() throws Exception { + Map extras = CasEnvConfig.INSTANCE.getNonEmptyServiceProperties(); + extras.forEach((k, v) -> this.registrationManager.addProperty(k, v)); + extras = CasEnvConfig.INSTANCE.getNonEmptyInstanceProperties(); + extras.forEach((k, v) -> this.registrationManager.addProperty(k, v)); + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java new file mode 100644 index 00000000000..007e3e56c96 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/RBACBootStrapService.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import static org.apache.servicecomb.foundation.ssl.SSLOption.DEFAULT_OPTION; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.servicecomb.foundation.auth.Cipher; +import org.apache.servicecomb.foundation.auth.DefaultCipher; +import org.apache.servicecomb.foundation.bootstrap.BootStrapService; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; +import org.apache.servicecomb.foundation.vertx.VertxConst; +import org.apache.servicecomb.http.client.auth.DefaultRequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.apache.servicecomb.registry.sc.SCClientUtils; +import org.apache.servicecomb.service.center.client.ServiceCenterAddressManager; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterRawClient; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +public class RBACBootStrapService implements BootStrapService { + private static final String RBAC_ADDRESS = "servicecomb.service.registry.address"; + + public static final String DEFAULT_REGISTRY_NAME = "default"; + + public static final String RBAC_ENABLED = "servicecomb.credentials.rbac.enabled"; + + public static final String ACCOUNT_NAME_KEY = "servicecomb.credentials.account.name"; + + public static final String PASSWORD_KEY = "servicecomb.credentials.account.password"; + + public static final String CIPHER_KEY = "servicecomb.credentials.cipher"; + + public static final String PROJECT_KEY = "servicecomb.credentials.project"; + + private static final String SSL_TAG = "sc.consumer"; + + @Override + public void startup(Environment environment) { + if (!getBooleanProperty(environment, false, RBAC_ENABLED)) { + return; + } + + ServiceCenterAddressManager addressManager = createAddressManager(environment); + addressManager.setEventBus(EventManager.getEventBus()); + SSLProperties sslProperties = createSSLProperties(environment); + sslProperties.setEnabled(addressManager.sslEnabled()); + + ServiceCenterClient serviceCenterClient = + new ServiceCenterClient(new ServiceCenterRawClient.Builder() + .setTenantName("default") + .setAddressManager(addressManager) + .setHttpTransport(createHttpTransport(environment, sslProperties)).build(), addressManager); + + Map clients = new HashMap<>(1); + clients.put(DEFAULT_REGISTRY_NAME, serviceCenterClient); + TokenCacheManager.getInstance().setServiceCenterClients(clients); + TokenCacheManager.getInstance().addTokenCache( + DEFAULT_REGISTRY_NAME, + getStringProperty(environment, null, ACCOUNT_NAME_KEY), + getStringProperty(environment, null, PASSWORD_KEY), + getCipher(getStringProperty(environment, DefaultCipher.CIPHER_NAME, CIPHER_KEY))); + } + + private static HttpTransport createHttpTransport(Environment environment, SSLProperties sslProperties) { + if (isProxyEnable(environment)) { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(HttpTransportFactory.defaultRequestConfig().build()); + HttpHost proxy = new HttpHost(getProxyHost(environment), + getProxyPort(environment), "http"); // now only support http proxy + httpClientBuilder.setProxy(proxy); + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials(getProxyUsername(environment), + getProxyPasswd(environment))); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + return HttpTransportFactory + .createHttpTransport(sslProperties, + new DefaultRequestAuthHeaderProvider(), httpClientBuilder); + } + + return HttpTransportFactory + .createHttpTransport(sslProperties, + new DefaultRequestAuthHeaderProvider(), HttpTransportFactory.defaultRequestConfig().build()); + } + + @VisibleForTesting + Cipher getCipher(String cipherName) { + if (DefaultCipher.CIPHER_NAME.equals(cipherName)) { + return DefaultCipher.getInstance(); + } + + List ciphers = SPIServiceUtils.getOrLoadSortedService(Cipher.class); + return ciphers.stream().filter(c -> c.name().equals(cipherName)).findFirst() + .orElseThrow(() -> new IllegalArgumentException("failed to find cipher named " + cipherName)); + } + + private ServiceCenterAddressManager createAddressManager(Environment environment) { + return SCClientUtils.createAddressManager(getProjectName(environment), getRBACAddressList(environment), + environment); + } + + private SSLProperties createSSLProperties(Environment environment) { + SSLProperties sslProperties = new SSLProperties(); + + SSLOption option = new SSLOption(); + option.setEngine(getStringProperty(environment, + DEFAULT_OPTION.getEngine(), + "ssl." + SSL_TAG + ".engine", + "ssl.engine")); + option.setProtocols( + getStringProperty(environment, + DEFAULT_OPTION.getProtocols(), + "ssl." + SSL_TAG + ".protocols", + "ssl.protocols")); + option.setCiphers( + getStringProperty(environment, DEFAULT_OPTION.getCiphers(), "ssl." + SSL_TAG + ".ciphers", "ssl.ciphers")); + option.setAuthPeer( + getBooleanProperty(environment, DEFAULT_OPTION.isAuthPeer(), "ssl." + SSL_TAG + ".authPeer", "ssl.authPeer")); + option.setCheckCNHost( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNHost(), + "ssl." + SSL_TAG + ".checkCN.host", + "ssl.checkCN.host")); + option.setCheckCNWhite( + getBooleanProperty(environment, + DEFAULT_OPTION.isCheckCNWhite(), + "ssl." + SSL_TAG + ".checkCN.white", + "ssl.checkCN.white")); + option.setCheckCNWhiteFile(getStringProperty(environment, + DEFAULT_OPTION.getCiphers(), + "ssl." + SSL_TAG + ".checkCN.white.file", + "ssl.checkCN.white.file")); + option.setAllowRenegotiate(getBooleanProperty(environment, + DEFAULT_OPTION.isAllowRenegotiate(), + "ssl." + SSL_TAG + ".allowRenegotiate", + "ssl.allowRenegotiate")); + option.setStorePath( + getStringProperty(environment, + DEFAULT_OPTION.getStorePath(), + "ssl." + SSL_TAG + ".storePath", + "ssl.storePath")); + option.setClientAuth( + getStringProperty(environment, + DEFAULT_OPTION.getClientAuth(), + "ssl." + SSL_TAG + ".clientAuth", + "ssl.clientAuth")); + option.setTrustStore( + getStringProperty(environment, + DEFAULT_OPTION.getTrustStore(), + "ssl." + SSL_TAG + ".trustStore", + "ssl.trustStore")); + option.setTrustStoreType(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreType(), + "ssl." + SSL_TAG + ".trustStoreType", + "ssl.trustStoreType")); + option.setTrustStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getTrustStoreValue(), + "ssl." + SSL_TAG + ".trustStoreValue", + "ssl.trustStoreValue")); + option.setKeyStore( + getStringProperty(environment, DEFAULT_OPTION.getKeyStore(), "ssl." + SSL_TAG + ".keyStore", "ssl.keyStore")); + option.setKeyStoreType( + getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreType(), + "ssl." + SSL_TAG + ".keyStoreType", + "ssl.keyStoreType")); + option.setKeyStoreValue(getStringProperty(environment, + DEFAULT_OPTION.getKeyStoreValue(), + "ssl." + SSL_TAG + ".keyStoreValue", + "ssl.keyStoreValue")); + option.setCrl(getStringProperty(environment, DEFAULT_OPTION.getCrl(), "ssl." + SSL_TAG + ".crl", "ssl.crl")); + option.setSslCustomClass( + getStringProperty(environment, null, "ssl." + SSL_TAG + ".sslCustomClass", "ssl.sslCustomClass")); + + sslProperties.setSslOption(option); + sslProperties.setSslCustom(SSLCustom.createSSLCustom(option.getSslCustomClass())); + return sslProperties; + } + + private String getStringProperty(Environment environment, String defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return environment.getProperty(key); + } + } + return defaultValue; + } + + private boolean getBooleanProperty(Environment environment, boolean defaultValue, String... keys) { + for (String key : keys) { + if (environment.getProperty(key) != null) { + return Boolean.parseBoolean(environment.getProperty(key)); + } + } + return defaultValue; + } + + private String getProjectName(Environment environment) { + return getStringProperty(environment, "default", PROJECT_KEY); + } + + private List getRBACAddressList(Environment environment) { + String address = environment.getProperty(RBAC_ADDRESS, "http://127.0.0.1:30100"); + return Arrays.asList(address.split(",")); + } + + + public static Boolean isProxyEnable(Environment environment) { + return environment.getProperty(VertxConst.PROXY_ENABLE, boolean.class, false); + } + + public static String getProxyHost(Environment environment) { + return environment.getProperty(VertxConst.PROXY_HOST, "127.0.0.1"); + } + + public static int getProxyPort(Environment environment) { + return environment.getProperty(VertxConst.PROXY_PORT, int.class, 8080); + } + + public static String getProxyUsername(Environment environment) { + return environment.getProperty(VertxConst.PROXY_USERNAME); + } + + public static String getProxyPasswd(Environment environment) { + return environment.getProperty(VertxConst.PROXY_PASSWD); + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/ServiceStageConfiguration.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/ServiceStageConfiguration.java new file mode 100644 index 00000000000..5a369b70bf9 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/ServiceStageConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.servicestage; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ServiceStageConfiguration { + @Bean + public CasEnvVariablesAdapter casEnvVariablesAdapter() { + return new CasEnvVariablesAdapter(); + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java new file mode 100644 index 00000000000..19bd550602b --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenAuthHeaderProvider.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; + +public class TokenAuthHeaderProvider implements AuthHeaderProvider { + @Override + public Map authHeaders(String host) { + String token = TokenCacheManager.getInstance().getToken(host); + if (StringUtils.isEmpty(token)) { + return new HashMap<>(); + } + + HashMap header = new HashMap<>(); + header.put("Authorization", "Bearer " + token); + return Collections.unmodifiableMap(header); + } +} diff --git a/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java new file mode 100644 index 00000000000..b4510bb4238 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/java/org/apache/servicecomb/huaweicloud/servicestage/TokenCacheManager.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.auth.Cipher; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.http.client.event.OperationEvents; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.model.RbacTokenRequest; +import org.apache.servicecomb.service.center.client.model.RbacTokenResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.eventbus.Subscribe; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import jakarta.ws.rs.core.Response.Status; + +public final class TokenCacheManager { + private static final Logger LOGGER = LoggerFactory.getLogger(TokenCacheManager.class); + + // special token used for special conditions + // e.g. un-authorized: will query token after token expired period + // e.g. not found: will query token after token expired period + public static final String INVALID_TOKEN = ""; + + private static final TokenCacheManager INSTANCE = new TokenCacheManager(); + + private Map serviceCenterClients; + + private TokenCache tokenCache; + + public static TokenCacheManager getInstance() { + return INSTANCE; + } + + private TokenCacheManager() { + } + + public void setServiceCenterClients(Map serviceCenterClients) { + this.serviceCenterClients = serviceCenterClients; + } + + public void addTokenCache(String registryName, String accountName, String password, Cipher cipher) { + tokenCache = new TokenCache(registryName, accountName, password, cipher); + } + + public String getToken(String host) { + if (tokenCache == null) { + return null; + } + return tokenCache.getToken(host); + } + + public class TokenCache { + private static final long TOKEN_REFRESH_TIME_IN_SECONDS = 20 * 60 * 1000; + + private final String registryName; + + private final String accountName; + + private final String password; + + private ExecutorService executorService; + + private LoadingCache cache; + + private final Cipher cipher; + + public TokenCache(String registryName, String accountName, String password, + Cipher cipher) { + this.registryName = registryName; + this.accountName = accountName; + this.password = password; + this.cipher = cipher; + + if (enabled()) { + executorService = Executors.newFixedThreadPool(1, t -> new Thread(t, "rbac-executor-" + this.registryName) { + @Override + public void run() { + try { + super.run(); + } catch (Throwable e) { + LOGGER.error("", e); + } + } + }); + cache = CacheBuilder.newBuilder() + .maximumSize(10) + .refreshAfterWrite(refreshTime(), TimeUnit.MILLISECONDS) + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return createHeaders(key); + } + + @Override + public ListenableFuture reload(String key, String oldValue) throws Exception { + return Futures.submit(() -> createHeaders(key), executorService); + } + }); + EventManager.getEventBus().register(this); + } + } + + @Subscribe + public void onNotPermittedEvent(OperationEvents.UnAuthorizedOperationEvent event) { + LOGGER.warn("address {} unAuthorized, refresh cache token!", event.getAddress()); + cache.refresh(getHostByAddress(event.getAddress())); + } + + private String getHostByAddress(String address) { + try { + URI uri = URI.create(address); + return uri.getHost(); + } catch (Exception e) { + LOGGER.error("get host by address [{}] error!", address, e); + return registryName; + } + } + + private String createHeaders(String host) { + LOGGER.info("start to create RBAC headers for host: {}", host); + + ServiceCenterClient serviceCenterClient = serviceCenterClients.get(this.registryName); + + RbacTokenRequest request = new RbacTokenRequest(); + request.setName(accountName); + request.setPassword(new String(cipher.decrypt(password.toCharArray()))); + + RbacTokenResponse rbacTokenResponse = serviceCenterClient.queryToken(request, host); + + if (Status.UNAUTHORIZED.getStatusCode() == rbacTokenResponse.getStatusCode() + || Status.FORBIDDEN.getStatusCode() == rbacTokenResponse.getStatusCode()) { + // password wrong, do not try anymore + LOGGER.warn("username or password may be wrong, stop trying to query tokens."); + return INVALID_TOKEN; + } + if (Status.NOT_FOUND.getStatusCode() == rbacTokenResponse.getStatusCode()) { + // service center not support, do not try + LOGGER.warn("service center do not support RBAC token, you should not config account info"); + return INVALID_TOKEN; + } + if (Status.INTERNAL_SERVER_ERROR.getStatusCode() == rbacTokenResponse.getStatusCode()) { + // return null for server_error, so the token information can be re-fetched on the next call. + // It will prompt 'CacheLoader returned null for key xxx' + LOGGER.warn("service center query RBAC token error!"); + return null; + } + + LOGGER.info("refresh host [{}] token successfully {}", host, rbacTokenResponse.getStatusCode()); + return rbacTokenResponse.getToken(); + } + + protected long refreshTime() { + return TOKEN_REFRESH_TIME_IN_SECONDS; + } + + public String getToken(String host) { + if (!enabled()) { + return null; + } + String address = host; + if (StringUtils.isEmpty(address)) { + address = registryName; + } + try { + return cache.get(address); + } catch (Exception e) { + LOGGER.error("failed to create token", e); + return null; + } + } + + private boolean enabled() { + return !StringUtils.isEmpty(this.accountName) + && !StringUtils.isEmpty(this.password); + } + } +} diff --git a/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider new file mode 100644 index 00000000000..a78d2c2e33b --- /dev/null +++ b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.huaweicloud.servicestage.AKSKAuthHeaderProvider +org.apache.servicecomb.huaweicloud.servicestage.TokenAuthHeaderProvider diff --git a/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.Cipher b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.Cipher new file mode 100644 index 00000000000..8d0efa25aef --- /dev/null +++ b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.Cipher @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.foundation.auth.ShaAKSKCipher diff --git a/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.bootstrap.BootStrapService b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.bootstrap.BootStrapService new file mode 100644 index 00000000000..90c339ba065 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.bootstrap.BootStrapService @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.huaweicloud.servicestage.RBACBootStrapService +org.apache.servicecomb.huaweicloud.servicestage.AKSKAuthHeaderProvider diff --git a/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.adapter.EnvAdapter b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.adapter.EnvAdapter new file mode 100644 index 00000000000..2aa5b486121 --- /dev/null +++ b/huawei-cloud/servicestage/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.adapter.EnvAdapter @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.huaweicloud.servicestage.CasEnvVariablesAdapter diff --git a/huawei-cloud/servicestage/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/huawei-cloud/servicestage/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..04b38f05d6f --- /dev/null +++ b/huawei-cloud/servicestage/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.huaweicloud.servicestage.ServiceStageConfiguration diff --git a/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestAKSKAuthHeaderProvider.java b/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestAKSKAuthHeaderProvider.java new file mode 100644 index 00000000000..2b82672c77c --- /dev/null +++ b/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestAKSKAuthHeaderProvider.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.huaweicloud.servicestage; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +public class TestAKSKAuthHeaderProvider { + @Test + public void test_project_name_properly_encoded_en() { + Environment environment = Mockito.mock(Environment.class); + Mockito.when(environment.getProperty("servicecomb.credentials.akskEnabled", + boolean.class, true)).thenReturn(true); + Mockito.when(environment.getProperty("servicecomb.credentials.project", + "default")).thenReturn("hello"); + Mockito.when(environment.getProperty("servicecomb.credentials.accessKey", + "")).thenReturn("access key"); + Mockito.when(environment.getProperty("servicecomb.credentials.secretKey", + "")).thenReturn("secret key"); + Mockito.when(environment.getProperty("servicecomb.credentials.akskCustomCipher", + "default")).thenReturn("default"); + + AKSKAuthHeaderProvider provider = new AKSKAuthHeaderProvider(); + provider.startup(environment); + Assertions.assertEquals("hello", provider.authHeaders().get("X-Service-Project")); + } + + @Test + public void test_project_name_properly_encoded_cn() { + Environment environment = Mockito.mock(Environment.class); + Mockito.when(environment.getProperty("servicecomb.credentials.akskEnabled", + boolean.class, true)).thenReturn(true); + Mockito.when(environment.getProperty("servicecomb.credentials.project", + "default")).thenReturn("测试"); + Mockito.when(environment.getProperty("servicecomb.credentials.accessKey", + "")).thenReturn("access key"); + Mockito.when(environment.getProperty("servicecomb.credentials.secretKey", + "")).thenReturn("secret key"); + Mockito.when(environment.getProperty("servicecomb.credentials.akskCustomCipher", + "default")).thenReturn("default"); + AKSKAuthHeaderProvider provider = new AKSKAuthHeaderProvider(); + provider.startup(environment); + Assertions.assertEquals("%E6%B5%8B%E8%AF%95", provider.authHeaders().get("X-Service-Project")); + } +} diff --git a/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestEnvVariablesAdapter.java b/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestEnvVariablesAdapter.java new file mode 100644 index 00000000000..5fc8bea722f --- /dev/null +++ b/huawei-cloud/servicestage/src/test/java/org/apache/servicecomb/huaweicloud/servicestage/TestEnvVariablesAdapter.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.huaweicloud.servicestage; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class TestEnvVariablesAdapter { + + @BeforeAll + public static void init() { + System.setProperty("CAS_APPLICATION_ID", "application-id"); + System.setProperty("CAS_ENVIRONMENT_ID", "env-id"); + System.setProperty("SERVICECOMB_SERVICE_PROPS", "component:ConsumerService,other:A"); + System.setProperty("SERVICECOMB_INSTANCE_PROPS", "route:gray"); + } + + @Test + public void testProcessInstance() { + // TODO: set CAS properties for service center + CasEnvVariablesAdapter adapter = new CasEnvVariablesAdapter(); +// MicroserviceInstance instance = new MicroserviceInstance(); +// adapter.beforeRegisterInstance(instance); +// +// Assertions.assertEquals(3, instance.getProperties().size()); +// Assertions.assertEquals("application-id", instance.getProperties().get("CAS_APPLICATION_ID")); +// Assertions.assertEquals("env-id", instance.getProperties().get("CAS_ENVIRONMENT_ID")); +// Assertions.assertEquals("gray", instance.getProperties().get("route")); +// +// Microservice microservice = new Microservice(); +// adapter.beforeRegisterService(microservice); +// Assertions.assertEquals(2, microservice.getProperties().size()); +// Assertions.assertEquals("ConsumerService", microservice.getProperties().get("component")); +// Assertions.assertEquals("A", microservice.getProperties().get("other")); + } + + @AfterAll + public static void destroy() { + System.getProperties().remove("CAS_APPLICATION_ID"); + System.getProperties().remove("CAS_ENVIRONMENT_ID"); + System.getProperties().remove("SERVICECOMB_SERVICE_PROPS"); + System.getProperties().remove("SERVICECOMB_INSTANCE_PROPS"); + } +} diff --git a/huawei-cloud/servicestage/src/test/resources/log4j2.xml b/huawei-cloud/servicestage/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/huawei-cloud/servicestage/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/integration-tests/dynamic-config-tests/pom.xml b/integration-tests/dynamic-config-tests/pom.xml deleted file mode 100644 index 7a1b45eb3ee..00000000000 --- a/integration-tests/dynamic-config-tests/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - dynamic-config-tests - Java Chassis::Integration Tests::Dynamic Configuration - - - org.apache.servicecomb - foundation-common - - - com.netflix.archaius - archaius-core - - - org.apache.servicecomb - config-apollo - - - org.slf4j - slf4j-log4j12 - - - - \ No newline at end of file diff --git a/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/DynamicConfigurationIT.java b/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/DynamicConfigurationIT.java deleted file mode 100644 index fbe557b120e..00000000000 --- a/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/DynamicConfigurationIT.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.dynamicconfig.test; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.netflix.config.DynamicPropertyFactory; - -import io.vertx.core.Vertx; - -public class DynamicConfigurationIT { - private static Vertx vertx = null; - - @BeforeClass - public static void setUp() throws Exception { - vertx = Vertx.vertx(); - vertx.deployVerticle(new SimApolloServer()); - - Log4jUtils.init(); - BeanUtils.init(); - } - - @AfterClass - public static void tearDown() { - vertx.close(); - } - - - @Test - public void testDynamicConfiguration() { - Assert.assertEquals(6666, DynamicPropertyFactory.getInstance().getIntProperty("timeout", 0).get()); - } -} diff --git a/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/SimApolloServer.java b/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/SimApolloServer.java deleted file mode 100644 index fac81834a16..00000000000 --- a/integration-tests/dynamic-config-tests/src/test/java/org/apache/dynamicconfig/test/SimApolloServer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.dynamicconfig.test; - -import io.vertx.core.AbstractVerticle; - -public class SimApolloServer extends AbstractVerticle { - public void start() { - String response = "{\n" - + " \"appId\": \"test\",\n" - + " \"clusterName\": \"default\",\n" - + " \"namespaceName\": \"application\",\n" - + " \"name\": \"20180703151728-release\",\n" - + " \"configurations\": {\n" - + " \"timeout\": \"6666\"\n" - + " },\n" - + " \"comment\": \"\",\n" - + " \"dataChangeCreatedBy\": \"apollo\",\n" - + " \"dataChangeLastModifiedBy\": \"apollo\",\n" - + " \"dataChangeCreatedTime\": \"2018-07-03T15:17:32.000+0800\",\n" - + " \"dataChangeLastModifiedTime\": \"2018-07-03T15:17:32.000+0800\"\n" - + "}"; - - vertx.createHttpServer().requestHandler(req -> { - req.response() - .putHeader("content-type", "application/json") - .end(response); - }).listen(23334); - } -} \ No newline at end of file diff --git a/integration-tests/dynamic-config-tests/src/test/resources/config/log4j.z.properties b/integration-tests/dynamic-config-tests/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 5520c4668a2..00000000000 --- a/integration-tests/dynamic-config-tests/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout \ No newline at end of file diff --git a/integration-tests/dynamic-config-tests/src/test/resources/microservice.yaml b/integration-tests/dynamic-config-tests/src/test/resources/microservice.yaml deleted file mode 100644 index b7b9e62fe10..00000000000 --- a/integration-tests/dynamic-config-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: dynamic-config-test -service_description: - name: apollo-test - version: 1.0.1 - -apollo: - config: - serverUri: http://localhost:23334 - serviceName: SampleApp - env: DEV - clusters: default - namespace: application - token: testtoken - refreshInterval: 2 - diff --git a/integration-tests/it-common-service/enable-it-jar b/integration-tests/it-common-service/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-common-service/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-common-service/pom.xml b/integration-tests/it-common-service/pom.xml deleted file mode 100644 index 31fa4a4376a..00000000000 --- a/integration-tests/it-common-service/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - it-common-service - Java Chassis::IT::CommonService - - - - org.apache.servicecomb.tests - it-common - - - - - org.apache.servicecomb.it.CommonServiceMain - - \ No newline at end of file diff --git a/integration-tests/it-common-service/src/main/java/org/apache/servicecomb/it/CommonServiceMain.java b/integration-tests/it-common-service/src/main/java/org/apache/servicecomb/it/CommonServiceMain.java deleted file mode 100644 index 7dfb1473882..00000000000 --- a/integration-tests/it-common-service/src/main/java/org/apache/servicecomb/it/CommonServiceMain.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -public class CommonServiceMain { - public static void main(String[] args) { - ITMain.main(args); - } -} diff --git a/integration-tests/it-common/enable-it-jar b/integration-tests/it-common/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-common/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-common/pom.xml b/integration-tests/it-common/pom.xml deleted file mode 100644 index 177e222268f..00000000000 --- a/integration-tests/it-common/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - it-common - Java Chassis::IT::Common - - - - ch.qos.logback - logback-classic - - - \ No newline at end of file diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/CommandReceiver.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/CommandReceiver.java deleted file mode 100644 index 55d9e666740..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/CommandReceiver.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.TextNode; - -public class CommandReceiver { - private static final Logger LOGGER = LoggerFactory.getLogger(CommandReceiver.class); - - public CommandReceiver() { - Thread thread = new Thread(this::run, "it-command-receiver"); - thread.setDaemon(true); - thread.start(); - } - - public void run() { - try { - doRun(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - private void doRun() throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - String line; - while ((line = reader.readLine()) != null) { - try { - JsonNode cmd = JsonUtils.OBJ_MAPPER.readTree(line); - dispatchCommand(cmd); - } catch (Throwable e) { - LOGGER.error("Failed to execute command: {}", line, e); - } - } - reader.close(); - } - - private void dispatchCommand(JsonNode cmd) { - LOGGER.info("dispatch command: {}", cmd); - if (TextNode.class.isInstance(cmd)) { - onStringCommand(cmd.asText()); - return; - } - - throw new UnsupportedOperationException(cmd.toString()); - } - - protected void onStringCommand(String command) { - switch (command) { - case "ms-stop": - stop(); - break; - default: - throw new UnsupportedOperationException(command); - } - } - - protected void stop() { - new Thread(() -> { - for (; ; ) { - SCBEngine.getInstance().destroy(); - if (ITBootListener.isDone() && SCBStatus.DOWN.equals(SCBEngine.getInstance().getStatus())) { - LOGGER.info("succeed to close " + RegistryUtils.getMicroservice().getServiceName()); - break; - } - ITUtils.forceWait(TimeUnit.SECONDS, 1); - } - - //make sure kill for servlet - System.exit(0); - - }, "it-stop").start(); - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITBootListener.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITBootListener.java deleted file mode 100644 index 185fb80d4bd..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITBootListener.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.URI; -import java.net.URISyntaxException; - -import org.apache.http.client.utils.URIBuilder; -import org.apache.servicecomb.core.BootListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.DynamicPropertyFactory; - -@Component -public class ITBootListener implements BootListener { - private static final Logger LOGGER = LoggerFactory.getLogger(ITBootListener.class); - - private static boolean done; - - public static boolean isDone() { - return done; - } - - @Override - public void onBootEvent(BootEvent event) { - if (!EventType.BEFORE_HANDLER.equals(event.getEventType())) { - return; - } - - selectPort("servicecomb.rest.address"); - selectPort("servicecomb.highway.address"); - done = true; - } - - protected void selectPort(String cfgKey) { - String endpoint = DynamicPropertyFactory.getInstance().getStringProperty(cfgKey, null).get(); - if (endpoint == null) { - return; - } - - URI uri = URI.create("http://" + endpoint); - if (uri.getPort() == 0) { - int port = getRandomPort(); - try { - ConcurrentCompositeConfiguration config = (ConcurrentCompositeConfiguration) DynamicPropertyFactory - .getBackingConfigurationSource(); - endpoint = new URIBuilder("http://" + endpoint).setPort(port).build().toString().substring(7); - config.getConfiguration(0).setProperty(cfgKey, endpoint); - LOGGER.info("change {} to {}.", cfgKey, endpoint); - } catch (URISyntaxException e) { - throw new IllegalStateException("Failed to build endpoint.", e); - } - } - } - - protected int getRandomPort() { - try (ServerSocket serverSocket = new ServerSocket(0)) { - return serverSocket.getLocalPort(); - } catch (IOException e) { - throw new IllegalStateException("Failed to get random port.", e); - } - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITMain.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITMain.java deleted file mode 100644 index 7be9a4638bb..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITMain.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -public class ITMain { - public static void main(String[] args) { - new CommandReceiver(); - - BeanUtils.init(); - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java deleted file mode 100644 index ada728b3c32..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import java.util.Comparator; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.reflect.MethodUtils; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.task.event.PeriodicPullEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class ITUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(ITUtils.class); - - private ITUtils() { - } - - public static void forceWait(TimeUnit timeUnit, long timeout) { - try { - timeUnit.sleep(timeout); - } catch (InterruptedException e) { - // eat the exception - } - } - - public static void waitBootFinished() { - for (; ; ) { - if (SCBEngine.getInstance().getStatus().equals(SCBStatus.UP)) { - return; - } - - forceWait(TimeUnit.MILLISECONDS, 100); - } - } - - public static Map waitMicroserviceReadyAndLimit(String appId, String microserviceName, - String strVersionRule, int minInstanceCount) { - Map instances = waitMicroserviceReady(appId, - microserviceName, - strVersionRule, - minInstanceCount); - return instances.values() - .stream() - .sorted(Comparator.comparing(MicroserviceInstance::getInstanceId)) - .limit(minInstanceCount) - .collect(Collectors.toMap(MicroserviceInstance::getInstanceId, Function.identity())); - } - - public static Map waitMicroserviceReady(String appId, String microserviceName, - String strVersionRule, int minInstanceCount) { - LOGGER.info("waiting for microservice online. appId={}, name={}, minInstanceCount={}", - appId, - microserviceName, - minInstanceCount); - - Map instances; - for (;;) { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry() - .getAppManager() - .getOrCreateMicroserviceVersionRule(appId, microserviceName, strVersionRule); - instances = microserviceVersionRule.getInstances(); - if (instances.size() >= minInstanceCount) { - break; - } - - LOGGER.info( - "waiting for microservice online. appId={}, name={}, expect minInstanceCount={}, real instanceCount={}.", - appId, - microserviceName, - minInstanceCount, - instances.size()); - // pull at once - EventManager.getEventBus().post(new PeriodicPullEvent()); - forceWait(TimeUnit.SECONDS, 1); - } - - LOGGER.info("microservice already online. appId={}, name={}, instanceCount={}", - appId, - microserviceName, - minInstanceCount); - return instances; - } - - public static void invokeExactStaticMethod(final Class[] classes, final String methodName, Object... args) { - for (Class cls : classes) { - invokeExactStaticMethod(cls, methodName, args); - } - } - - @SuppressWarnings("unchecked") - public static T invokeExactStaticMethod(final Class cls, final String methodName, Object... args) { - try { - return (T) MethodUtils.invokeExactStaticMethod(cls, methodName, args); - } catch (Throwable e) { - throw new IllegalStateException(String.format("Failed to invoke, class=%s, method=%s", cls.getName(), methodName), - e); - } - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java deleted file mode 100644 index 1dcebb00534..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/CommonModel.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class CommonModel { - private int iValue; - - public int getiValue() { - return iValue; - } - - public void setiValue(int iValue) { - this.iValue = iValue; - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/Generic.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/Generic.java deleted file mode 100644 index 085b2d1da68..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/Generic.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class Generic { - public T value; -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestBaseModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestBaseModel.java deleted file mode 100644 index 30e16314210..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestBaseModel.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class RequestBaseModel { - private int type; - - private Integer integerType; - - private String message; - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public Integer getIntegerType() { - return integerType; - } - - public void setIntegerType(Integer integerType) { - this.integerType = integerType; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestModel.java deleted file mode 100644 index 945a87f816b..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/RequestModel.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class RequestModel extends RequestBaseModel { - private int catalog; - - private Integer integerCatalog; - - private String extendedMessage; - - public int getCatalog() { - return catalog; - } - - public void setCatalog(int catalog) { - this.catalog = catalog; - } - - public Integer getIntegerCatalog() { - return integerCatalog; - } - - public void setIntegerCatalog(Integer integerCatalog) { - this.integerCatalog = integerCatalog; - } - - public String getExtendedMessage() { - return extendedMessage; - } - - public void setExtendedMessage(String extendedMessage) { - this.extendedMessage = extendedMessage; - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseBaseModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseBaseModel.java deleted file mode 100644 index e045ef7c30e..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseBaseModel.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class ResponseBaseModel { - private int type; - - private Integer integerType; - - private String message; - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public Integer getIntegerType() { - return integerType; - } - - public void setIntegerType(Integer integerType) { - this.integerType = integerType; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseModel.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseModel.java deleted file mode 100644 index e816aa6047b..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/ResponseModel.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class ResponseModel extends ResponseBaseModel { - private int catalog; - - private Integer integerCatalog; - - private String extendedMessage; - - public int getCatalog() { - return catalog; - } - - public void setCatalog(int catalog) { - this.catalog = catalog; - } - - public Integer getIntegerCatalog() { - return integerCatalog; - } - - public void setIntegerCatalog(Integer integerCatalog) { - this.integerCatalog = integerCatalog; - } - - public String getExtendedMessage() { - return extendedMessage; - } - - public void setExtendedMessage(String extendedMessage) { - this.extendedMessage = extendedMessage; - } -} diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/User.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/User.java deleted file mode 100644 index 3f87a94731f..00000000000 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/schema/User.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.foundation.common.utils.JsonUtils; - -import com.fasterxml.jackson.core.JsonProcessingException; - -public class User { - private String name = "nameA"; - - private int age = 100; - - private int index; - - private String[] names; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String[] getNames() { - return names; - } - - public void setNames(String[] names) { - this.names = names; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @Override - public String toString() { - return "User [name=" + name + ", age=" + age + ", index=" + index + "]"; - } - - public String jsonString() { - try { - return JsonUtils.writeValueAsString(this); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/integration-tests/it-common/src/main/resources/logback.xml b/integration-tests/it-common/src/main/resources/logback.xml deleted file mode 100644 index d753514a002..00000000000 --- a/integration-tests/it-common/src/main/resources/logback.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - %d [%level] [%thread] - %msg (%F:%L\)%n - - - - - - \ No newline at end of file diff --git a/integration-tests/it-common/src/main/resources/microservice.yaml b/integration-tests/it-common/src/main/resources/microservice.yaml deleted file mode 100644 index 43df9e29764..00000000000 --- a/integration-tests/it-common/src/main/resources/microservice.yaml +++ /dev/null @@ -1,51 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -servicecomb-config-order: -10000 - -APPLICATION_ID: integration-test -service_description: - name: $invalid-name-must-be-overridden - version: 1.0.0 - environment: development -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - instance: - healthCheck: - interval: 5 - times: 3 - request: - # 10 minute - timeout: 600000 - rest: - address: 0.0.0.0:0 - server: - thread-count: 8 - client: - thread-count: 8 - connection: - maxPoolSize: 30 - highway: - address: 0.0.0.0:0 - server: - thread-count: 8 - client: - thread-count: 8 - uploads: - directory: target \ No newline at end of file diff --git a/integration-tests/it-consumer/pom.xml b/integration-tests/it-consumer/pom.xml deleted file mode 100644 index 730aff8bb0c..00000000000 --- a/integration-tests/it-consumer/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - it-consumer - Java Chassis::IT::Consumer - - - - org.apache.servicecomb.tests - it-common - - - com.squareup.okhttp3 - okhttp - compile - - - - org.apache.maven - maven-model - 3.3.9 - - - - - org.apache.servicecomb.it.ConsumerMain - - \ No newline at end of file diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java deleted file mode 100644 index 75f89919541..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.it.deploy.Deploys; -import org.apache.servicecomb.it.deploy.MicroserviceDeploy; -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.apache.servicecomb.it.schema.TestApiOperation; -import org.apache.servicecomb.it.testcase.TestAcceptType; -import org.apache.servicecomb.it.testcase.TestAnnotatedAttribute; -import org.apache.servicecomb.it.testcase.TestApiParam; -import org.apache.servicecomb.it.testcase.TestChangeTransport; -import org.apache.servicecomb.it.testcase.TestDataTypePrimitive; -import org.apache.servicecomb.it.testcase.TestDefaultJsonValueJaxrsSchema; -import org.apache.servicecomb.it.testcase.TestDefaultValue; -import org.apache.servicecomb.it.testcase.TestDownload; -import org.apache.servicecomb.it.testcase.TestDownloadSlowStreamEdge; -import org.apache.servicecomb.it.testcase.TestExceptionConvertEdge; -import org.apache.servicecomb.it.testcase.TestGenericEdge; -import org.apache.servicecomb.it.testcase.TestIgnoreMethod; -import org.apache.servicecomb.it.testcase.TestIgnoreStaticMethod; -import org.apache.servicecomb.it.testcase.TestParamCodec; -import org.apache.servicecomb.it.testcase.TestParamCodecEdge; -import org.apache.servicecomb.it.testcase.TestRequestBodySpringMvcSchema; -import org.apache.servicecomb.it.testcase.TestRestController; -import org.apache.servicecomb.it.testcase.TestRestServerConfig; -import org.apache.servicecomb.it.testcase.TestRestServerConfigEdge; -import org.apache.servicecomb.it.testcase.TestTrace; -import org.apache.servicecomb.it.testcase.TestTraceEdge; -import org.apache.servicecomb.it.testcase.base.TestGeneric; -import org.apache.servicecomb.it.testcase.thirdparty.Test3rdPartyInvocation; - -public class ConsumerMain { - private static ResultPrinter resultPrinter = new ResultPrinter(); - - private static Deploys deploys = new Deploys(); - - public static boolean autoExit = true; - - public static void main(String[] args) throws Throwable { - deploys.init(); - deploys.getServiceCenter().ensureReady(); - - BeanUtils.init(); - ITUtils.waitBootFinished(); - - try { - run(); - } finally { - SCBEngine.getInstance().destroy(); - deploys.getServiceCenter().stop(); - } - - resultPrinter.print(); - - if (autoExit) { - System.exit(0); - } - } - - protected static void run() throws Throwable { - // deploy edge/zuul - // if not ready, will start a new instance and wait for ready - deploys.getEdge().ensureReady(); - // deploys.getZuul().ensureReady(zuul); - - try { - ITJUnitUtils.run(TestIgnoreStaticMethod.class); - ITJUnitUtils.run(TestIgnoreMethod.class); - ITJUnitUtils.run(TestApiParam.class); - ITJUnitUtils.run(TestApiOperation.class); - - testOneProducer(deploys.getBaseProducer(), ConsumerMain::testStandalone); - testOneProducer(deploys.getBaseHttp2Producer(), ConsumerMain::testH2Standalone); - testOneProducer(deploys.getBaseHttp2CProducer(), ConsumerMain::testH2CStandalone); - - testOneProducer(deploys.getSpringBoot2StandaloneProducer(), ConsumerMain::testSpringBoot2Standalone); - testOneProducer(deploys.getSpringBoot2ServletProducer(), ConsumerMain::testSpringBoot2Servlet); - } finally { - deploys.getEdge().stop(); - } - } - - private static void runShareTestCases() throws Throwable { - ITJUnitUtils.runWithHighwayAndRest(TestChangeTransport.class); - ITJUnitUtils.runWithHighwayAndRest(TestDataTypePrimitive.class); - ITJUnitUtils.runWithHighwayAndRest(TestAnnotatedAttribute.class); - - // only rest support default value feature - ITJUnitUtils.runWithRest(TestDefaultValue.class); - ITJUnitUtils.runWithRest(TestAcceptType.class); - - ITJUnitUtils.runWithRest(TestDownload.class); - ITJUnitUtils.runWithHighwayAndRest(TestExceptionConvertEdge.class); - - ITJUnitUtils.runWithHighwayAndRest(TestTrace.class); - ITJUnitUtils.run(TestTraceEdge.class); - - ITJUnitUtils.runWithHighwayAndRest(TestParamCodec.class); - ITJUnitUtils.run(TestParamCodecEdge.class); - - //generic - ITJUnitUtils.runWithRest(TestGeneric.class); - ITJUnitUtils.run(TestGenericEdge.class); - - ITJUnitUtils.run(TestRequestBodySpringMvcSchema.class); - ITJUnitUtils.run(TestDefaultJsonValueJaxrsSchema.class); - ITJUnitUtils.run(TestRestController.class); - } - - interface ITTask { - void run() throws Throwable; - } - - private static void testOneProducer(MicroserviceDeploy microserviceDeploy, ITTask task) throws Throwable { - microserviceDeploy.ensureReady(); - ITJUnitUtils.addProducer(microserviceDeploy.getMicroserviceDeployDefinition().getMicroserviceName()); - - try { - task.run(); - } finally { - ITJUnitUtils.popProducer(); - microserviceDeploy.stop(); - } - } - - private static void testStandalone() throws Throwable { - runShareTestCases(); - - // currently not support update 3rd url, so only test once - ITJUnitUtils.run(Test3rdPartyInvocation.class); - - // about url len, different deploy have different url len, so only test standalone - ITJUnitUtils.runWithRest(TestRestServerConfig.class); - ITJUnitUtils.run(TestRestServerConfigEdge.class); - - // currently, only support vertx download - ITJUnitUtils.run(TestDownloadSlowStreamEdge.class); - } - - private static void testH2CStandalone() throws Throwable { - runShareTestCases(); - - //as setMaxInitialLineLength() is not work for http2, do not need - // ITJUnitUtils.runWithRest(TestRestServerConfig.class) - ITJUnitUtils.run(TestRestServerConfigEdge.class); - } - - private static void testH2Standalone() throws Throwable { - runShareTestCases(); - - //as setMaxInitialLineLength() is not work for http2, do not need - // ITJUnitUtils.runWithRest(TestRestServerConfig.class) - ITJUnitUtils.run(TestRestServerConfigEdge.class); - } - - private static void testSpringBoot2Standalone() throws Throwable { - runShareTestCases(); - - // currently, only support vertx download - ITJUnitUtils.run(TestDownloadSlowStreamEdge.class); - } - - private static void testSpringBoot2Servlet() throws Throwable { - runShareTestCases(); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/Consumers.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/Consumers.java deleted file mode 100644 index ea24dad8596..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/Consumers.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.apache.servicecomb.it.extend.engine.ITInvoker; -import org.apache.servicecomb.it.extend.engine.ITSCBRestTemplate; -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.springframework.web.client.RestTemplate; - -public class Consumers { - private String producerName; - - private String schemaId; - - private Class intfCls; - - private ITSCBRestTemplate scbRestTemplate; - - private RestTemplate edgeRestTemplate; - - private RestTemplate zuulRestTemplate; - - private INTF intf; - - private String transport; - - public Consumers(String schemaId, Class intfCls) { - this.schemaId = schemaId; - this.intfCls = intfCls; - } - - public void init() { - this.producerName = ITJUnitUtils.getProducerName(); - this.transport = ITJUnitUtils.getTransport(); - intf = ITInvoker.createProxy(producerName, schemaId, transport, intfCls); - scbRestTemplate = new ITSCBRestTemplate(schemaId).init(); - edgeRestTemplate = GateRestTemplate.createEdgeRestTemplate(schemaId).init(); - zuulRestTemplate = null;// GateRestTemplate.createZuulRestTemplate(schemaId).init(); - } - - public String getSchemaId() { - return schemaId; - } - - public INTF getIntf() { - return intf; - } - - public RestTemplate getSCBRestTemplate() { - return scbRestTemplate; - } - - public RestTemplate getEdgeRestTemplate() { - return edgeRestTemplate; - } - - public RestTemplate getZuulRestTemplate() { - return zuulRestTemplate; - } - - public String getTransport() { - return transport; - } -} \ No newline at end of file diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ResultPrinter.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ResultPrinter.java deleted file mode 100644 index 2a35762bc42..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ResultPrinter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.apache.servicecomb.it.junit.SCBFailure; - -public class ResultPrinter { - private long start = System.currentTimeMillis(); - - public String formatTotalTime() { - long totalTime = System.currentTimeMillis() - start; - long hour = 0; - long minute = 0; - long second = 0; - second = totalTime / 1000; - if (totalTime <= 1000 && totalTime > 0) { - second = 1; - } - if (second > 60) { - minute = second / 60; - second = second % 60; - } - if (minute > 60) { - hour = minute / 60; - minute = minute % 60; - } - // 转换时分秒 00:00:00 - String duration = - (hour >= 10 ? hour : "0" + hour) + ":" + (minute >= 10 ? minute : "0" + minute) + ":" + (second >= 10 ? second - : "0" + second); - return duration; - } - - public void print() { - StringBuilder sb = new StringBuilder(); - String totalTime = formatTotalTime(); - for (SCBFailure failure : ITJUnitUtils.getFailures()) { - sb.append(String.format("%s, %s\n" - + "%s\n", - failure.getParents(), - failure.getTestHeader(), - failure.getTrace())); - } - sb.append(String.format("\nrun count:%d, failed count: %d, totalTime: %s.\n", - ITJUnitUtils.getRunCount(), - ITJUnitUtils.getFailures().size(), - totalTime)); - System.out.println(sb.toString()); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/DeployDefinition.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/DeployDefinition.java deleted file mode 100644 index 99becf4fcdb..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/DeployDefinition.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -import io.vertx.core.json.Json; - -public class DeployDefinition { - protected String deployName; - - protected String displayName; - - protected String startCompleteLog; - - protected String workDir; - - /** - *

-   * edge as the example:
-   *  support:
-   *  1.absolute path: /home/xxx/it-edge/it-edge-1.0.0.jar
-   *  2.relate to work dir:
-   *      if work dir is /home/xxx
-   *      cmd is it-edge/it-edge-1.0.0.jar
-   *  3.run in ide, cmd is it-edge/it-edge-1.0.0.jar
-   *      will try: integration-tests/target/it-edge/it-edge-1.0.0.jar
-   *  4.run in ide, cmd is it-edge
-   *      will try: integration-tests/target/it-edge/it-edge-1.0.0.jar
-   *  
- */ - protected String cmd; - - protected String[] args; - - public String getDeployName() { - return deployName; - } - - public void setDeployName(String deployName) { - this.deployName = deployName; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public String getStartCompleteLog() { - return startCompleteLog; - } - - public void setStartCompleteLog(String startCompleteLog) { - this.startCompleteLog = startCompleteLog; - } - - public String getWorkDir() { - return workDir; - } - - public void setWorkDir(String workDir) { - this.workDir = workDir; - } - - public String getCmd() { - return cmd; - } - - public void setCmd(String cmd) { - this.cmd = cmd; - } - - public String[] getArgs() { - return args; - } - - public void setArgs(String[] args) { - this.args = args; - } - - public void init() { - if (displayName == null) { - displayName = deployName; - } - } - - @Override - public String toString() { - return Json.encodePrettily(this); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/Deploys.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/Deploys.java deleted file mode 100644 index 0b5a2a2b143..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/Deploys.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.URL; - -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Deploys { - private static final Logger LOGGER = LoggerFactory.getLogger(Deploys.class); - - private static final String DEFAULT_MICROSERVICE_VERSION = "1.0.0"; - - private String pomVersion; - - private ServiceCenterDeploy serviceCenter; - - private MicroserviceDeploy edge; - - private MicroserviceDeploy baseProducer; - - private MicroserviceDeploy baseHttp2CProducer; - - private MicroserviceDeploy baseHttp2Producer; - - private MicroserviceDeploy springBoot2StandaloneProducer; - - private MicroserviceDeploy springBoot2ServletProducer; - - private MicroserviceDeploy zuul; - - public ServiceCenterDeploy getServiceCenter() { - return serviceCenter; - } - - public MicroserviceDeploy getEdge() { - return edge; - } - - public MicroserviceDeploy getZuul() { - return zuul; - } - - public MicroserviceDeploy getBaseProducer() { - return baseProducer; - } - - public MicroserviceDeploy getBaseHttp2Producer() { - return baseHttp2Producer; - } - - public MicroserviceDeploy getBaseHttp2CProducer() { - return baseHttp2CProducer; - } - - public MicroserviceDeploy getSpringBoot2StandaloneProducer() { - return springBoot2StandaloneProducer; - } - - public MicroserviceDeploy getSpringBoot2ServletProducer() { - return springBoot2ServletProducer; - } - - public void init() throws Throwable { - initPomVersion(); - LOGGER.info("test version: {}", pomVersion); - - serviceCenter = new ServiceCenterDeploy(); - initEdge(); - initBaseProducer(); - initBaseHttp2CProducer(); - initBaseHttp2Producer(); - initSpringBoot2StandaloneProducer(); - initSpringBoot2ServletProducer(); -// initZuul(); - } - - public void setPomVersion(String pomVersion) { - this.pomVersion = pomVersion; - } - - private void initPomVersion() throws Throwable { - // already set manually - if (pomVersion != null) { - return; - } - - // already package to jar - pomVersion = Deploys.class.getPackage().getImplementationVersion(); - if (pomVersion != null) { - return; - } - - // run in ide - MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new FileReader("pom.xml")); - pomVersion = model.getVersion(); - if (pomVersion != null) { - return; - } - - if (model.getParent() == null) { - throw new IllegalStateException("can not find pom ServiceComb version"); - } - - pomVersion = model.getParent().getVersion(); - if (pomVersion != null) { - return; - } - - throw new IllegalStateException("can not find pom ServiceComb version"); - } - - private void initDeployDefinition(DeployDefinition deployDefinition) { - deployDefinition.init(); - doInitDeployDefinition(deployDefinition); - LOGGER.info("definition of {} is: {}", deployDefinition.getDeployName(), deployDefinition); - } - - private void doInitDeployDefinition(DeployDefinition deployDefinition) { - // absolute path or relate to current work dir - File cmd = new File(deployDefinition.getCmd()); - if (cmd.exists() && cmd.isFile()) { - deployDefinition.setCmd(cmd.getAbsolutePath()); - return; - } - - // run in ide - File workDir = new File("integration-tests"); - if (initDeployDefinition(deployDefinition, workDir)) { - return; - } - - // run "mvn install" - workDir = new File("..").getAbsoluteFile(); - if (initDeployDefinition(deployDefinition, workDir)) { - return; - } - - throw new IllegalStateException(String - .format("can not find deploy cmd, work dir: %s, definition: %s", new File("").getAbsolutePath(), - deployDefinition)); - } - - private boolean initDeployDefinition(DeployDefinition deployDefinition, File workDir) { - // deployDefinition.getCmd() is it-edge/target/it-edge-1.0.0.jar - File cmd = new File(workDir, deployDefinition.getCmd()); - if (cmd.exists() && cmd.isFile()) { - deployDefinition.setCmd(cmd.getAbsolutePath()); - return true; - } - - // deployDefinition.getCmd() is it-edge - // change it-edge to it-edge/it-edge-1.0.0.jar - cmd = new File(workDir, String.format("%s/target/%s-%s.jar", - deployDefinition.getCmd(), - deployDefinition.getCmd(), - pomVersion)); - if (cmd.exists()) { - try { - deployDefinition.setCmd(cmd.getCanonicalPath()); - } catch (IOException e) { - throw new IllegalStateException("Failed to getCanonicalPath of " + cmd.getAbsolutePath(), e); - } - return true; - } - - return false; - } - - private void initBaseProducer() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("baseProducer"); - definition.setCmd("it-producer"); - definition.setArgs(new String[] {}); - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-producer"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - baseProducer = new MicroserviceDeploy(definition); - } - - private void initBaseHttp2Producer() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("baseHttp2Producer"); - definition.setCmd("it-producer"); - definition.setArgs(new String[] {}); - URL urlServer = Thread.currentThread().getContextClassLoader().getResource("certificates/server.p12"); - URL urlTrust = Thread.currentThread().getContextClassLoader().getResource("certificates/trust.jks"); - if (urlServer != null && urlTrust != null) { - definition.setArgs(new String[] {"-Dservicecomb.rest.address=0.0.0.0:0?sslEnabled=true&protocol=http2", - "-Dservicecomb.highway.address=0.0.0.0:0?sslEnabled=true", - "-Dserver.p12=" + urlServer.getPath(), - "-Dtrust.jks=" + urlTrust.getPath() - }); - } - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-producer-h2"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - baseHttp2Producer = new MicroserviceDeploy(definition); - } - - private void initBaseHttp2CProducer() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("baseHttp2CProducer"); - definition.setCmd("it-producer"); - definition.setArgs(new String[] {"-Dservicecomb.rest.address=0.0.0.0:0?protocol=http2"}); - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-producer-h2c"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - baseHttp2CProducer = new MicroserviceDeploy(definition); - } - - private void initSpringBoot2ServletProducer() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("springBoot2ServletProducer"); - definition.setCmd("it-producer-deploy-springboot2-servlet"); - definition.setArgs(new String[] {}); - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-producer-deploy-springboot2-servlet"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - springBoot2ServletProducer = new MicroserviceDeploy(definition); - } - - private void initSpringBoot2StandaloneProducer() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("springBoot2StandaloneProducer"); - definition.setCmd("it-producer-deploy-springboot2-standalone"); - definition.setArgs(new String[] {}); - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-producer-deploy-springboot2-standalone"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - springBoot2StandaloneProducer = new MicroserviceDeploy(definition); - } - - private void initEdge() { - MicroserviceDeployDefinition definition = new MicroserviceDeployDefinition(); - definition.setDeployName("edge"); - definition.setCmd("it-edge"); - definition.setArgs(new String[] {}); - definition.setAppId("integration-test"); - definition.setMicroserviceName("it-edge"); - definition.setVersion(DEFAULT_MICROSERVICE_VERSION); - - initDeployDefinition(definition); - - edge = new MicroserviceDeploy(definition); - } - - // private void initZuul() { - // MicroserviceDeployDefinition zuulDefinition = new MicroserviceDeployDefinition(); - // zuulDefinition.setDeployName("zuul"); - // zuulDefinition.setCmd("it-zuul"); - // - // initDeployDefinition(zuulDefinition); - // - // zuul = new MicroserviceDeploy(zuulDefinition); - // } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java deleted file mode 100644 index e24cfcbecc9..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.servicecomb.it.ITUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MicroserviceDeploy extends NormalDeploy { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceDeploy.class); - - private MicroserviceDeployDefinition microserviceDeployDefinition; - - public MicroserviceDeploy(DeployDefinition deployDefinition) { - super(deployDefinition); - this.microserviceDeployDefinition = (MicroserviceDeployDefinition) deployDefinition; - - this.microserviceDeployDefinition.setStartCompleteLog("ServiceComb is ready."); - } - - public MicroserviceDeployDefinition getMicroserviceDeployDefinition() { - return microserviceDeployDefinition; - } - - @Override - protected String[] createCmds() { - // must set jar at the end of the cmds - return new String[] {"java", "-jar"}; - } - - @Override - protected String[] addArgs(String[] cmds) { - // add jar - return ArrayUtils.addAll(super.addArgs(cmds), - "-DselfController=" + RegistryUtils.getMicroserviceInstance().getInstanceId(), - "-Dservice_description.name=" + microserviceDeployDefinition.getMicroserviceName(), - deployDefinition.getCmd()); - } - - public void ensureReady() throws Throwable { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() - .getOrCreateMicroserviceVersionRule(microserviceDeployDefinition.getAppId(), - microserviceDeployDefinition.getMicroserviceName(), - microserviceDeployDefinition.getVersion()); - if (microserviceVersionRule.getInstances().size() > 0) { - LOGGER.info("{} already ready.", microserviceDeployDefinition.getDisplayName()); - return; - } - - deploy(); - waitStartComplete(); - ITUtils.waitMicroserviceReady(microserviceDeployDefinition.getAppId(), - microserviceDeployDefinition.getMicroserviceName(), - microserviceDeployDefinition.getVersion(), - 1); - } - - @Override - public void stop() { - if (subProcess == null) { - return; - } - - sendCommand("ms-stop"); - waitStop(); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeployDefinition.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeployDefinition.java deleted file mode 100644 index 42d8d9e7884..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeployDefinition.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -public class MicroserviceDeployDefinition extends DeployDefinition { - private String appId; - - private String microserviceName; - - private String version; - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public void setMicroserviceName(String microserviceName) { - this.microserviceName = microserviceName; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - @Override - public void init() { - if (displayName == null) { - displayName = microserviceName + "-" + version; - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/NormalDeploy.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/NormalDeploy.java deleted file mode 100644 index bb91446b5af..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/NormalDeploy.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - - -import java.io.BufferedWriter; -import java.io.File; -import java.io.OutputStreamWriter; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NormalDeploy { - private static final Logger LOGGER = LoggerFactory.getLogger(NormalDeploy.class); - - protected DeployDefinition deployDefinition; - - protected Process subProcess; - - protected BufferedWriter subProcessCommandWriter; - - protected SubProcessLogger subProcessLogger; - - private int prevFailCount; - - public NormalDeploy(DeployDefinition deployDefinition) { - this.deployDefinition = deployDefinition; - } - - public void deploy() throws Throwable { - String[] cmds = createCmds(); - cmds = addArgs(cmds); - - this.prevFailCount = ITJUnitUtils.getFailures().size(); - - subProcess = createProcessBuilder(cmds).start(); - subProcessCommandWriter = new BufferedWriter(new OutputStreamWriter(subProcess.getOutputStream())); - subProcessLogger = new SubProcessLogger(deployDefinition.getDisplayName(), subProcess.getInputStream(), - deployDefinition.getStartCompleteLog()); - } - - protected String[] addArgs(String[] cmds) { - cmds = ArrayUtils.addAll(cmds, deployDefinition.getArgs()); - return cmds; - } - - protected String[] createCmds() { - return new String[] {deployDefinition.getCmd()}; - } - - protected ProcessBuilder createProcessBuilder(String[] cmds) { - ProcessBuilder processBuilder = new ProcessBuilder(cmds).redirectErrorStream(true); - if (deployDefinition.getWorkDir() != null) { - processBuilder.directory(new File(deployDefinition.getWorkDir())); - } - return processBuilder; - } - - public void waitStartComplete() { - subProcessLogger.waitStartComplete(); - } - - public void sendCommand(Object command) { - String strCmd = null; - try { - strCmd = JsonUtils.writeValueAsString(command); - subProcessCommandWriter.write(strCmd + "\n"); - subProcessCommandWriter.flush(); - } catch (Throwable e) { - LOGGER.error("Failed to send command, displayName={}, command={}", deployDefinition.getDisplayName(), strCmd, e); - } - } - - protected void afterStop() { - IOUtils.closeQuietly(subProcessCommandWriter); - subProcessCommandWriter = null; - - SubProcessLogger old = subProcessLogger; - IOUtils.closeQuietly(subProcessLogger); - subProcessLogger = null; - - if (prevFailCount != ITJUnitUtils.getFailures().size()) { - List logs = old.getAndClearLog(); - for (String line : logs) { - System.out.println(line); - } - } - } - - public void waitStop() { - if (subProcess == null) { - LOGGER.info("Ignore, already stop or reusing exist instance, displayName={}.", deployDefinition.getDisplayName()); - return; - } - - for (; ; ) { - try { - subProcess.waitFor(); - break; - } catch (InterruptedException e) { - LOGGER.info("Ignore InterruptedException, try to wait stop again, displayName={}.", - deployDefinition.getDisplayName()); - } - } - subProcess = null; - afterStop(); - - LOGGER.info("stop complete, displayName={}.", deployDefinition.getDisplayName()); - } - - public void stop() { - if (subProcess == null) { - LOGGER.info("Ignore, already stop or reusing exist instance, displayName={}.", deployDefinition.getDisplayName()); - return; - } - - subProcess.destroy(); - subProcess = null; - afterStop(); - LOGGER.info("stop complete, displayName={}.", deployDefinition.getDisplayName()); - } - - public List getAndClearLog() { - SubProcessLogger logger = subProcessLogger; - if (logger != null) { - return logger.getAndClearLog(); - } - - return Collections.emptyList(); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/ServiceCenterDeploy.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/ServiceCenterDeploy.java deleted file mode 100644 index 9a38dbcc224..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/ServiceCenterDeploy.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.SystemUtils; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.client.RestTemplate; - -import io.swagger.util.Json; - -public class ServiceCenterDeploy extends NormalDeploy { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterDeploy.class); - - public ServiceCenterDeploy() { - super(new DeployDefinition()); - - deployDefinition.setDeployName("serviceCenter"); - deployDefinition.setDisplayName("serviceCenter"); - if (SystemUtils.IS_OS_WINDOWS) { - deployDefinition.setCmd("service-center.exe"); - } else { - deployDefinition.setCmd("service-center"); - } - deployDefinition.setStartCompleteLog("server is ready"); - } - - public void ensureReady() throws Throwable { - // check if is running - // {"version":"1.0.0","buildTag":"20180608145515.1.0.0.b913a2d","runMode":"dev","apiVersion":"3.0.0"} - try { - String address = "http://localhost:30100/version"; - ServiceCenterInfo serviceCenterInfo = new RestTemplate().getForObject(address, ServiceCenterInfo.class); - if (serviceCenterInfo != null && serviceCenterInfo.getVersion() != null) { - LOGGER.info("{} already started, {}.", deployDefinition.getDisplayName(), Json.pretty(serviceCenterInfo)); - return; - } - } catch (Throwable e) { - LOGGER.info("failed to get ServiceCenter version, message={}", e.getMessage()); - } - - initServiceCenterCmd(); - LOGGER.info("definition of {} is: {}", deployDefinition.getDeployName(), deployDefinition); - - deploy(); - waitStartComplete(); - } - - protected void initServiceCenterCmd() throws IOException { - // where is service center - // 1.find from env, for local dev environment - LOGGER.info("try to find serviceCenter by env {}.", "serviceCenterHome"); - String dir = System.getenv("serviceCenterHome"); - if (dir != null) { - LOGGER.info("serviceCenterHome={}.", dir); - File file = new File(dir, deployDefinition.getCmd()); - if (file.exists()) { - FileUtils.cleanDirectory(new File(dir, "data")); - deployDefinition.setWorkDir(dir); - deployDefinition.setCmd(file.getAbsolutePath()); - return; - } - - LOGGER.info("{} is not exist.", file.getAbsolutePath()); - } - - // 2.docker, for CI environment - LOGGER.info("can not find serviceCenter by env {}, try run by docker.", "serviceCenterHome"); - deployDefinition.setCmd("docker"); - deployDefinition.setArgs(new String[] { - "run", - "-p", - "127.0.0.1:30100:30100", - "servicecomb/service-center" - }); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/SubProcessLogger.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/SubProcessLogger.java deleted file mode 100644 index 22ee9bd0c85..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/SubProcessLogger.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.deploy; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.it.ITUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SubProcessLogger implements Closeable { - private static final Logger LOGGER = LoggerFactory.getLogger(SubProcessLogger.class); - - private final String displayName; - - private BufferedReader reader; - - private Thread thread; - - private String startCompleteLog; - - private volatile boolean startCompleted; - - private List logs = new ArrayList<>(); - - public SubProcessLogger(String displayName, InputStream inputStream, String startCompleteLog) { - this.displayName = displayName; - this.startCompleteLog = startCompleteLog; - - BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); - this.reader = new BufferedReader(new InputStreamReader(bufferedInputStream)); - - thread = new Thread(this::run, "SubProcessLogger-" + displayName); - thread.start(); - } - - private void run() { - try { - doRun(); - } catch (IOException e) { - LOGGER.error("Failed to read log.", e); - } - } - - private void doRun() throws IOException { - String line; - while ((line = reader.readLine()) != null) { - logs.add(String.format("[%s] %s", displayName, line)); - - checkStartComplete(line); - } - } - - public List getAndClearLog() { - List old = logs; - logs = new ArrayList<>(); - return old; - } - - private void checkStartComplete(String line) { - if (startCompleted || startCompleteLog == null) { - return; - } - - startCompleted = line.contains(startCompleteLog); - } - - public boolean isStartCompleted() { - return startCompleted; - } - - public void waitStartComplete() { - if (startCompleteLog == null) { - throw new IllegalStateException( - String.format("[%s] not set startCompleteLog, can not wait start complete.", displayName)); - } - - LOGGER.info("waiting {} start.", displayName); - long startTime = System.currentTimeMillis(); - for (; ; ) { - if (startCompleted) { - LOGGER.info("{} start completed.", displayName); - return; - } - - if (System.currentTimeMillis() - startTime > TimeUnit.MINUTES.toMillis(1)) { - throw new IllegalStateException(String.format("[%s] timeout to wait for start complete.", displayName)); - } - - ITUtils.forceWait(TimeUnit.MILLISECONDS, 500); - } - } - - @Override - public void close() throws IOException { - reader.close(); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java deleted file mode 100644 index 5378d196f95..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import java.util.Arrays; - -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.client.RestTemplate; - -public class GateRestTemplate extends RestTemplate { - private final String gateName; - - private final String schemaId; - - private String urlPrefix; - - public static GateRestTemplate createEdgeRestTemplate(String schemaId) { - return new GateRestTemplate("it-edge", schemaId); - } - - public static GateRestTemplate createZuulRestTemplate(String schemaId) { - return new GateRestTemplate("it-zuul", schemaId); - } - - public GateRestTemplate(String gateName, String schemaId) { - this.gateName = gateName; - this.schemaId = schemaId; - } - - public GateRestTemplate init() { - urlPrefix = getUrlPrefix(gateName, ITJUnitUtils.getProducerName(), schemaId); - - setUriTemplateHandler(new ITUriTemplateHandler(urlPrefix)); - - setMessageConverters(Arrays.asList( - new MappingJackson2HttpMessageConverter(), - new StringHttpMessageConverter() - )); - - return this; - } - - public String getUrlPrefix() { - return urlPrefix; - } - - private String getUrlPrefix(String gateName, String producerName, String schemaId) { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() - .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), gateName, - DefinitionConst.VERSION_RULE_ALL); - MicroserviceInstance microserviceInstance = microserviceVersionRule.getInstances().values().stream().findFirst() - .get(); - URIEndpointObject edgeAddress = new URIEndpointObject(microserviceInstance.getEndpoints().get(0)); - - String urlSchema = "http"; - if (edgeAddress.isSslEnabled()) { - urlSchema = "https"; - } - - microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() - .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), producerName, - DefinitionConst.VERSION_RULE_ALL); - MicroserviceVersionMeta microserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - SchemaMeta schemaMeta = microserviceVersionMeta.getMicroserviceMeta().ensureFindSchemaMeta(schemaId); - return String - .format("%s://%s:%d/rest/%s%s", urlSchema, edgeAddress.getHostOrIp(), edgeAddress.getPort(), producerName, - schemaMeta.getSwagger().getBasePath()); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequest.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequest.java deleted file mode 100644 index 567e4878027..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import java.net.URI; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest; -import org.springframework.http.HttpMethod; - -public class ITClientHttpRequest extends CseClientHttpRequest { - private String transport; - - public ITClientHttpRequest(URI uri, HttpMethod method, String transport) { - super(uri, method); - this.transport = transport; - } - - @Override - protected ReferenceConfig findReferenceConfig(String microserviceName) { - ReferenceConfig referenceConfig = CseContext.getInstance().getConsumerProviderManager() - .createReferenceConfig(microserviceName); - if (transport != null) { - referenceConfig.setTransport(transport); - } - return referenceConfig; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequestFactory.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequestFactory.java deleted file mode 100644 index a5def644c63..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITClientHttpRequestFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import java.net.URI; - -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequestFactory; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.ClientHttpRequest; - -public class ITClientHttpRequestFactory extends CseClientHttpRequestFactory { - private String transport; - - public ITClientHttpRequestFactory() { - this.transport = ITJUnitUtils.getTransport(); - } - - @Override - public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) { - return new ITClientHttpRequest(uri, httpMethod, transport); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITInvoker.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITInvoker.java deleted file mode 100644 index eea40b92381..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITInvoker.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import java.lang.reflect.Proxy; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.provider.pojo.Invoker; - -/** - * allow set transport, that makes integration test easier - */ -public class ITInvoker extends Invoker { - public static T createProxy(String microserviceName, String schemaId, String transport, Class consumerIntf) { - ITInvoker invoker = new ITInvoker(microserviceName, schemaId, transport, consumerIntf); - return invoker.getProxy(); - } - - private String transport; - - private Object proxy; - - public ITInvoker(String microserviceName, String schemaId, String transport, Class consumerIntf) { - super(microserviceName, schemaId, consumerIntf); - this.transport = transport; - this.proxy = Proxy.newProxyInstance(consumerIntf.getClassLoader(), new Class[] {consumerIntf}, this); - } - - public String getMicroserviceName() { - return microserviceName; - } - - public String getSchemaId() { - return schemaId; - } - - public String getTransport() { - return transport; - } - - @SuppressWarnings("unchecked") - public T getProxy() { - return (T) proxy; - } - - @Override - protected ReferenceConfig findReferenceConfig() { - ReferenceConfig referenceConfig = CseContext.getInstance() - .getConsumerProviderManager() - .createReferenceConfig(microserviceName); - referenceConfig.setTransport(transport); - return referenceConfig; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java deleted file mode 100644 index b1ed1f95e3d..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import org.apache.servicecomb.core.definition.MicroserviceVersionMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.apache.servicecomb.provider.springmvc.reference.CseRestTemplate; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; - -public class ITSCBRestTemplate extends CseRestTemplate { - private String urlPrefix; - - private String schemaId; - - private String basePath; - - public ITSCBRestTemplate(String schemaId) { - this.schemaId = schemaId; - } - - public ITSCBRestTemplate init() { - String producerName = ITJUnitUtils.getProducerName(); - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() - .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), producerName, - DefinitionConst.VERSION_RULE_ALL); - MicroserviceVersionMeta microserviceVersionMeta = microserviceVersionRule.getLatestMicroserviceVersion(); - SchemaMeta schemaMeta = microserviceVersionMeta.getMicroserviceMeta().ensureFindSchemaMeta(schemaId); - basePath = schemaMeta.getSwagger().getBasePath(); - urlPrefix = String.format("cse://%s%s", producerName, basePath); - - setUriTemplateHandler(new ITUriTemplateHandler(urlPrefix)); - setRequestFactory(new ITClientHttpRequestFactory()); - - return this; - } - - public String getBasePath() { - return basePath; - } - - public String getUrlPrefix() { - return urlPrefix; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITUriTemplateHandler.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITUriTemplateHandler.java deleted file mode 100644 index 72b2104294b..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITUriTemplateHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.extend.engine; - -import java.net.URI; -import java.util.Map; - -import org.springframework.web.util.DefaultUriTemplateHandler; - -public class ITUriTemplateHandler extends DefaultUriTemplateHandler { - private String urlPrefix; - - public ITUriTemplateHandler(String urlPrefix) { - this.urlPrefix = urlPrefix; - } - - @Override - protected URI expandInternal(String uriTemplate, Object... uriVariables) { - return super.expandInternal(changeUrl(uriTemplate), uriVariables); - } - - @Override - protected URI expandInternal(String uriTemplate, Map uriVariables) { - return super.expandInternal(changeUrl(uriTemplate), uriVariables); - } - - private String changeUrl(String uriTemplate) { - return urlPrefix + uriTemplate; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/ITJUnitUtils.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/ITJUnitUtils.java deleted file mode 100644 index 522f1284472..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/ITJUnitUtils.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.junit; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.commons.lang3.reflect.MethodUtils; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.apache.servicecomb.it.extend.engine.ITSCBRestTemplate; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunListener; - -import com.google.common.reflect.ClassPath; - -public final class ITJUnitUtils { - private static ClassLoader classLoader = JvmUtils.findClassLoader(); - - private static JUnitCore jUnitCore = new JUnitCore(); - - private static Stack parents = new Stack<>(); - - private static List failures = new ArrayList<>(); - - private static AtomicInteger runCount = new AtomicInteger(); - - private static String transport; - - private static String producerName; - - public static String getProducerName() { - return producerName; - } - - public static void setProducerName(String producerName) { - ITJUnitUtils.producerName = producerName; - } - - static { - jUnitCore.addListener(new RunListener() { - @Override - public void testFailure(Failure failure) { - SCBFailure scbFailure = new SCBFailure(failure.getDescription(), failure.getException()); - failures.add(scbFailure); - System.out.println(scbFailure.toString()); - } - }); - } - - private ITJUnitUtils() { - } - - public static int getRunCount() { - return runCount.get(); - } - - public static Stack getParents() { - return parents; - } - - public static void pushTransport(String transport) { - ITJUnitUtils.transport = transport; - addParent(transport); - } - - public static String getTransport() { - return transport; - } - - public static void popTransport() { - ITJUnitUtils.transport = null; - popParent(); - } - - public static void addProducer(String producerName) { - ITJUnitUtils.setProducerName(producerName); - parents.add(producerName); - } - - public static void popProducer() { - ITJUnitUtils.setProducerName(null); - parents.pop(); - } - - public static void addParent(String name) { - parents.add(name); - } - - public static void popParent() { - parents.pop(); - } - - public static List cloneParents() { - return new ArrayList<>(parents); - } - - public static List getFailures() { - return failures; - } - - public static void runFromPackage(String packageName) throws Throwable { - Class[] classes = findAllClassInPackage(packageName); - run(classes); - } - - public static void run(Class... classes) throws Throwable { - initClasses(classes); - Result result = jUnitCore.run(classes); - runCount.addAndGet(result.getRunCount()); - } - - private static void initClasses(Class[] classes) throws Throwable { - for (Class cls : classes) { - for (Field field : FieldUtils.getAllFieldsList(cls)) { - if (Consumers.class.isAssignableFrom(field.getType()) - || GateRestTemplate.class.isAssignableFrom(field.getType()) - || ITSCBRestTemplate.class.isAssignableFrom(field.getType())) { - Object target = FieldUtils.readStaticField(field, true); - MethodUtils.invokeMethod(target, "init"); - } - } - } - } - - public static Class[] findAllClassInPackage(String packageName) { - try { - return ClassPath.from(classLoader) - .getTopLevelClassesRecursive(packageName).stream() - .map(clsInfo -> clsInfo.load()) - .toArray(Class[]::new); - } catch (IOException e) { - throw new IllegalStateException("failed to find all classes in package " + packageName, e); - } - } - - public static void runWithHighwayAndRest(Class... classes) throws Throwable { - runWithTransports(Arrays.asList(Const.HIGHWAY, Const.RESTFUL), classes); - } - - public static void runWithRest(Class... classes) throws Throwable { - runWithTransports(Arrays.asList(Const.RESTFUL), classes); - } - - public static void runWithTransports(List transports, Class... classes) throws Throwable { - for (String transport : transports) { - ITJUnitUtils.pushTransport(transport); - - ITJUnitUtils.run(classes); - - ITJUnitUtils.popTransport(); - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/SCBFailure.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/SCBFailure.java deleted file mode 100644 index faa3c23a6a6..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/junit/SCBFailure.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.junit; - -import java.util.List; - -import org.junit.runner.Description; -import org.junit.runner.notification.Failure; - -public class SCBFailure extends Failure { - private static final long serialVersionUID = 6467681668616080232L; - - private List parents; - - public SCBFailure(Description description, Throwable thrownException) { - super(description, thrownException); - parents = ITJUnitUtils.cloneParents(); - } - - public List getParents() { - return parents; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationJaxrsSchema.java deleted file mode 100644 index 42db9d48b7a..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationJaxrsSchema.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -import io.swagger.annotations.ApiOperation; - -@RestSchema(schemaId = "apiOperationJaxrsSchema") -@Path("/apiOperationJaxrsSchema") -public class ApiOperationJaxrsSchema { - @POST - @Path("/testMediaType1") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.TEXT_HTML) - @ApiOperation(value = "testMediaType1", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_XML) - public String testMediaType1(String input) { - return input; - } - - @POST - @Path("/testMediaType2") - @ApiOperation(value = "testMediaType2", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_HTML) - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_XML) - public String testMediaType2(String input) { - return input; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationSpringMVCSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationSpringMVCSchema.java deleted file mode 100644 index 78781f69abb..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiOperationSpringMVCSchema.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.SwaggerDefinition; - -@RestSchema(schemaId = "apiOperationSpringMVCSchema") -@RequestMapping(value = "/apiOperationSpringMVCSchema", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_HTML) -@SwaggerDefinition(consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_XML) -public class ApiOperationSpringMVCSchema { - @RequestMapping(value = "/testMediaType1", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_HTML) - @ApiOperation(value = "testMediaType1", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_XML) - public String testMediaType1(@RequestBody String input) { - return input; - } - - @ApiOperation(value = "testMediaType2", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_HTML) - @PutMapping(value = "/testMediaType2", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_XML) - public String testMediaType2(@RequestBody String input) { - return input; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java deleted file mode 100644 index fe83aa59c01..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamJaxrsSchema.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -import io.swagger.annotations.ApiParam; - -@RestSchema(schemaId = "apiParamJaxrs") -@Path("/apiParamJaxrs") -public class ApiParamJaxrsSchema { - @POST - @Path("/body") - public void body(@ApiParam(value = "desc of body param") CommonModel model) { - - } - - @POST - @Path("/query") - public void query(@ApiParam(value = "desc of query param") @QueryParam("input") int input) { - - } - - @POST - @Path("/queryArr") - public void queryArr(@ApiParam(value = "desc of queryArr param") - @QueryParam("input") String[] input) { - - } - - @POST - @Path("/header") - public void header(@ApiParam(value = "desc of header param") @HeaderParam("input") int input) { - - } - - @POST - @Path("/cookie") - public void cookie(@ApiParam(value = "desc of cookie param") @CookieParam("input") int input) { - - } - - @POST - @Path("/form") - public void form(@ApiParam(value = "desc of form param") @FormParam("input") int input) { - - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java deleted file mode 100644 index 1673ba858bb..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamPojoSchema.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.pojo.RpcSchema; - -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.SwaggerDefinition; - -@RpcSchema(schemaId = "apiParamPojo") -@SwaggerDefinition(basePath = "/apiParamPojo") -public class ApiParamPojoSchema { - public void model(@ApiParam(value = "desc of model param") CommonModel model) { - - } - - public void simple(@ApiParam(value = "desc of simple param") int input) { - - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java deleted file mode 100644 index b52f9f4184f..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/ApiParamSpringmvcSchema.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; - -@RestSchema(schemaId = "apiParamSpringmvc") -@RequestMapping(path = "/apiParamSpringmvc") -public class ApiParamSpringmvcSchema { - @PostMapping(path = "/body") - public void body(@ApiParam(value = "desc of body param", - required = true, - name = "modelEx", - examples = @Example(value = { - @ExampleProperty(mediaType = "k1", value = "v1"), - @ExampleProperty(mediaType = "k2", value = "v2")})) @RequestBody CommonModel model) { - - } - - @PostMapping(path = "/query") - public void query(@ApiParam(value = "desc of query param", - required = true, - readOnly = true, - allowEmptyValue = true, - name = "inputEx", - example = "10") int input) { - - } - - @PostMapping(path = "/queryArr") - public void queryArr(@ApiParam(value = "desc of queryArr param", - required = true, - readOnly = true, - allowEmptyValue = true, - name = "inputEx", - example = "10", - collectionFormat = "csv") int[] inputArr) { - - } - - @PostMapping(path = "/header") - public void header(@ApiParam(value = "desc of header param") @RequestHeader("input") int input) { - - } - - @PostMapping(path = "/cookie") - public void cookie(@ApiParam(value = "desc of cookie param") @CookieValue("input") int input) { - - } - - @PostMapping(path = "/form") - public void form(@ApiParam(value = "desc of form param") @RequestAttribute("input") int input) { - - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodJaxrsSchema.java deleted file mode 100644 index b3318a57caf..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodJaxrsSchema.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -import io.swagger.annotations.ApiOperation; - -@RestSchema(schemaId = "ignoreMethodJaxrs") -@Path("/v1/ignoreMethodJaxrs") -public class IgnoreMethodJaxrsSchema { - @ApiOperation(value = "", hidden = true) - @GET - @Path("hideByApiOperation") - public int hideByApiOperation() { - return 0; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodPojoSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodPojoSchema.java deleted file mode 100644 index 9b3ae4e9e80..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodPojoSchema.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.SwaggerDefinition; - -@RestSchema(schemaId = "ignoreMethodPojo") -@SwaggerDefinition(basePath = "/v1/ignoreMethodPojo") -public class IgnoreMethodPojoSchema { - @ApiOperation(value = "", hidden = true) - public int hideByApiOperation() { - return 0; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodSpringmvcSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodSpringmvcSchema.java deleted file mode 100644 index 71c5517acab..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreMethodSpringmvcSchema.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.swagger.annotations.ApiOperation; - -@RestSchema(schemaId = "ignoreMethodSpringmvc") -@RequestMapping(path = "/v1/ignoreMethodSpringmvc") -public class IgnoreMethodSpringmvcSchema { - @ApiOperation(value = "", hidden = true) - @GetMapping(path = "") - public int hideByApiOperation() { - return 0; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodJaxrsSchema.java deleted file mode 100644 index 568d1eea49b..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodJaxrsSchema.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "ignoreStaticMethodJaxrsSchema") -@Path("/ignoreStaticMethodJaxrsSchema") -public class IgnoreStaticMethodJaxrsSchema { - - private IgnoreStaticMethodJaxrsSchema() { - } - - private static IgnoreStaticMethodJaxrsSchema INSTANCE = new IgnoreStaticMethodJaxrsSchema(); - - public static IgnoreStaticMethodJaxrsSchema getINSTANCE() { - return INSTANCE; - } - - @GET - @Path("staticSub") - public static int staticSub(@QueryParam("num1") int num1, @QueryParam("num2") int num2) { - return num1 - num2; - } - - @GET - @Path("add") - public int add(@QueryParam("num1") int num1, @QueryParam("num2") int num2) { - return num1 + num2; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodPojoSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodPojoSchema.java deleted file mode 100644 index c10692c9b46..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodPojoSchema.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.pojo.RpcSchema; - -import io.swagger.annotations.SwaggerDefinition; - -@RpcSchema(schemaId = "ignoreStaticMethodPojoSchema") -@SwaggerDefinition(basePath = "/ignoreStaticMethodPojoSchema") -public class IgnoreStaticMethodPojoSchema { - - private IgnoreStaticMethodPojoSchema() { - } - - private static IgnoreStaticMethodPojoSchema INSTANCE = new IgnoreStaticMethodPojoSchema(); - - public static IgnoreStaticMethodPojoSchema getINSTANCE() { - return INSTANCE; - } - - public static int staticSub(int num1, int num2) { - return num1 - num2; - } - - public int add(int num1, int num2) { - return num1 + num2; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodSpringmvcSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodSpringmvcSchema.java deleted file mode 100644 index 3515038bb9d..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/IgnoreStaticMethodSpringmvcSchema.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "ignoreStaticMethodSpringmvcSchema") -@RequestMapping(path = "/ignoreStaticMethodSpringmvcSchema") -public class IgnoreStaticMethodSpringmvcSchema { - - private IgnoreStaticMethodSpringmvcSchema() { - } - - private static IgnoreStaticMethodSpringmvcSchema INSTANCE = new IgnoreStaticMethodSpringmvcSchema(); - - public static IgnoreStaticMethodSpringmvcSchema getINSTANCE() { - return INSTANCE; - } - - @GetMapping("staticSub") - public static int staticSub(int num1, int num2) { - return num1 - num2; - } - - @GetMapping("add") - public int add(int num1, int num2) { - return num1 + num2; - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/TestApiOperation.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/TestApiOperation.java deleted file mode 100644 index dee26995863..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/schema/TestApiOperation.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.Operation; -import io.swagger.models.Swagger; - -public class TestApiOperation { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - - protected Operation getOperation(String schemaId, String opName) { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(schemaId); - return schemaMeta.findOperation(opName).getSwaggerOperation(); - } - - @Test - public void jaxrs_TestMediaType1() { - Operation operation = getOperation("apiOperationJaxrsSchema", "testMediaType1"); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - } - - @Test - public void jaxrs_TestMediaType2() { - Operation operation = getOperation("apiOperationJaxrsSchema", "testMediaType2"); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - } - - @Test - public void springMVC_TestMediaType1() { - Operation operation = getOperation("apiOperationSpringMVCSchema", "testMediaType1"); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - } - - @Test - public void springMVC_TestMediaType2() { - Operation operation = getOperation("apiOperationSpringMVCSchema", "testMediaType2"); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - } - - @Test - public void springMVC_TestSwaggerDefinitionMediaType() { - Swagger swagger = microserviceMeta.findSchemaMeta("apiOperationSpringMVCSchema").getSwagger(); - Assert.assertThat(swagger.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - Assert.assertThat(swagger.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAcceptType.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAcceptType.java deleted file mode 100644 index 9b2f2b18e92..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAcceptType.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; - -public class TestAcceptType { - interface AcceptTypeIntf { - } - - private static Consumers consumersAcceptTypeSpringmvc = new Consumers<>("acceptTypeSpringmvcSchema", - AcceptTypeIntf.class); - - private static Consumers consumersAcceptTypeJaxrs = new Consumers<>("acceptTypeJaxrsSchema", - AcceptTypeIntf.class); - - @Test - public void testTextPlain_rt() { - checkTextPlain(consumersAcceptTypeSpringmvc); - checkTextPlain(consumersAcceptTypeJaxrs); - } - - private void checkTextPlain(Consumers consumers) { - String result = textHeader_rt(consumers, MediaType.TEXT_PLAIN_VALUE); - Assert.assertEquals("cse", result); - try { - textHeader_rt(consumers, MediaType.APPLICATION_JSON_VALUE); - Assert.fail("should throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(406, e.getStatusCode()); - Assert.assertTrue(e.getMessage().contains("Accept application/json is not supported")); - } catch (Throwable e) { - Assert.fail(" should throw InvocationException"); - } - } - - private String textHeader_rt(Consumers consumers, String type) { - HttpHeaders headers = new HttpHeaders(); - headers.add("accept", type); - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/sayHi?name=cse", - HttpMethod.GET, - entity, - String.class); - return response.getBody(); - } - - @Test - public void testProducerApplicationJson_rt() { - checkApplicationJson(consumersAcceptTypeSpringmvc); - checkApplicationJson(consumersAcceptTypeJaxrs); - } - - private void checkApplicationJson(Consumers consumers) { - String result = jsonHeader_rt(consumers, MediaType.APPLICATION_JSON_VALUE); - Assert.assertEquals("cse", result); - try { - jsonHeader_rt(consumersAcceptTypeSpringmvc, MediaType.TEXT_PLAIN_VALUE); - Assert.fail("should throw exception"); - } catch (InvocationException e) { - Assert.assertEquals(406, e.getStatusCode()); - Assert.assertTrue(e.getMessage().contains("Accept text/plain is not supported")); - } catch (Throwable e) { - Assert.fail("should throw InvocationException"); - } - } - - private String jsonHeader_rt(Consumers consumers, String type) { - HttpHeaders headers = new HttpHeaders(); - headers.add("accept", type); - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/sayHello?name=cse", - HttpMethod.GET, - entity, - String.class); - return response.getBody(); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAnnotatedAttribute.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAnnotatedAttribute.java deleted file mode 100644 index 232c1a10f91..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestAnnotatedAttribute.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -public class TestAnnotatedAttribute { - interface AnnotatedAttributeIntf { - String fromHeader(String inputs); - } - - private static Consumers consumersSpringmvc = - new Consumers<>("annotatedAttributeSpringmvc", AnnotatedAttributeIntf.class); - - @Test - public void fromHeader_springmvc_rt() { - fromHeader_rt(consumersSpringmvc); - } - - @Test - public void fromQuery_springmvc_rt() { - fromQuery_rt(consumersSpringmvc); - } - - @Test - public void fromCookie_springmvc_rt() { - fromCookie_rt(consumersSpringmvc); - } - - @Test - public void fromCookieRequired_springmvc_rt() { - fromCookieRequired_rt(consumersSpringmvc); - } - - @Test - public void fromCookieDefaultValue_springmvc_rt() { - fromCookieDefaultValue_rt(consumersSpringmvc); - } - - @Test - public void fromPath_springmvc_rt() { - fromPath_rt(consumersSpringmvc); - } - - @Test - public void fromPart_springmvc_rt() { - fromPart_rt(consumersSpringmvc); - } - - @Test - public void fromAttribute_springmvc_rt() { - fromAttribute_rt(consumersSpringmvc); - } - - protected void fromHeader_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("input", "default"); - headers.add("input2", "fromValue"); - headers.add("input3", "fromName"); - - @SuppressWarnings("rawtypes") - HttpEntity entity = new HttpEntity<>(null, headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/fromHeader", - HttpMethod.GET, - entity, - String.class); - assertEquals("default,fromValue,fromName", response.getBody()); - } - - protected void fromQuery_rt(Consumers consumers) { - String result = consumers.getSCBRestTemplate() - .getForObject("/fromQuery?input={1}&input2={2}&input3={3}", - String.class, - "default", - "fromValue", - "fromName"); - assertEquals("default,fromValue,fromName", result); - } - - protected void fromCookie_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.COOKIE, "input=default"); - headers.add(HttpHeaders.COOKIE, "input2=fromValue"); - headers.add(HttpHeaders.COOKIE, "input3=fromName"); - - HttpEntity requestEntity = new HttpEntity<>(headers); - ResponseEntity result = consumers.getSCBRestTemplate() - .exchange("/fromCookie", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("default,fromValue,fromName", result.getBody()); - } - - protected void fromCookieRequired_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - HttpEntity requestEntity = new HttpEntity<>(headers); - try { - consumers.getSCBRestTemplate() - .exchange("/fromCookieRequired", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("required is true, throw exception", "but not throw exception"); - } catch (InvocationException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("InvocationException: code=400;msg=CommonExceptionData [message=Parameter is not valid.]", - e.getMessage()); - } - headers.add(HttpHeaders.COOKIE, "input1=default1"); - requestEntity = new HttpEntity<>(headers); - try { - consumers.getSCBRestTemplate() - .exchange("/fromCookieRequired", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("required is true, throw exception", "but not throw exception"); - } catch (InvocationException e) { - assertEquals(400, e.getStatusCode()); - assertEquals("InvocationException: code=400;msg=CommonExceptionData [message=Parameter is not valid.]", - e.getMessage()); - } - headers.add(HttpHeaders.COOKIE, "input=joker"); - requestEntity = new HttpEntity<>(headers); - ResponseEntity result = consumers.getSCBRestTemplate() - .exchange("/fromCookieRequired", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("joker", result.getBody()); - } - - protected void fromCookieDefaultValue_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - HttpEntity requestEntity = new HttpEntity<>(headers); - ResponseEntity result = consumers.getSCBRestTemplate() - .exchange("/fromCookieDefaultValue", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("default", result.getBody()); - - headers.add(HttpHeaders.COOKIE, "input1=jokers"); - requestEntity = new HttpEntity<>(headers); - result = consumers.getSCBRestTemplate() - .exchange("/fromCookieDefaultValue", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("default", result.getBody()); - - headers.add(HttpHeaders.COOKIE, "input=joker"); - requestEntity = new HttpEntity<>(headers); - result = consumers.getSCBRestTemplate() - .exchange("/fromCookieDefaultValue", - HttpMethod.GET, - requestEntity, - String.class); - assertEquals("joker", result.getBody()); - } - - protected void fromPath_rt(Consumers consumers) { - String result = consumers.getSCBRestTemplate() - .getForObject("/fromPath/{1}/{2}/{3}", - String.class, - "default", - "fromValue", - "fromName"); - assertEquals("default,fromValue,fromName", result); - } - - protected void fromPart_rt(Consumers consumers) { - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("input", "default"); - map.add("input2", "fromValue"); - map.add("input3", "fromName"); - - String result = consumers.getSCBRestTemplate() - .postForObject("/fromPart", - new HttpEntity<>(map), - String.class); - assertEquals("default,fromValue,fromName", result); - } - - protected void fromAttribute_rt(Consumers consumers) { - Map body = new HashMap<>(); - body.put("input", "default"); - body.put("input2", "fromValue"); - body.put("input3", "fromName"); - ResponseEntity result = consumers.getSCBRestTemplate() - .exchange("/fromAttribute", - HttpMethod.POST, - new HttpEntity<>(body), - String.class); - assertEquals("default,fromValue,fromName", result.getBody()); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java deleted file mode 100644 index 08dd414589b..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestApiParam.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; - -public class TestApiParam { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - - Parameter parameter; - - protected void check(String schemaId, String opName) { - check(schemaId, opName, opName); - } - - protected void check(String schemaId, String opName, String paramType) { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta(schemaId); - OperationMeta operationMeta = schemaMeta.findOperation(opName); - parameter = operationMeta.getSwaggerOperation().getParameters().get(0); - Assert.assertEquals("desc of " + opName + " param", parameter.getDescription()); - Assert.assertEquals(paramType, parameter.getIn()); - } - - @Test - public void pojoModel() { - check("apiParamPojo", "model", "body"); - } - - @Test - public void pojoSimple() { - check("apiParamPojo", "simple", "body"); - } - - @Test - public void jaxrsBody() { - check("apiParamJaxrs", "body"); - } - - @Test - public void jaxrsQuery() { - check("apiParamJaxrs", "query"); - } - - @Test - public void jaxrsQueryArray() { - check("apiParamJaxrs", "queryArr", "query"); - - Assert.assertEquals("multi", ((QueryParameter) parameter).getCollectionFormat()); - } - - @Test - public void jaxrsHeader() { - check("apiParamJaxrs", "header"); - } - - @Test - public void jaxrsCookie() { - check("apiParamJaxrs", "cookie"); - } - - @Test - public void jaxrsForm() { - check("apiParamJaxrs", "form", "formData"); - } - - @Test - public void springmvcBody() { - check("apiParamSpringmvc", "body"); - - Assert.assertTrue(parameter.getRequired()); - Assert.assertEquals("modelEx", parameter.getName()); - Assert.assertEquals("v1", ((BodyParameter) parameter).getExamples().get("k1")); - Assert.assertEquals("v2", ((BodyParameter) parameter).getExamples().get("k2")); - } - - @Test - public void springmvcQuery() { - check("apiParamSpringmvc", "query"); - - Assert.assertTrue(parameter.getRequired()); - Assert.assertTrue(parameter.isReadOnly()); - Assert.assertTrue(parameter.getAllowEmptyValue()); - Assert.assertEquals("inputEx", parameter.getName()); - Assert.assertEquals(10L, ((QueryParameter) parameter).getExample()); - Assert.assertNull(((QueryParameter) parameter).getCollectionFormat()); - } - - @Test - public void springmvcQueryArray() { - check("apiParamSpringmvc", "queryArr", "query"); - - Assert.assertTrue(parameter.getRequired()); - Assert.assertTrue(parameter.isReadOnly()); - Assert.assertTrue(parameter.getAllowEmptyValue()); - Assert.assertEquals("inputEx", parameter.getName()); - Assert.assertEquals("10", ((QueryParameter) parameter).getExample()); - Assert.assertEquals("csv", ((QueryParameter) parameter).getCollectionFormat()); - } - - @Test - public void springmvcHeader() { - check("apiParamSpringmvc", "header"); - } - - @Test - public void springmvcCookie() { - check("apiParamSpringmvc", "cookie"); - } - - @Test - public void springmvcForm() { - check("apiParamSpringmvc", "form", "formData"); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestChangeTransport.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestChangeTransport.java deleted file mode 100644 index 633dad08954..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestChangeTransport.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.it.Consumers; -import org.junit.Assert; -import org.junit.Test; - -public class TestChangeTransport { - interface ChangeTranportIntf { - String checkTransport(); - } - - static Consumers consumersPojo = new Consumers<>("transportPojo", ChangeTranportIntf.class); - - static Consumers consumersJaxrs = new Consumers<>("transportJaxrs", ChangeTranportIntf.class); - - static Consumers consumersSpringmvc = new Consumers<>("transportSpringmvc", - ChangeTranportIntf.class); - - void checkTransport_intf(Consumers consumers) { - Assert.assertEquals(consumers.getTransport(), consumers.getIntf().checkTransport()); - } - - void checkTransport_rt(Consumers consumers) { - Assert.assertEquals(consumers.getTransport(), - consumers.getSCBRestTemplate().getForObject("/checkTransport", String.class)); - } - - @Test - public void checkTransport_pojo_intf() { - checkTransport_intf(consumersPojo); - } - - @Test - public void checkTransport_pojo_rt() { - Assert.assertEquals(consumersPojo.getTransport(), - consumersPojo.getSCBRestTemplate().postForObject("/checkTransport", "", String.class)); - } - - @Test - public void checkTransport_jaxrs_intf() { - checkTransport_intf(consumersJaxrs); - } - - @Test - public void checkTransport_jaxrs_rt() { - checkTransport_rt(consumersJaxrs); - } - - @Test - public void checkTransport_springmvc_intf() { - checkTransport_intf(consumersSpringmvc); - } - - @Test - public void checkTransport_springmvc_rt() { - checkTransport_rt(consumersSpringmvc); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java deleted file mode 100644 index 54c6285ccb2..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java +++ /dev/null @@ -1,1257 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import java.net.URI; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.it.extend.engine.ITSCBRestTemplate; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.util.UriComponentsBuilder; - -public class TestDataTypePrimitive { - interface DataTypePojoIntf { - int intBody(int input); - - int intAdd(int num1, int num2); - - String stringBody(String input); - - String stringConcat(String str1, String str2); - - double doubleBody(double input); - - double doubleAdd(double num1, double num2); - - float floatBody(float input); - - float floatAdd(float num1, float num2); - - Color enumBody(Color color); - } - - public interface DataTypeRestIntf { - int intPath(int input); - - int intQuery(int input); - - int intHeader(int input); - - int intCookie(int input); - - int intBody(int input); - - int intForm(int input); - - int intAdd(int num1, int num2); - - //string - String stringPath(String input); - - String stringQuery(String input); - - String stringHeader(String input); - - String stringCookie(String input); - - String stringForm(String input); - - String stringBody(String input); - - String stringConcat(String str1, String str2); - - //double - double doublePath(double input); - - double doubleQuery(double input); - - double doubleHeader(double input); - - double doubleCookie(double input); - - double doubleBody(double input); - - double doubleForm(double input); - - double doubleAdd(double num1, double num2); - - //float - float floatPath(float input); - - float floatQuery(float input); - - float floatHeader(float input); - - float floatCookie(float input); - - float floatBody(float input); - - float floatForm(float input); - - float floatAdd(float num1, float num2); - - // enum - Color enumBody(Color color); - - // query array - String queryArr(String[] queryArr); - - String queryArrCSV(String[] queryArr); - - String queryArrSSV(String[] queryArr); - - String queryArrTSV(String[] queryArr); - - String queryArrPIPES(String[] queryArr); - - String queryArrMULTI(String[] queryArr); - } - - private static Consumers consumersPojo = new Consumers<>("dataTypePojo", DataTypePojoIntf.class); - - private static Consumers consumersJaxrs = - new Consumers<>("dataTypeJaxrs", DataTypeRestIntf.class); - - private static Consumers consumersSpringmvc = new Consumers<>("dataTypeSpringmvc", - DataTypeRestIntf.class); - - @Test - public void int_pojo_intf() { - assertEquals(10, consumersPojo.getIntf().intBody(10)); - } - - @Test - public void double_pojo_intf() { - assertEquals(10.2, consumersPojo.getIntf().doubleBody(10.2), 0.0); - } - - @Test - public void string_pojo_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersPojo.getIntf().stringBody(expect)); - } - - @Test - public void int_pojo_rt() { - Map map = new HashMap<>(); - map.put("input", 10); - assertEquals(10, (int) consumersPojo.getSCBRestTemplate().postForObject("/intBody", map, int.class)); - } - - @Test - public void double_pojo_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2); - assertEquals(10.2, consumersPojo.getSCBRestTemplate().postForObject("/doubleBody", map, double.class), - 0.0); - } - - @Test - public void string_pojo_rt() { - String expect = "serviceComb"; - Map map = new HashMap<>(); - map.put("input", expect); - assertEquals(expect, consumersPojo.getSCBRestTemplate().postForObject("/stringBody", map, String.class)); - } - - @Test - public void intAdd_pojo_intf() { - assertEquals(12, consumersPojo.getIntf().intAdd(10, 2)); - } - - @Test - public void doubleAdd_pojo_intf() { - assertEquals(20.5, consumersPojo.getIntf().doubleAdd(10.2, 10.3), 0.0); - } - - @Test - public void string_concat_pojo_intf() { - assertEquals("serviceComb", consumersPojo.getIntf().stringConcat("service", "Comb")); - } - - @Test - public void intAdd_pojo_rt() { - Map map = new HashMap<>(); - map.put("num1", 10); - map.put("num2", 2); - assertEquals(12, (int) consumersPojo.getSCBRestTemplate().postForObject("/intAdd", map, int.class)); - } - - @Test - public void doubleAdd_pojo_rt() { - Map map = new HashMap<>(); - map.put("num1", 10.2); - map.put("num2", 10.3); - assertEquals(20.5, consumersPojo.getSCBRestTemplate().postForObject("/doubleAdd", map, double.class), 0.0); - } - - @Test - public void string_concat_pojo_rt() { - Map map = new HashMap<>(); - map.put("str1", "service"); - map.put("str2", "Comb"); - assertEquals("serviceComb", - consumersPojo.getSCBRestTemplate().postForObject("/stringConcat", map, String.class)); - } - - @Test - public void enumBody_pojo_intf() { - assertEquals(Color.BLUE, consumersPojo.getIntf().enumBody(Color.BLUE)); - } - - @Test - public void enumBody_pojo_rt() { - Map body = new HashMap<>(); - body.put("color", Color.BLUE); - assertEquals(Color.BLUE, - consumersPojo.getSCBRestTemplate().postForObject("/enumBody", body, Color.class)); - } - - @Test - public void intPath_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intPath(10)); - } - - @Test - public void doublePath_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doublePath(10.2), 0.0); - } - - @Test - public void stringPath_jaxrs_intf() { - String expect = "serviceComb/serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringPath(expect)); - } - - @Test - public void intPath_jaxrs_rt() { - assertEquals(10, (int) consumersJaxrs.getSCBRestTemplate().getForObject("/intPath/10", int.class)); - } - - @Test - public void doublePath_jaxrs_rt() { - assertEquals(10.2, consumersJaxrs.getSCBRestTemplate().getForObject("/doublePath/10.2", double.class), - 0.0); - } - - @Test - public void stringPath_jaxrs_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersJaxrs.getSCBRestTemplate().getForObject("/stringPath/" + expect, String.class)); - } - - @Test - public void stringPath_jaxrs_rt_with_encoded_slash() { - String requestPathParam = "serviceComb%2FserviceComb"; - String expectResponse = "serviceComb/serviceComb"; - // build request uri to avoid Spring's encoding path - URI requestUri = UriComponentsBuilder - .fromUriString(((ITSCBRestTemplate) consumersJaxrs.getSCBRestTemplate()).getUrlPrefix() - + "/stringPath/" + requestPathParam) - .build(true).toUri(); - assertEquals(expectResponse, - consumersJaxrs.getSCBRestTemplate().getForObject(requestUri, String.class)); - } - - @Test - public void intQuery_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intQuery(10)); - } - - @Test - public void doubleQuery_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doubleQuery(10.2), 0.0); - } - - @Test - public void stringQuery_jaxrs_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringQuery(expect)); - } - - @Test - public void intQuery_jaxrs_rt() { - assertEquals(10, (int) consumersJaxrs.getSCBRestTemplate().getForObject("/intQuery?input=10", int.class)); - } - - @Test - public void doubleQuery_jaxrs_rt() { - assertEquals(10.2, - consumersJaxrs.getSCBRestTemplate().getForObject("/doubleQuery?input=10.2", double.class), 0.0); - } - - @Test - public void stringQuery_jaxrs_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersJaxrs.getSCBRestTemplate().getForObject("/stringQuery?input=" + expect, String.class)); - } - - @Test - public void intHeader_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intHeader(10)); - } - - @Test - public void doubleHeader_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doubleHeader(10.2), 0.0); - } - - @Test - public void stringHeader_jaxrs_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringHeader(expect)); - } - - @Test - public void intHeader_jaxrs_rt() { - intHeader_rt(consumersJaxrs); - } - - @Test - public void doubleHeader_jaxrs_rt() { - doubleHeader_rt(consumersJaxrs); - } - - protected void intHeader_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("input", "10"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/intHeader", - HttpMethod.GET, - entity, - int.class); - assertEquals(10, (int) response.getBody()); - } - - protected void doubleHeader_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("input", "10.2"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/doubleHeader", - HttpMethod.GET, - entity, - double.class); - assertEquals(10.2, response.getBody(), 0.0); - } - - @Test - public void stringHeader_jaxrs_rt() { - stringHeader_rt(consumersJaxrs); - } - - protected void stringHeader_rt(Consumers consumers) { - String expect = "serviceComb"; - HttpHeaders headers = new HttpHeaders(); - headers.add("input", expect); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/stringHeader", - HttpMethod.GET, - entity, - String.class); - assertEquals(expect, response.getBody()); - } - - @Test - public void intCookie_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intCookie(10)); - } - - @Test - public void doubleCookie_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doubleCookie(10.2), 0.0); - } - - @Test - public void stringCookie_jaxrs_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringCookie(expect)); - } - - @Test - public void intCookie_jaxrs_rt() { - intCookie_rt(consumersJaxrs); - } - - @Test - public void doubleCookie_jaxrs_rt() { - doubleCookie_rt(consumersJaxrs); - } - - void intCookie_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", "input=10"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/intCookie", - HttpMethod.GET, - entity, - int.class); - assertEquals(10, (int) response.getBody()); - } - - void doubleCookie_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", "input=10.2"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/doubleCookie", - HttpMethod.GET, - entity, - double.class); - assertEquals(10.2, response.getBody(), 0.0); - } - - @Test - public void stringCookie_jaxrs_rt() { - stringCookie_rt(consumersJaxrs); - } - - void stringCookie_rt(Consumers consumers) { - String expect = "serviceComb"; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", "input=" + expect); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/stringCookie", - HttpMethod.GET, - entity, - String.class); - assertEquals(expect, response.getBody()); - } - - @Test - public void intForm_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intForm(10)); - } - - @Test - public void doubleForm_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doubleForm(10.2), 0.0); - } - - @Test - public void stringForm_jaxrs_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringForm(expect)); - } - - @Test - public void intForm_jaxrs_rt() { - Map map = new HashMap<>(); - map.put("input", 10); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10, - (int) consumersJaxrs.getSCBRestTemplate().postForEntity("/intForm", formEntity, int.class).getBody()); - //just use map is ok - assertEquals(10, - (int) consumersJaxrs.getSCBRestTemplate().postForEntity("/intForm", map, int.class).getBody()); - } - - @Test - public void doubleForm_jaxrs_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10.2, - consumersJaxrs.getSCBRestTemplate().postForEntity("/doubleForm", formEntity, double.class).getBody(), - 0.0); - //just use map is ok - assertEquals(10.2, - consumersJaxrs.getSCBRestTemplate().postForEntity("/doubleForm", map, double.class).getBody(), 0.0); - } - - @Test - public void stringForm_jaxrs_rt() { - String expect = "serviceComb"; - Map map = new HashMap<>(); - map.put("input", expect); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(expect, - consumersJaxrs.getSCBRestTemplate() - .postForEntity("/stringForm", formEntity, String.class) - .getBody()); - - //you can use another method to invoke it - assertEquals(expect, - consumersJaxrs.getSCBRestTemplate().postForEntity("/stringForm", map, String.class).getBody()); - } - - @Test - public void intBody_jaxrs_intf() { - assertEquals(10, consumersJaxrs.getIntf().intBody(10)); - } - - @Test - public void doubleBody_jaxrs_intf() { - assertEquals(10.2, consumersJaxrs.getIntf().doubleBody(10.2), 0.0); - } - - @Test - public void stringBody_jaxrs_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersJaxrs.getIntf().stringBody(expect)); - } - - @Test - public void intBody_jaxrs_rt() { - assertEquals(10, (int) consumersJaxrs.getSCBRestTemplate().postForObject("/intBody", 10, int.class)); - } - - @Test - public void doubleBody_jaxrs_rt() { - assertEquals(10.2, consumersJaxrs.getSCBRestTemplate().postForObject("/doubleBody", 10.2, double.class), - 0.0); - } - - @Test - public void stringBody_jaxrs_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersJaxrs.getSCBRestTemplate().postForObject("/stringBody", expect, String.class)); - } - - @Test - public void intAdd_jaxrs_intf() { - assertEquals(12, consumersJaxrs.getIntf().intAdd(10, 2)); - } - - @Test - public void doubleAdd_jaxrs_intf() { - assertEquals(20.5, consumersJaxrs.getIntf().doubleAdd(10.2, 10.3), 0.0); - } - - @Test - public void string_concat_jaxrs_intf() { - assertEquals("serviceComb", consumersJaxrs.getIntf().stringConcat("service", "Comb")); - } - - @Test - public void intAdd_jaxrs_rt() { - assertEquals(12, (int) consumersJaxrs.getSCBRestTemplate().getForObject("/intAdd?num1=10&num2=2", int.class)); - } - - @Test - public void doubleAdd_jaxrs_rt() { - assertEquals(20.5, - consumersJaxrs.getSCBRestTemplate().getForObject("/doubleAdd?num1=10.2&num2=10.3", double.class), 0.0); - } - - @Test - public void string_concat_jaxrs_rt() { - assertEquals("serviceComb", consumersJaxrs.getSCBRestTemplate() - .getForObject("/stringConcat?str1=service&str2=Comb", String.class)); - } - - @Test - public void enumBody_jaxrs_intf() { - assertEquals(Color.BLUE, consumersJaxrs.getIntf().enumBody(Color.BLUE)); - } - - @Test - public void enumBody_jaxrs_rt() { - assertEquals(Color.BLUE, - consumersJaxrs.getSCBRestTemplate().postForObject("/enumBody", Color.BLUE, Color.class)); - } - - @Test - public void intPath_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intPath(10)); - } - - @Test - public void doublePath_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doublePath(10.2), 0.0); - } - - @Test - public void stringPath_springmvc_intf() { - String expect = "serviceComb/serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringPath(expect)); - } - - @Test - public void doublePath_springmvc_rt() { - assertEquals(10.2, consumersSpringmvc.getSCBRestTemplate().getForObject("/doublePath/10.2", double.class), - 0.0); - } - - @Test - public void intPath_springmvc_rt() { - assertEquals(10, (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intPath/10", int.class)); - } - - @Test - public void stringPath_springmvc_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringPath/" + expect, String.class)); - } - - @Test - public void stringPath_springmvc_rt_with_encoded_slash() { - String requestPathParam = "serviceComb%2FserviceComb"; - String expectResponse = "serviceComb/serviceComb"; - URI requestUri = UriComponentsBuilder - .fromUriString(((ITSCBRestTemplate) consumersSpringmvc.getSCBRestTemplate()).getUrlPrefix() - + "/stringPath/" + requestPathParam) - .build(true).toUri(); - assertEquals(expectResponse, - consumersSpringmvc.getSCBRestTemplate().getForObject(requestUri, String.class)); - } - - @Test - public void intQuery_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intQuery(10)); - } - - @Test - public void doubleQuery_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doubleQuery(10.2), 0.0); - } - - @Test - public void stringQuery_springmvc_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringQuery(expect)); - } - - @Test - public void intQuery_springmvc_rt() { - assertEquals(10, (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intQuery?input=10", int.class)); - } - - @Test - public void doubleQuery_springmvc_rt() { - assertEquals(10.2, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleQuery?input=10.2", double.class), 0.0); - } - - @Test - public void stringQuery_springmvc_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringQuery?input=" + expect, String.class)); - } - - @Test - public void intHeader_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intHeader(10)); - } - - @Test - public void doubleHeader_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doubleHeader(10.2), 0.0); - } - - @Test - public void stringHeader_springmvc_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringHeader(expect)); - } - - @Test - public void intHeader_springmvc_rt() { - intHeader_rt(consumersSpringmvc); - } - - @Test - public void doubleHeader_springmvc_rt() { - doubleHeader_rt(consumersSpringmvc); - } - - @Test - public void stringHeader_springmvc_rt() { - stringHeader_rt(consumersSpringmvc); - } - - @Test - public void intCookie_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intCookie(10)); - } - - @Test - public void doubleCookie_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doubleCookie(10.2), 0.0); - } - - @Test - public void stringCookie_springmvc_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringCookie(expect)); - } - - @Test - public void intCookie_springmvc_rt() { - intCookie_rt(consumersSpringmvc); - } - - @Test - public void doubleCookie_springmvc_rt() { - doubleCookie_rt(consumersSpringmvc); - } - - @Test - public void stringCookie_springmvc_rt() { - stringCookie_rt(consumersSpringmvc); - } - - @Test - public void intForm_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intForm(10)); - } - - @Test - public void doubleForm_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doubleForm(10.2), 0.0); - } - - @Test - public void stringForm_springmvc_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringForm(expect)); - } - - @Test - public void intForm_springmvc_rt() { - Map map = new HashMap<>(); - map.put("input", 10); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10, - (int) consumersSpringmvc.getSCBRestTemplate().postForEntity("/intForm", formEntity, int.class).getBody()); - } - - @Test - public void doubleForm_springmvc_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10.2, - consumersSpringmvc.getSCBRestTemplate().postForEntity("/doubleForm", formEntity, double.class) - .getBody(), 0.0); - } - - @Test - public void stringForm_springmvc_rt() { - String expect = "serviceComb"; - Map map = new HashMap<>(); - map.put("input", expect); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(expect, - consumersSpringmvc.getSCBRestTemplate().postForEntity("/stringForm", formEntity, String.class) - .getBody()); - - assertEquals(expect, - consumersSpringmvc.getSCBRestTemplate().postForEntity("/stringForm", map, String.class) - .getBody()); - } - - @Test - public void intBody_springmvc_intf() { - assertEquals(10, consumersSpringmvc.getIntf().intBody(10)); - } - - @Test - public void doubleBody_springmvc_intf() { - assertEquals(10.2, consumersSpringmvc.getIntf().doubleBody(10.2), 0.0); - } - - @Test - public void stringBody_springmvc_intf() { - String expect = "serviceComb"; - assertEquals(expect, consumersSpringmvc.getIntf().stringBody(expect)); - } - - @Test - public void intBody_springmvc_rt() { - assertEquals(10, (int) consumersSpringmvc.getSCBRestTemplate().postForObject("/intBody", 10, int.class)); - } - - @Test - public void doubleBody_springmvc_rt() { - assertEquals(10.2, - consumersSpringmvc.getSCBRestTemplate().postForObject("/doubleBody", 10.2, double.class), 0.0); - } - - @Test - public void stringBody_springmvc_rt() { - String expect = "serviceComb"; - assertEquals(expect, - consumersSpringmvc.getSCBRestTemplate().postForObject("/stringBody", expect, String.class)); - } - - @Test - public void intAdd_springmvc_intf() { - assertEquals(12, consumersSpringmvc.getIntf().intAdd(10, 2)); - } - - @Test - public void doubleAdd_springmvc_intf() { - assertEquals(20.5, consumersSpringmvc.getIntf().doubleAdd(10.2, 10.3), 0.0); - } - - @Test - public void string_concat_springmvc_intf() { - assertEquals("serviceComb", consumersSpringmvc.getIntf().stringConcat("service", "Comb")); - } - - @Test - public void intAdd_springmvc_rt() { - assertEquals(12, (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intAdd?num1=10&num2=2", int.class)); - } - - @Test - public void doubleAdd_springmvc_rt() { - assertEquals(20.5, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleAdd?num1=10.2&num2=10.3", double.class), - 0.0); - } - - @Test - public void string_concat_springmvc_rt() { - assertEquals("serviceComb", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/stringConcat?str1=service&str2=Comb", String.class)); - } - - //float - @Test - public void float_pojo_intf() { - assertEquals(10.2f, consumersPojo.getIntf().floatBody(10.2f), 0.0f); - } - - @Test - public void float_pojo_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2f); - assertEquals(10.2f, consumersPojo.getSCBRestTemplate().postForObject("/floatBody", map, float.class), - 0.0f); - } - - @Test - public void floatAdd_pojo_intf() { - assertEquals(20.5f, consumersPojo.getIntf().floatAdd(10.2f, 10.3f), 0.0f); - } - - @Test - public void floatAdd_pojo_rt() { - Map map = new HashMap<>(); - map.put("num1", 10.2f); - map.put("num2", 10.3f); - assertEquals(20.5f, consumersPojo.getSCBRestTemplate().postForObject("/floatAdd", map, float.class), 0.0f); - } - - @Test - public void floatPath_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatPath(10.2f), 0.0f); - } - - @Test - public void floatPath_jaxrs_rt() { - assertEquals(10.2f, consumersJaxrs.getSCBRestTemplate().getForObject("/floatPath/10.2f", float.class), - 0.0f); - } - - @Test - public void floatQuery_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatQuery(10.2f), 0.0f); - } - - @Test - public void floatQuery_jaxrs_rt() { - assertEquals(10.2f, - consumersJaxrs.getSCBRestTemplate().getForObject("/floatQuery?input=10.2f", float.class), 0.0f); - } - - @Test - public void floatHeader_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatHeader(10.2f), 0.0f); - } - - @Test - public void floatHeader_jaxrs_rt() { - floatHeader_rt(consumersJaxrs); - } - - protected void floatHeader_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("input", "10.2f"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/floatHeader", - HttpMethod.GET, - entity, - float.class); - assertEquals(10.2f, response.getBody(), 0.0f); - } - - @Test - public void floatCookie_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatCookie(10.2f), 0.0f); - } - - @Test - public void floatCookie_jaxrs_rt() { - floatCookie_rt(consumersJaxrs); - } - - void floatCookie_rt(Consumers consumers) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", "input=10.2f"); - - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/floatCookie", - HttpMethod.GET, - entity, - float.class); - assertEquals(10.2f, response.getBody(), 0.0f); - } - - @Test - public void floatForm_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatForm(10.2f), 0.0f); - } - - @Test - public void floatForm_jaxrs_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2f); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10.2f, - consumersJaxrs.getSCBRestTemplate().postForEntity("/floatForm", formEntity, float.class).getBody(), - 0.0f); - //just use map is ok - assertEquals(10.2f, - consumersJaxrs.getSCBRestTemplate().postForEntity("/floatForm", map, float.class).getBody(), 0.0f); - } - - @Test - public void floatBody_jaxrs_intf() { - assertEquals(10.2f, consumersJaxrs.getIntf().floatBody(10.2f), 0.0f); - } - - @Test - public void floatBody_jaxrs_rt() { - assertEquals(10.2f, consumersJaxrs.getSCBRestTemplate().postForObject("/floatBody", 10.2f, float.class), - 0.0f); - } - - @Test - public void floatAdd_jaxrs_intf() { - assertEquals(20.5f, consumersJaxrs.getIntf().floatAdd(10.2f, 10.3f), 0.0f); - } - - @Test - public void floatAdd_jaxrs_rt() { - assertEquals(20.5f, - consumersJaxrs.getSCBRestTemplate().getForObject("/floatAdd?num1=10.2f&num2=10.3f", float.class), 0.0f); - } - - @Test - public void floatPath_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatPath(10.2f), 0.0f); - } - - @Test - public void floatPath_springmvc_rt() { - assertEquals(10.2f, consumersSpringmvc.getSCBRestTemplate().getForObject("/floatPath/10.2f", float.class), - 0.0f); - } - - @Test - public void floatQuery_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatQuery(10.2f), 0.0f); - } - - @Test - public void floatQuery_springmvc_rt() { - assertEquals(10.2f, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatQuery?input=10.2f", float.class), 0.0f); - } - - @Test - public void floatHeader_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatHeader(10.2f), 0.0f); - } - - @Test - public void floatHeader_springmvc_rt() { - floatHeader_rt(consumersSpringmvc); - } - - @Test - public void floatCookie_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatCookie(10.2f), 0.0f); - } - - @Test - public void floatCookie_springmvc_rt() { - floatCookie_rt(consumersSpringmvc); - } - - @Test - public void floatForm_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatForm(10.2f), 0.0f); - } - - @Test - public void floatForm_springmvc_rt() { - Map map = new HashMap<>(); - map.put("input", 10.2f); - HttpEntity> formEntity = new HttpEntity<>(map); - - assertEquals(10.2f, - consumersSpringmvc.getSCBRestTemplate().postForEntity("/floatForm", formEntity, float.class) - .getBody(), 0.0f); - } - - @Test - public void floatBody_springmvc_intf() { - assertEquals(10.2f, consumersSpringmvc.getIntf().floatBody(10.2f), 0.0f); - } - - @Test - public void floatBody_springmvc_rt() { - assertEquals(10.2f, - consumersSpringmvc.getSCBRestTemplate().postForObject("/floatBody", 10.2f, float.class), 0.0f); - } - - @Test - public void floatAdd_springmvc_intf() { - assertEquals(20.5f, consumersSpringmvc.getIntf().floatAdd(10.2f, 10.3f), 0.0f); - } - - @Test - public void floatAdd_springmvc_rt() { - assertEquals(20.5f, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatAdd?num1=10.2f&num2=10.3f", float.class), - 0.0f); - } - - @Test - public void enumBody_springmvc_intf() { - assertEquals(Color.BLUE, consumersSpringmvc.getIntf().enumBody(Color.BLUE)); - } - - @Test - public void enumBody_springmvc_rt() { - assertEquals(Color.BLUE, - consumersSpringmvc.getSCBRestTemplate().postForObject("/enumBody", Color.BLUE, Color.class)); - } - - // query array - @Test - public void queryArr_springmvc_intf() { - // default - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArr(new String[] {"a", "b", "c"})); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getIntf().queryArr(new String[] {"a", "", " ", "b", "c"})); - // CSV - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArrCSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersSpringmvc.getIntf().queryArrCSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getIntf().queryArrCSV(new String[] {"a", "", " ", "b", "c"})); - // SSV - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArrSSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersSpringmvc.getIntf().queryArrSSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - // TSV - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArrTSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersSpringmvc.getIntf().queryArrTSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getIntf().queryArrTSV(new String[] {"a", "", " ", "b", "c"})); - // PIPES - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArrPIPES(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersSpringmvc.getIntf() - .queryArrPIPES(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getIntf().queryArrPIPES(new String[] {"a", "", " ", "b", "c"})); - // MULTI - assertEquals("[a, b, c]3", - consumersSpringmvc.getIntf().queryArrMULTI(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersSpringmvc.getIntf() - .queryArrMULTI(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getIntf().queryArrMULTI(new String[] {"a", "", " ", "b", "c"})); - } - - @Test - public void queryArr_springmvc_rt() { - // default - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArr?queryArr=a&queryArr=b&queryArr=c", String.class)); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArr?queryArr=a&queryArr=&queryArr= &queryArr=b&queryArr=c", String.class)); - // csv - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrCSV?queryArr=a,b,c", String.class)); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrCSV?queryArr=a,, ,b,c", String.class)); - // ssv - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrSSV?queryArr=a b c", String.class)); - // tsv - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrTSV?queryArr=a\tb\tc", String.class)); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrTSV?queryArr=a\t\t \tb\tc", String.class)); - // pipes - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrPIPES?queryArr=a|b|c", String.class)); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrPIPES?queryArr=a|| |b|c", String.class)); - // multi - assertEquals("[a, b, c]3", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrMULTI?queryArr=a&queryArr=b&queryArr=c", String.class)); - assertEquals("[a, , , b, c]5", - consumersSpringmvc.getSCBRestTemplate() - .getForObject("/queryArrMULTI?queryArr=a&queryArr=&queryArr= &queryArr=b&queryArr=c", String.class)); - } - - @Test - public void queryArr_jaxrs_intf() { - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArr(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArr(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getIntf().queryArr(new String[] {"a", "", " ", "b", "c"})); - - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArrCSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArrCSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getIntf().queryArrCSV(new String[] {"a", "", " ", "b", "c"})); - - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArrSSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArrSSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArrTSV(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArrTSV(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getIntf().queryArrTSV(new String[] {"a", "", " ", "b", "c"})); - - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArrPIPES(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArrPIPES(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getIntf().queryArrPIPES(new String[] {"a", "", " ", "b", "c"})); - - assertEquals("[a, b, c]3", - consumersJaxrs.getIntf().queryArrMULTI(new String[] {"a", "b", "c"})); - assertEquals("[a, b, , c]4", - consumersJaxrs.getIntf().queryArrMULTI(new String[] {null, "a", null, null, "b", null, "", null, "c", null})); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getIntf().queryArrMULTI(new String[] {"a", "", " ", "b", "c"})); - } - - @Test - public void queryArr_jaxrs_rt() { - // default - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArr?queryArr=a&queryArr=b&queryArr=c", String.class)); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArr?queryArr=a&queryArr=&queryArr= &queryArr=b&queryArr=c", String.class)); - // csv - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrCSV?queryArr=a,b,c", String.class)); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrCSV?queryArr=a,, ,b,c", String.class)); - // ssv - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrSSV?queryArr=a b c", String.class)); - // tsv - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrTSV?queryArr=a\tb\tc", String.class)); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrTSV?queryArr=a\t\t \tb\tc", String.class)); - // pipes - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrPIPES?queryArr=a|b|c", String.class)); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrPIPES?queryArr=a|| |b|c", String.class)); - // multi - assertEquals("[a, b, c]3", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrMULTI?queryArr=a&queryArr=b&queryArr=c", String.class)); - assertEquals("[a, , , b, c]5", - consumersJaxrs.getSCBRestTemplate() - .getForObject("/queryArrMULTI?queryArr=a&queryArr=&queryArr= &queryArr=b&queryArr=c", String.class)); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultJsonValueJaxrsSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultJsonValueJaxrsSchema.java deleted file mode 100644 index 44b485eb220..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultJsonValueJaxrsSchema.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -public class TestDefaultJsonValueJaxrsSchema { - static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("defaultJsonValueJaxrs"); - - @Test - public void invokeFromEdgeWithQuery() { - String result = client.getForObject("/queryInput?size=3", String.class); - Assert.assertEquals(result, "expected:3:3"); - - result = client.getForObject("/queryInput", String.class); - Assert.assertEquals(result, "expected:0:0"); - - result = client.getForObject("/queryInput?size=", String.class); - Assert.assertEquals(result, "expected:0:null"); - } - - @SuppressWarnings("unchecked") - @Test - public void invokeFromEdgeWithRawJson() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - Map body = new HashMap<>(); - body.put("type", 100); - HttpEntity> entity = new HttpEntity<>(body, headers); - Map result = - client.postForObject("/jsonInput", entity, Map.class); - Assert.assertEquals(result.get("type"), 100); - Assert.assertEquals(result.get("message"), "expected:null:null"); - - body = new HashMap<>(); - body.put("type", 100); - body.put("defaultValue", null); - entity = new HttpEntity<>(body, headers); - result = - client.postForObject("/jsonInput", entity, Map.class); - Assert.assertEquals(result.get("type"), 100); - Assert.assertEquals(result.get("message"), "expected:null:null"); - - body = new HashMap<>(); - body.put("type", 200); - body.put("defaultValue", -1); - entity = new HttpEntity<>(body, headers); - result = - client.postForObject("/jsonInput", entity, Map.class); - Assert.assertEquals(result.get("type"), 200); - Assert.assertEquals(result.get("message"), "expected:-1:null"); - - body = new HashMap<>(); - body.put("type", 200); - body.put("defaultValue", -1); - body.put("items", null); - entity = new HttpEntity<>(body, headers); - result = - client.postForObject("/jsonInput", entity, Map.class); - Assert.assertEquals(result.get("type"), 200); - Assert.assertEquals(result.get("message"), "expected:-1:null"); - - body = new HashMap<>(); - body.put("type", 200); - body.put("defaultValue", -1); - body.put("items", new ArrayList()); - entity = new HttpEntity<>(body, headers); - result = - client.postForObject("/jsonInput", entity, Map.class); - Assert.assertEquals(result.get("type"), 200); - Assert.assertEquals(result.get("message"), "expected:-1:0"); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java deleted file mode 100644 index d0b8039c2ae..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Test; - -public class TestDefaultValue { - interface DefaultValueIntf { - int intQuery(Integer input); - - int intHeader(Integer input); - - int intForm(Integer input); - - String stringQuery(String input); - - String stringHeader(String input); - - String stringForm(String input); - - double doubleQuery(Double input); - - double doubleHeader(Double input); - - double doubleForm(Double input); - - // float - float floatQuery(Float input); - - float floatHeader(Float input); - - float floatForm(Float input); - } - - interface DefaultValueRequireIntf extends DefaultValueIntf { - int intQueryRequire(Integer input); - - int intHeaderRequire(Integer input); - - int intFormRequire(Integer input); - - String stringQueryRequire(String input); - - String stringHeaderRequire(String input); - - String stringFormRequire(String input); - - double doubleQueryRequire(Double input); - - double doubleHeaderRequire(Double input); - - double doubleFormRequire(Double input); - - float floatQueryRequire(Float input); - - float floatHeaderRequire(Float input); - - float floatFormRequire(Float input); - } - - private String defaultStr = "string"; - - private int defaultInt = 13; - - private double defaultDouble = 10.2; - - private float defaultFloat = 10.2f; - - private static Consumers consumersJaxrs = new Consumers<>("defaultValueJaxrs", - DefaultValueIntf.class); - - private static Consumers consumersSpringmvc = new Consumers<>("defaultValueSpringmvc", - DefaultValueRequireIntf.class); - - @Test - public void intQuery_jaxrs_intf() { - assertEquals(defaultInt, consumersJaxrs.getIntf().intQuery(null)); - } - - @Test - public void doubleQuery_jaxrs_intf() { - assertEquals(defaultDouble, consumersJaxrs.getIntf().doubleQuery(null), 0.0); - } - - @Test - public void stringQuery_jaxrs_intf() { - assertEquals(defaultStr, consumersJaxrs.getIntf().stringQuery(null)); - } - - @Test - public void intQuery_jaxrs_rt() { - assertEquals(defaultInt, (int) consumersJaxrs.getSCBRestTemplate().getForObject("/intQuery", int.class)); - } - - @Test - public void doubleQuery_jaxrs_rt() { - assertEquals(defaultDouble, consumersJaxrs.getSCBRestTemplate().getForObject("/doubleQuery", double.class), - 0.0); - } - - @Test - public void stringQuery_jaxrs_rt() { - assertEquals(defaultStr, consumersJaxrs.getSCBRestTemplate().getForObject("/stringQuery", String.class)); - } - - @Test - public void intHeader_jaxrs_intf() { - assertEquals(defaultInt, consumersJaxrs.getIntf().intHeader(null)); - } - - @Test - public void doubleHeader_jaxrs_intf() { - assertEquals(defaultDouble, consumersJaxrs.getIntf().doubleHeader(null), 0.0); - } - - @Test - public void stringHeader_jaxrs_intf() { - assertEquals(defaultStr, consumersJaxrs.getIntf().stringHeader(null)); - } - - @Test - public void intHeader_jaxrs_rt() { - assertEquals(defaultInt, (int) consumersJaxrs.getSCBRestTemplate().getForObject("/intHeader", int.class)); - } - - @Test - public void doubleHeader_jaxrs_rt() { - assertEquals(defaultDouble, - consumersJaxrs.getSCBRestTemplate().getForObject("/doubleHeader", double.class), 0.0); - } - - @Test - public void stringHeader_jaxrs_rt() { - assertEquals(defaultStr, - consumersJaxrs.getSCBRestTemplate().getForObject("/stringHeader", String.class)); - } - - @Test - public void intForm_jaxrs_intf() { - assertEquals(defaultInt, consumersJaxrs.getIntf().intForm(null)); - } - - @Test - public void doubleForm_jaxrs_intf() { - assertEquals(defaultDouble, consumersJaxrs.getIntf().doubleForm(null), 0.0); - } - - @Test - public void stringForm_jaxrs_intf() { - assertEquals(defaultStr, consumersJaxrs.getIntf().stringForm(null)); - } - - @Test - public void intForm_jaxrs_rt() { - assertEquals(defaultInt, (int) consumersJaxrs.getSCBRestTemplate().postForObject("/intForm", null, int.class)); - } - - @Test - public void doubleForm_jaxrs_rt() { - assertEquals(defaultDouble, - consumersJaxrs.getSCBRestTemplate().postForObject("/doubleForm", null, double.class), 0.0); - } - - @Test - public void stringForm_jaxrs_rt() { - assertEquals(defaultStr, - consumersJaxrs.getSCBRestTemplate().postForObject("/stringForm", null, String.class)); - } - - @Test - public void intQuery_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intQuery(null)); - } - - @Test - public void doubleQuery_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleQuery(null), 0.0); - } - - @Test - public void stringQuery_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringQuery(null)); - } - - @Test - public void intQuery_springmvc_rt() { - assertEquals(defaultInt, (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intQuery", int.class)); - } - - @Test - public void doubleQuery_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleQuery", double.class), 0.0); - } - - @Test - public void stringQuery_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringQuery", String.class)); - } - - @Test - public void stringQueryRequiredTrue_springmvc_rt() { - try { - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringQueryRequiredTrue", String.class); - assertEquals("required is true, throw exception", "not throw exception"); - } catch (InvocationException e) { - assertEquals(400, e.getStatusCode()); - assertEquals(true, e.getMessage().contains("Parameter is not valid")); - } - } - - @Test - public void intHeader_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intHeader(null)); - } - - @Test - public void doubleHeader_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleHeader(null), 0.0); - } - - @Test - public void stringHeader_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringHeader(null)); - } - - @Test - public void intHeader_springmvc_rt() { - assertEquals(defaultInt, (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intHeader", int.class)); - } - - @Test - public void doubleHeader_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleHeader", double.class), 0.0); - } - - @Test - public void stringHeader_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringHeader", String.class)); - } - - @Test - public void stringHeaderRequiredTrue_springmvc_rt() { - try { - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringHeaderRequiredTrue", String.class); - assertEquals("required is true, throw exception", "not throw exception"); - } catch (InvocationException e) { - assertEquals(400, e.getStatusCode()); - assertEquals(true, e.getMessage().contains("Parameter is not valid")); - } - } - - @Test - public void intForm_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intForm(null)); - } - - @Test - public void doubleForm_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleForm(null), 0.0); - } - - @Test - public void stringForm_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringForm(null)); - } - - @Test - public void intForm_springmvc_rt() { - assertEquals(defaultInt, - (int) consumersSpringmvc.getSCBRestTemplate().postForObject("/intForm", null, int.class)); - } - - @Test - public void doubleForm_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().postForObject("/doubleForm", null, double.class), 0.0); - } - - @Test - public void stringForm_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().postForObject("/stringForm", null, String.class)); - } - - @Test - public void stringFormRequiredTrue_springmvc_rt() { - try { - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringFormRequiredTrue", String.class); - assertEquals("required is true, throw exception", "not throw exception"); - } catch (InvocationException e) { - assertEquals(400, e.getStatusCode()); - assertEquals(true, e.getMessage().contains("Parameter is not valid")); - } - } - - @Test - public void intQuery_require_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intQueryRequire(null)); - } - - @Test - public void doubleQuery_require_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleQueryRequire(null), 0.0); - } - - @Test - public void stringQuery_require_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringQueryRequire(null)); - } - - @Test - public void intQuery_require_springmvc_rt() { - assertEquals(defaultInt, - (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intQueryRequire", int.class)); - } - - @Test - public void doubleQuery_require_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleQueryRequire", double.class), 0.0); - } - - @Test - public void stringQuery_require_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringQueryRequire", String.class)); - } - - @Test - public void intHeader_require_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intHeaderRequire(null)); - } - - @Test - public void doubleHeader_require_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleHeaderRequire(null), 0.0); - } - - @Test - public void stringHeader_require_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringHeaderRequire(null)); - } - - @Test - public void intHeader_require_springmvc_rt() { - assertEquals(defaultInt, - (int) consumersSpringmvc.getSCBRestTemplate().getForObject("/intHeaderRequire", int.class)); - } - - @Test - public void doubleHeader_require_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().getForObject("/doubleHeaderRequire", double.class), 0.0); - } - - @Test - public void stringHeader_require_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().getForObject("/stringHeaderRequire", String.class)); - } - - @Test - public void intForm_require_springmvc_intf() { - assertEquals(defaultInt, consumersSpringmvc.getIntf().intFormRequire(null)); - } - - @Test - public void doubleForm_require_springmvc_intf() { - assertEquals(defaultDouble, consumersSpringmvc.getIntf().doubleFormRequire(null), 0.0); - } - - @Test - public void stringForm_require_springmvc_intf() { - assertEquals(defaultStr, consumersSpringmvc.getIntf().stringFormRequire(null)); - } - - @Test - public void intForm_require_springmvc_rt() { - assertEquals(defaultInt, - (int) consumersSpringmvc.getSCBRestTemplate().postForObject("/intFormRequire", null, int.class)); - } - - @Test - public void doubleForm_require_springmvc_rt() { - assertEquals(defaultDouble, - consumersSpringmvc.getSCBRestTemplate().postForObject("/doubleFormRequire", null, double.class), 0.0); - } - - @Test - public void stringForm_require_springmvc_rt() { - assertEquals(defaultStr, - consumersSpringmvc.getSCBRestTemplate().postForObject("/stringFormRequire", null, String.class)); - } - - //float - @Test - public void floatQuery_jaxrs_intf() { - assertEquals(defaultFloat, consumersJaxrs.getIntf().floatQuery(null), 0.0f); - } - - @Test - public void floatQuery_jaxrs_rt() { - assertEquals(defaultFloat, consumersJaxrs.getSCBRestTemplate().getForObject("/floatQuery", float.class), - 0.0f); - } - - @Test - public void floatHeader_jaxrs_intf() { - assertEquals(defaultFloat, consumersJaxrs.getIntf().floatHeader(null), 0.0f); - } - - @Test - public void floatHeader_jaxrs_rt() { - assertEquals(defaultFloat, - consumersJaxrs.getSCBRestTemplate().getForObject("/floatHeader", float.class), 0.0f); - } - - @Test - public void floatForm_jaxrs_intf() { - assertEquals(defaultFloat, consumersJaxrs.getIntf().floatForm(null), 0.0f); - } - - @Test - public void floatForm_jaxrs_rt() { - assertEquals(defaultFloat, - consumersJaxrs.getSCBRestTemplate().postForObject("/floatForm", null, float.class), 0.0f); - } - - @Test - public void floatQuery_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatQuery(null), 0.0f); - } - - @Test - public void floatQuery_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatQuery", float.class), 0.0f); - } - - @Test - public void floatHeader_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatHeader(null), 0.0f); - } - - @Test - public void floatHeader_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatHeader", float.class), 0.0f); - } - - @Test - public void floatForm_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatForm(null), 0.0f); - } - - @Test - public void floatForm_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().postForObject("/floatForm", null, float.class), 0.0f); - } - - @Test - public void floatQuery_require_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatQueryRequire(null), 0.0f); - } - - @Test - public void floatQuery_require_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatQueryRequire", float.class), 0.0f); - } - - @Test - public void floatHeader_require_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatHeaderRequire(null), 0.0f); - } - - - @Test - public void floatHeader_require_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().getForObject("/floatHeaderRequire", float.class), 0.0f); - } - - @Test - public void floatForm_require_springmvc_intf() { - assertEquals(defaultFloat, consumersSpringmvc.getIntf().floatFormRequire(null), 0.0f); - } - - @Test - public void floatForm_require_springmvc_rt() { - assertEquals(defaultFloat, - consumersSpringmvc.getSCBRestTemplate().postForObject("/floatFormRequire", null, float.class), 0.0f); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownload.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownload.java deleted file mode 100644 index a370e4953fc..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownload.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.apache.commons.io.FileUtils; -import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.it.testcase.support.DownloadSchemaIntf; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; - -import com.google.common.collect.Iterables; - -public class TestDownload { - private File dir = new File("target/download"); - - private static Consumers consumers = new Consumers<>("download", - DownloadSchemaIntf.class); - - private List> futures = new ArrayList<>(); - - private String content = "file content"; - - public TestDownload() { - FileUtils.deleteQuietly(dir); - } - - private String readFileToString(File file) { - try { - return FileUtils.readFileToString(file); - } catch (IOException e) { - return "read file failed:" + e.getMessage(); - } - } - - private CompletableFuture checkFile(ReadStreamPart part) { - CompletableFuture future = part.saveToFile("target/download/" - + UUID.randomUUID().toString() - + "-" - + part.getSubmittedFileName()); - return checkFuture(future); - } - - private String getStackTrace(Throwable e) { - StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - return writer.toString(); - } - - private CompletableFuture checkFuture(CompletableFuture future) { - Error error = new Error(); - future.whenComplete((result, e) -> { - Object value = result; - if (File.class.isInstance(value)) { - File file = (File) value; - value = readFileToString(file); - file.delete(); - } else if (byte[].class.isInstance(value)) { - value = new String((byte[]) value); - } - - Assert.assertEquals(getStackTrace(error), content, value); - }); - - return future; - } - - private ReadStreamPart templateGet(String methodPath) { - return consumers.getSCBRestTemplate() - .getForObject("/" + methodPath + "?content={content}", - ReadStreamPart.class, - content); - } - - private ReadStreamPart templateExchange(String methodPath, String type) { - HttpHeaders headers = new HttpHeaders(); - headers.add("accept", type); - HttpEntity entity = new HttpEntity<>(headers); - ResponseEntity response = consumers.getSCBRestTemplate() - .exchange("/" + methodPath + "?content={content}", - HttpMethod.GET, - entity, - ReadStreamPart.class, content); - return response.getBody(); - } - - @Test - @SuppressWarnings("unchecked") - public void runRest() { - futures.add(checkFile(consumers.getIntf().tempFileEntity(content))); - futures.add(checkFuture(templateGet("tempFileEntity").saveAsBytes())); - futures.add(checkFuture(templateExchange("tempFileEntity", MediaType.TEXT_PLAIN_VALUE).saveAsBytes())); - futures.add(checkFuture(templateExchange("tempFileEntity", MediaType.APPLICATION_JSON_VALUE).saveAsBytes())); - - futures.add(checkFile(consumers.getIntf().tempFilePart(content))); - futures.add(checkFuture(templateGet("tempFilePart").saveAsString())); - futures.add(checkFuture(templateExchange("tempFilePart", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("tempFilePart", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - futures.add(checkFile(consumers.getIntf().file(content))); - futures.add(checkFuture(templateGet("file").saveAsString())); - futures.add(checkFuture(templateExchange("file", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("file", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - { - ReadStreamPart part = consumers.getIntf().chineseAndSpaceFile(content); - Assert.assertEquals("测 试.test.txt", part.getSubmittedFileName()); - futures.add(checkFile(part)); - - part = templateGet("chineseAndSpaceFile"); - Assert.assertEquals("测 试.test.txt", part.getSubmittedFileName()); - futures.add(checkFuture(part.saveAsString())); - - ReadStreamPart part2 = templateExchange("chineseAndSpaceFile", MediaType.TEXT_PLAIN_VALUE); - Assert.assertEquals("测 试.test.txt", part2.getSubmittedFileName()); - futures.add(checkFuture(part2.saveAsString())); - - ReadStreamPart part3 = templateExchange("chineseAndSpaceFile", MediaType.APPLICATION_JSON_VALUE); - Assert.assertEquals("测 试.test.txt", part3.getSubmittedFileName()); - futures.add(checkFuture(part3.saveAsString())); - } - - futures.add(checkFile(consumers.getIntf().resource(content))); - futures.add(checkFuture(templateGet("resource").saveAsString())); - futures.add(checkFuture(templateExchange("resource", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("resource", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - futures.add(checkFile(consumers.getIntf().entityResource(content))); - futures.add(checkFuture(templateGet("entityResource").saveAsString())); - futures.add(checkFuture(templateExchange("entityResource", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("entityResource", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - futures.add(checkFile(consumers.getIntf().entityInputStream(content))); - futures.add(checkFuture(templateGet("entityInputStream").saveAsString())); - futures.add(checkFuture(templateExchange("entityInputStream", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("entityInputStream", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - futures.add(checkFile(consumers.getIntf().bytes(content))); - futures.add(checkFuture(templateGet("bytes").saveAsString())); - futures.add(checkFuture(templateExchange("bytes", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("bytes", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - futures.add(checkFile(consumers.getIntf().netInputStream(content))); - futures.add(checkFuture(templateGet("netInputStream").saveAsString())); - futures.add(checkFuture(templateExchange("netInputStream", MediaType.TEXT_PLAIN_VALUE).saveAsString())); - futures.add(checkFuture(templateExchange("netInputStream", MediaType.APPLICATION_JSON_VALUE).saveAsString())); - - try { - CompletableFuture - .allOf(Iterables.toArray((List>) (Object) futures, CompletableFuture.class)) - .get(); - } catch (InterruptedException | ExecutionException e1) { - Assert.fail("test download failed: " + getStackTrace(e1)); - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java deleted file mode 100644 index 8c9cfa5545d..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import java.io.IOException; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Test; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -public class TestDownloadSlowStreamEdge { - static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("download"); - - @Test - public void clearInputStreamAfterDisconnect() throws IOException { -// URL url = new URL(client.getUrlPrefix() + "/slowInputStream"); -// HttpURLConnection conn = (HttpURLConnection) url.openConnection(); -// conn.getInputStream().close(); -// conn.disconnect(); - - OkHttpClient httpClient = new OkHttpClient(); - Request request = new Request.Builder().url(client.getUrlPrefix() + "/slowInputStream") - .build(); - Response response = httpClient.newCall(request).execute(); - - response.body().byteStream(); - response.body().close(); - - client.getForObject("/waitSlowInputStreamClosed", Void.class); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestExceptionConvertEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestExceptionConvertEdge.java deleted file mode 100644 index d022c271112..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestExceptionConvertEdge.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpStatus; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestClientException; - -public class TestExceptionConvertEdge { - private static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("edgeExceptionConvertSchema"); - - @Test - public void testTimeoutAdd() { - int result = client.getForObject("/add?x=10&y=12", Integer.class); - Assert.assertEquals(22, result); - - try { - client.getForObject("/add?x=88&y=21", Object.class); - } catch (RestClientException e) { - HttpClientErrorException exception = (HttpClientErrorException) e; - Assert.assertEquals(HttpStatus.EXPECTATION_FAILED, exception.getStatusCode()); - Assert.assertTrue(exception.getResponseBodyAsString().contains("change the response")); - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestGenericEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestGenericEdge.java deleted file mode 100644 index f20380b8a9a..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestGenericEdge.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.apache.servicecomb.it.schema.Generic; -import org.apache.servicecomb.it.schema.User; -import org.junit.Test; - -public class TestGenericEdge { - private static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("generic"); - - @Test - public void testGenericMap() { - Generic> mapGeneric = new Generic<>(); - Map map = new HashMap<>(); - map.put("test", "hello"); - mapGeneric.value = map; - @SuppressWarnings("unchecked") - Generic> result = client.postForObject("/genericMap", mapGeneric, Generic.class); - String test = result.value.get("test"); - assertEquals(test, "hello"); - } - - @Test - public void testGenericMapList() { - Generic>> mapListGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add("hello"); - map.put("test", list); - mapListGeneric.value = map; - @SuppressWarnings("unchecked") - Generic>> result = client.postForObject("/genericMapList", mapListGeneric, Generic.class); - String test = result.value.get("test").get(0); - assertEquals("hello", test); - } - - @Test - public void testGenericUser() { - Generic generic = new Generic<>(); - generic.value = new User(); - @SuppressWarnings("unchecked") - Generic> result = client.postForObject("/genericUser", generic, Generic.class); - Map resultUser = result.value; - assertEquals("nameA", resultUser.get("name")); - assertEquals(100, resultUser.get("age")); - } - - @Test - @SuppressWarnings("unchecked") - public void testGenericMapListUser() { - Generic>> mapListUserGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add(new User()); - map.put("test", list); - mapListUserGeneric.value = map; - - Generic>>> result = client - .postForObject("/genericMapListUser", mapListUserGeneric, Generic.class); - Map resultUser = result.value.get("test").get(0); - - assertEquals("nameA", resultUser.get("name")); - assertEquals(100, resultUser.get("age")); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreMethod.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreMethod.java deleted file mode 100644 index 5a836d46286..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreMethod.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.junit.Assert; -import org.junit.Test; - -public class TestIgnoreMethod { - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - - @Test - public void ignoreMethodPojo_apiOperation() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreMethodPojo"); - Assert.assertNull(schemaMeta.findOperation("hideByApiOperation")); - } - - @Test - public void ignoreMethodJaxrs_apiOperation() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreMethodJaxrs"); - Assert.assertNull(schemaMeta.findOperation("hideByApiOperation")); - } - - @Test - public void ignoreMethodSpringmvc_apiOperation() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreMethodSpringmvc"); - Assert.assertNull(schemaMeta.findOperation("hideByApiOperation")); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreStaticMethod.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreStaticMethod.java deleted file mode 100644 index cfa613d32b1..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestIgnoreStaticMethod.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.junit.Assert; -import org.junit.Test; - -public class TestIgnoreStaticMethod { - private MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - - @Test - public void ignoreStaticMethod_pojo() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreStaticMethodPojoSchema"); - OperationMeta add = schemaMeta.findOperation("add"); - Assert.assertNotNull(add); - - OperationMeta sub = schemaMeta.findOperation("staticSub"); - Assert.assertNull(sub); - } - - - @Test - public void ignoreStaticMethod_Jaxrs() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreStaticMethodJaxrsSchema"); - OperationMeta add = schemaMeta.findOperation("add"); - Assert.assertNotNull(add); - - OperationMeta sub = schemaMeta.findOperation("staticSub"); - Assert.assertNull(sub); - } - - @Test - public void ignoreStaticMethod_Springmvc() { - SchemaMeta schemaMeta = microserviceMeta.findSchemaMeta("ignoreStaticMethodSpringmvcSchema"); - OperationMeta add = schemaMeta.findOperation("add"); - Assert.assertNotNull(add); - - OperationMeta sub = schemaMeta.findOperation("staticSub"); - Assert.assertNull(sub); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodec.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodec.java deleted file mode 100644 index 8a2bc252ce8..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodec.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.it.Consumers; -import org.junit.Test; - -public class TestParamCodec { - interface ParamCodecSchemaIntf { - String spaceCharCodec(String pathVal, String q); - } - - static Consumers consumers = new Consumers<>("paramCodec", ParamCodecSchemaIntf.class); - - @Test - public void spaceCharEncode_intf() { - String paramString = "a%2B+%20b%% %20c"; - String result = consumers.getIntf().spaceCharCodec(paramString, paramString); - assertEquals(paramString + " +%20%% " + paramString + " true", result); - } - - @Test - public void spaceCharEncode_rt() { - String paramString = "a%2B+%20b%% %20c"; - String result = consumers.getSCBRestTemplate() - .getForObject("/spaceCharCodec/" + paramString + "?q=" + paramString, String.class); - assertEquals(paramString + " +%20%% " + paramString + " true", result); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodecEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodecEdge.java deleted file mode 100644 index 408efe023d2..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestParamCodecEdge.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Test; - -public class TestParamCodecEdge { - static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("paramCodec"); - - @Test - public void spaceCharEncode() { - String paramString = "a%2B+%20b%% %20c"; - String result = client.getForObject("/spaceCharCodec/" + paramString + "?q=" + paramString, String.class); - assertEquals(paramString + " +%20%% " + paramString + " true", result); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRequestBodySpringMvcSchema.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRequestBodySpringMvcSchema.java deleted file mode 100644 index f630611fdc4..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRequestBodySpringMvcSchema.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -public class TestRequestBodySpringMvcSchema { - private static GateRestTemplate edgeClient = GateRestTemplate.createEdgeRestTemplate("requestBodySpringMvcSchema"); - - @Test - public void basicRequestResponse() { - basicRequestResponseImpl(); - basicRequestResponseImpl(); - basicRequestResponseImpl(); - } - - @Test - public void testDefaultForPremitive() { - testDefaultForPremitiveImpl(); - testDefaultForPremitiveImpl(); - testDefaultForPremitiveImpl(); - } - - private void testDefaultForPremitiveImpl() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - Map request = new HashMap<>(); - request.put("integerType", 100); - request.put("message", "hi"); - request.put("catalog", 100); - request.put("extendedMessage", "hi"); - - HttpEntity> entity = new HttpEntity<>(request, headers); - @SuppressWarnings("unchecked") - Map result = - edgeClient.postForObject("/base", entity, Map.class); - Assert.assertEquals(result.size(), 6); - Assert.assertEquals(result.get("type"), 0); - Assert.assertEquals(result.get("integerType"), request.get("integerType")); - Assert.assertEquals(result.get("message"), request.get("message")); - Assert.assertEquals(result.get("catalog"), request.get("catalog")); - Assert.assertEquals(result.get("integerCatalog"), null); - Assert.assertEquals(result.get("extendedMessage"), request.get("extendedMessage")); - } - - private void basicRequestResponseImpl() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - Map request = new HashMap<>(); - request.put("type", 100); - request.put("integerType", 100); - request.put("message", "hi"); - request.put("catalog", 100); - request.put("integerCatalog", 100); - request.put("extendedMessage", "hi"); - - HttpEntity> entity = new HttpEntity<>(request, headers); - @SuppressWarnings("unchecked") - Map result = - edgeClient.postForObject("/base", entity, Map.class); - Assert.assertEquals(result.size(), request.size()); - Assert.assertEquals(result.get("type"), request.get("type")); - Assert.assertEquals(result.get("integerType"), request.get("integerType")); - Assert.assertEquals(result.get("message"), request.get("message")); - Assert.assertEquals(result.get("catalog"), request.get("catalog")); - Assert.assertEquals(result.get("integerCatalog"), request.get("integerCatalog")); - Assert.assertEquals(result.get("extendedMessage"), request.get("extendedMessage")); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestController.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestController.java deleted file mode 100644 index 722a4391313..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestController.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.it.extend.engine.ITSCBRestTemplate; -import org.junit.Assert; -import org.junit.Test; - -public class TestRestController { - private static ITSCBRestTemplate restControllerSchemaClient = new ITSCBRestTemplate - ("org.apache.servicecomb.it.schema.RestControllerSchema"); - - private static ITSCBRestTemplate restControllerEmptyMappingSchemaClient = new ITSCBRestTemplate - ("org.apache.servicecomb.it.schema.RestControllerEmptyMappingSchema"); - - private static ITSCBRestTemplate restControllerWithRequestMappingSchemaClient = new ITSCBRestTemplate - ("org.apache.servicecomb.it.schema.RestControllerWithRequestMappingSchema"); - - private static ITSCBRestTemplate restControllerWithRestSchemaSchemaClient = new ITSCBRestTemplate - ("RestControllerWithRestSchemaSchema"); - - @Test - public void restControllerSchemaClient() { - Assert.assertEquals("/", restControllerSchemaClient.getBasePath()); - int result = restControllerSchemaClient.getForObject("/restControllerSchemaQuery?input=2", int.class); - Assert.assertEquals(2, result); - } - - @Test - public void restControllerEmptyMappingSchemaClient() { - // empty path default to class name(@RequestMapping(path = "")). Shall we change this behavior in future? - Assert.assertEquals("/RestControllerEmptyMappingSchema", restControllerEmptyMappingSchemaClient.getBasePath()); - int result = restControllerEmptyMappingSchemaClient - .getForObject("/restControllerEmptyMappingSchemaQuery?input=2", int.class); - Assert.assertEquals(2, result); - } - - @Test - public void restControllerWithRequestMappingSchemaClient() { - Assert.assertEquals("/restControllerWithRequest", restControllerWithRequestMappingSchemaClient.getBasePath()); - int result = restControllerWithRequestMappingSchemaClient - .getForObject("/restControllerWithRequestMappingSchemaQuery?input=2", int.class); - Assert.assertEquals(2, result); - } - - @Test - public void restControllerWithRestSchemaSchemaClient() { - Assert.assertEquals("/restControllerWithRestSchemaSchema", restControllerWithRestSchemaSchemaClient.getBasePath()); - int result = restControllerWithRestSchemaSchemaClient - .getForObject("/restControllerWithRestSchemaSchemaQuery?input=2", int.class); - Assert.assertEquals(2, result); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfig.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfig.java deleted file mode 100644 index 9adfb2181c4..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfig.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.base.Strings; - -public class TestRestServerConfig { - // GET /v1/restServerConfig/testMaxInitialLineLength?q=...... HTTP/1.1 - private static final String INITIAL_LINE_SUFFIX = " HTTP/1.1"; - - private static final String INITIAL_LINE_PREFIX = "GET /v1/restServerConfig/testMaxInitialLineLength?q="; - - interface RestServerConfigSchemaIntf { - String testMaxInitialLineLength(String q); - } - - static Consumers consumers = new Consumers<>("restServerConfig", - RestServerConfigSchemaIntf.class); - - /** - * Max initial line length is set to 5000 - */ - @Test - public void testMaxInitialLineLength5000() { - String q = Strings.repeat("q", 5000 - INITIAL_LINE_PREFIX.length() - INITIAL_LINE_SUFFIX.length()); - String result = consumers.getIntf().testMaxInitialLineLength(q); - Assert.assertEquals("OK", result); - } - - @Test - public void testMaxInitialLineLength5001() { - String q = Strings.repeat("q", 5001 - INITIAL_LINE_PREFIX.length() - INITIAL_LINE_SUFFIX.length()); - try { - consumers.getIntf().testMaxInitialLineLength(q); - Assert.fail("an exception is expected!"); - } catch (InvocationException e) { - Assert.assertEquals(414, e.getStatusCode()); - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfigEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfigEdge.java deleted file mode 100644 index d2e24484d1e..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestRestServerConfigEdge.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Scanner; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestClientException; - -public class TestRestServerConfigEdge { - static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("dataTypeJaxrs"); - - @Test - public void testIllegalPathParam() throws IOException { - String paramString = "%%A"; - String requestUri = client.getUrlPrefix() + "/intPath/" + paramString; - - URL url = new URL(requestUri); - HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); - - String errorBody = null; - int responseCode = urlConnection.getResponseCode(); - String responseMessage = urlConnection.getResponseMessage(); - try (Scanner scanner = new Scanner(urlConnection.getErrorStream())) { - errorBody = scanner.nextLine(); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - urlConnection.disconnect(); - - assertEquals(400, responseCode); - assertEquals("Bad Request", responseMessage); - assertEquals("Bad Request", errorBody); - } - - @Test - public void test404ThrownByServicCombNotConvertedTo500() { - String notFoundRequestUri = client.getUrlPrefix() + "/intPath2/123"; - - try { - client.getForEntity(notFoundRequestUri, int.class); - fail("an exception is expected!"); - } catch (RestClientException e) { - Assert.assertEquals(404, ((HttpClientErrorException) e).getRawStatusCode()); - Assert.assertEquals("CommonExceptionData [message=Not Found]", ((HttpClientErrorException) e).getStatusText()); - } - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTrace.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTrace.java deleted file mode 100644 index df4a6ad2a4a..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTrace.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestTrace { - interface TraceSchemaIntf { - CompletableFuture echoProxy(); - } - - static Consumers consumers = new Consumers<>("trace", TraceSchemaIntf.class); - - @BeforeClass - public static void classSetup() { - InvocationContext context = new InvocationContext(); - context.addContext(Const.TRACE_ID_NAME, "testId"); - ContextUtils.setInvocationContext(context); - } - - @AfterClass - public static void classTeardown() { - ContextUtils.removeInvocationContext(); - } - - @Test - public void echo_intf() throws ExecutionException, InterruptedException { - String traceId = consumers.getIntf().echoProxy().get(); - Assert.assertEquals("testId", traceId); - } - - @Test - public void echo_rt() { - String traceId = consumers.getSCBRestTemplate().getForObject("/echo-proxy", String.class); - Assert.assertEquals("testId", traceId); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTraceEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTraceEdge.java deleted file mode 100644 index 06b08bfebf9..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestTraceEdge.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; - -public class TestTraceEdge { - static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("trace"); - - @Test - public void echo() { - HttpHeaders headers = new HttpHeaders(); - headers.add(Const.TRACE_ID_NAME, "testId"); - - HttpEntity requestEntity = new HttpEntity<>(null, headers); - - String traceId = client.exchange("/echo-proxy", HttpMethod.GET, requestEntity, String.class).getBody(); - Assert.assertEquals("testId", traceId); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/base/TestGeneric.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/base/TestGeneric.java deleted file mode 100644 index 276bd3721a4..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/base/TestGeneric.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase.base; - -import static org.junit.Assert.assertEquals; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.it.Consumers; -import org.apache.servicecomb.it.schema.Generic; -import org.apache.servicecomb.it.schema.User; -import org.junit.Test; -import org.springframework.http.HttpStatus; - -public class TestGeneric { - interface GenericIntf { - Holder holderUser(Holder input); - - Generic genericUser(Generic input); - - Generic genericLong(Generic input); - - Generic genericDate(Generic input); - - Generic genericEnum(Generic input); - - Generic> genericGenericUser(Generic> input); - - Generic> genericMap(Generic> mapGeneric); - - Generic>> genericMapList(Generic>> mapListGeneric); - - Generic>> genericMapListUser(Generic>> mapListUserGeneric); - } - - private static Consumers consumers = new Consumers<>("generic", GenericIntf.class); - - private String expectUserStr = "{\"name\":\"nameA\",\"age\":100,\"index\":0,\"names\":null}"; - - private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - - @Test - public void testHolderUser_intf() { - Holder holder = new Holder<>(new User()); - Holder result = consumers.getIntf().holderUser(holder); - assertEquals(result.value.jsonString(), expectUserStr); - } - - @Test - public void testHolderUser_rt() { - Holder holder = new Holder<>(new User()); - @SuppressWarnings("unchecked") - Holder result = consumers.getSCBRestTemplate().postForObject("/holderUser", holder, Holder.class); - assertEquals(result.value.jsonString(), expectUserStr); - } - - @Test - public void testGenericUser_intf() { - Generic generic = new Generic<>(); - generic.value = new User(); - - Generic result = consumers.getIntf().genericUser(generic); - assertEquals(result.value.jsonString(), expectUserStr); - } - - @Test - public void testGenericUser_rt() { - Generic generic = new Generic<>(); - generic.value = new User(); - @SuppressWarnings("unchecked") - Generic result = consumers.getSCBRestTemplate().postForObject("/genericUser", generic, Generic.class); - assertEquals(result.value.jsonString(), expectUserStr); - } - - @Test - public void testGenericLong_intf() { - Generic generic = new Generic<>(); - generic.value = 100L; - Generic result = consumers.getIntf().genericLong(generic); - assertEquals(Long.class, result.value.getClass()); - assertEquals(100L, (long) result.value); - } - - @Test - public void testGenericLong_rt() { - Generic generic = new Generic<>(); - generic.value = 100L; - @SuppressWarnings("unchecked") - Generic result = consumers.getSCBRestTemplate().postForObject("/genericLong", generic, Generic.class); - assertEquals(Long.class, result.value.getClass()); - assertEquals(100L, (long) result.value); - } - - @Test - public void testGenericDate_intf() { - Generic generic = new Generic<>(); - generic.value = new Date(1001); - Generic result = consumers.getIntf().genericDate(generic); - assertEquals(result.value.getClass(), Date.class); - simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - assertEquals("1970-01-01T00:00:01.001Z", simpleDateFormat.format(result.value)); - } - - @Test - public void testGenericDate_rt() { - Generic generic = new Generic<>(); - generic.value = new Date(1001); - @SuppressWarnings("unchecked") - Generic result = consumers.getSCBRestTemplate().postForObject("/genericDate", generic, Generic.class); - assertEquals(result.value.getClass(), Date.class); - simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - assertEquals("1970-01-01T00:00:01.001Z", simpleDateFormat.format(result.value)); - } - - @Test - public void testGenericEnum_intf() { - Generic generic = new Generic<>(); - generic.value = HttpStatus.OK; - - Generic result = consumers.getIntf().genericEnum(generic); - assertEquals(HttpStatus.class, result.value.getClass()); - assertEquals(HttpStatus.OK, result.value); - } - - @Test - public void testGenericEnum_rt() { - Generic generic = new Generic<>(); - generic.value = HttpStatus.OK; - @SuppressWarnings("unchecked") - Generic result = consumers.getSCBRestTemplate().postForObject("/genericEnum", generic, Generic.class); - assertEquals(HttpStatus.class, result.value.getClass()); - assertEquals(HttpStatus.OK, result.value); - } - - @Test - public void testGenericGenericUser_intf() { - Generic> generic = new Generic<>(); - generic.value = new Generic<>(); - generic.value.value = new User(); - - Generic> result = consumers.getIntf().genericGenericUser(generic); - assertEquals(result.value.value.jsonString(), expectUserStr); - } - - @Test - public void testGenericGenericUser_rt() { - Generic> generic = new Generic<>(); - generic.value = new Generic<>(); - generic.value.value = new User(); - @SuppressWarnings("unchecked") - Generic> result = consumers.getSCBRestTemplate() - .postForObject("/genericGenericUser", generic, Generic.class); - assertEquals(result.value.value.jsonString(), expectUserStr); - } - - @Test - public void testGenericMap_intf() { - Generic> mapGeneric = new Generic<>(); - Map map = new HashMap<>(); - map.put("test", "hello"); - mapGeneric.value = map; - Generic> result = consumers.getIntf().genericMap(mapGeneric); - String test = result.value.get("test"); - assertEquals(test, "hello"); - } - - @Test - public void testGenericMap_rt() { - Generic> mapGeneric = new Generic<>(); - Map map = new HashMap<>(); - map.put("test", "hello"); - mapGeneric.value = map; - @SuppressWarnings("unchecked") - Generic> result = consumers.getSCBRestTemplate() - .postForObject("/genericMap", mapGeneric, Generic.class); - String test = result.value.get("test"); - assertEquals(test, "hello"); - } - - @Test - public void testGenericListMap_intf() { - Generic>> mapListGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add("hello"); - map.put("test", list); - mapListGeneric.value = map; - Generic>> result = consumers.getIntf().genericMapList(mapListGeneric); - String test = result.value.get("test").get(0); - assertEquals(test, "hello"); - } - - @Test - public void testGenericListMap_rt() { - Generic>> mapListGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add("hello"); - map.put("test", list); - mapListGeneric.value = map; - @SuppressWarnings("unchecked") - Generic>> result = consumers.getSCBRestTemplate() - .postForObject("/genericMapList", mapListGeneric, Generic.class); - String test = result.value.get("test").get(0); - assertEquals(test, "hello"); - } - - @Test - public void testGenericListUserMap_intf() { - Generic>> mapListUserGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add(new User()); - map.put("test", list); - mapListUserGeneric.value = map; - Generic>> result = consumers.getIntf().genericMapListUser(mapListUserGeneric); - String test = result.value.get("test").get(0).jsonString(); - assertEquals(test, expectUserStr); - } - - @Test - public void testGenericListUserMap_rt() { - Generic>> mapListUserGeneric = new Generic<>(); - Map> map = new HashMap<>(); - List list = new ArrayList<>(); - list.add(new User()); - map.put("test", list); - mapListUserGeneric.value = map; - @SuppressWarnings("unchecked") - Generic>> result = consumers.getSCBRestTemplate() - .postForObject("/genericMapListUser", mapListUserGeneric, Generic.class); - String test = result.value.get("test").get(0).jsonString(); - assertEquals(test, expectUserStr); - } -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/support/DownloadSchemaIntf.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/support/DownloadSchemaIntf.java deleted file mode 100644 index 9bc373ff440..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/support/DownloadSchemaIntf.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.testcase.support; - -import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; - -public interface DownloadSchemaIntf { - ReadStreamPart tempFileEntity(String content); - - ReadStreamPart tempFilePart(String content); - - ReadStreamPart file(String content); - - ReadStreamPart chineseAndSpaceFile(String content); - - ReadStreamPart resource(String content); - - ReadStreamPart entityResource(String content); - - ReadStreamPart entityInputStream(String content); - - ReadStreamPart bytes(String content); - - ReadStreamPart netInputStream(String content); -} diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/thirdparty/Test3rdPartyInvocation.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/thirdparty/Test3rdPartyInvocation.java deleted file mode 100644 index c0086c591f0..00000000000 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/thirdparty/Test3rdPartyInvocation.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.testcase.thirdparty; - -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.it.extend.engine.GateRestTemplate; -import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.web.client.RestTemplate; - -public class Test3rdPartyInvocation { - - private static final String THIRD_PARTY_MICROSERVICE_NAME = "3rdPartyDataTypeJaxrs"; - - private static final String ASYNC_THIRD_PARTY_MICROSERVICE_NAME = THIRD_PARTY_MICROSERVICE_NAME + "Async"; - - // to get endpoint from urlPrefix - static GateRestTemplate rt = GateRestTemplate.createEdgeRestTemplate("dataTypeJaxrs"); - - private static DataTypeJaxrsSchemaIntf dataTypeJaxrsSchema; - - private static DataTypeJaxrsSchemaAsyncIntf dataTypeJaxrsSchemaAsync; - - @BeforeClass - public static void beforeClass() { - String urlPrefix = rt.getUrlPrefix(); - int beginIndex = urlPrefix.indexOf("//"); - int endIndex = urlPrefix.indexOf("/", beginIndex + 3); - String endpoint = "rest:" + urlPrefix.substring(beginIndex, endIndex); - RegistryUtils.getServiceRegistry() - .registerMicroserviceMappingByEndpoints( - THIRD_PARTY_MICROSERVICE_NAME, "1.2.1", - Collections.singletonList(endpoint), - DataTypeJaxrsSchemaIntf.class); - - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setEndpoints(Collections.singletonList(endpoint)); - RegistryUtils.getServiceRegistry() - .registerMicroserviceMapping( - ASYNC_THIRD_PARTY_MICROSERVICE_NAME, "1.1.1", - Collections.singletonList(instance), - DataTypeJaxrsSchemaAsyncIntf.class - ); - - dataTypeJaxrsSchema = Invoker.createProxy( - THIRD_PARTY_MICROSERVICE_NAME, THIRD_PARTY_MICROSERVICE_NAME, DataTypeJaxrsSchemaIntf.class); - dataTypeJaxrsSchemaAsync = Invoker.createProxy( - ASYNC_THIRD_PARTY_MICROSERVICE_NAME, ASYNC_THIRD_PARTY_MICROSERVICE_NAME, DataTypeJaxrsSchemaAsyncIntf.class); - } - - @Test - public void testSyncInvoke_RPC() { - Assert.assertEquals(1, dataTypeJaxrsSchema.intPath(1)); - Assert.assertEquals(2, dataTypeJaxrsSchema.intQuery(2)); - Assert.assertEquals(3, dataTypeJaxrsSchema.intHeader(3)); - Assert.assertEquals(4, dataTypeJaxrsSchema.intCookie(4)); - Assert.assertEquals(5, dataTypeJaxrsSchema.intForm(5)); - Assert.assertEquals(6, dataTypeJaxrsSchema.intBody(6)); - Assert.assertEquals(7, dataTypeJaxrsSchema.intAdd(3, 4)); - Assert.assertEquals("abc", dataTypeJaxrsSchema.stringPath("abc")); - Assert.assertEquals("def", dataTypeJaxrsSchema.stringQuery("def")); - Assert.assertEquals("ghi", dataTypeJaxrsSchema.stringHeader("ghi")); - Assert.assertEquals("jkl", dataTypeJaxrsSchema.stringCookie("jkl")); - Assert.assertEquals("mn", dataTypeJaxrsSchema.stringForm("mn")); - Assert.assertEquals("opq", dataTypeJaxrsSchema.stringBody("opq")); - Assert.assertEquals("uvwxyz", dataTypeJaxrsSchema.stringConcat("uvw", "xyz")); - } - - @Test - public void testAsyncInvoke_RPC() throws ExecutionException, InterruptedException { - Holder addChecked = new Holder<>(false); - dataTypeJaxrsSchemaAsync.intAdd(5, 6).whenComplete((result, t) -> { - Assert.assertEquals(11, result.intValue()); - Assert.assertNull(t); - addChecked.value = true; - }).get(); - Assert.assertTrue(addChecked.value); - - Holder postStringChecked = new Holder<>(false); - dataTypeJaxrsSchemaAsync.stringBody("abc").whenComplete((result, t) -> { - Assert.assertEquals("abc", result); - Assert.assertNull(t); - postStringChecked.value = true; - }).get(); - Assert.assertTrue(postStringChecked.value); - - Holder concatChecked = new Holder<>(false); - dataTypeJaxrsSchemaAsync.stringConcat("uvw", "xyz").whenComplete((result, t) -> { - Assert.assertEquals("uvwxyz", result); - Assert.assertNull(t); - concatChecked.value = true; - }).get(); - Assert.assertTrue(concatChecked.value); - } - - @Test - public void testSyncInvoke_RestTemplate() { - RestTemplate restTemplate = RestTemplateBuilder.create(); - ResponseEntity responseEntity = restTemplate - .getForEntity( - "cse://" + THIRD_PARTY_MICROSERVICE_NAME + "/rest/it-producer/v1/dataTypeJaxrs/intAdd?num1=11&num2=22", - int.class); - Assert.assertEquals(200, responseEntity.getStatusCodeValue()); - Assert.assertEquals(33, responseEntity.getBody().intValue()); - - ResponseEntity stringBodyResponse = restTemplate - .exchange("cse://" + THIRD_PARTY_MICROSERVICE_NAME + "/rest/it-producer/v1/dataTypeJaxrs/stringBody", - HttpMethod.POST, - new HttpEntity<>("abc"), String.class); - Assert.assertEquals(200, stringBodyResponse.getStatusCodeValue()); - Assert.assertEquals("abc", stringBodyResponse.getBody()); - } - - @Test - public void testAsyncInvoke_RestTemplate() throws ExecutionException, InterruptedException { - CseAsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate(); - ListenableFuture> responseFuture = cseAsyncRestTemplate - .getForEntity( - "cse://" + ASYNC_THIRD_PARTY_MICROSERVICE_NAME - + "/rest/it-producer/v1/dataTypeJaxrs/intAdd?num1=11&num2=22", - Integer.class); - ResponseEntity responseEntity = responseFuture.get(); - Assert.assertEquals(200, responseEntity.getStatusCodeValue()); - Assert.assertEquals(33, responseEntity.getBody().intValue()); - - ListenableFuture> stringBodyFuture = cseAsyncRestTemplate - .exchange("cse://" + ASYNC_THIRD_PARTY_MICROSERVICE_NAME + "/rest/it-producer/v1/dataTypeJaxrs/stringBody", - HttpMethod.POST, - new HttpEntity<>("abc"), String.class); - ResponseEntity stringBodyResponse = stringBodyFuture.get(); - Assert.assertEquals(200, stringBodyResponse.getStatusCodeValue()); - Assert.assertEquals("abc", stringBodyResponse.getBody()); - } - - @Path("/rest/it-producer/v1/dataTypeJaxrs") - interface DataTypeJaxrsSchemaIntf { - @Path("intPath/{input}") - @GET - int intPath(@PathParam("input") int input); - - @Path("intQuery") - @GET - int intQuery(@QueryParam("input") int input); - - @Path("intHeader") - @GET - int intHeader(@HeaderParam("input") int input); - - @Path("intCookie") - @GET - int intCookie(@CookieParam("input") int input); - - @Path("intForm") - @POST - int intForm(@FormParam("input") int input); - - @Path("intBody") - @POST - int intBody(int input); - - @Path("intAdd") - @GET - int intAdd(@QueryParam("num1") int num1, @QueryParam("num2") int num2); - - //strinnum1 - @Path("stringPath/{input}") - @GET - String stringPath(@PathParam("input") String input); - - @Path("stringQuery") - @GET - String stringQuery(@QueryParam("input") String input); - - @Path("stringHeader") - @GET - String stringHeader(@HeaderParam("input") String input); - - @Path("stringCookie") - @GET - String stringCookie(@CookieParam("input") String input); - - @Path("stringForm") - @POST - String stringForm(@FormParam("input") String input); - - @Path("stringBody") - @POST - String stringBody(String input); - - @Path("stringConcat") - @GET - String stringConcat(@QueryParam("str1") String str1, @QueryParam("str2") String str2); - } - - @Path("/rest/it-producer/v1/dataTypeJaxrs") - interface DataTypeJaxrsSchemaAsyncIntf { - @Path("intAdd") - @GET - CompletableFuture intAdd(@QueryParam("num1") int num1, @QueryParam("num2") int num2); - - @Path("stringBody") - @POST - CompletableFuture stringBody(String input); - - @Path("stringConcat") - @GET - CompletableFuture stringConcat(@QueryParam("str1") String str1, @QueryParam("str2") String str2); - } -} diff --git a/integration-tests/it-consumer/src/main/resources/certificates/server.p12 b/integration-tests/it-consumer/src/main/resources/certificates/server.p12 deleted file mode 100644 index 631313ec650..00000000000 Binary files a/integration-tests/it-consumer/src/main/resources/certificates/server.p12 and /dev/null differ diff --git a/integration-tests/it-consumer/src/main/resources/certificates/trust.jks b/integration-tests/it-consumer/src/main/resources/certificates/trust.jks deleted file mode 100644 index 57aeff73332..00000000000 Binary files a/integration-tests/it-consumer/src/main/resources/certificates/trust.jks and /dev/null differ diff --git a/integration-tests/it-consumer/src/main/resources/microservice.yaml b/integration-tests/it-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index 387fcb332bd..00000000000 --- a/integration-tests/it-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -service_description: - name: it-consumer diff --git a/integration-tests/it-consumer/src/test/java/org/apache/servicecomb/it/TestMain.java b/integration-tests/it-consumer/src/test/java/org/apache/servicecomb/it/TestMain.java deleted file mode 100644 index ce4b42f88e8..00000000000 --- a/integration-tests/it-consumer/src/test/java/org/apache/servicecomb/it/TestMain.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -import org.apache.servicecomb.it.junit.ITJUnitUtils; -import org.junit.Assert; -import org.junit.Test; - -public class TestMain { - @Test - public void testMain() throws Throwable { - ConsumerMain.autoExit = false; - ConsumerMain.main(new String[] {}); - Assert.assertTrue(ITJUnitUtils.getFailures().isEmpty()); - } -} diff --git a/integration-tests/it-edge/enable-it-jar b/integration-tests/it-edge/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-edge/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-edge/pom.xml b/integration-tests/it-edge/pom.xml deleted file mode 100644 index 1406b1f40cd..00000000000 --- a/integration-tests/it-edge/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - it-edge - Java Chassis::IT::Edge - - - org.apache.servicecomb.it.edge.EdgeMain - - - - - org.apache.servicecomb.tests - it-common - - - org.apache.servicecomb - edge-core - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - provider-pojo - - - \ No newline at end of file diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/Auth.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/Auth.java deleted file mode 100644 index 67180695af7..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/Auth.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.authentication; - -import java.util.concurrent.CompletableFuture; - -public interface Auth { - CompletableFuture auth(String info); -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/encrypt/Hcr.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/encrypt/Hcr.java deleted file mode 100644 index c219b0e9ebf..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/authentication/encrypt/Hcr.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.authentication.encrypt; - -public class Hcr { - private String bodyKey; - - private String signatureKey; - - public String getBodyKey() { - return bodyKey; - } - - public void setBodyKey(String bodyKey) { - this.bodyKey = bodyKey; - } - - public String getSignatureKey() { - return signatureKey; - } - - public void setSignatureKey(String signatureKey) { - this.signatureKey = signatureKey; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeConst.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeConst.java deleted file mode 100644 index a8d1b529a79..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeConst.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.apache.servicecomb.it.edge;/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -public interface EdgeConst { - String ENCRYPT_CONTEXT = "encryptContext"; -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeDispatcher.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeDispatcher.java deleted file mode 100644 index 7770c7c3466..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeDispatcher.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge; - -import java.util.Map; - -import org.apache.servicecomb.edge.core.AbstractEdgeDispatcher; -import org.apache.servicecomb.edge.core.CompatiblePathVersionMapper; -import org.apache.servicecomb.edge.core.EdgeInvocation; - -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; - -public class EdgeDispatcher extends AbstractEdgeDispatcher { - private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); - - @Override - public int getOrder() { - return 10000; - } - - @Override - public void init(Router router) { - String regex = "/api/([^\\\\/]+)/([^\\\\/]+)/(.*)"; - router.routeWithRegex(regex).handler(CookieHandler.create()); - router.routeWithRegex(regex).handler(createBodyHandler()); - router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); - } - - protected void onRequest(RoutingContext context) { - Map pathParams = context.pathParams(); - String microserviceName = pathParams.get("param0"); - String pathVersion = pathParams.get("param1"); - String path = context.request().path().substring(5 + microserviceName.length()); - - EdgeInvocation edgeInvocation = new EdgeInvocation(); - edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); - - edgeInvocation.init(microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeMain.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeMain.java deleted file mode 100644 index 3a042c662e8..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/EdgeMain.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge; - -import org.apache.servicecomb.it.ITMain; - -public class EdgeMain { - public static void main(String[] args) { - ITMain.main(args); - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomException.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomException.java deleted file mode 100644 index e9f7fffec55..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomException.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge.converter; - -public class CustomException { - private String data; - - private int statusCode; - - public CustomException(String data, int statusCode) { - this.data = data; - this.statusCode = statusCode; - } - - public String getData() { - return data; - } - - public void setData(String data) { - this.data = data; - } - - public int getStatusCode() { - return statusCode; - } - - public void setStatusCode(int statusCode) { - this.statusCode = statusCode; - } - - @Override - public String toString() { - return "CustomException{" + - "data='" + data + '\'' + - ", statusCode=" + statusCode + - '}'; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomExceptionConverter.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomExceptionConverter.java deleted file mode 100644 index 8678f4c939b..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/converter/CustomExceptionConverter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge.converter; - -import java.util.concurrent.TimeoutException; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class CustomExceptionConverter implements ExceptionToProducerResponseConverter { - @Override - public Class getExceptionClass() { - return TimeoutException.class; - } - - @Override - public int getOrder() { - return -12; - } - - @Override - public Response convert(SwaggerInvocation swaggerInvocation, TimeoutException e) { - CustomException customException = new CustomException("change the response", 777); - InvocationException stt = new InvocationException(Status.EXPECTATION_FAILED, customException); - return Response.failResp(stt); - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/Encrypt.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/Encrypt.java deleted file mode 100644 index cacc21316c7..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/Encrypt.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge.encrypt; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.it.authentication.encrypt.Hcr; - -public interface Encrypt { - CompletableFuture queryUserId(String serviceToken); - - CompletableFuture queryHcr(String hcrId); -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptContext.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptContext.java deleted file mode 100644 index 0f037961684..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptContext.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt; - -import org.apache.servicecomb.it.authentication.encrypt.Hcr; - -public class EncryptContext { - private Hcr hcr; - - private String userId; - - public EncryptContext(Hcr hcr, String userId) { - this.hcr = hcr; - this.userId = userId; - } - - public Hcr getHcr() { - return hcr; - } - - public void setHcr(Hcr hcr) { - this.hcr = hcr; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeDispatcher.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeDispatcher.java deleted file mode 100644 index 6c2bca75f63..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeDispatcher.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge.encrypt; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.edge.core.AbstractEdgeDispatcher; -import org.apache.servicecomb.edge.core.CompatiblePathVersionMapper; -import org.apache.servicecomb.it.authentication.encrypt.Hcr; -import org.apache.servicecomb.provider.pojo.Invoker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; - -public class EncryptEdgeDispatcher extends AbstractEdgeDispatcher { - private static final Logger LOGGER = LoggerFactory.getLogger(EncryptEdgeDispatcher.class); - - private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); - - private Encrypt encrypt = Invoker.createProxy("auth", "encrypt", Encrypt.class); - - private String prefix = "encryptApi"; - - @Override - public int getOrder() { - return 10000; - } - - @Override - public void init(Router router) { - { - String regex = "/" + prefix + "/([^\\\\/]+)/([^\\\\/]+)/(.*)"; - router.routeWithRegex(regex).handler(CookieHandler.create()); - router.routeWithRegex(regex).handler(createBodyHandler()); - router.routeWithRegex(regex).failureHandler(this::onFailure).handler(this::onRequest); - } - } - - protected void onRequest(RoutingContext context) { - HttpServerRequest httpServerRequest = context.request(); - - // queryUserId always success - CompletableFuture userIdFuture = queryUserId(httpServerRequest); - queryHcr(httpServerRequest).thenCombine(userIdFuture, (hcr, userId) -> { - // hcr and userId all success - routeToBackend(context, hcr, userId); - return null; - }).whenComplete((v, e) -> { - // failed to query hcr - if (e != null) { - context.response().end("failed to query hcr: " + e.getMessage()); - return; - } - }); - } - - private CompletableFuture queryUserId(HttpServerRequest httpServerRequest) { - String serviceToken = httpServerRequest.getParam("serviceToken"); - if (serviceToken == null) { - // no need to query userId - return CompletableFuture.completedFuture(null); - } - - CompletableFuture future = new CompletableFuture<>(); - encrypt.queryUserId(serviceToken).whenComplete((userId, e) -> { - if (e != null) { - // treat as success, just userId is null - LOGGER.error("Failed to query userId, serviceToken={}.", serviceToken, e); - } - - future.complete(userId); - }); - - return future; - } - - private CompletableFuture queryHcr(HttpServerRequest httpServerRequest) { - String hcrId = httpServerRequest.getParam("hcrId"); - return encrypt.queryHcr(hcrId); - } - - private void routeToBackend(RoutingContext context, Hcr hcr, String userId) { - Map pathParams = context.pathParams(); - String microserviceName = pathParams.get("param0"); - String pathVersion = pathParams.get("param1"); - String path = context.request().path().substring(prefix.length() + 1); - - EncryptEdgeInvocation edgeInvocation = new EncryptEdgeInvocation(new EncryptContext(hcr, userId)); - edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); - - edgeInvocation.init(microserviceName, context, path, httpServerFilters); - edgeInvocation.edgeInvoke(); - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeInvocation.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeInvocation.java deleted file mode 100644 index c9d2c9297d8..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/EncryptEdgeInvocation.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt; - -import org.apache.servicecomb.edge.core.EdgeInvocation; - -public class EncryptEdgeInvocation extends EdgeInvocation { - private EncryptContext encryptContext; - - public EncryptEdgeInvocation(EncryptContext encryptContext) { - this.encryptContext = encryptContext; - } - - @Override - protected void createInvocation() { - super.createInvocation(); - - invocation.getHandlerContext().put("encryptContext", encryptContext); - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/DecodeBodyFilter.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/DecodeBodyFilter.java deleted file mode 100644 index 00f3974bd73..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/DecodeBodyFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt.filter; - -import java.util.Map; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.it.authentication.encrypt.Hcr; -import org.apache.servicecomb.it.edge.EdgeConst; -import org.apache.servicecomb.it.edge.encrypt.EncryptContext; -import org.apache.servicecomb.swagger.invocation.Response; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -public class DecodeBodyFilter implements HttpServerFilter { - private JavaType bodyType = TypeFactory.defaultInstance().constructMapType(Map.class, String.class, String[].class); - - @Override - public int getOrder() { - return -9000; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); - if (encryptContext == null) { - return null; - } - Hcr hcr = encryptContext.getHcr(); - - String encodedBody = requestEx.getParameter("body"); - if (encodedBody == null) { - return null; - } - - encodedBody = encodedBody.substring(hcr.getBodyKey().length()); - - try { - Map decodedBody = RestObjectMapperFactory.getRestObjectMapper() - .readValue(encodedBody, bodyType); - requestEx.getParameterMap().putAll(decodedBody); - } catch (Throwable e) { - // should be a meaning exception response - return Response.producerFailResp(e); - } - return null; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureRequestFilter.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureRequestFilter.java deleted file mode 100644 index 3eb60906e2c..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureRequestFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt.filter; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.it.authentication.encrypt.Hcr; -import org.apache.servicecomb.it.edge.EdgeConst; -import org.apache.servicecomb.it.edge.encrypt.EncryptContext; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; - -public class EdgeSignatureRequestFilter implements HttpServerFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(EdgeSignatureRequestFilter.class); - - @Override - public int getOrder() { - return -10000; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); - if (encryptContext == null) { - return null; - } - Hcr hcr = encryptContext.getHcr(); - - // signature for query and form - List names = Collections.list(requestEx.getParameterNames()); - names.sort(Comparator.naturalOrder()); - - Hasher hasher = Hashing.sha256().newHasher(); - hasher.putString(hcr.getSignatureKey(), StandardCharsets.UTF_8); - for (String name : names) { - hasher.putString(name, StandardCharsets.UTF_8); - hasher.putString(requestEx.getParameter(name), StandardCharsets.UTF_8); - } - LOGGER.info("afterReceiveRequest signature: {}", hasher.hash().toString()); - - return null; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java deleted file mode 100644 index b62513574c9..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/EdgeSignatureResponseFilter.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt.filter; - -import java.nio.charset.StandardCharsets; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.it.authentication.encrypt.Hcr; -import org.apache.servicecomb.it.edge.EdgeConst; -import org.apache.servicecomb.it.edge.encrypt.EncryptContext; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; - -import io.vertx.core.buffer.Buffer; - -public class EdgeSignatureResponseFilter implements HttpServerFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(EdgeSignatureResponseFilter.class); - - @Override - public int getOrder() { - return 10000; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - return null; - } - - @Override - public void beforeSendResponse(Invocation invocation, HttpServletResponseEx responseEx) { - if (invocation == null) { - return; - } - - EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); - if (encryptContext == null) { - return; - } - Hcr hcr = encryptContext.getHcr(); - - // bad practice: it's better to set signature in response header - Buffer bodyBuffer = responseEx.getBodyBuffer(); - String body = bodyBuffer.toString(); - if (body.endsWith("}")) { - Hasher hasher = Hashing.sha256().newHasher(); - hasher.putString(hcr.getSignatureKey(), StandardCharsets.UTF_8); - hasher.putString(body, StandardCharsets.UTF_8); - String signature = hasher.hash().toString(); - LOGGER.info("beforeSendResponse signature: {}", signature); - - body = body.substring(0, body.length() - 1) + ",\"signature\":\"" + signature + "\"}"; - responseEx.setBodyBuffer(Buffer.buffer(body)); - } - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/UserIdFilter.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/UserIdFilter.java deleted file mode 100644 index 083dd69e3bf..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/encrypt/filter/UserIdFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.edge.encrypt.filter; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.it.edge.EdgeConst; -import org.apache.servicecomb.it.edge.encrypt.EncryptContext; -import org.apache.servicecomb.swagger.invocation.Response; - -public class UserIdFilter implements HttpServerFilter { - @Override - public int getOrder() { - return -8000; - } - - @Override - public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx requestEx) { - EncryptContext encryptContext = (EncryptContext) invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT); - if (encryptContext == null) { - return null; - } - - String userId = encryptContext.getUserId(); - if (userId != null) { - requestEx.setParameter("userId", userId); - } - - return null; - } -} diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/handler/AuthHandler.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/handler/AuthHandler.java deleted file mode 100644 index 691d27c924e..00000000000 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/handler/AuthHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.edge.handler; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.it.authentication.Auth; -import org.apache.servicecomb.it.edge.EdgeConst; -import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AuthHandler implements Handler { - private static Logger LOGGER = LoggerFactory.getLogger(AuthHandler.class); - - private static Auth auth; - - static { - auth = Invoker.createProxy("auth", "auth", Auth.class); - } - - @Override - public void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) { - } - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { - if (invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT) != null) { - invocation.next(asyncResp); - return; - } - - auth.auth("").whenComplete((succ, e) -> doHandle(invocation, asyncResp, succ, e)); - } - - protected void doHandle(Invocation invocation, AsyncResponse asyncResp, Boolean authSucc, Throwable authException) { - if (authException != null) { - asyncResp.consumerFail(new InvocationException(Status.UNAUTHORIZED, (Object) authException.getMessage())); - return; - } - - if (!authSucc) { - asyncResp.consumerFail(new InvocationException(Status.UNAUTHORIZED, (Object) "auth failed")); - } - - LOGGER.debug("auth success."); - try { - invocation.next(asyncResp); - } catch (Throwable e) { - asyncResp.consumerFail(e); - } - } -} diff --git a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter b/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter deleted file mode 100644 index a0e033db153..00000000000 --- a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpServerFilter +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.it.edge.encrypt.filter.EdgeSignatureRequestFilter -org.apache.servicecomb.it.edge.encrypt.filter.DecodeBodyFilter -org.apache.servicecomb.it.edge.encrypt.filter.UserIdFilter -org.apache.servicecomb.it.edge.encrypt.filter.EdgeSignatureResponseFilter \ No newline at end of file diff --git a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter deleted file mode 100644 index 2b858b4f4da..00000000000 --- a/integration-tests/it-edge/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.it.edge.converter.CustomExceptionConverter \ No newline at end of file diff --git a/integration-tests/it-edge/src/main/resources/config/cse.handler.xml b/integration-tests/it-edge/src/main/resources/config/cse.handler.xml deleted file mode 100644 index c9027e728ae..00000000000 --- a/integration-tests/it-edge/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/integration-tests/it-edge/src/main/resources/microservice.yaml b/integration-tests/it-edge/src/main/resources/microservice.yaml deleted file mode 100644 index 0d49d44a167..00000000000 --- a/integration-tests/it-edge/src/main/resources/microservice.yaml +++ /dev/null @@ -1,132 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -service_description: - name: it-edge - -servicecomb: - handler: - chain: - Consumer: - default: loadbalance - service: - it-auth: loadbalance - # this is not the majority, not testing this feature by default - # rest: - # parameter: - # decodeAsObject: true - # query: - # ignoreDefaultValue: true - # emptyAsNull: true - operation: - it-producer: - generic: - genericUser: - transport: rest - genericMapListUser: - transport: rest - download: - slowInputStream: - transport: rest - defaultJsonValueJaxrs: - jsonInput: - transport: rest - queryInput: - transport: rest - it-producer-h2: - generic: - genericUser: - transport: rest - genericMapListUser: - transport: rest - download: - slowInputStream: - transport: rest - defaultJsonValueJaxrs: - jsonInput: - transport: rest - queryInput: - transport: rest - it-producer-h2c: - generic: - genericUser: - transport: rest - genericMapListUser: - transport: rest - download: - slowInputStream: - transport: rest - defaultJsonValueJaxrs: - jsonInput: - transport: rest - queryInput: - transport: rest - it-producer-deploy-springboot2-servlet: - generic: - genericUser: - transport: rest - genericMapListUser: - transport: rest - download: - slowInputStream: - transport: rest - defaultJsonValueJaxrs: - jsonInput: - transport: rest - queryInput: - transport: rest - it-producer-deploy-springboot2-standalone: - generic: - genericUser: - transport: rest - genericMapListUser: - transport: rest - download: - slowInputStream: - transport: rest - defaultJsonValueJaxrs: - jsonInput: - transport: rest - queryInput: - transport: rest - http: - dispatcher: - edge: - default: - enabled: true - prefix: rest - withVersion: true - prefixSegmentCount: 2 - url: - enabled: true - mappings: - businessV1: - prefixSegmentCount: 1 - path: "/url/business/v1/.*" - microserviceName: business - versionRule: 1.0.0-2.0.0 - businessV2: - prefixSegmentCount: 1 - path: "/url/business/v2/.*" - microserviceName: business - versionRule: 2.0.0-3.0.0 - request: - it-producer: - edgeExceptionConvertSchema: - timeout: 30000 - add: - timeout: 1000 diff --git a/integration-tests/it-producer-deploy-springboot2-servlet/enable-it-jar b/integration-tests/it-producer-deploy-springboot2-servlet/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-servlet/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-producer-deploy-springboot2-servlet/pom.xml b/integration-tests/it-producer-deploy-springboot2-servlet/pom.xml deleted file mode 100644 index aa993b8bffa..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-servlet/pom.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.tests - it-producer-deploy-springboot2-servlet - 1.2.0-SNAPSHOT - - - - - org.apache.servicecomb - java-chassis-dependencies-springboot2 - 1.2.0-SNAPSHOT - pom - import - - - - - - - org.apache.servicecomb.tests - it-producer - 1.2.0-SNAPSHOT - - - org.apache.servicecomb - spring-boot2-starter-servlet - - - org.apache.servicecomb - foundation-test-scaffolding - compile - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - -parameters - UTF-8 - 1.8 - 1.8 - - - - org.apache.rat - apache-rat-plugin - - - DISCLAIMER - .travis.yml - **/*.md - **/*.MD - **/target/* - - **/etc/eclipse-java-google-style.xml - **/etc/intellij-java-google-style.xml - - **/resources/ssl/** - - **/src/release/licenses/** - - **/logs/**.log - **/**.log - - **/target/** - - **/io/vertx/ext/web/impl/MimeTypesUtils.java - **/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java - **/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java - - **/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java - - - - - - - - - org.apache.servicecomb.it.SpringBoot2ServletApplication - - - - - it-jar - - - enable-it-jar - - - - - - - org.springframework.boot - spring-boot-maven-plugin - 2.0.0.RELEASE - - - - repackage - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - . - - - - - - - - - - \ No newline at end of file diff --git a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java b/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java deleted file mode 100644 index 6b19ad8f4f7..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it; - -import org.apache.servicecomb.springboot2.starter.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class SpringBoot2ServletApplication { - - /** - * Allow encoded slash in path param(%2F). - * This property is set for {@code stringPath} tests in {@code TestDataTypePrimitive} - */ - private static final String TOMCAT_ALLOW_ENCODED_SLASH = "org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH"; - - public static void main(String[] args) { - new CommandReceiver(); - - System.setProperty(TOMCAT_ALLOW_ENCODED_SLASH, "true"); - SpringApplication.run(SpringBoot2ServletApplication.class, args); - System.clearProperty(TOMCAT_ALLOW_ENCODED_SLASH); - } -} diff --git a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/application.yaml b/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/application.yaml deleted file mode 100644 index e622a69759e..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/application.yaml +++ /dev/null @@ -1,23 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -server: - port: 8080 - -spring: - main: - web-application-type: servlet diff --git a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/microservice.yaml b/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/microservice.yaml deleted file mode 100644 index 9134e86193b..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/resources/microservice.yaml +++ /dev/null @@ -1,24 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -servicecomb-config-order: 2 - -service_description: - name: it-producer-deploy-springboot2-servlet - -servicecomb: - rest: - address: 0.0.0.0:8080 \ No newline at end of file diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/enable-it-jar b/integration-tests/it-producer-deploy-springboot2-standalone/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-standalone/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/pom.xml b/integration-tests/it-producer-deploy-springboot2-standalone/pom.xml deleted file mode 100644 index 04915c158cc..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-standalone/pom.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - 4.0.0 - - 1.2.0-SNAPSHOT - org.apache.servicecomb.tests - it-producer-deploy-springboot2-standalone - - - - - org.apache.servicecomb - java-chassis-dependencies-springboot2 - ${project.version} - pom - import - - - - - - - org.apache.servicecomb.tests - it-producer - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-standalone - - - org.apache.servicecomb - foundation-test-scaffolding - compile - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - -parameters - UTF-8 - 1.8 - 1.8 - - - - org.apache.rat - apache-rat-plugin - - - DISCLAIMER - .travis.yml - **/*.md - **/*.MD - **/target/* - - **/etc/eclipse-java-google-style.xml - **/etc/intellij-java-google-style.xml - - **/resources/ssl/** - - **/src/release/licenses/** - - **/logs/**.log - **/**.log - - **/target/** - - **/io/vertx/ext/web/impl/MimeTypesUtils.java - **/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java - **/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java - - **/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java - - - - - - - - - org.apache.servicecomb.it.SpringBoot2StandaloneApplication - - - - - it-jar - - - enable-it-jar - - - - - - - org.springframework.boot - spring-boot-maven-plugin - 2.0.0.RELEASE - - - - repackage - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - . - - - - - - - - - - \ No newline at end of file diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java deleted file mode 100644 index 75ce296fd33..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it; - -import org.apache.servicecomb.springboot2.starter.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class SpringBoot2StandaloneApplication { - public static void main(String[] args) { - new CommandReceiver(); - - SpringApplication.run(SpringBoot2StandaloneApplication.class, args); - } -} diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/application.yaml b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/application.yaml deleted file mode 100644 index 65bcf8a4257..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/application.yaml +++ /dev/null @@ -1,19 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -spring: - main: - web-application-type: none diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml deleted file mode 100644 index f773dd9cf3e..00000000000 --- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml +++ /dev/null @@ -1,25 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -servicecomb-config-order: 1 - -service_description: - name: it-producer-deploy-springboot2-standalone - -servicecomb: - rest: - server: - maxInitialLineLength: 5000 diff --git a/integration-tests/it-producer/enable-it-jar b/integration-tests/it-producer/enable-it-jar deleted file mode 100644 index 2944f981947..00000000000 --- a/integration-tests/it-producer/enable-it-jar +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ diff --git a/integration-tests/it-producer/pom.xml b/integration-tests/it-producer/pom.xml deleted file mode 100644 index d336018c489..00000000000 --- a/integration-tests/it-producer/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - it-producer - Java Chassis::IT::Producer - - - - org.apache.servicecomb.tests - it-common - - - - - org.apache.servicecomb.it.BaseProducerMain - - \ No newline at end of file diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/BaseProducerMain.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/BaseProducerMain.java deleted file mode 100644 index 37c7191c879..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/BaseProducerMain.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it; - -public class BaseProducerMain { - public static void main(String[] args) { - ITMain.main(args); - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/DemoSSLCustom.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/DemoSSLCustom.java deleted file mode 100644 index d27dc2e3761..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/DemoSSLCustom.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it; - -import java.net.URL; - -import org.apache.servicecomb.foundation.ssl.SSLCustom; - -public class DemoSSLCustom extends SSLCustom { - @Override - public char[] decode(char[] encrypted) { - return encrypted; - } - - @Override - public String getFullPath(String filename) { - URL url = Thread.currentThread().getContextClassLoader().getResource("certificates/" + filename); - // can not get cert from jar - if (url == null || url.getPath().contains("!")) { - // get from env - return System.getProperty(filename); - } - return url.getPath(); - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeJaxrsSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeJaxrsSchema.java deleted file mode 100644 index 37804d03367..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeJaxrsSchema.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "acceptTypeJaxrsSchema") -@Path("/v1/acceptTypeJaxrsSchema") -public class AcceptTypeJaxrsSchema { - @Path("/sayHi") - @GET - @Produces("text/plain;charset=UTF-8") - public String sayHi(@QueryParam("name") String name) { - return name; - } - - @Path("/sayHello") - @GET - @Produces("application/json;charset=UTF-8") - public String sayHello(@QueryParam("name") String name) { - return name; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeSpringmvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeSpringmvcSchema.java deleted file mode 100644 index f9d72dd3eb2..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AcceptTypeSpringmvcSchema.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -@RestSchema(schemaId = "acceptTypeSpringmvcSchema") -@RequestMapping(path = "/v1/acceptTypeSpringmvcSchema") -public class AcceptTypeSpringmvcSchema { - @RequestMapping(path = "/sayHi", method = RequestMethod.GET, produces = "text/plain;charset=UTF-8") - public String sayHi(@RequestParam(name = "name", defaultValue = "test") String name) { - return name; - } - - @RequestMapping(path = "/sayHello", method = RequestMethod.GET, produces = "application/json;charset=UTF-8") - public String sayHello(@RequestParam(name = "name", defaultValue = "test") String name) { - return name; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AnnotatedAttributeSpringmvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AnnotatedAttributeSpringmvcSchema.java deleted file mode 100644 index 9439eeb9400..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/AnnotatedAttributeSpringmvcSchema.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; - -@RestSchema(schemaId = "annotatedAttributeSpringmvc") -@RequestMapping(path = "/v1/annotatedAttributeSpringmvc") -public class AnnotatedAttributeSpringmvcSchema { - - @GetMapping("fromHeader") - public String fromHeader(@RequestHeader("input") String inputs, @RequestHeader(value = "input2") String inputs2, - @RequestHeader(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } - - @GetMapping("fromQuery") - public String fromQuery(@RequestParam("input") String inputs, @RequestParam(value = "input2") String inputs2, - @RequestParam(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } - - @GetMapping("fromCookie") - public String fromCookie(@CookieValue("input") String inputs, @CookieValue(value = "input2") String inputs2, - @CookieValue(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } - - @GetMapping("fromCookieRequired") - public String fromCookieRequired( - @CookieValue(name = "input", required = true) String input) { - return input; - } - - @GetMapping("fromCookieDefaultValue") - public String fromCookieDefaultValue( - @CookieValue(name = "input", required = true, defaultValue = "default") String input) { - return input; - } - - @GetMapping("fromPath/{input}/{input2}/{input3}") - public String fromPath(@PathVariable("input") String inputs, @PathVariable(value = "input2") String inputs2, - @PathVariable(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } - - @PostMapping("fromPart") - public String fromPart(@RequestPart("input") String inputs, @RequestPart(value = "input2") String inputs2, - @RequestPart(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } - - @PostMapping("fromAttribute") - public String fromAttribute(@RequestAttribute("input") String inputs, - @RequestAttribute(value = "input2") String inputs2, @RequestAttribute(name = "input3") String inputs3) { - return inputs + "," + inputs2 + "," + inputs3; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeJaxrsSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeJaxrsSchema.java deleted file mode 100644 index 032a94b8fb7..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeJaxrsSchema.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import java.util.Arrays; - -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.provider.rest.common.RestSchema; - -import io.swagger.annotations.ApiParam; - -@RestSchema(schemaId = "dataTypeJaxrs") -@Path("/v1/dataTypeJaxrs") -public class DataTypeJaxrsSchema { - @Path("intPath/{input}") - @GET - public int intPath(@PathParam("input") int input) { - return input; - } - - @Path("intQuery") - @GET - public int intQuery(@QueryParam("input") int input) { - return input; - } - - @Path("intHeader") - @GET - public int intHeader(@HeaderParam("input") int input) { - return input; - } - - @Path("intCookie") - @GET - public int intCookie(@CookieParam("input") int input) { - return input; - } - - @Path("intForm") - @POST - public int intForm(@FormParam("input") int input) { - return input; - } - - @Path("intBody") - @POST - public int intBody(int input) { - return input; - } - - @Path("intAdd") - @GET - public int intAdd(@QueryParam("num1") int num1, @QueryParam("num2") int num2) { - return num1 + num2; - } - - //string - @Path("stringPath/{input}") - @GET - public String stringPath(@PathParam("input") String input) { - return input; - } - - @Path("stringQuery") - @GET - public String stringQuery(@QueryParam("input") String input) { - return input; - } - - @Path("stringHeader") - @GET - public String stringHeader(@HeaderParam("input") String input) { - return input; - } - - @Path("stringCookie") - @GET - public String stringCookie(@CookieParam("input") String input) { - return input; - } - - @Path("stringForm") - @POST - public String stringForm(@FormParam("input") String input) { - return input; - } - - @Path("stringBody") - @POST - public String stringBody(String input) { - return input; - } - - @Path("stringConcat") - @GET - public String stringConcat(@QueryParam("str1") String str1, @QueryParam("str2") String str2) { - return str1 + str2; - } - - //double - @Path("doublePath/{input}") - @GET - public double doublePath(@PathParam("input") double input) { - return input; - } - - @Path("doubleQuery") - @GET - public double doubleQuery(@QueryParam("input") double input) { - return input; - } - - @Path("doubleHeader") - @GET - public double doubleHeader(@HeaderParam("input") double input) { - return input; - } - - @Path("doubleCookie") - @GET - public double doubleCookie(@CookieParam("input") double input) { - return input; - } - - @Path("doubleForm") - @POST - public double doubleForm(@FormParam("input") double input) { - return input; - } - - @Path("doubleBody") - @POST - public double doubleBody(double input) { - return input; - } - - @Path("doubleAdd") - @GET - public double doubleAdd(@QueryParam("num1") double num1, @QueryParam("num2") double num2) { - return num1 + num2; - } - - // float - @Path("floatPath/{input}") - @GET - public float floatPath(@PathParam("input") float input) { - return input; - } - - @Path("floatQuery") - @GET - public float floatQuery(@QueryParam("input") float input) { - return input; - } - - @Path("floatHeader") - @GET - public float floatHeader(@HeaderParam("input") float input) { - return input; - } - - @Path("floatCookie") - @GET - public float floatCookie(@CookieParam("input") float input) { - return input; - } - - @Path("floatForm") - @POST - public float floatForm(@FormParam("input") float input) { - return input; - } - - @Path("floatBody") - @POST - public float floatBody(float input) { - return input; - } - - @Path("floatAdd") - @GET - public float floatAdd(@QueryParam("num1") float num1, @QueryParam("num2") float num2) { - return num1 + num2; - } - - @Path("enumBody") - @POST - public Color enumBody(Color color) { - return color; - } - - // query array - @Path("queryArr") - @GET - public String queryArr(@QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @Path("queryArrCSV") - @GET - public String queryArrCSV(@ApiParam(collectionFormat = "csv") @QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @Path("queryArrSSV") - @GET - public String queryArrSSV(@ApiParam(collectionFormat = "ssv") @QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @Path("queryArrTSV") - @GET - public String queryArrTSV(@ApiParam(collectionFormat = "tsv") @QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @Path("queryArrPIPES") - @GET - public String queryArrPIPES(@ApiParam(collectionFormat = "pipes") @QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @Path("queryArrMULTI") - @GET - public String queryArrMULTI(@ApiParam(collectionFormat = "multi") @QueryParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypePojoSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypePojoSchema.java deleted file mode 100644 index 23dc575918f..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypePojoSchema.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.provider.pojo.RpcSchema; - -import io.swagger.annotations.SwaggerDefinition; - -@RpcSchema(schemaId = "dataTypePojo") -@SwaggerDefinition(basePath = "/v1/dataTypePojo") -public class DataTypePojoSchema { - public int intBody(int input) { - return input; - } - - public int intAdd(int num1, int num2) { - return num1 + num2; - } - - public String stringBody(String input) { - return input; - } - - public String stringConcat(String str1, String str2) { - return str1 + str2; - } - - public double doubleBody(double input) { - return input; - } - - public double doubleAdd(double num1, double num2) { - return num1 + num2; - } - - public float floatBody(float input) { - return input; - } - - public float floatAdd(float num1, float num2) { - return num1 + num2; - } - - public Color enumBody(Color color) { - return color; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeSpringmvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeSpringmvcSchema.java deleted file mode 100644 index 7c800b0228c..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DataTypeSpringmvcSchema.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import java.util.Arrays; - -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import io.swagger.annotations.ApiParam; - -@RestSchema(schemaId = "dataTypeSpringmvc") -@RequestMapping(path = "/v1/dataTypeSpringmvc") -public class DataTypeSpringmvcSchema { - @GetMapping("intPath/{input}") - public int intPath(@PathVariable("input") int input) { - return input; - } - - @GetMapping("intQuery") - public int intQuery(@RequestParam("input") int input) { - return input; - } - - @GetMapping("intHeader") - public int intHeader(@RequestHeader("input") int input) { - return input; - } - - @GetMapping("intCookie") - public int intCookie(@CookieValue("input") int input) { - return input; - } - - @PostMapping("intForm") - public int intForm(@RequestAttribute("input") int input) { - return input; - } - - @PostMapping("intBody") - public int intBody(@RequestBody int input) { - return input; - } - - @GetMapping(path = "intAdd") - public int intAdd(int num1, int num2) { - return num1 + num2; - } - - //String - - @GetMapping("stringPath/{input}") - public String stringPath(@PathVariable("input") String input) { - return input; - } - - @GetMapping("stringQuery") - public String stringQuery(@RequestParam("input") String input) { - return input; - } - - @GetMapping("stringHeader") - public String stringHeader(@RequestHeader("input") String input) { - return input; - } - - @GetMapping("stringCookie") - public String stringCookie(@CookieValue("input") String input) { - return input; - } - - @PostMapping("stringBody") - public String stringBody(@RequestBody String input) { - return input; - } - - @PostMapping("stringForm") - public String stringForm(@RequestAttribute("input") String input) { - return input; - } - - @GetMapping(path = "stringConcat") - public String stringConcat(String str1, String str2) { - return str1 + str2; - } - - //double - @GetMapping("doublePath/{input}") - public double doublePath(@PathVariable("input") double input) { - return input; - } - - @GetMapping("doubleQuery") - public double doubleQuery(@RequestParam("input") double input) { - return input; - } - - @GetMapping("doubleHeader") - public double doubleHeader(@RequestHeader("input") double input) { - return input; - } - - @GetMapping("doubleCookie") - public double doubleCookie(@CookieValue("input") double input) { - return input; - } - - @PostMapping("doubleForm") - public double doubleForm(@RequestAttribute("input") double input) { - return input; - } - - @PostMapping("doubleBody") - public double doubleBody(@RequestBody double input) { - return input; - } - - @GetMapping(path = "doubleAdd") - public double doubleAdd(double num1, double num2) { - return num1 + num2; - } - - //float - @GetMapping("floatPath/{input}") - public float floatPath(@PathVariable("input") float input) { - return input; - } - - @GetMapping("floatQuery") - public float floatQuery(@RequestParam("input") float input) { - return input; - } - - @GetMapping("floatHeader") - public float floatHeader(@RequestHeader("input") float input) { - return input; - } - - @GetMapping("floatCookie") - public float floatCookie(@CookieValue("input") float input) { - return input; - } - - @PostMapping("floatForm") - public float floatForm(@RequestAttribute("input") float input) { - return input; - } - - @PostMapping("floatBody") - public float floatBody(@RequestBody float input) { - return input; - } - - @GetMapping(path = "floatAdd") - public float floatAdd(float num1, float num2) { - return num1 + num2; - } - - @PostMapping(path = "enumBody") - public Color enumBody(@RequestBody Color color) { - return color; - } - - // query array - @GetMapping("queryArr") - public String queryArr(@RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @GetMapping("queryArrCSV") - public String queryArrCSV(@ApiParam(collectionFormat = "csv") @RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @GetMapping("queryArrSSV") - public String queryArrSSV(@ApiParam(collectionFormat = "ssv") @RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @GetMapping("queryArrTSV") - public String queryArrTSV(@ApiParam(collectionFormat = "tsv") @RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @GetMapping("queryArrPIPES") - public String queryArrPIPES(@ApiParam(collectionFormat = "pipes") @RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } - - @GetMapping("queryArrMULTI") - public String queryArrMULTI(@ApiParam(collectionFormat = "multi") @RequestParam("queryArr") String[] queryArr) { - return Arrays.toString(queryArr) + queryArr.length; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueJaxrsSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueJaxrsSchema.java deleted file mode 100644 index 65308533dd1..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueJaxrsSchema.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "defaultJsonValueJaxrs") -@Path("/v1/defaultJsonValueJaxrs") -public class DefaultJsonValueJaxrsSchema { - @Path("jsonInput") - @POST - public DefaultJsonValueResponse jsonInput(DefaultJsonValueRequest request) { - DefaultJsonValueResponse response = new DefaultJsonValueResponse(); - response.setType(request.getType()); - StringBuilder sb = new StringBuilder(); - sb.append(request.getDefaultValue()); - response.setMessage("expected:" + sb.toString() + ":" + (request.getItems() == null ? null - : request.getItems().size())); - return response; - } - - @Path("queryInput") - @GET - public String queryInput(HttpServletRequest request, @QueryParam("size") int size) { - return "expected:" + size + ":" + request.getParameter("size"); - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueRequest.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueRequest.java deleted file mode 100644 index 3410eac3611..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueRequest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import java.util.ArrayList; -import java.util.List; - -public class DefaultJsonValueRequest { - private int type; - - private Integer defaultValue = 30; - - private List items = new ArrayList<>(); - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public Integer getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(Integer defaultValue) { - this.defaultValue = defaultValue; - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueResponse.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueResponse.java deleted file mode 100644 index 69079eab152..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultJsonValueResponse.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -public class DefaultJsonValueResponse { - private int type; - - private String message; - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueJaxrsSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueJaxrsSchema.java deleted file mode 100644 index 3d9aa575745..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueJaxrsSchema.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "defaultValueJaxrs") -@Path("/v1/defaultValueJaxrs") -public class DefaultValueJaxrsSchema { - @Path("intQuery") - @GET - public int intQuery(@QueryParam("input") @DefaultValue("13") int input) { - return input; - } - - @Path("intHeader") - @GET - public int intHeader(@HeaderParam(value = "input") @DefaultValue("13") int input) { - return input; - } - - @Path("intForm") - @POST - public int intForm(@FormParam("input") @DefaultValue("13") int input) { - return input; - } - - @Path("stringQuery") - @GET - public String stringQuery(@QueryParam("input") @DefaultValue("string") String input) { - return input; - } - - @Path("stringHeader") - @GET - public String stringHeader(@HeaderParam(value = "input") @DefaultValue("string") String input) { - return input; - } - - @Path("stringForm") - @POST - public String stringForm(@FormParam("input") @DefaultValue("string") String input) { - return input; - } - - @Path("doubleQuery") - @GET - public double doubleQuery(@QueryParam("input") @DefaultValue("10.2") double input) { - return input; - } - - @Path("doubleHeader") - @GET - public double doubleHeader(@HeaderParam(value = "input") @DefaultValue("10.2") double input) { - return input; - } - - @Path("doubleForm") - @POST - public double doubleForm(@FormParam("input") @DefaultValue("10.2") double input) { - return input; - } - - // float - @Path("floatQuery") - @GET - public float floatQuery(@QueryParam("input") @DefaultValue("10.2") float input) { - return input; - } - - @Path("floatHeader") - @GET - public float floatHeader(@HeaderParam(value = "input") @DefaultValue("10.2") float input) { - return input; - } - - @Path("floatForm") - @POST - public float floatForm(@FormParam("input") @DefaultValue("10.2") float input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueSpringmvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueSpringmvcSchema.java deleted file mode 100644 index f0501d2fb65..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DefaultValueSpringmvcSchema.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; - -@RestSchema(schemaId = "defaultValueSpringmvc") -@RequestMapping(path = "/v1/defaultValueSpringmvc") -public class DefaultValueSpringmvcSchema { - @GetMapping(path = "intQuery") - public int intQuery(@RequestParam(name = "input", required = false, defaultValue = "13") int input) { - return input; - } - - @GetMapping(path = "intHeader") - public int intHeader(@RequestHeader(name = "input", required = false, defaultValue = "13") int input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "integer", format = "int32", paramType = "form", value = "", defaultValue = "13", required = false)}) - @PostMapping(path = "intForm") - public int intForm(int input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "intQueryRequire") - public int intQueryRequire(@RequestParam(name = "input", required = true, defaultValue = "13") int input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "intHeaderRequire") - public int intHeaderRequire(@RequestHeader(name = "input", required = true, defaultValue = "13") int input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "integer", format = "int32", paramType = "form", value = "a defaultValue form param", required = false, defaultValue = "13")}) - @PostMapping(path = "intFormRequire") - public int intFormRequire(int input) { - return input; - } - - //string - @GetMapping("stringQuery") - public String stringQuery(@RequestParam(value = "input", defaultValue = "string") String input) { - return input; - } - - @GetMapping("stringQueryRequiredTrue") - public String stringQueryRequiredTrue(@RequestParam(value = "input") String input) { - return input; - } - - @GetMapping("stringHeader") - public String stringHeader(@RequestHeader(value = "input", defaultValue = "string") String input) { - return input; - } - - @GetMapping("stringHeaderRequiredTrue") - public String stringHeaderRequiredTrue(@RequestHeader(value = "input") String input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "string", paramType = "form", value = "", defaultValue = "string", required = false)}) - @PostMapping(path = "stringForm") - public String stringForm(String input) { - return input; - } - - @GetMapping("stringFormRequiredTrue") - public String stringFormRequiredTrue(@RequestPart(value = "input") String input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "stringQueryRequire") - public String stringQueryRequire( - @RequestParam(name = "input", required = true, defaultValue = "string") String input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "stringHeaderRequire") - public String stringHeaderRequire( - @RequestHeader(name = "input", required = true, defaultValue = "string") String input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "string", paramType = "form", value = "a defalutValue form param", required = false, defaultValue = "string")}) - @PostMapping(path = "stringFormRequire") - public String stringFormRequire(String input) { - return input; - } - - //double - @GetMapping("doubleQuery") - public double doubleQuery(@RequestParam(value = "input", defaultValue = "10.2") double input) { - return input; - } - - @GetMapping("doubleHeader") - public double doubleHeader(@RequestHeader(value = "input", defaultValue = "10.2") double input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "number", format = "double", paramType = "form", value = "", defaultValue = "10.2", required = false)}) - @PostMapping(path = "doubleForm") - public double doubleForm(double input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "doubleQueryRequire") - public double doubleQueryRequire( - @RequestParam(name = "input", required = true, defaultValue = "10.2") double input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "doubleHeaderRequire") - public double doubleHeaderRequire( - @RequestHeader(name = "input", required = true, defaultValue = "10.2") double input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "number", format = "double", paramType = "form", value = "a defaultValue form param", required = false, defaultValue = "10.2")}) - @PostMapping(path = "doubleFormRequire") - public double doubleFormRequire(double input) { - return input; - } - - - //float - @GetMapping(path = "floatQuery") - public float floatQuery(@RequestParam(name = "input", required = false, defaultValue = "10.2") float input) { - return input; - } - - @GetMapping(path = "floatHeader") - public float floatHeader(@RequestHeader(name = "input", required = false, defaultValue = "10.2") float input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "number", format = "float", paramType = "form", value = "", defaultValue = "10.2", required = false)}) - @PostMapping(path = "floatForm") - public float floatForm(float input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "floatQueryRequire") - public float floatQueryRequire(@RequestParam(name = "input", required = true, defaultValue = "10.2") float input) { - return input; - } - - // springmvc rule: required should be false because defaultValue have value - @GetMapping(path = "floatHeaderRequire") - public float floatHeaderRequire(@RequestHeader(name = "input", required = true, defaultValue = "10.2") float input) { - return input; - } - - @ApiImplicitParams({ - @ApiImplicitParam(name = "input", dataType = "number", format = "float", paramType = "form", value = "a defaultValue form param", required = false, defaultValue = "10.2")}) - @PostMapping(path = "floatFormRequire") - public float floatFormRequire(float input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java deleted file mode 100644 index 2f3ba54206a..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.lang.Thread.State; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URL; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.Part; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.bootstrap.HttpServer; -import org.apache.http.impl.bootstrap.ServerBootstrap; -import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.foundation.common.part.FilePart; -import org.apache.servicecomb.it.ITUtils; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@RestSchema(schemaId = "download") -@RequestMapping(path = "/v1/download") -public class DownloadSchema implements BootListener { - File tempDir = new File("target/downloadTemp"); - - HttpServer server; - - public DownloadSchema() throws IOException { - FileUtils.deleteQuietly(tempDir); - FileUtils.forceMkdir(tempDir); - - // for download from net stream case - server = ServerBootstrap - .bootstrap() - .setListenerPort(0) - .registerHandler("/download/netInputStream", (req, resp, context) -> { - String uri = req.getRequestLine().getUri(); - String query = URI.create(uri).getQuery(); - int idx = query.indexOf('='); - String content = query.substring(idx + 1); - content = URLDecoder.decode(content, StandardCharsets.UTF_8.name()); - resp.setEntity(new StringEntity(content, StandardCharsets.UTF_8.name())); - }).create(); - server.start(); - } - - @Override - public void onBootEvent(BootEvent event) { - if (EventType.AFTER_CLOSE.equals(event.getEventType())) { - server.stop(); - } - } - - protected File createTempFile(String content) throws IOException { - return createTempFile(null, content); - } - - protected File createTempFile(String name, String content) throws IOException { - if (name == null) { - name = "download-" + UUID.randomUUID().toString() + ".txt"; - } - File file = new File(tempDir, name); - FileUtils.write(file, content); - return file; - } - - // customize HttpHeaders.CONTENT_DISPOSITION to be "attachment;filename=tempFileEntity.txt" - @GetMapping(path = "/tempFileEntity") - public ResponseEntity tempFileEntity(String content) throws IOException { - File file = createTempFile(content); - - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=tempFileEntity.txt") - .body(new FilePart(null, file) - .setDeleteAfterFinished(true)); - } - - // generate HttpHeaders.CONTENT_DISPOSITION to be "attachment;filename=tempFilePart.txt" automatically - @GetMapping(path = "/tempFilePart") - public Part tempFilePart(String content) throws IOException { - File file = createTempFile(content); - - return new FilePart(null, file) - .setDeleteAfterFinished(true) - .setSubmittedFileName("tempFilePart.txt"); - } - - @GetMapping(path = "/file") - public File file(String content) throws IOException { - return createTempFile("file.txt", content); - } - - @GetMapping(path = "/chineseAndSpaceFile") - public Part chineseAndSpaceFile(String content) throws IOException { - File file = createTempFile(content); - return new FilePart(null, file) - .setDeleteAfterFinished(true) - .setSubmittedFileName("测 试.test.txt"); - } - - @GetMapping(path = "/resource") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public Resource resource(String content) { - return new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8)) { - @Override - public String getFilename() { - return "resource.txt"; - } - }; - } - - @GetMapping(path = "/entityResource") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public ResponseEntity entityResource(String content) { - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=entityResource.txt") - .body(new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8))); - } - - @GetMapping(path = "/entityInputStream") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public ResponseEntity entityInputStream(String content) { - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=entityInputStream.txt") - .body(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); - } - - @GetMapping(path = "/bytes") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public ResponseEntity bytes(String content) { - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=bytes.txt") - .body(content.getBytes(StandardCharsets.UTF_8)); - } - - @GetMapping(path = "/netInputStream") - @ApiResponses({ - @ApiResponse(code = 200, response = File.class, message = ""), - }) - public ResponseEntity netInputStream(String content) throws IOException { - URL url = new URL("http://localhost:" + server.getLocalPort() + "/download/netInputStream?content=" - + URLEncoder.encode(content, StandardCharsets.UTF_8.name())); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - return ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=netInputStream.txt") - .body(conn.getInputStream()); - } - - private Thread slowInputStreamThread; - - @GetMapping(path = "/waitSlowInputStreamClosed") - public void waitSlowInputStreamClosed() { - while (!slowInputStreamThread.getState().equals(State.TERMINATED)) { - ITUtils.forceWait(TimeUnit.MILLISECONDS, 500); - } - } - - @ApiResponses({@ApiResponse(code = 200, response = File.class, message = "")}) - @GetMapping(path = "/slowInputStream") - public ResponseEntity slowInputStream() throws IOException { - PipedInputStream in = new PipedInputStream(); - PipedOutputStream out = new PipedOutputStream(); - in.connect(out); - - slowInputStreamThread = new Thread(() -> { - Thread.currentThread().setName("download thread"); - byte[] bytes = "1".getBytes(); - for (; ; ) { - try { - out.write(bytes); - out.flush(); - Thread.sleep(1000); - } catch (Throwable e) { - break; - } - } - - IOUtils.closeQuietly(out); - }); - slowInputStreamThread.start(); - - ResponseEntity responseEntity = ResponseEntity - .ok() - .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=slowInputStream.txt") - .body(in); - return responseEntity; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/EdgeExceptionConvertSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/EdgeExceptionConvertSchema.java deleted file mode 100644 index 4e8031e1dc1..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/EdgeExceptionConvertSchema.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -@RestSchema(schemaId = "edgeExceptionConvertSchema") -@RequestMapping(path = "/v1/edgeExceptionConvertSchema") -public class EdgeExceptionConvertSchema { - @RequestMapping(path = "/add", method = RequestMethod.GET) - public int add(int x, int y) { - if (x == 88) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - return x + y; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/GenericSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/GenericSchema.java deleted file mode 100644 index 03bf10f997b..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/GenericSchema.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.http.HttpStatus; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "generic") -@RequestMapping(path = "/v1/generic") -public class GenericSchema { - - @PostMapping(path = "holderUser") - public Holder holderUser(@RequestBody Holder input) { - Assert.isInstanceOf(Holder.class, input); - Assert.isInstanceOf(User.class, input.value); - return input; - } - - @PostMapping(path = "genericUser") - public Generic genericUser(@RequestBody Generic input) { - Assert.isInstanceOf(Generic.class, input); - Assert.isInstanceOf(User.class, input.value); - return input; - } - - @PostMapping(path = "genericLong") - public Generic genericLong(@RequestBody Generic input) { - Assert.isInstanceOf(Generic.class, input); - Assert.isInstanceOf(Long.class, input.value); - return input; - } - - @PostMapping(path = "genericDate") - public Generic genericDate(@RequestBody Generic input) { - Assert.isInstanceOf(Generic.class, input); - Assert.isInstanceOf(Date.class, input.value); - return input; - } - - @PostMapping(path = "genericEnum") - public Generic genericEnum(@RequestBody Generic input) { - Assert.isInstanceOf(Generic.class, input); - Assert.isInstanceOf(HttpStatus.class, input.value); - return input; - } - - @PostMapping(path = "genericGenericUser") - public Generic> genericGenericUser(@RequestBody Generic> input) { - Assert.isInstanceOf(Generic.class, input); - Assert.isInstanceOf(Generic.class, input.value); - Assert.isInstanceOf(User.class, input.value.value); - return input; - } - - @PostMapping(path = "genericMap") - public Generic> genericMap(@RequestBody Generic> mapGeneric) { - Assert.isInstanceOf(Generic.class, mapGeneric); - Assert.isInstanceOf(Map.class, mapGeneric.value); - return mapGeneric; - } - - @PostMapping(path = "genericMapList") - public Generic>> genericMapList( - @RequestBody Generic>> mapListGeneric) { - Assert.isInstanceOf(Generic.class, mapListGeneric); - Assert.isInstanceOf(Map.class, mapListGeneric.value); - return mapListGeneric; - } - - @PostMapping(path = "genericMapListUser") - public Generic>> genericMapListUser( - @RequestBody Generic>> mapListUserGeneric) { - Assert.isInstanceOf(Generic.class, mapListUserGeneric); - Assert.isInstanceOf(Map.class, mapListUserGeneric.value); - return mapListUserGeneric; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/ParamCodecSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/ParamCodecSchema.java deleted file mode 100644 index d7980b03bd2..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/ParamCodecSchema.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "paramCodec") -@Path("/v1/paramCodec") -public class ParamCodecSchema { - /** - * Test path param and query param encode&decode - */ - @Path("spaceCharCodec/{pathVal}") - @GET - public String spaceCharCodec(@PathParam("pathVal") String pathVal, @QueryParam("q") String q) { - String expectedParamString = "a%2B+%20b%% %20c"; - return pathVal + " +%20%% " + q + " " + (expectedParamString.equals(pathVal) && expectedParamString.equals(q)); - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RequestBodySpringMvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RequestBodySpringMvcSchema.java deleted file mode 100644 index 6efdcbb7882..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RequestBodySpringMvcSchema.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "requestBodySpringMvcSchema") -@RequestMapping(path = "/v1/requestBodySpringMvcSchema") -public class RequestBodySpringMvcSchema { - @PostMapping(path = "base") - public ResponseModel base(@RequestBody RequestModel request) { - ResponseModel response = new ResponseModel(); - response.setType(request.getType()); - response.setIntegerType(request.getIntegerType()); - response.setMessage(request.getMessage()); - response.setCatalog(request.getCatalog()); - response.setIntegerCatalog(request.getIntegerCatalog()); - response.setExtendedMessage(request.getExtendedMessage()); - return response; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerEmptyMappingSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerEmptyMappingSchema.java deleted file mode 100644 index ff0cdb5b887..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerEmptyMappingSchema.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping(path = "") -public class RestControllerEmptyMappingSchema { - @GetMapping(path = "restControllerEmptyMappingSchemaQuery") - public int intQuery(@RequestParam(name = "input", required = false, defaultValue = "13") int input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerSchema.java deleted file mode 100644 index 08c6b98613e..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerSchema.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class RestControllerSchema { - @GetMapping(path = "restControllerSchemaQuery") - public int intQuery(@RequestParam(name = "input", required = false, defaultValue = "13") int input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRequestMappingSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRequestMappingSchema.java deleted file mode 100644 index c0acc903316..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRequestMappingSchema.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping(path = "/restControllerWithRequest") -public class RestControllerWithRequestMappingSchema { - @GetMapping(path = "restControllerWithRequestMappingSchemaQuery") - public int intQuery(@RequestParam(name = "input", required = false, defaultValue = "13") int input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRestSchemaSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRestSchemaSchema.java deleted file mode 100644 index 9795aa98d29..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestControllerWithRestSchemaSchema.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RestSchema(schemaId = "RestControllerWithRestSchemaSchema") -@RequestMapping(path = "/restControllerWithRestSchemaSchema") -public class RestControllerWithRestSchemaSchema { - @GetMapping(path = "restControllerWithRestSchemaSchemaQuery") - public int intQuery(@RequestParam(name = "input", required = false, defaultValue = "13") int input) { - return input; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestServerConfigSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestServerConfigSchema.java deleted file mode 100644 index d8a3dac9aff..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/RestServerConfigSchema.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.it.schema; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "restServerConfig") -@Path("/v1/restServerConfig") -public class RestServerConfigSchema { - @Path("/testMaxInitialLineLength") - @GET - public String testMaxInitialLineLength(@QueryParam("q") String q) { - return "OK"; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TraceSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TraceSchema.java deleted file mode 100644 index 93e8ccbd247..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TraceSchema.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.provider.pojo.Invoker; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.netflix.config.DynamicPropertyFactory; - -@RestSchema(schemaId = "trace") -@RequestMapping(path = "/v1/trace") -public class TraceSchema { - interface TraceSchemaIntf { - CompletableFuture echo(); - } - - TraceSchemaIntf intf = Invoker.createProxy( - DynamicPropertyFactory.getInstance().getStringProperty(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, null).get(), - "trace", - TraceSchemaIntf.class); - - @GetMapping(path = "echo") - public String echo(InvocationContext context) { - return context.getContext(Const.TRACE_ID_NAME); - } - - @GetMapping(path = "echo-proxy") - public String echoProxy() throws ExecutionException, InterruptedException { - return intf.echo().get(); - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportJaxrsSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportJaxrsSchema.java deleted file mode 100644 index 9c229058416..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportJaxrsSchema.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.provider.rest.common.InvocationToHttpServletRequest; -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "transportJaxrs") -@Path("/v1/transportJaxrs") -public class TransportJaxrsSchema { - @Path("checkTransport") - @GET - public String checkTransport(HttpServletRequest request) { - return request instanceof InvocationToHttpServletRequest ? Const.HIGHWAY : Const.RESTFUL; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportPojoSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportPojoSchema.java deleted file mode 100644 index 474a595c591..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportPojoSchema.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.provider.rest.common.InvocationToHttpServletRequest; - -import io.swagger.annotations.SwaggerDefinition; - -@RpcSchema(schemaId = "transportPojo") -@SwaggerDefinition(basePath = "/v1/transportPojo") -public class TransportPojoSchema { - public String checkTransport(HttpServletRequest request) { - return request instanceof InvocationToHttpServletRequest ? Const.HIGHWAY : Const.RESTFUL; - } -} diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportSpringmvcSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportSpringmvcSchema.java deleted file mode 100644 index 51e3eb0d8d5..00000000000 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/TransportSpringmvcSchema.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.it.schema; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.provider.rest.common.InvocationToHttpServletRequest; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "transportSpringmvc") -@RequestMapping(path = "/v1/transportSpringmvc") -public class TransportSpringmvcSchema { - @GetMapping(path = "checkTransport") - public String checkTransport(HttpServletRequest request) { - return request instanceof InvocationToHttpServletRequest ? Const.HIGHWAY : Const.RESTFUL; - } -} diff --git a/integration-tests/it-producer/src/main/resources/certificates/server.p12 b/integration-tests/it-producer/src/main/resources/certificates/server.p12 deleted file mode 100644 index 631313ec650..00000000000 Binary files a/integration-tests/it-producer/src/main/resources/certificates/server.p12 and /dev/null differ diff --git a/integration-tests/it-producer/src/main/resources/certificates/trust.jks b/integration-tests/it-producer/src/main/resources/certificates/trust.jks deleted file mode 100644 index 57aeff73332..00000000000 Binary files a/integration-tests/it-producer/src/main/resources/certificates/trust.jks and /dev/null differ diff --git a/integration-tests/it-producer/src/main/resources/microservice.yaml b/integration-tests/it-producer/src/main/resources/microservice.yaml deleted file mode 100644 index eaec944e57b..00000000000 --- a/integration-tests/it-producer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,39 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -service_description: - name: it-producer - -servicecomb: - rest: - server: - maxInitialLineLength: 5000 - -#########SSL options -ssl.protocols: TLSv1.2 -ssl.authPeer: false -ssl.checkCN.host: false - -#########certificates config -ssl.trustStore: trust.jks -ssl.trustStoreType: JKS -ssl.trustStoreValue: Changeme_123 -ssl.keyStore: server.p12 -ssl.keyStoreType: PKCS12 -ssl.keyStoreValue: Changeme_123 -ssl.crl: revoke.crl -ssl.sslCustomClass: org.apache.servicecomb.it.DemoSSLCustom diff --git a/integration-tests/jaxrs-tests/pom.xml b/integration-tests/jaxrs-tests/pom.xml deleted file mode 100644 index 6333118ade8..00000000000 --- a/integration-tests/jaxrs-tests/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - jaxrs-tests - Java Chassis::Integration Tests::JAXRS - - - - org.apache.servicecomb.demo - demo-schema - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - - diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsIntegrationTestBase.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsIntegrationTestBase.java deleted file mode 100644 index 485ea679164..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsIntegrationTestBase.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests; - -import static java.time.temporal.ChronoUnit.SECONDS; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.springframework.http.HttpHeaders.CONTENT_TYPE; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; -import static org.springframework.http.HttpMethod.PUT; -import static org.springframework.http.HttpStatus.ACCEPTED; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import java.io.IOException; -import java.time.ZonedDateTime; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.User; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -@Ignore -public class JaxrsIntegrationTestBase { - - private final String baseUrl = "http://127.0.0.1:8080/"; - - private final RestTemplate restTemplate = new RestTemplate(); - - private final String codeFirstUrl = baseUrl + "codeFirstJaxrs/"; - - private final String schemaFirstUrl = baseUrl + "schemaFirstJaxrs/"; - - private final String[] urls = {codeFirstUrl, schemaFirstUrl}; - - @Test - public void ableToQueryAtRootBasePath() { - ResponseEntity responseEntity = restTemplate - .getForEntity(baseUrl + "sayHi?name=Mike", String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Hi Mike")); - } - - @Test - public void ableToQueryAtRootPath() { - ResponseEntity responseEntity = restTemplate - .getForEntity(baseUrl, String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Welcome home")); - } - - @Test - public void ablePostMap() { - Map users = new HashMap<>(); - users.put("user1", userOfNames("name11", "name12")); - users.put("user2", userOfNames("name21", "name22")); - - ParameterizedTypeReference> reference = new ParameterizedTypeReference>() { - }; - for (String url : urls) { - ResponseEntity> responseEntity = restTemplate.exchange(url + "testUserMap", - POST, - jsonRequest(users), - reference); - - assertThat(responseEntity.getStatusCode(), is(OK)); - - Map body = responseEntity.getBody(); - assertArrayEquals(body.get("user1").getNames(), new String[] {"name11", "name12"}); - assertArrayEquals(body.get("user2").getNames(), new String[] {"name21", "name22"}); - } - } - - private User userOfNames(String... names) { - User user1 = new User(); - user1.setNames(names); - return user1; - } - - @Test - public void ableToConsumeTextPlain() { - String body = "a=1"; - - for (String url : urls) { - ResponseEntity responseEntity = restTemplate.postForEntity( - url + "textPlain", - body, - String.class); - - assertEquals(body, jsonBodyOf(responseEntity, String.class)); - } - } - - @Test - public void ableToPostBytes() throws IOException { - byte[] body = new byte[] {0, 1, 2}; - - for (String url : urls) { - byte[] result = restTemplate.postForObject( - url + "bytes", - jsonRequest(RestObjectMapperFactory.getRestObjectMapper().writeValueAsBytes(body)), - byte[].class); - - result = RestObjectMapperFactory.getRestObjectMapper().readValue(result, byte[].class); - - assertEquals(1, result[0]); - assertEquals(1, result[1]); - assertEquals(2, result[2]); - assertEquals(3, result.length); - } - } - - @Test - public void getsJaxrsResponse() { - // String srcMicroserviceName = RegistryUtils.getMicroservice().getServiceName(); - // String context = String.format("{x-cse-src-microservice=%s}", srcMicroserviceName); - - ResponseEntity responseEntity = restTemplate - .getForEntity(codeFirstUrl + "response", User.class); - - assertEquals(202, responseEntity.getStatusCode().value()); - assertEquals("User [name=nameA, age=100, index=0]", responseEntity.getBody().toString()); - // assertEquals("h1v " + context, responseEntity.getHeaders().getFirst("h1")); - // assertEquals("h2v " + context, responseEntity.getHeaders().getFirst("h2")); - } - - @Test - public void ableToPostDate() throws Exception { - ZonedDateTime date = ZonedDateTime.now().truncatedTo(SECONDS); - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("date", RestObjectMapperFactory.getRestObjectMapper().convertToString(Date.from(date.toInstant()))); - - HttpHeaders headers = new HttpHeaders(); - headers.add(CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE); - - int seconds = 1; - for (String url : urls) { - Date result = restTemplate.postForObject(url + "addDate?seconds={seconds}", - new HttpEntity<>(body, headers), - Date.class, - seconds); - - assertEquals(Date.from(date.plusSeconds(seconds).toInstant()), result); - } - } - - @Test - public void ableToDeleteWithQueryString() { - for (String url : urls) { - ResponseEntity responseEntity = restTemplate.exchange(url + "addstring?s=a&s=b", - HttpMethod.DELETE, - null, - String.class); - - assertEquals("ab", responseEntity.getBody()); - } - } - - @Test - public void ableToGetBoolean() { - for (String url : urls) { - boolean result = restTemplate.getForObject(url + "istrue", boolean.class); - assertEquals(true, result); - } - } - - @Test - public void putsEndWithPathParam() { - for (String url : urls) { - ResponseEntity responseEntity = restTemplate - .exchange(url + "sayhi/{name}", PUT, null, String.class, "world"); - - assertThat(responseEntity.getStatusCode(), is(ACCEPTED)); - assertEquals("world sayhi", jsonBodyOf(responseEntity, String.class)); - } - } - - @Test - public void putsContainingPathParam() { - for (String url : urls) { - ResponseEntity responseEntity = restTemplate - .exchange(url + "sayhi/{name}/v2", PUT, null, String.class, "world"); - - assertEquals("world sayhi 2", jsonBodyOf(responseEntity, String.class)); - } - } - - @Test - public void ableToPostWithHeader() { - Person person = new Person(); - person.setName("person name"); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(APPLICATION_JSON); - headers.add("prefix", "prefix prefix"); - - HttpEntity requestEntity = new HttpEntity<>(person, headers); - for (String url : urls) { - ResponseEntity responseEntity = restTemplate - .postForEntity(url + "saysomething", requestEntity, String.class); - - assertEquals("prefix prefix person name", jsonBodyOf(responseEntity, String.class)); - } - } - - @Test - public void ableToPostWithHeaderWithIdentifier() { - Person person = new Person(); - person.setName("person name"); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(APPLICATION_JSON); - headers.add("prefix-test", "prefix prefix"); - - HttpEntity requestEntity = new HttpEntity<>(person, headers); - for (String url : urls) { - ResponseEntity responseEntity = restTemplate - .postForEntity(url + "saysomething1", requestEntity, String.class); - - assertEquals("prefix prefix person name", jsonBodyOf(responseEntity, String.class)); - } - } - - @Test - public void ableToPostObjectAsJson() { - Map personFieldMap = new HashMap<>(); - personFieldMap.put("name", "person name from map"); - - for (String url : urls) { - Person person = restTemplate - .postForObject(url + "sayhello", jsonRequest(personFieldMap), Person.class); - assertEquals("hello person name from map", person.toString()); - - Person input = new Person(); - input.setName("person name from Object"); - person = restTemplate.postForObject(url + "sayhello", jsonRequest(input), Person.class); - - assertEquals("hello person name from Object", person.toString()); - } - } - - @Test - public void ableToPostForm() { - MultiValueMap params = new LinkedMultiValueMap<>(); - params.add("a", "5"); - params.add("b", "3"); - - HttpHeaders headers = new HttpHeaders(); - headers.add(CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE); - for (String url : urls) { - int result = restTemplate - .postForObject(url + "add", new HttpEntity<>(params, headers), Integer.class); - - assertEquals(8, result); - } - } - - @Test - public void ableToExchangeCookie() { - Map params = new HashMap<>(); - params.put("a", "5"); - - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.COOKIE, "b=3"); - - HttpEntity requestEntity = new HttpEntity<>(headers); - ResponseEntity result = restTemplate.exchange( - codeFirstUrl + "reduce?a={a}", - GET, - requestEntity, - Integer.class, - params); - - assertThat(result.getBody(), is(2)); - } - - @Test - public void ableToExchangeRequestContext() { - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "3"); - - ResponseEntity result = restTemplate.getForEntity( - schemaFirstUrl + "reduce?a={a}&b={b}", - Integer.class, - params); - - assertThat(result.getBody(), is(2)); - } - - @Test - public void ableToGetAtDefaultPath() { - for (String url : urls) { - int result = restTemplate.getForObject(url, Integer.class); - - assertThat(result, is(100)); - } - } - - private HttpEntity jsonRequest(T body) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(APPLICATION_JSON); - return new HttpEntity<>(body, headers); - } - - private T jsonBodyOf(ResponseEntity entity, Class aClass) { - try { - return RestObjectMapperFactory.getRestObjectMapper().readValue(entity.getBody(), aClass); - } catch (IOException e) { - throw new IllegalStateException("Failed to read JSON from response " + entity.getBody(), e); - } - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsTestMain.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsTestMain.java deleted file mode 100644 index ddf77124194..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsTestMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class JaxrsTestMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/RawJaxrsIntegrationTest.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/RawJaxrsIntegrationTest.java deleted file mode 100644 index 74fb18e086a..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/RawJaxrsIntegrationTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; - -import org.junit.BeforeClass; - -public class RawJaxrsIntegrationTest extends JaxrsIntegrationTestBase { - - @BeforeClass - public static void setUp() throws Exception { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - JaxrsTestMain.main(new String[0]); - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/CodeFirstJaxrs.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/CodeFirstJaxrs.java deleted file mode 100644 index 1940c7f4fc7..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/CodeFirstJaxrs.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests.endpoints; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.response.Headers; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; - -@RestSchema(schemaId = "codeFirst") -@Path("/codeFirstJaxrs") -public class CodeFirstJaxrs extends SomeAbstractJaxrsRestEndpoint { - - @ApiResponse(code = 200, response = User.class, message = "") - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) - @Path("/response") - @GET - public Response response(InvocationContext c1) { - Response response = Response.createSuccess(Status.ACCEPTED, new User()); - Headers headers = response.getHeaders(); - headers.addHeader("h1", "h1v " + c1.getContext().toString()); - - InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.addHeader("h2", "h2v " + c2.getContext().toString()); - - return response; - } - - @Path("/reduce") - @GET - @ApiImplicitParams({ - @ApiImplicitParam(name = "a", dataType = "integer", format = "int32", paramType = "query")}) - public int reduce(HttpServletRequest request, @CookieParam("b") int b) { - int a = Integer.parseInt(request.getParameter("a")); - return a - b; - } - - @Path("/addstring") - @DELETE - @Produces(TEXT_PLAIN) - public String addString(@QueryParam("s") List s) { - String result = ""; - for (String x : s) { - result += x; - } - return result; - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/EnglishGreetingRestEndpoint.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/EnglishGreetingRestEndpoint.java deleted file mode 100644 index f93fabe9afb..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/EnglishGreetingRestEndpoint.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests.endpoints; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "englishGreetingRestEndpoint") -@Path("/") -public class EnglishGreetingRestEndpoint { - - @GET - @Path("/sayHi") - @Produces(TEXT_PLAIN) - public String sayHi(@QueryParam("name") String name) { - return "Hi " + name; - } - - @GET - @Path("") - @Produces(TEXT_PLAIN) - public String home() { - return "Welcome home"; - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrs.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrs.java deleted file mode 100644 index 28f18c2f1c8..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrs.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests.endpoints; - -import java.util.Date; -import java.util.Map; - -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.User; - -public interface SchemaFirstJaxrs { - - int add(int a, int b); - - int reduce(int a, int b); - - Person sayHello(Person user); - - String testRawJsonString(String jsonInput); - - String saySomething(String prefix, Person user); - - String saySomething1(String prefix_test, Person user); - - String sayHi(String name); - - String sayHi2(String name); - - boolean isTrue(); - - String addString(String[] s); - - Map testUserMap(Map userMap); - - String textPlain(String body); - - byte[] bytes(byte[] input); - - Date addDate(Date date, long seconds); - - int defaultPath(); -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrsImpl.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrsImpl.java deleted file mode 100644 index 71d72542779..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SchemaFirstJaxrsImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests.endpoints; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; - -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "schemaFirst") -@Path("/schemaFirstJaxrs") -public class SchemaFirstJaxrsImpl extends SomeAbstractJaxrsRestEndpoint { - - @Path("/reduce") - @GET - public int reduce(@Context HttpServletRequest request) { - int a = Integer.parseInt(request.getParameter("a")); - int b = Integer.parseInt(request.getParameter("b")); - return a - b; - } - - @Path("/addstring") - @DELETE - @Produces(TEXT_PLAIN) - public String addString(@QueryParam("s") String[] s) { - String result = ""; - for (String x : s) { - result += x; - } - return result; - } -} diff --git a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SomeAbstractJaxrsRestEndpoint.java b/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SomeAbstractJaxrsRestEndpoint.java deleted file mode 100644 index 54948a60aea..00000000000 --- a/integration-tests/jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/endpoints/SomeAbstractJaxrsRestEndpoint.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests.endpoints; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.Date; -import java.util.Map; - -import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; - -@Produces(MediaType.APPLICATION_JSON) -public class SomeAbstractJaxrsRestEndpoint { - - @Path("/testUserMap") - @POST - public Map testUserMap(Map userMap) { - return userMap; - } - - @Path("/textPlain") - @POST - @Consumes(TEXT_PLAIN) - public String textPlain(String body) { - return body; - } - - @Path("/bytes") - @POST - public byte[] bytes(byte[] input) { - input[0] = (byte) (input[0] + 1); - return input; - } - - @Path("/addDate") - @POST - public Date addDate(@FormParam("date") Date date, @QueryParam("seconds") long seconds) { - return new Date(date.getTime() + seconds * 1000); - } - - @GET - public int defaultPath() { - return 100; - } - - @Path("/add") - @POST - public int add(@FormParam("a") int a, @FormParam("b") int b) { - return a + b; - } - - @Path("/sayhello") - @POST - public Person sayHello(Person user) { - user.setName("hello " + user.getName()); - return user; - } - - @SuppressWarnings("unchecked") - @Path("/testrawjson") - @POST - public String testRawJsonString(String jsonInput) { - Map person; - try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - return "hello " + person.get("name"); - } - - @Path("/saysomething") - @POST - public String saySomething(@HeaderParam("prefix") String prefix, Person user) { - return prefix + " " + user.getName(); - } - - @Path("/saysomething1") - @POST - public String saySomething1(@HeaderParam("prefix-test") String prefix_test, Person user) { - return prefix_test + " " + user.getName(); - } - - @Path("/sayhi/{name}") - @PUT - public String sayHi(@PathParam("name") String name) { - ContextUtils.getInvocationContext().setStatus(202); - return name + " sayhi"; - } - - @Path("/sayhi/{name}/v2") - @PUT - public String sayHi2(@PathParam("name") String name) { - return name + " sayhi 2"; - } - - @Path("/istrue") - @GET - public boolean isTrue() { - return true; - } -} diff --git a/integration-tests/jaxrs-tests/src/test/resources/config/log4j.z.properties b/integration-tests/jaxrs-tests/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 5520c4668a2..00000000000 --- a/integration-tests/jaxrs-tests/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout \ No newline at end of file diff --git a/integration-tests/jaxrs-tests/src/test/resources/log4j.properties b/integration-tests/jaxrs-tests/src/test/resources/log4j.properties deleted file mode 100644 index 705b2f7c5a0..00000000000 --- a/integration-tests/jaxrs-tests/src/test/resources/log4j.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.rootLogger=WARN, stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/jaxrs-tests/src/test/resources/microservice.yaml b/integration-tests/jaxrs-tests/src/test/resources/microservice.yaml deleted file mode 100644 index 4b5aa684cb7..00000000000 --- a/integration-tests/jaxrs-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: jaxrstest-it -service_description: - name: jaxrs - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/jaxrs-tests/src/test/resources/microservices/jaxrs/schemaFirst.yaml b/integration-tests/jaxrs-tests/src/test/resources/microservices/jaxrs/schemaFirst.yaml deleted file mode 100644 index c9ccda14305..00000000000 --- a/integration-tests/jaxrs-tests/src/test/resources/microservices/jaxrs/schemaFirst.yaml +++ /dev/null @@ -1,290 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: "swagger definition for org.apache.servicecomb.demo.jaxrs.tests.endpoints.SchemaFirstJaxrsImpl" - version: 1.0.0 - x-java-interface: org.apache.servicecomb.demo.jaxrs.tests.endpoints.SchemaFirstJaxrs -basePath: "/schemaFirstJaxrs" -produces: - - application/json - -paths: - /add: - post: - operationId: add - parameters: - - name: a - in: formData - required: true - type: integer - format: int32 - - name: b - in: formData - required: true - type: integer - format: int32 - responses: - 200: - description: add numer - schema: - type: integer - format: int32 - /reduce: - get: - operationId: reduce - parameters: - - name: a - in: query - required: true - type: integer - format: int32 - - name: b - in: query - required: true - type: integer - format: int32 - responses: - 200: - description: reduce - schema: - type: integer - format: int32 - /sayhello: - post: - operationId: sayHello - parameters: - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say hello - schema: - $ref: '#/definitions/Person' - /testrawjson: - post: - operationId: testRawJsonString - parameters: - - name: jsonInput - in: body - required: true - x-raw-json: true - type: string - responses: - 200: - description: test RawJson String - schema: - type: string - /saysomething: - post: - operationId: saySomething - parameters: - - name: prefix - in: header - required: true - type: string - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say something - schema: - type: string - /saysomething1: - post: - operationId: saySomething1 - parameters: - - name: prefix-test - in: header - required: true - type: string - - name: user - in: body - required: true - schema: - $ref: '#/definitions/Person' - responses: - 200: - description: say something - schema: - type: string - /sayhi/{name}: - put: - operationId: sayHi - parameters: - - name: name - in: path - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - 202: - description: say hi - schema: - type: string - /sayhi/{name}/v2: - put: - operationId: sayHi2 - parameters: - - name: name - in: path - required: true - type: string - responses: - 200: - description: say hi - schema: - type: string - /istrue: - get: - operationId: isTrue - responses: - 200: - description: is true - schema: - type: boolean - /addstring: - delete: - operationId: addString - produces: - - text/plain - parameters: - - name: s - in: query - required: true - type: array - items: - type: string - responses: - 200: - description: add string - schema: - type: string - - /testUserMap: - post: - operationId: testUserMap - parameters: - - name: userMap - in: body - required: false - schema: - type: object - additionalProperties: - $ref: '#/definitions/User' - responses: - 200: - description: response of 200 - schema: - type: object - additionalProperties: - $ref: '#/definitions/User' - /addDate: - post: - operationId: addDate - parameters: - - name: date - in: formData - required: false - type: string - format: date-time - - name: seconds - in: query - required: false - type: integer - format: int64 - responses: - 200: - description: response of 200 - schema: - type: string - format: date-time - /textPlain: - post: - operationId: textPlain - consumes: - - text/plain - parameters: - - name: body - in: body - required: false - schema: - type: string - responses: - 200: - description: response of 200 - schema: - type: string - /: - get: - operationId: defaultPath - parameters: [] - responses: - 200: - description: response of 200 - schema: - type: integer - format: int32 - /bytes: - post: - operationId: bytes - parameters: - - name: input - in: body - required: false - schema: - type: string - format: byte - responses: - 200: - description: response of 200 - schema: - type: string - format: byte -definitions: - User: - type: object - properties: - name: - type: string - age: - type: integer - format: int32 - index: - type: integer - format: int32 - names: - type: array - items: - type: string - x-java-class: org.apache.servicecomb.demo.server.User - Person: - type: object - properties: - name: - type: string - x-java-class: org.apache.servicecomb.demo.compute.Person diff --git a/integration-tests/pojo-test/pom.xml b/integration-tests/pojo-test/pom.xml deleted file mode 100644 index 423f754e1db..00000000000 --- a/integration-tests/pojo-test/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - pojo-test - Java Chassis::Integration Tests::POJO - - - - org.apache.servicecomb.demo - demo-schema - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoIntegrationTestBase.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoIntegrationTestBase.java deleted file mode 100644 index 7eb6f43a840..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoIntegrationTestBase.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.hamcrest.Matchers.both; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.lessThan; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.TestRequest; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.demo.smartcare.Application; -import org.apache.servicecomb.demo.smartcare.Group; -import org.apache.servicecomb.demo.smartcare.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class PojoIntegrationTestBase { - - protected static void setUpLocalRegistry() { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - } - - @Test - public void remoteHelloPojo_sayHello() { - String result = PojoService.hello.SayHello("whatever"); - assertThat(result, is("Hello Message fast")); - } - - @Test - public void remoteHelloPojo_sayHelloAgain() { - long startTime = System.currentTimeMillis(); - String result = PojoService.hello.SayHelloAgain("whatever"); - long stopTime = System.currentTimeMillis(); - long elapsedTime = stopTime - startTime; - - assertThat(result, is("Hello Message slow")); - assertThat(elapsedTime, - is(both(greaterThan(4000L)).and(lessThan(7000L)))); - } - - @Test - public void remoteSmartCarePojo_addApplication() { - Group group = new Group(); - group.setName("group0"); - Application application = new Application(); - application.setName("app0"); - application.setDefaultGroup("group0"); - application.setVersion("v1"); - application.setDynamicFlag(true); - List groups = new ArrayList<>(); - groups.add(group); - application.setGroups(groups); - - Response result = PojoService.smartCare.addApplication(application); - assertThat(result.getResultCode(), is(0)); - assertThat(result.getResultMessage(), is("add application app0 success")); - } - - @Test - public void remoteSmartCarePojo_delApplication() { - Response result = PojoService.smartCare.delApplication("app0"); - - assertThat(result.getResultCode(), is(1)); - assertThat(result.getResultMessage(), is("delete application app0 failed")); - } - - @Test - public void remoteTestPojo_testStringArray() { - String result = PojoService.test.testStringArray(new String[] {"a", "b"}); - assertThat(result, is("arr is '[a, b]'")); - } - - @Test - public void remoteTestPojo_getTestString() { - // test empty string - String result = PojoService.test.getTestString(""); - assertThat(result, is("code is ''")); - - // test null - result = PojoService.test.getTestString(null); - assertThat(result, is("code is 'null'")); - - // test Chinese - result = PojoService.test.getTestString("测试"); - assertThat(result, is("code is '测试'")); - - // test String with space - result = PojoService.test.getTestString("a b"); - assertThat(result, is("code is 'a b'")); - } - - @Test - public void remoteTestPojo_postTestStatic() { - String result = PojoService.test.postTestStatic(1); - assertThat(result, is(nullValue())); - result = PojoService.test.patchTestStatic(1); - assertThat(result, is(nullValue())); - } - - @Test - public void remoteTestPojo_testException() { - // when code is 200 - String result = PojoService.test.testException(200); - assertThat(result, is("200")); - - // when code is 456 - try { - PojoService.test.testException(456); - fail("Exception expected, but threw nothing"); - } catch (InvocationException e) { - assertThat(e.getErrorData(), is("456 error")); - } catch (Exception e) { - fail("InvocationException expected, but threw " + e); - } - - // when code is 556 - try { - PojoService.test.testException(556); - fail("InvocationException expected, but threw nothing"); - } catch (InvocationException e) { - assertThat(e.getStatusCode(), is(556)); - assertThat(e.getErrorData().toString(), is("[556 error]")); - } catch (Exception e) { - fail("InvocationException expected, but threw " + e); - } - - // when code is 557 - try { - PojoService.test.testException(557); - fail("InvocationException expected, but threw nothing"); - } catch (InvocationException e) { - assertThat(e.getStatusCode(), is(557)); - assertThat(e.getErrorData().toString(), is("[[557 error]]")); - } catch (Exception e) { - fail("InvocationException expected, but threw " + e); - } - - // when code is 123(other number, the default case) - result = PojoService.test.testException(123); - assertThat(result, is("not expected")); - } - - @Test - public void remoteTestPojo_splitParam() { - User result = PojoService.test.splitParam(1, new User()); - assertThat(result.toString(), - is("User [name=nameA, users count:0, age=100, index=1]")); - } - - @Test - public void remoteTestPojo_wrapParam() { - // when request is null - User result = PojoService.test.wrapParam(null); - assertThat(result, is(nullValue())); - - // when request is not null - User user = new User(); - byte[] buffer = new byte[1024]; - - TestRequest request = new TestRequest(); - request.setUser(user); - request.setIndex(0); - request.setData(buffer); - request.getUsers().add(user); - - result = PojoService.test.wrapParam(request); - assertThat(result.toString(), - is("User [name=nameA, users count:1, age=100, index=0]")); - } - - @Test - public void remoteTestPojo_addString() { - String result = PojoService.test.addString(new String[] {"a", "b"}); - assertThat(result, is("[a, b]")); - } - - @Test - public void remoteCodeFirstPojo_testUserMap() { - User user1 = new User(); - user1.setNames(new String[] {"u1", "u2"}); - - User user2 = new User(); - user2.setNames(new String[] {"u3", "u4"}); - - Map userMap = new HashMap<>(); - userMap.put("u1", user1); - userMap.put("u2", user2); - Map result = PojoService.codeFirst.testUserMap(userMap); - - assertThat(result.get("u1").getNames()[0], is("u1")); - assertThat(result.get("u1").getNames()[1], is("u2")); - assertThat(result.get("u2").getNames()[0], is("u3")); - assertThat(result.get("u2").getNames()[1], is("u4")); - } - - @Test - public void remoteCodeFirstPojo_testUserArray() { - User user1 = new User(); - user1.setNames(new String[] {"u1", "u2"}); - - User user2 = new User(); - user2.setNames(new String[] {"u3", "u4"}); - - User[] users = new User[] {user1, user2}; - List result = PojoService.codeFirst.testUserArray(Arrays.asList(users)); - - assertThat(result.get(0).getNames()[0], is("u1")); - assertThat(result.get(0).getNames()[1], is("u2")); - assertThat(result.get(1).getNames()[0], is("u3")); - assertThat(result.get(1).getNames()[1], is("u4")); - } - - @Test - public void remoteCodeFirstPojo_testStrings() { - String[] result = PojoService.codeFirst.testStrings(new String[] {"a", "b"}); - assertThat(Arrays.asList(result), contains("aa0", "b")); - } - - @Test - public void remoteCodeFirstPojo_testBytes() { - byte[] input = new byte[] {0, 1, 2}; - byte[] result = PojoService.codeFirst.testBytes(input); - - assertEquals(3, result.length); - assertEquals(1, result[0]); - assertEquals(1, result[1]); - assertEquals(2, result[2]); - } - - @Test - public void remoteCodeFirstPojo_reduce() { - int result = PojoService.codeFirst.reduce(5, 3); - assertThat(result, is(2)); - } - - @Test - public void remoteCodeFirstPojo_addDate() { - Date date = new Date(); - int seconds = 1; - Date result = PojoService.codeFirst.addDate(date, seconds); - - assertThat(result, equalTo(new Date(date.getTime() + seconds * 1000))); - } - - @Test - public void remoteCodeFirstPojo_sayHello() { - Person input = new Person(); - input.setName("person name"); - - Person result = PojoService.codeFirst.sayHello(input); - assertThat(result.getName(), is("hello person name")); - } - - @Test - public void remoteCodeFirstPojo_saySomething() { - Person person = new Person(); - person.setName("person name"); - - String result = PojoService.codeFirst.saySomething("prefix prefix", person); - assertThat(result, is("prefix prefix person name")); - } - - @Test - public void remoteCodeFirstPojo_sayHi() { - String result = PojoService.codeFirst.sayHi("world"); - assertThat(result, is("world sayhi")); - } - - @Test - public void remoteCodeFirstPojo_isTrue() { - boolean result = PojoService.codeFirst.isTrue(); - assertThat(result, is(true)); - } - - @Test - public void remoteCodeFirstPojo_addString() { - String result = PojoService.codeFirst.addString(Arrays.asList("a", "b")); - assertThat(result, is("ab")); - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoService.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoService.java deleted file mode 100644 index dcc8cc98aa4..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoService.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import javax.inject.Inject; - -import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import org.apache.servicecomb.demo.helloworld.greeter.Hello; -import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.smartcare.SmartCare; -import org.springframework.stereotype.Component; - -@Component -public class PojoService { - - static Hello hello; - - static SmartCare smartCare; - - static org.apache.servicecomb.demo.server.Test test; - - static CodeFirstPojoIntf codeFirst; - - @Inject - public void setHello(Hello hello) { - PojoService.hello = hello; - } - - @Inject - public void setSmartCare(SmartCare smartCare) { - PojoService.smartCare = smartCare; - } - - @Inject - public void setTest(Test test) { - PojoService.test = test; - } - - @Inject - public void setCodeFirst(CodeFirstPojoIntf codeFirst) { - PojoService.codeFirst = codeFirst; - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoTestMain.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoTestMain.java deleted file mode 100644 index 0f74293d71b..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoTestMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class PojoTestMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/RawPojoIntegrationTest.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/RawPojoIntegrationTest.java deleted file mode 100644 index cb20f2e74e0..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/RawPojoIntegrationTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import org.junit.BeforeClass; - -public class RawPojoIntegrationTest extends PojoIntegrationTestBase { - - @BeforeClass - public static void setUp() throws Exception { - setUpLocalRegistry(); - PojoTestMain.main(new String[0]); - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/SomePojoConfig.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/SomePojoConfig.java deleted file mode 100644 index 6aa3d9bc0e0..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/SomePojoConfig.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import org.apache.servicecomb.demo.helloworld.greeter.Hello; -import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.smartcare.SmartCare; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; - -@Component -public class SomePojoConfig { - - @RpcReference(microserviceName = "pojo", schemaId = "helloworld.Greeter") - private Hello hello; - - @RpcReference(microserviceName = "pojo", schemaId = "smartcare") - private SmartCare smartCare; - - @RpcReference(microserviceName = "pojo", schemaId = "server") - private Test test; - - @RpcReference(microserviceName = "pojo", schemaId = "codeFirst") - private CodeFirstPojoIntf codeFirst; - - @Bean - Hello hello() { - return hello; - } - - @Bean - SmartCare smartCare() { - return smartCare; - } - - @Bean - Test test() { - return test; - } - - @Bean - CodeFirstPojoIntf codeFirst() { - return codeFirst; - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/CodeFirstPojo.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/CodeFirstPojo.java deleted file mode 100644 index f42031587d1..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/CodeFirstPojo.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test.endpoints; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.demo.CodeFirstPojoIntf; -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; - -@RpcSchema(schemaId = "codeFirst") -public class CodeFirstPojo implements CodeFirstPojoIntf { - - @Override - public Map testUserMap(Map userMap) { - return userMap; - } - - @Override - public List testUserArray(List users) { - return users; - } - - public String[] testStrings(String[] input) { - input[0] += input[0] + "0"; - return input; - } - - public byte[] testBytes(byte[] input) { - input[0] = (byte) (input[0] + 1); - return input; - } - - public int reduce(int a, int b) { - return a - b; - } - - public Date addDate(Date date, long second) { - return new Date(date.getTime() + second * 1000); - } - - public Person sayHello(Person user) { - user.setName("hello " + user.getName()); - return user; - } - - public String saySomething(String prefix, Person user) { - return prefix + " " + user.getName(); - } - - public String sayHi(String name) { - ContextUtils.getInvocationContext().setStatus(202); - return name + " sayhi"; - } - - public String sayHi2(String name) { - return name + " sayhi 2"; - } - - public boolean isTrue() { - return true; - } - - public String addString(List s) { - String result = ""; - for (String x : s) { - result += x; - } - return result; - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/HelloImpl.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/HelloImpl.java deleted file mode 100644 index 3d2fe122393..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/HelloImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test.endpoints; - -import org.apache.servicecomb.demo.helloworld.greeter.Hello; -import org.apache.servicecomb.provider.pojo.RpcSchema; - -@RpcSchema(schemaId = "helloworld.Greeter") -public class HelloImpl implements Hello { - - @Override - public String SayHello(String name) { - return "Hello Message fast"; - } - - @Override - public String SayHelloAgain(String name) { - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello Message slow"; - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/SmartCareImpl.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/SmartCareImpl.java deleted file mode 100644 index 3b629078e1c..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/SmartCareImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test.endpoints; - -import org.apache.servicecomb.demo.smartcare.Application; -import org.apache.servicecomb.demo.smartcare.Response; -import org.apache.servicecomb.demo.smartcare.SmartCare; -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@RpcSchema(schemaId = "smartcare") -public class SmartCareImpl implements SmartCare { - - private static final Logger LOG = LoggerFactory.getLogger(SmartCareImpl.class); - - @Override - public Response addApplication(Application application) { - // TODO: add application - LOG.info(application.toString()); - - Response resp = new Response(); - resp.setResultCode(0); - resp.setResultMessage("add application " + application.getName() + " success"); - return resp; - } - - @SuppressWarnings("divzero") - @Override - public Response delApplication(String appName) { - // TODO: delete application - LOG.info(appName); - - try { - System.out.println(5 / 0); - } catch (Exception e) { - Response resp = new Response(); - resp.setResultCode(1); - resp.setResultMessage("delete application " + appName + " failed"); - return resp; - } - - return null; - } -} diff --git a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/TestImpl.java b/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/TestImpl.java deleted file mode 100644 index 46d1bf70440..00000000000 --- a/integration-tests/pojo-test/src/test/java/org/apache/servicecomb/demo/pojo/test/endpoints/TestImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test.endpoints; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.demo.server.Test; -import org.apache.servicecomb.demo.server.TestRequest; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -@RpcSchema(schemaId = "server") -public class TestImpl implements Test { - - @Override - public String testStringArray(String[] arr) { - return String.format("arr is '%s'", Arrays.toString(arr)); - } - - @Override - public String getTestString(String code) { - return String.format("code is '%s'", String.valueOf(code)); - } - - @Override - public String postTestStatic(int code) { - return null; - } - - @Override - public String patchTestStatic(int code) { - return null; - } - - private User doTest(int index, User user, List users, byte[] data) { - if (user == null) { - user = new User(); - } - - user.setIndex(index); - - int userCount = (users == null) ? 0 : users.size(); - user.setName(user.getName() + ", users count:" + userCount); - return user; - } - - @Override - public String testException(int code) { - String strCode = String.valueOf(code); - switch (code) { - case 200: - return strCode; - case 456: - throw new InvocationException(code, strCode, strCode + " error"); - case 556: - throw new InvocationException(code, strCode, Arrays.asList(strCode + " error")); - case 557: - throw new InvocationException(code, strCode, Arrays.asList(Arrays.asList(strCode + " error"))); - default: - break; - } - - return "not expected"; - } - - @Override - public User splitParam(int index, User user) { - return doTest(index, user, null, null); - } - - @Override - public User wrapParam(TestRequest request) { - if (request == null) { - return null; - } - return doTest(request.getIndex(), request.getUser(), request.getUsers(), request.getData()); - } - - @Override - public String addString(String[] strArr) { - String result = Arrays.toString(strArr); - System.out.println("addString: " + result); - return result; - } - - @Override - public String testTraceId() { - return ContextUtils.getInvocationContext().getContext(Const.TRACE_ID_NAME); - } -} diff --git a/integration-tests/pojo-test/src/test/resources/config/log4j.z.properties b/integration-tests/pojo-test/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 02401e6e706..00000000000 --- a/integration-tests/pojo-test/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/pojo-test/src/test/resources/microservice.yaml b/integration-tests/pojo-test/src/test/resources/microservice.yaml deleted file mode 100644 index 0cdcb3167a3..00000000000 --- a/integration-tests/pojo-test/src/test/resources/microservice.yaml +++ /dev/null @@ -1,27 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: pojotest-it -service_description: - name: pojo - version: 0.0.4 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - highway: - address: 0.0.0.0:7070 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml deleted file mode 100644 index 6383ccb4937..00000000000 --- a/integration-tests/pom.xml +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - org.apache.servicecomb - java-chassis-parent - 1.2.0-SNAPSHOT - ../parent - - 4.0.0 - - org.apache.servicecomb.tests - integration-tests - Java Chassis::Integration Tests - pom - - - jaxrs-tests - springmvc-tests - tracing-tests - test-common - spring-jaxrs-tests - pojo-test - spring-zuul-tracing-tests - spring-pojo-tests - dynamic-config-tests - spring-pojo-connection-limit-test - - it-common - it-producer - it-edge - it-common-service - - it-producer-deploy-springboot2-standalone - it-producer-deploy-springboot2-servlet - - - it-consumer - - - - - - org.apache.servicecomb.tests - it-common - ${project.version} - - - - org.apache.servicecomb.demo - demo-schema - ${project.version} - - - org.apache.servicecomb.tests - test-common - ${project.version} - test-jar - - - io.zipkin.zipkin2 - zipkin - 2.4.2 - - - io.zipkin.java - zipkin-junit - 2.4.2 - test - - - com.squareup.okhttp3 - okhttp - 3.6.0 - test - - - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - javax.servlet - javax.servlet-api - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - metrics-core - - - - org.hamcrest - hamcrest-core - compile - - - org.hamcrest - hamcrest-all - compile - - - junit - junit - compile - - - org.apache.servicecomb - foundation-test-scaffolding - compile - - - - - - it-jar - - - enable-it-jar - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - default-jar - package - - - - - - repository - true - file:///${settings.localRepository}/ - ${it.main} - - - . .. - - - - - - - - - diff --git a/integration-tests/spring-jaxrs-tests/pom.xml b/integration-tests/spring-jaxrs-tests/pom.xml deleted file mode 100644 index b6dc2b09a15..00000000000 --- a/integration-tests/spring-jaxrs-tests/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-jaxrs-tests - Java Chassis::Integration Tests::Spring JAXRS - - - - org.apache.servicecomb.tests - jaxrs-tests - 1.2.0-SNAPSHOT - test-jar - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.springframework.boot - spring-boot-starter-test - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter - - - org.slf4j - * - - - ch.qos.logback - * - - - - - - - diff --git a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java b/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java deleted file mode 100644 index 834dff515d6..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.junit.Assert.assertEquals; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import com.netflix.config.DynamicProperty; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = JaxrsSpringMain.class) -public class JaxrsSpringIntegrationTest extends JaxrsIntegrationTestBase { - @BeforeClass - public static void setUp() { - System.setProperty("property.test5", "from_system_property"); - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - } - - @AfterClass - public static void tearDown() { - System.clearProperty("property.test5"); - } - - @Test - public void testGetConfigFromSpringBoot() { - DynamicProperty dynamicProperty = DynamicProperty.getInstance("property.test0"); - assertEquals("from_properties", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test1"); - assertEquals("from_yml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test2"); - assertEquals("from_yaml_from_yml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test3"); - assertEquals("from_yaml_dev_from_properties", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test4"); - assertEquals("from_microservice_yaml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test5"); - assertEquals("from_system_property", dynamicProperty.getString()); - } -} diff --git a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringMain.java b/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringMain.java deleted file mode 100644 index 3917fdde583..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringMain.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.jaxrs.tests; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class JaxrsSpringMain { - public static void main(final String[] args) throws Exception { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - SpringApplication.run(JaxrsSpringMain.class, args); - } -} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml deleted file mode 100644 index 5a6e140e53e..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test3: from_yaml_dev_${property.test0} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml deleted file mode 100644 index 2fcc1991fa3..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test3: from_yaml_prod_${property.test0} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties b/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties deleted file mode 100644 index 79e10ad7018..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -property.test0=from_properties -property.test5=from_properties diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml deleted file mode 100644 index ebe87f61e92..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -property: - test0: from_yaml - test1: from_yaml - test2: from_yaml_${property.test1} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml deleted file mode 100644 index a350c10c97f..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml +++ /dev/null @@ -1,24 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test0: from_yml - test1: from_yml - -spring: - profiles: - active: dev diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/log4j.properties b/integration-tests/spring-jaxrs-tests/src/test/resources/log4j.properties deleted file mode 100644 index e5addd94352..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/log4j.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=WARN, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml deleted file mode 100644 index 16660f63c34..00000000000 --- a/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test2: from_microservice_yaml - test4: from_microservice_yaml - test5: from_microservice_yaml diff --git a/integration-tests/spring-pojo-connection-limit-test/pom.xml b/integration-tests/spring-pojo-connection-limit-test/pom.xml deleted file mode 100644 index d827eeb7fec..00000000000 --- a/integration-tests/spring-pojo-connection-limit-test/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-pojo-connection-limit-test - Java Chassis::Integration Tests::Spring POJO Connection Limit - - - - org.apache.servicecomb.tests - pojo-test - ${project.version} - test-jar - - - org.apache.servicecomb.demo - demo-signature - - - - - org.springframework.boot - spring-boot-test - - - org.springframework - spring-test - - - - \ No newline at end of file diff --git a/integration-tests/spring-pojo-connection-limit-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringConnectionLimitIntegrationTest.java b/integration-tests/spring-pojo-connection-limit-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringConnectionLimitIntegrationTest.java deleted file mode 100644 index 8c6d586888d..00000000000 --- a/integration-tests/spring-pojo-connection-limit-test/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringConnectionLimitIntegrationTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.junit.Assert.fail; - -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -public class PojoSpringConnectionLimitIntegrationTest { - @BeforeClass - public static void setUpClass() throws Exception { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - PojoTestMain.main(null); - } - - @Test - public void remoteHelloPojo_sayHello() { - try { - PojoService.hello.SayHello("whatever"); - fail("connection limit failed"); - } catch (Exception e) { - Assert.assertEquals("java.io.IOException: socket closed", e.getCause().toString()); - } - } -} \ No newline at end of file diff --git a/integration-tests/spring-pojo-connection-limit-test/src/test/resources/log4j.properties b/integration-tests/spring-pojo-connection-limit-test/src/test/resources/log4j.properties deleted file mode 100644 index 8cc015c91d0..00000000000 --- a/integration-tests/spring-pojo-connection-limit-test/src/test/resources/log4j.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.rootLogger=WARN, stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n \ No newline at end of file diff --git a/integration-tests/spring-pojo-connection-limit-test/src/test/resources/microservice.yaml b/integration-tests/spring-pojo-connection-limit-test/src/test/resources/microservice.yaml deleted file mode 100644 index d1333f0c150..00000000000 --- a/integration-tests/spring-pojo-connection-limit-test/src/test/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: pojotest-it -service_description: - name: pojo - version: 0.0.4 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - highway: - address: 0.0.0.0:7070 - server: - connection-limit: 0 \ No newline at end of file diff --git a/integration-tests/spring-pojo-tests/pom.xml b/integration-tests/spring-pojo-tests/pom.xml deleted file mode 100644 index de13a9fffb2..00000000000 --- a/integration-tests/spring-pojo-tests/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-pojo-tests - Java Chassis::Integration Tests::Spring POJO - - - - org.apache.servicecomb.tests - pojo-test - ${project.version} - test-jar - - - org.apache.servicecomb.demo - demo-signature - - - - - org.springframework.boot - spring-boot-test - - - org.springframework - spring-test - - - - - diff --git a/integration-tests/spring-pojo-tests/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringIntegrationTest.java b/integration-tests/spring-pojo-tests/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringIntegrationTest.java deleted file mode 100644 index 388ed686756..00000000000 --- a/integration-tests/spring-pojo-tests/src/test/java/org/apache/servicecomb/demo/pojo/test/PojoSpringIntegrationTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.pojo.test; - -import org.apache.servicecomb.core.SCBEngine; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -public class PojoSpringIntegrationTest extends PojoIntegrationTestBase { - - @BeforeClass - public static void setUpClass() throws Exception { - setUpLocalRegistry(); - PojoTestMain.main(null); - } - - @AfterClass - public static void teardownClass() { - SCBEngine.getInstance().destroy(); - } -} \ No newline at end of file diff --git a/integration-tests/spring-pojo-tests/src/test/resources/log4j.properties b/integration-tests/spring-pojo-tests/src/test/resources/log4j.properties deleted file mode 100644 index e5addd94352..00000000000 --- a/integration-tests/spring-pojo-tests/src/test/resources/log4j.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=WARN, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/spring-zuul-tracing-tests/pom.xml b/integration-tests/spring-zuul-tracing-tests/pom.xml deleted file mode 100644 index 2b76e2cccbf..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-zuul-tracing-tests - Java Chassis::Integration Tests::Spring Zuul Tracing - - - - org.apache.servicecomb.tests - test-common - test-jar - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - - - org.springframework.cloud - spring-cloud-starter-zuul - - - javax.ws.rs - jsr311-api - - - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.apache.servicecomb - spring-boot-starter-discovery - - - org.apache.servicecomb - spring-cloud-zuul-zipkin - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - * - - - - - org.springframework.boot - spring-boot-starter-test - - - io.zipkin.java - zipkin-junit - - - com.squareup.okhttp3 - okhttp - test - - - diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/LoggingFilterConfig.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/LoggingFilterConfig.java deleted file mode 100644 index 82f34a633d1..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/LoggingFilterConfig.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static javax.servlet.DispatcherType.ASYNC; -import static javax.servlet.DispatcherType.ERROR; -import static javax.servlet.DispatcherType.FORWARD; -import static javax.servlet.DispatcherType.INCLUDE; -import static javax.servlet.DispatcherType.REQUEST; - -import java.io.IOException; -import java.lang.invoke.MethodHandles; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; - -@Configuration -class LoggingFilterConfig { - - @Bean - DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean() { - DelegatingFilterProxyRegistrationBean bean = new DelegatingFilterProxyRegistrationBean("traceLoggingFilter"); - - bean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, REQUEST); - bean.setOrder(Ordered.LOWEST_PRECEDENCE); - return bean; - } - - @Bean - LoggingFilter traceLoggingFilter() { - return new LoggingFilter(); - } - - private static class LoggingFilter implements Filter { - - private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - logger.info("logged tracing filter"); - filterChain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - } - } -} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java deleted file mode 100644 index 1402cc2372e..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; -import static org.springframework.http.HttpStatus.OK; - -import java.util.Collection; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.tests.tracing.TracingTestBase; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; - -import com.netflix.config.DynamicProperty; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TracedZuulMain.class, webEnvironment = RANDOM_PORT) -public class SpringCloudZuulTracingTest extends TracingTestBase { - - @Autowired - private TestRestTemplate testRestTemplate; - - @BeforeClass - public static void beforeClass() { - System.setProperty("property.test5", "from_system_property"); - } - - @AfterClass - public static void afterClass() { - System.clearProperty("property.test5"); - } - - @After - public void tearDown() { - appender.clear(); - } - - @Test - public void tracesCallsReceivedFromZuulToCalledService() throws InterruptedException { - ResponseEntity responseEntity = testRestTemplate.getForEntity("/dummy/rest/blah", String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("blah")); - - TimeUnit.MILLISECONDS.sleep(1000); - - Collection tracingMessages = appender.pollLogs(".*\\[\\w+/\\w+/\\w*\\]\\s+INFO.*(logged tracing|/blah).*"); - assertThat(tracingMessages.size(), greaterThanOrEqualTo(2)); - - assertThatSpansReceivedByZipkin(tracingMessages, "/dummy/rest/blah", "/blah"); - } - - @Test - public void tracesFailedCallsReceivedByZuul() throws InterruptedException { - ResponseEntity response = testRestTemplate.getForEntity("/dummy/rest/oops", String.class); - assertThat(response.getStatusCodeValue(), is(590)); - assertThat(response.getBody(), is("CommonExceptionData [message=Cse Internal Server Error]")); - - TimeUnit.MILLISECONDS.sleep(1000); - - Collection tracingMessages = appender.pollLogs(".*\\[\\w+/\\w+/\\w*\\]\\s+INFO.*(logged tracing|/oops).*"); - assertThat(tracingMessages.size(), greaterThanOrEqualTo(2)); - - assertThatSpansReceivedByZipkin(tracingMessages, "/dummy/rest/oops", "/oops", "590"); - } - - @Test - public void testGetConfigFromSpringBoot() { - DynamicProperty dynamicProperty = DynamicProperty.getInstance("property.test0"); - assertEquals("from_properties", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test1"); - assertEquals("from_yml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test2"); - assertEquals("from_yaml_from_yml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test3"); - assertEquals("from_yaml_dev_from_properties", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test4"); - assertEquals("from_microservice_yaml", dynamicProperty.getString()); - dynamicProperty = DynamicProperty.getInstance("property.test5"); - assertEquals("from_system_property", dynamicProperty.getString()); - - ResponseEntity responseEntity = testRestTemplate.getForEntity("/dummy/rest/testProperty", String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), - is("from_properties-from_yml-from_yaml_from_yml-from_yaml_dev_from_properties-from_microservice_yaml-from_system_property")); - } -} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java deleted file mode 100644 index 0463594668b..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -import java.lang.invoke.MethodHandles; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.RequestMapping; - -@RestSchema(schemaId = "tracedController") -@RequestMapping("/rest") -public class TracedController { - private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - @Value("${property.test0}") - private String propertyTest0; - - @Value("${property.test1}") - private String propertyTest1; - - @Value("${property.test2}") - private String propertyTest2; - - @Value("${property.test3}") - private String propertyTest3; - - @Value("${property.test4}") - private String propertyTest4; - - @Value("${property.test5}") - private String propertyTest5; - - @RequestMapping(value = "/blah", method = GET, produces = TEXT_PLAIN_VALUE) - public String blah() { - logger.info("in /blah"); - - return "blah"; - } - - @RequestMapping(value = "/oops", method = GET, produces = TEXT_PLAIN_VALUE) - public String oops() { - logger.info("in /oops"); - - throw new IllegalStateException("oops"); - } - - @RequestMapping(value = "/testProperty", method = GET, produces = TEXT_PLAIN_VALUE) - public String testProperty() { - logger.info("in /testProperty"); - - return propertyTest0 - + "-" + propertyTest1 - + "-" + propertyTest2 - + "-" + propertyTest3 - + "-" + propertyTest4 - + "-" + propertyTest5; - } -} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedZuulMain.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedZuulMain.java deleted file mode 100644 index a2476cd06be..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedZuulMain.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; - -@SpringBootApplication -@EnableZuulProxy -@EnableServiceComb -public class TracedZuulMain { - - public static void main(String[] args) { - SpringApplication.run(TracedZuulMain.class, args); - } -} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml deleted file mode 100644 index 5a6e140e53e..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test3: from_yaml_dev_${property.test0} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml deleted file mode 100644 index 2fcc1991fa3..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test3: from_yaml_prod_${property.test0} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties deleted file mode 100644 index 17149654857..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -spring.main.web-environment=true - -property.test0=from_properties -property.test5=from_properties diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml deleted file mode 100644 index 1d4dc74ab3f..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml +++ /dev/null @@ -1,34 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -zuul: - routes: - dummy: - serviceId: dummy - -# disable netflix eurkea since it's not used for service discovery -ribbon: - eureka: - enabled: false - -server: - port: 0 - -property: - test0: from_yaml - test1: from_yaml - test2: from_yaml_${property.test1} \ No newline at end of file diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml deleted file mode 100644 index a350c10c97f..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml +++ /dev/null @@ -1,24 +0,0 @@ -# --------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --------------------------------------------------------------------------- - -property: - test0: from_yml - test1: from_yml - -spring: - profiles: - active: dev diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/log4j.properties b/integration-tests/spring-zuul-tracing-tests/src/test/resources/log4j.properties deleted file mode 100644 index a25e46fe6b3..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/log4j.properties +++ /dev/null @@ -1,25 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=WARN, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml deleted file mode 100644 index 89c0b185464..00000000000 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,41 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: tracing-app -service_description: - name: dummy - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: tracing-provider,bizkeeper-provider - Consumer: - default: tracing-consumer,loadbalance,bizkeeper-consumer - tracing: - collector: - address: http://localhost:9411/ - -property: - test2: from_microservice_yaml - test4: from_microservice_yaml - test5: from_microservice_yaml diff --git a/integration-tests/springmvc-tests/pom.xml b/integration-tests/springmvc-tests/pom.xml deleted file mode 100644 index f54191022df..00000000000 --- a/integration-tests/springmvc-tests/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - springmvc-tests - pom - Java Chassis::Integration Tests::Spring MVC - - - springmvc-tests-common - springmvc-tests-general - springmvc-tests-simplified-mapping - springmvc-tests-general-with-springboot - springmvc-tests-simplified-mapping-with-springboot - springmvc-tests-connection-limit - - - - - org.apache.servicecomb.demo - demo-schema - - - diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-common/pom.xml deleted file mode 100644 index d367cafc2c5..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - Java Chassis::Integration Tests::Spring MVC Common - springmvc-tests-common - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java deleted file mode 100644 index c84ef3e5246..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import static java.time.temporal.ChronoUnit.SECONDS; -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.springframework.http.HttpHeaders.CONTENT_TYPE; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; -import static org.springframework.http.HttpMethod.PUT; -import static org.springframework.http.HttpStatus.ACCEPTED; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.io.IOUtils; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.compute.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.io.FileSystemResource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; -import org.springframework.web.client.AsyncRestTemplate; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -@Ignore -public class SpringMvcIntegrationTestBase { - @ClassRule - public static final TemporaryFolder folder = new TemporaryFolder(); - - private final String baseUrl = "http://127.0.0.1:8080/"; - - private final RestTemplate restTemplate = new RestTemplate(); - - private final AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(); - - private final String codeFirstUrl = baseUrl + "codeFirstSpringmvc/"; - - private final String controllerUrl = baseUrl + "springmvc/controller/"; - - public static void setUpLocalRegistry() { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - } - - @Test - public void ableToQueryAtRootBasePath() throws Exception { - ResponseEntity responseEntity = restTemplate - .getForEntity(baseUrl + "sayHi?name=Mike", String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Hi Mike")); - - responseEntity = restTemplate - .getForEntity(baseUrl + "sayHi?name={name}", String.class, "小 强"); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Hi 小 强")); - - //integration test for AsyncRestTemplate - ListenableFuture> listenableFuture = asyncRestTemplate - .getForEntity(baseUrl + "sayHi?name=Mike", String.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(OK)); - assertThat(futureResponse.getBody(), is("Hi Mike")); - - listenableFuture = asyncRestTemplate.getForEntity(baseUrl + "sayHi?name={name}", String.class, "小 强"); - futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(OK)); - assertThat(futureResponse.getBody(), is("Hi 小 强")); - } - - @Test - public void ableToQueryAtRootPath() throws Exception { - ResponseEntity responseEntity = restTemplate - .getForEntity(baseUrl, String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Welcome home")); - - ListenableFuture> listenableFuture = asyncRestTemplate.getForEntity(baseUrl, String.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(OK)); - assertThat(futureResponse.getBody(), is("Welcome home")); - } - - @Test - public void ableToQueryAtNonRootPath() throws Exception { - ResponseEntity responseEntity = restTemplate - .getForEntity(baseUrl + "french/bonjour?name=Mike", String.class); - - assertThat(responseEntity.getStatusCode(), is(OK)); - assertThat(responseEntity.getBody(), is("Bonjour Mike")); - - ListenableFuture> listenableFuture = asyncRestTemplate - .getForEntity(baseUrl + "french/bonjour?name=Mike", String.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(OK)); - assertThat(futureResponse.getBody(), is("Bonjour Mike")); - } - - @Test - public void ableToPostMap() throws Exception { - Map users = new HashMap<>(); - users.put("user1", userOfNames("name11", "name12")); - users.put("user2", userOfNames("name21", "name22")); - - ParameterizedTypeReference> reference = new ParameterizedTypeReference>() { - }; - ResponseEntity> responseEntity = restTemplate.exchange(codeFirstUrl + "testUserMap", - POST, - jsonRequest(users), - reference); - - assertThat(responseEntity.getStatusCode(), is(OK)); - - Map body = responseEntity.getBody(); - assertArrayEquals(body.get("user1").getNames(), new String[] {"name11", "name12"}); - assertArrayEquals(body.get("user2").getNames(), new String[] {"name21", "name22"}); - - ListenableFuture>> listenableFuture = asyncRestTemplate - .exchange(codeFirstUrl + "testUserMap", - POST, - jsonRequest(users), - reference); - ResponseEntity> futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(OK)); - body = futureResponse.getBody(); - assertArrayEquals(body.get("user1").getNames(), new String[] {"name11", "name12"}); - assertArrayEquals(body.get("user2").getNames(), new String[] {"name21", "name22"}); - } - - private User userOfNames(String... names) { - User user1 = new User(); - user1.setNames(names); - return user1; - } - - @Test - public void ableToConsumeTextPlain() throws Exception { - String body = "a=1"; - String result = restTemplate.postForObject( - codeFirstUrl + "textPlain", - body, - String.class); - - assertThat(jsonOf(result, String.class), is(body)); - - HttpEntity entity = new HttpEntity<>(body); - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "textPlain", entity, String.class); - ResponseEntity responseEntity = listenableFuture.get(); - assertThat(jsonOf(responseEntity.getBody(), String.class), is(body)); - } - - @Test - public void ableToPostBytes() throws Exception { - byte[] body = new byte[] {0, 1, 2}; - - byte[] result = restTemplate.postForObject( - codeFirstUrl + "bytes", - jsonRequest(RestObjectMapperFactory.getRestObjectMapper().writeValueAsBytes(body)), - byte[].class); - - result = RestObjectMapperFactory.getRestObjectMapper().readValue(result, byte[].class); - - assertEquals(1, result[0]); - assertEquals(1, result[1]); - assertEquals(2, result[2]); - assertEquals(3, result.length); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "bytes", - jsonRequest(RestObjectMapperFactory.getRestObjectMapper().writeValueAsBytes(body)), - byte[].class); - ResponseEntity responseEntity = listenableFuture.get(); - result = RestObjectMapperFactory.getRestObjectMapper().readValue(responseEntity.getBody(), byte[].class); - assertEquals(1, result[0]); - assertEquals(1, result[1]); - assertEquals(2, result[2]); - assertEquals(3, result.length); - } - - @Test - public void ableToUploadFile() throws Exception { - String file1Content = "hello world"; - String file2Content = "bonjour"; - String username = "mike"; - - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("file1", new FileSystemResource(newFile(file1Content).getAbsolutePath())); - map.add("someFile", new FileSystemResource(newFile(file2Content).getAbsolutePath())); - map.add("name", username); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); - String result = restTemplate.postForObject( - codeFirstUrl + "upload", - new HttpEntity<>(map, headers), - String.class); - - assertThat(result, is(file1Content + file2Content + username)); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "upload", - new HttpEntity<>(map, headers), - String.class); - ResponseEntity responseEntity = listenableFuture.get(); - assertThat(responseEntity.getBody(), is(file1Content + file2Content + username)); - } - - @Test - public void ableToUploadFileFromConsumer() throws Exception { - String file1Content = "hello world"; - String file2Content = "bonjour"; - String username = "mike"; - - Map map = new HashMap<>(); - map.put("file1", new FileSystemResource(newFile(file1Content).getAbsolutePath())); - map.put("someFile", new FileSystemResource(newFile(file2Content).getAbsolutePath())); - map.put("name", username); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); - String result = RestTemplateBuilder.create().postForObject( - "cse://springmvc-tests/codeFirstSpringmvc/upload", - new HttpEntity<>(map, headers), - String.class); - - assertThat(result, is(file1Content + file2Content + username)); - AsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate(); - ListenableFuture> listenableFuture = cseAsyncRestTemplate - .postForEntity("cse://springmvc-tests/codeFirstSpringmvc/upload", - new HttpEntity<>(map, headers), - String.class); - ResponseEntity responseEntity = listenableFuture.get(); - assertThat(responseEntity.getBody(), is(file1Content + file2Content + username)); - } - - @Test - public void ableToUploadFileWithoutAnnotation() throws Exception { - String file1Content = "hello world"; - String file2Content = "bonjour"; - String username = "mike"; - - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("file1", new FileSystemResource(newFile(file1Content).getAbsolutePath())); - map.add("file2", new FileSystemResource(newFile(file2Content).getAbsolutePath())); - map.add("name", username); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); - String result = restTemplate.postForObject( - codeFirstUrl + "uploadWithoutAnnotation", - new HttpEntity<>(map, headers), - String.class); - - assertThat(result, is(file1Content + file2Content + username)); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "uploadWithoutAnnotation", - new HttpEntity<>(map, headers), - String.class); - ResponseEntity responseEntity = listenableFuture.get(); - assertThat(responseEntity.getBody(), is(file1Content + file2Content + username)); - } - - @Test - public void blowsUpWhenFileNameDoesNotMatch() throws Exception { - String file1Content = "hello world"; - String file2Content = "bonjour"; - - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("file1", new FileSystemResource(newFile(file1Content).getAbsolutePath())); - map.add("unmatched name", new FileSystemResource(newFile(file2Content).getAbsolutePath())); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); - - ResponseEntity response = null; - try { - response = restTemplate - .postForEntity(codeFirstUrl + "uploadWithoutAnnotation", new HttpEntity<>(map, headers), String.class); - assertEquals("required is true, throw exception", "but not throw exception"); - } catch (RestClientException e) { - assertEquals("400 Bad Request",e.getMessage()); - } - } - - @Test - public void ableToPostDate() throws Exception { - ZonedDateTime date = ZonedDateTime.now().truncatedTo(SECONDS); - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("date", RestObjectMapperFactory.getRestObjectMapper().convertToString(Date.from(date.toInstant()))); - - HttpHeaders headers = new HttpHeaders(); - headers.add(CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE); - - int seconds = 1; - Date result = restTemplate.postForObject(codeFirstUrl + "addDate?seconds={seconds}", - new HttpEntity<>(body, headers), - Date.class, - seconds); - - assertThat(result, is(Date.from(date.plusSeconds(seconds).toInstant()))); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "addDate?seconds={seconds}", - new HttpEntity<>(body, headers), - Date.class, - seconds); - ResponseEntity dateResponseEntity = listenableFuture.get(); - assertThat(dateResponseEntity.getBody(), is(Date.from(date.plusSeconds(seconds).toInstant()))); - } - - @Test - public void ableToDeleteWithQueryString() throws Exception { - ResponseEntity responseEntity = restTemplate.exchange(codeFirstUrl + "addstring?s=a&s=b", - HttpMethod.DELETE, - null, - String.class); - - assertThat(responseEntity.getBody(), is("ab")); - ListenableFuture> listenableFuture = asyncRestTemplate - .exchange(codeFirstUrl + "addstring?s=a&s=b", HttpMethod.DELETE, null, String.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getBody(), is("ab")); - } - - @Test - public void ableToGetBoolean() throws Exception { - boolean result = restTemplate.getForObject(codeFirstUrl + "istrue", boolean.class); - - assertThat(result, is(true)); - - ListenableFuture> listenableFuture = asyncRestTemplate - .getForEntity(codeFirstUrl + "istrue", boolean.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getBody(), is(true)); - } - - @Test - public void putsEndWithPathParam() throws Exception { - ResponseEntity responseEntity = restTemplate - .exchange(codeFirstUrl + "sayhi/{name}", PUT, null, String.class, "world"); - - assertThat(responseEntity.getStatusCode(), is(ACCEPTED)); - assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi")); - - ListenableFuture> listenableFuture = asyncRestTemplate - .exchange(codeFirstUrl + "sayhi/{name}", PUT, null, String.class, "world"); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getStatusCode(), is(ACCEPTED)); - assertThat(jsonOf(futureResponse.getBody(), String.class), is("world sayhi")); - } - - @Test - public void putsContainingPathParam() throws Exception { - ResponseEntity responseEntity = restTemplate - .exchange(codeFirstUrl + "sayhi/{name}/v2", PUT, null, String.class, "world"); - - assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi 2")); - ListenableFuture> listenableFuture = asyncRestTemplate - .exchange(codeFirstUrl + "sayhi/{name}/v2", PUT, null, String.class, "world"); - responseEntity = listenableFuture.get(); - assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi 2")); - } - - @Test - public void ableToPostWithHeader() throws Exception { - Person person = new Person(); - person.setName("person name"); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(APPLICATION_JSON); - headers.add("prefix", "prefix prefix"); - - HttpEntity requestEntity = new HttpEntity<>(person, headers); - ResponseEntity responseEntity = restTemplate - .postForEntity(codeFirstUrl + "saysomething", requestEntity, String.class); - - assertThat(jsonOf(responseEntity.getBody(), String.class), is("prefix prefix person name")); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "saysomething", requestEntity, String.class); - responseEntity = listenableFuture.get(); - assertThat(jsonOf(responseEntity.getBody(), String.class), is("prefix prefix person name")); - } - - @Test - public void ableToPostObjectAsJson() throws Exception { - Map personFieldMap = new HashMap<>(); - personFieldMap.put("name", "person name from map"); - - Person person = restTemplate - .postForObject(codeFirstUrl + "sayhello", jsonRequest(personFieldMap), Person.class); - assertThat(person.toString(), is("hello person name from map")); - - Person input = new Person(); - input.setName("person name from Object"); - person = restTemplate.postForObject(codeFirstUrl + "sayhello", jsonRequest(input), Person.class); - - assertThat(person.toString(), is("hello person name from Object")); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "sayhello", jsonRequest(personFieldMap), Person.class); - ResponseEntity futureResponse = listenableFuture.get(); - person = futureResponse.getBody(); - assertThat(person.toString(), is("hello person name from map")); - - listenableFuture = asyncRestTemplate.postForEntity(codeFirstUrl + "sayhello", jsonRequest(input), Person.class); - futureResponse = listenableFuture.get(); - person = futureResponse.getBody(); - assertThat(person.toString(), is("hello person name from Object")); - } - - @Test - public void ableToPostForm() throws Exception { - MultiValueMap params = new LinkedMultiValueMap<>(); - params.add("a", "5"); - params.add("b", "3"); - - HttpHeaders headers = new HttpHeaders(); - headers.add(CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE); - int result = restTemplate - .postForObject(codeFirstUrl + "add", new HttpEntity<>(params, headers), Integer.class); - - assertThat(result, is(8)); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(codeFirstUrl + "add", new HttpEntity<>(params, headers), Integer.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getBody(), is(8)); - } - - @Test - public void ableToExchangeCookie() throws Exception { - Map params = new HashMap<>(); - params.put("a", "5"); - - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.COOKIE, "b=3"); - - HttpEntity requestEntity = new HttpEntity<>(headers); - ResponseEntity result = restTemplate.exchange( - codeFirstUrl + "reduce?a={a}", - GET, - requestEntity, - Integer.class, - params); - - assertThat(result.getBody(), is(2)); - - ListenableFuture> listenableFuture = asyncRestTemplate - .exchange(codeFirstUrl + "reduce?a={a}", - GET, - requestEntity, - Integer.class, - params); - result = listenableFuture.get(); - assertThat(result.getBody(), is(2)); - } - - @Test - public void getsEndWithRequestVariables() throws Exception { - int result = restTemplate.getForObject( - controllerUrl + "add?a={a}&b={b}", - Integer.class, - 3, - 4); - - assertThat(result, is(7)); - ListenableFuture> listenableFuture = asyncRestTemplate - .getForEntity(controllerUrl + "add?a={a}&b={b}", - Integer.class, - 3, - 4); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(futureResponse.getBody(), is(7)); - } - - @Test - public void postsEndWithPathParam() throws Exception { - String result = restTemplate.postForObject( - controllerUrl + "sayhello/{name}", - null, - String.class, - "world"); - - assertThat(jsonOf(result, String.class), is("hello world")); - - List> convertersOld = restTemplate.getMessageConverters(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - restTemplate.setMessageConverters(converters); - result = restTemplate.postForObject( - controllerUrl + "sayhello/{name}", - null, - String.class, - "中 国"); - - assertThat(result, is("hello 中 国")); - restTemplate.setMessageConverters(convertersOld); - - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(controllerUrl + "sayhello/{name}", - null, - String.class, - "world"); - ResponseEntity futureResonse = listenableFuture.get(); - assertThat(jsonOf(futureResonse.getBody(), String.class), is("hello world")); - asyncRestTemplate.setMessageConverters(converters); - listenableFuture = asyncRestTemplate.postForEntity(controllerUrl + "sayhello/{name}", - null, - String.class, - "中 国"); - futureResonse = listenableFuture.get(); - assertThat(futureResonse.getBody(), is("hello 中 国")); - asyncRestTemplate.setMessageConverters(convertersOld); - } - - @Test - public void ableToPostObjectAsJsonWithRequestVariable() throws Exception { - Person input = new Person(); - input.setName("world"); - - String result = restTemplate.postForObject( - controllerUrl + "saysomething?prefix={prefix}", - jsonRequest(input), - String.class, - "hello"); - - assertThat(jsonOf(result, String.class), is("hello world")); - - List> convertersOld = restTemplate.getMessageConverters(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - restTemplate.setMessageConverters(converters); - input = new Person(); - input.setName("中国"); - - result = restTemplate.postForObject( - controllerUrl + "saysomething?prefix={prefix}", - jsonRequest(input), - String.class, - "hello"); - - assertThat(result, is("hello 中国")); - restTemplate.setMessageConverters(convertersOld); - - input.setName("world"); - ListenableFuture> listenableFuture = asyncRestTemplate - .postForEntity(controllerUrl + "saysomething?prefix={prefix}", - jsonRequest(input), - String.class, - "hello"); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(jsonOf(futureResponse.getBody(), String.class), is("hello world")); - - asyncRestTemplate.setMessageConverters(converters); - input.setName("中国"); - listenableFuture = asyncRestTemplate.postForEntity(controllerUrl + "saysomething?prefix={prefix}", - jsonRequest(input), - String.class, - "hello"); - futureResponse = listenableFuture.get(); - assertThat(futureResponse.getBody(), is("hello 中国")); - asyncRestTemplate.setMessageConverters(convertersOld); - } - - @Test - public void ensureServerWorksFine() throws Exception { - String result = restTemplate.getForObject( - controllerUrl + "sayhi?name=world", - String.class); - - assertThat(jsonOf(result, String.class), is("hi world [world]")); - ListenableFuture> listenableFuture = asyncRestTemplate - .getForEntity(controllerUrl + "sayhi?name=world", - String.class); - ResponseEntity futureResponse = listenableFuture.get(); - assertThat(jsonOf(futureResponse.getBody(), String.class), is("hi world [world]")); - } - - @Test - public void ensureServerBlowsUp() { - ResponseEntity response = restTemplate - .getForEntity(controllerUrl + "sayhi?name=throwexception", String.class); - assertThat(response.getStatusCodeValue(), is(590)); - assertThat(response.getBody(), is("{\"message\":\"Cse Internal Server Error\"}")); - } - - @Test - public void ableToSetCustomHeader() { - HttpHeaders headers = new HttpHeaders(); - headers.set("name", "world"); - - HttpEntity requestEntity = new HttpEntity<>(headers); - ResponseEntity result = restTemplate.exchange( - controllerUrl + "sayhei", - GET, - requestEntity, - String.class); - - assertThat(jsonOf(result.getBody(), String.class), is("hei world")); - - ListenableFuture> listenableFuture = asyncRestTemplate.exchange(controllerUrl + "sayhei", - GET, - requestEntity, - String.class); -// ResponseEntity responseEntity = listenableFuture.get(); - listenableFuture.addCallback( - new ListenableFutureCallback>() { - @Override - public void onFailure(Throwable ex) { - } - - @Override - public void onSuccess(ResponseEntity result) { - assertThat(jsonOf(result.getBody(), String.class), is("hei world")); - } - } - ); - } - - private HttpEntity jsonRequest(T body) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(APPLICATION_JSON); - return new HttpEntity<>(body, headers); - } - - private T jsonOf(String json, Class aClass) { - try { - return RestObjectMapperFactory.getRestObjectMapper().readValue(json, aClass); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to read JSON from " + json + ", Exception is: " + e); - } - } - - private File newFile(String fileContent) throws IOException { - File file = folder.newFile(); - try (FileOutputStream output = new FileOutputStream(file)) { - IOUtils.write(fileContent, output); - } - return file; - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvc.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvc.java deleted file mode 100644 index c235b799909..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvc.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.multipart.MultipartFile; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; - -@Profile("!SimplifiedMapping") -@RestSchema(schemaId = "codeFirst") -@RequestMapping(path = "/codeFirstSpringmvc", produces = MediaType.APPLICATION_JSON_VALUE) -public class CodeFirstSpringmvc extends CodeFirstSpringmvcBase { - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) - @RequestMapping(path = "/responseEntity", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - @Override - public ResponseEntity responseEntity(InvocationContext c1, @RequestAttribute("date") Date date) { - return super.responseEntity(c1, date); - } - - @ApiResponse(code = 200, response = User.class, message = "") - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) - @RequestMapping(path = "/cseResponse", method = RequestMethod.GET) - @Override - public Response cseResponse(InvocationContext c1) { - return super.cseResponse(c1); - } - - @RequestMapping(path = "/testUserMap", method = RequestMethod.POST) - @Override - public Map testUserMap(@RequestBody Map userMap) { - return super.testUserMap(userMap); - } - - @RequestMapping(path = "/textPlain", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE) - @Override - public String textPlain(@RequestBody String body) { - return super.textPlain(body); - } - - @RequestMapping(path = "/bytes", method = RequestMethod.POST) - @Override - public byte[] bytes(@RequestBody byte[] input) { - return super.bytes(input); - } - - @RequestMapping(path = "/upload", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - @Override - public String fileUpload(@RequestPart(name = "file1") MultipartFile file1, - @RequestPart(name = "someFile") MultipartFile file2, @RequestAttribute("name") String name) { - return super.fileUpload(file1, file2, name); - } - - @RequestMapping(path = "/uploadWithoutAnnotation", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public String fileUploadWithoutAnnotation(MultipartFile file1, MultipartFile file2, - @RequestAttribute("name") String name) { - return super.fileUpload(file1, file2, name); - } - - @RequestMapping(path = "/addDate", method = RequestMethod.POST) - @Override - public Date addDate(@RequestAttribute("date") Date date, @QueryParam("seconds") long seconds) { - return super.addDate(date, seconds); - } - - // this should be ignored as it's hidden - @ApiOperation(value = "", hidden = true, httpMethod = "POST") - public int add(@RequestParam("a") int a) { - return a; - } - - @RequestMapping(path = "/add", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - @Override - public int add(@RequestAttribute("a") int a, @RequestAttribute("b") int b) { - return super.add(a, b); - } - - @RequestMapping(path = "/reduce", method = RequestMethod.GET) - @ApiImplicitParams({@ApiImplicitParam(name = "a", dataType = "integer", format = "int32", paramType = "query")}) - @Override - public int reduce(HttpServletRequest request, @CookieValue(name = "b") int b) { - return super.reduce(request, b); - } - - @RequestMapping(path = "/sayhello", method = RequestMethod.POST) - @Override - public Person sayHello(@RequestBody Person user) { - return super.sayHello(user); - } - - @RequestMapping(path = "/testrawjson", method = RequestMethod.POST) - @Override - public String testRawJsonString(String jsonInput) { - return super.testRawJsonString(jsonInput); - } - - @RequestMapping(path = "/saysomething", method = RequestMethod.POST) - @Override - public String saySomething(@RequestHeader(name = "prefix") String prefix, @RequestBody Person user) { - return super.saySomething(prefix, user); - } - - @RequestMapping(path = "/sayhi/{name}", method = RequestMethod.PUT) - @Override - public String sayHi(@PathVariable(name = "name") String name) { - return super.sayHi(name); - } - - @RequestMapping(path = "/sayhi/{name}/v2", method = RequestMethod.PUT) - @Override - public String sayHi2(@PathVariable(name = "name") String name) { - return super.sayHi2(name); - } - - @RequestMapping(path = "/istrue", method = RequestMethod.GET) - @Override - public boolean isTrue() { - return super.isTrue(); - } - - @RequestMapping(path = "/addstring", method = RequestMethod.DELETE, produces = MediaType.TEXT_PLAIN_VALUE) - @Override - public String addString(@RequestParam(name = "s") List s) { - return super.addString(s); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcBase.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcBase.java deleted file mode 100644 index 912da180d1c..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcBase.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.Response.Status; - -import org.apache.commons.io.IOUtils; -import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.response.Headers; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.multipart.MultipartFile; - -public class CodeFirstSpringmvcBase { - public ResponseEntity responseEntity(InvocationContext c1, Date date) { - HttpHeaders headers = new HttpHeaders(); - headers.add("h1", "h1v " + c1.getContext().toString()); - - InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.add("h2", "h2v " + c2.getContext().toString()); - - return new ResponseEntity(date, headers, HttpStatus.ACCEPTED); - } - - public Response cseResponse(InvocationContext c1) { - Response response = Response.createSuccess(Status.ACCEPTED, new User()); - Headers headers = response.getHeaders(); - headers.addHeader("h1", "h1v " + c1.getContext().toString()); - - InvocationContext c2 = ContextUtils.getInvocationContext(); - headers.addHeader("h2", "h2v " + c2.getContext().toString()); - - return response; - } - - public Map testUserMap(Map userMap) { - return userMap; - } - - public String textPlain(String body) { - return body; - } - - public byte[] bytes(byte[] input) { - input[0] = (byte) (input[0] + 1); - return input; - } - - public String fileUpload(MultipartFile file1, MultipartFile file2, String name) { - try { - return IOUtils.toString(file1.getBytes(), StandardCharsets.UTF_8.name()) - + IOUtils.toString(file2.getBytes(), StandardCharsets.UTF_8.name()) - + name; - } catch (IOException e) { - throw new IllegalArgumentException(e); - } - } - - public Date addDate(Date date, long seconds) { - return new Date(date.getTime() + seconds * 1000); - } - - public int add(int a) { - return a; - } - - public int add(int a, int b) { - return a + b; - } - - public int reduce(HttpServletRequest request, int b) { - int a = Integer.parseInt(request.getParameter("a")); - return a - b; - } - - public Person sayHello(Person user) { - user.setName("hello " + user.getName()); - return user; - } - - @SuppressWarnings("unchecked") - public String testRawJsonString(String jsonInput) { - Map person; - try { - person = RestObjectMapperFactory.getRestObjectMapper().readValue(jsonInput.getBytes(), Map.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - return "hello " + person.get("name"); - } - - public String saySomething(String prefix, Person user) { - return prefix + " " + user.getName(); - } - - public String sayHi(String name) { - ContextUtils.getInvocationContext().setStatus(202); - return name + " sayhi"; - } - - public String sayHi2(String name) { - return name + " sayhi 2"; - } - - public boolean isTrue() { - return true; - } - - public String addString(List s) { - String result = ""; - for (String x : s) { - result += x; - } - return result; - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcSimplifiedMappingAnnotation.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcSimplifiedMappingAnnotation.java deleted file mode 100644 index 65e6b8ccd99..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/CodeFirstSpringmvcSimplifiedMappingAnnotation.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.demo.server.User; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.multipart.MultipartFile; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; - -@Profile("SimplifiedMapping") -@RestSchema(schemaId = "codeFirstSpringmvcSimplifiedMappingAnnotation") -@RequestMapping(path = "/codeFirstSpringmvc", produces = MediaType.APPLICATION_JSON_VALUE) -public class CodeFirstSpringmvcSimplifiedMappingAnnotation extends CodeFirstSpringmvcBase { - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) - @PostMapping(path = "/responseEntity") - @Override - public ResponseEntity responseEntity(InvocationContext c1, @RequestAttribute("date") Date date) { - return super.responseEntity(c1, date); - } - - @ApiResponse(code = 200, response = User.class, message = "") - @ResponseHeaders({@ResponseHeader(name = "h1", response = String.class), - @ResponseHeader(name = "h2", response = String.class)}) - @GetMapping(path = "/cseResponse") - @Override - public Response cseResponse(InvocationContext c1) { - return super.cseResponse(c1); - } - - @PostMapping(path = "/testUserMap") - @Override - public Map testUserMap(@RequestBody Map userMap) { - return super.testUserMap(userMap); - } - - @PostMapping(path = "/textPlain", consumes = MediaType.TEXT_PLAIN_VALUE) - @Override - public String textPlain(@RequestBody String body) { - return super.textPlain(body); - } - - @PostMapping(path = "/bytes") - @Override - public byte[] bytes(@RequestBody byte[] input) { - return super.bytes(input); - } - - @PostMapping(path = "/upload", produces = MediaType.TEXT_PLAIN_VALUE) - @Override - public String fileUpload(@RequestPart(name = "file1") MultipartFile file1, - @RequestPart(name = "someFile") MultipartFile file2, @RequestAttribute("name") String name) { - return super.fileUpload(file1, file2, name); - } - - @PostMapping(path = "/uploadWithoutAnnotation", produces = MediaType.TEXT_PLAIN_VALUE) - public String fileUploadWithoutAnnotation(MultipartFile file1, MultipartFile file2, - @RequestAttribute("name") String name) { - return super.fileUpload(file1, file2, name); - } - - @PostMapping(path = "/addDate") - @Override - public Date addDate(@RequestAttribute("date") Date date, @QueryParam("seconds") long seconds) { - return super.addDate(date, seconds); - } - - - // this should be ignored as it's hidden - @ApiOperation(value = "", hidden = true, httpMethod = "POST") - public int add(@RequestParam("a") int a) { - return a; - } - - @PostMapping(path = "/add") - @Override - public int add(@RequestAttribute("a") int a, @RequestAttribute("b") int b) { - return super.add(a, b); - } - - @GetMapping(path = "/reduce") - @ApiImplicitParams({@ApiImplicitParam(name = "a", dataType = "integer", format = "int32", paramType = "query")}) - @Override - public int reduce(HttpServletRequest request, @CookieValue(name = "b") int b) { - return super.reduce(request, b); - } - - @PostMapping(path = "/sayhello") - @Override - public Person sayHello(@RequestBody Person user) { - return super.sayHello(user); - } - - @PostMapping(path = "/testrawjson") - @Override - public String testRawJsonString(String jsonInput) { - return super.testRawJsonString(jsonInput); - } - - @PostMapping(path = "/saysomething") - @Override - public String saySomething(@RequestHeader(name = "prefix") String prefix, @RequestBody Person user) { - return super.saySomething(prefix, user); - } - - @PutMapping(path = "/sayhi/{name}") - @Override - public String sayHi(@PathVariable(name = "name") String name) { - return super.sayHi(name); - } - - @PutMapping(path = "/sayhi/{name}/v2") - @Override - public String sayHi2(@PathVariable(name = "name") String name) { - return super.sayHi2(name); - } - - @GetMapping(path = "/istrue") - @Override - public boolean isTrue() { - return super.isTrue(); - } - - @DeleteMapping(path = "/addstring", produces = MediaType.TEXT_PLAIN_VALUE) - @Override - public String addString(@RequestParam(name = "s") List s) { - return super.addString(s); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerBase.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerBase.java deleted file mode 100644 index 1898bb55e3c..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerBase.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import java.util.Arrays; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.demo.controller.Person; - -public class ControllerBase { - public int add(int a, int b) { - return a + b; - } - - public String sayHello(String name) { - return "hello " + name; - } - - public String saySomething(String prefix, Person user) { - return prefix + " " + user.getName(); - } - - public String sayHi(HttpServletRequest request) { - String[] values = request.getParameterValues("name"); - if (values != null && values.length > 0 && values[0].equals("throwexception")) { - throw new RuntimeException(); - } - return "hi " + request.getParameter("name") + " " + Arrays.toString(values); - } - - public String sayHei(String name) { - return "hei " + name; - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerImpl.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerImpl.java deleted file mode 100644 index 7d4b407e83d..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -@Profile("!SimplifiedMapping") -@RestSchema(schemaId = "controller") -@RequestMapping(path = "/springmvc/controller", produces = MediaType.APPLICATION_JSON) -public class ControllerImpl extends ControllerBase { - @RequestMapping(path = "/add", method = RequestMethod.GET) - @Override - public int add(@RequestParam("a") int a, @RequestParam("b") int b) { - return super.add(a, b); - } - - @RequestMapping(path = "/sayhello/{name}", method = RequestMethod.POST) - @Override - public String sayHello(@PathVariable("name") String name) { - return super.sayHello(name); - } - - @RequestMapping(path = "/saysomething", method = RequestMethod.POST) - @Override - public String saySomething(String prefix, @RequestBody Person user) { - return super.saySomething(prefix, user); - } - - @RequestMapping(path = "/sayhi", method = RequestMethod.GET) - @Override - public String sayHi(HttpServletRequest request) { - return super.sayHi(request); - } - - @RequestMapping(path = "/sayhei", method = RequestMethod.GET) - @Override - public String sayHei(@RequestHeader("name") String name) { - return super.sayHei(name); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerSimplifiedMappingAnnotationImpl.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerSimplifiedMappingAnnotationImpl.java deleted file mode 100644 index b3957d18bf1..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/ControllerSimplifiedMappingAnnotationImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.demo.controller.Person; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@Profile("SimplifiedMapping") -@RestSchema(schemaId = "controllerSimplifiedMappingAnnotationImpl") -@RequestMapping(path = "/springmvc/controller", produces = MediaType.APPLICATION_JSON) -public class ControllerSimplifiedMappingAnnotationImpl extends ControllerBase { - @GetMapping(path = "/add") - @Override - public int add(@RequestParam("a") int a, @RequestParam("b") int b) { - return super.add(a, b); - } - - @PostMapping(path = "/sayhello/{name}") - @Override - public String sayHello(@PathVariable("name") String name) { - return super.sayHello(name); - } - - @PostMapping(path = "/saysomething") - @Override - public String saySomething(String prefix, @RequestBody Person user) { - return super.saySomething(prefix, user); - } - - @GetMapping(path = "/sayhi") - @Override - public String sayHi(HttpServletRequest request) { - return super.sayHi(request); - } - - @GetMapping(path = "/sayhei") - @Override - public String sayHei(@RequestHeader("name") String name) { - return super.sayHei(name); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpoint.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpoint.java deleted file mode 100644 index 4eb8e2f2f94..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpoint.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -@Profile("!SimplifiedMapping") -@RestSchema(schemaId = "englishGreetingRestEndpoint") -@RequestMapping(path = "/") -public class EnglishGreetingRestEndpoint extends EnglishGreetingRestEndpointBase { - @RequestMapping(path = "/sayHi", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String sayHi(@RequestParam("name") String name) { - return super.sayHi(name); - } - - @RequestMapping(path = "", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String home() { - return super.home(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpointBase.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpointBase.java deleted file mode 100644 index c32bc9ee17f..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingRestEndpointBase.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -public class EnglishGreetingRestEndpointBase { - - public String sayHi(String name) { - return "Hi " + name; - } - - public String home() { - return "Welcome home"; - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingSimplifiedMappingAnnotationRestEndpoint.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingSimplifiedMappingAnnotationRestEndpoint.java deleted file mode 100644 index 33aec9ce011..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/EnglishGreetingSimplifiedMappingAnnotationRestEndpoint.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -@Profile("SimplifiedMapping") -@RestSchema(schemaId = "englishGreetingSimplifiedMappingAnnotationRestEndpoint") -@RequestMapping(path = "/") -public class EnglishGreetingSimplifiedMappingAnnotationRestEndpoint extends EnglishGreetingRestEndpointBase { - @GetMapping(path = "/sayHi", produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String sayHi(@RequestParam("name") String name) { - return super.sayHi(name); - } - - @GetMapping(path = "", produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String home() { - return super.home(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpoint.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpoint.java deleted file mode 100644 index bf24bd36e27..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpoint.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -@Profile("!SimplifiedMapping") -@RestSchema(schemaId = "frenchGreetingRestEndpoint") -@RequestMapping(path = "/french") -public class FrenchGreetingRestEndpoint extends FrenchGreetingRestEndpointBase { - @RequestMapping(path = "/bonjour", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String bonjour(@RequestParam("name") String name) { - return super.bonjour(name); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpointBase.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpointBase.java deleted file mode 100644 index 4bcfba99fe4..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingRestEndpointBase.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -public class FrenchGreetingRestEndpointBase { - public String bonjour(String name) { - return "Bonjour " + name; - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingSimplifiedMappingAnnotationRestEndpoint.java b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingSimplifiedMappingAnnotationRestEndpoint.java deleted file mode 100644 index 56033e80166..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/endpoints/FrenchGreetingSimplifiedMappingAnnotationRestEndpoint.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests.endpoints; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.context.annotation.Profile; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -@Profile("SimplifiedMapping") -@RestSchema(schemaId = "frenchGreetingSimplifiedMappingAnnotationRestEndpoint") -@RequestMapping(path = "/french") -public class FrenchGreetingSimplifiedMappingAnnotationRestEndpoint extends FrenchGreetingRestEndpointBase { - @GetMapping(path = "/bonjour", produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - @Override - public String bonjour(@RequestParam("name") String name) { - return super.bonjour(name); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-connection-limit/pom.xml deleted file mode 100644 index f2e59da6f11..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - springmvc-tests-connection-limit - Java Chassis::Integration Tests::Spring MVC Connection Limit - - - - org.apache.servicecomb.tests - springmvc-tests-common - 1.2.0-SNAPSHOT - test-jar - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java b/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java deleted file mode 100644 index 546274d2b44..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.junit.Assert.fail; - -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.web.client.RestTemplate; - -public class RawSpringMvcIntegrationTest { - - private RestTemplate restTemplate = RestTemplateBuilder.create(); - - private final String baseUrl = "http://127.0.0.1:8080/"; - - private final String controllerUrl = baseUrl + "springmvc/controller/"; - - @BeforeClass - public static void init() throws Exception { - System.setProperty("servicecomb.uploads.directory", "/tmp"); - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - SpringMvcTestMain.main(new String[0]); - } - - @Test - public void ensureServerWorksFine() { - try { - restTemplate.getForObject(controllerUrl + "sayhi?name=world", String.class); - fail("connection limit failed"); - } catch (Exception ex) { - Assert.assertEquals("java.net.SocketException: Unexpected end of file from server", ex.getCause().toString()); - } - } - - @AfterClass - public static void shutdown() { - SCBEngine.getInstance().destroy(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java b/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java deleted file mode 100644 index 99d937049f5..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class SpringMvcTestMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/config/log4j.z.properties b/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 02401e6e706..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/microservice.yaml b/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/microservice.yaml deleted file mode 100644 index 97340cf5d27..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-connection-limit/src/test/resources/microservice.yaml +++ /dev/null @@ -1,33 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvctest-it -service_description: - name: springmvc-tests - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - server: - connection-limit: 0 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/pom.xml deleted file mode 100644 index d12ec8c28b1..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - Java Chassis::Integration Tests::Spring MVC General With Spring Boot - springmvc-tests-general-with-springboot - - - - org.apache.servicecomb.tests - springmvc-tests-common - ${project.version} - test-jar - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.springframework.boot - spring-boot-test - - - org.springframework - spring-test - - - org.hibernate - hibernate-validator - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringIntegrationTest.java b/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringIntegrationTest.java deleted file mode 100644 index 1eb879344ee..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringIntegrationTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.core.SCBEngine; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.springframework.boot.SpringApplication; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -public class SpringMvcSpringIntegrationTest extends SpringMvcIntegrationTestBase { - @BeforeClass - public static void init() { - System.setProperty("servicecomb.uploads.directory", "/tmp"); - setUpLocalRegistry(); - SpringApplication.run(SpringMvcSpringMain.class); - } - - @AfterClass - public static void shutdown() { - SCBEngine.getInstance().destroy(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java b/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java deleted file mode 100644 index e149464af89..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -class SpringMvcSpringMain { -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/log4j.properties b/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/log4j.properties deleted file mode 100644 index 705b2f7c5a0..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/log4j.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.rootLogger=WARN, stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/microservice.yaml b/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/microservice.yaml deleted file mode 100644 index a5d81f8712e..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general-with-springboot/src/test/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvctest-it -service_description: - name: springmvc-tests - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/springmvc-tests/springmvc-tests-general/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-general/pom.xml deleted file mode 100644 index 435dc2a926c..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - Java Chassis::Integration Tests::Spring MVC General - springmvc-tests-general - - - - org.apache.servicecomb.tests - springmvc-tests-common - 1.2.0-SNAPSHOT - test-jar - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java b/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java deleted file mode 100644 index 30924d7f8d6..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcIntegrationTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.core.SCBEngine; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -public class RawSpringMvcIntegrationTest extends SpringMvcIntegrationTestBase { - @BeforeClass - public static void init() throws Exception { - System.setProperty("servicecomb.uploads.directory", "/tmp"); - setUpLocalRegistry(); - SpringMvcTestMain.main(new String[0]); - } - - @AfterClass - public static void shutdown() { - SCBEngine.getInstance().destroy(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java b/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java deleted file mode 100644 index 99d937049f5..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class SpringMvcTestMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/config/log4j.z.properties b/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 02401e6e706..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/microservice.yaml b/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/microservice.yaml deleted file mode 100644 index a5d81f8712e..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-general/src/test/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvctest-it -service_description: - name: springmvc-tests - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/pom.xml deleted file mode 100644 index 90f6ca5fbc0..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - Java Chassis::Integration Tests::Spring MVC Simplified Mapping With Spring Boot - springmvc-tests-simplified-mapping-with-springboot - - - - org.apache.servicecomb.tests - springmvc-tests-common - 1.2.0-SNAPSHOT - test-jar - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.springframework.boot - spring-boot-test - - - org.springframework - spring-test - - - org.hibernate - hibernate-validator - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java deleted file mode 100644 index e149464af89..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringMain.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -class SpringMvcSpringMain { -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringSimplifiedMappingAnnotationIntegrationTest.java b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringSimplifiedMappingAnnotationIntegrationTest.java deleted file mode 100644 index 8987561d216..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcSpringSimplifiedMappingAnnotationIntegrationTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.core.SCBEngine; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.springframework.boot.SpringApplication; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -public class SpringMvcSpringSimplifiedMappingAnnotationIntegrationTest extends SpringMvcIntegrationTestBase { - @BeforeClass - public static void init() { - System.setProperty("spring.profiles.active", "SimplifiedMapping"); - System.setProperty("servicecomb.uploads.directory", "/tmp"); - setUpLocalRegistry(); - SpringApplication.run(SpringMvcSpringMain.class); - } - - @AfterClass - public static void shutdown() { - SCBEngine.getInstance().destroy(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/log4j.properties b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/log4j.properties deleted file mode 100644 index 705b2f7c5a0..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/log4j.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.rootLogger=WARN, stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/microservice.yaml b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/microservice.yaml deleted file mode 100644 index a5d81f8712e..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping-with-springboot/src/test/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvctest-it -service_description: - name: springmvc-tests - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/pom.xml b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/pom.xml deleted file mode 100644 index e5121ce44ac..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - springmvc-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - Java Chassis::Integration Tests::Spring MVC Simplified Mapping - springmvc-tests-simplified-mapping - - - - org.apache.servicecomb.tests - springmvc-tests-common - 1.2.0-SNAPSHOT - test-jar - - - - \ No newline at end of file diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcSimplifiedMappingAnnotationIntegrationTest.java b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcSimplifiedMappingAnnotationIntegrationTest.java deleted file mode 100644 index f167347fc4f..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/RawSpringMvcSimplifiedMappingAnnotationIntegrationTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.core.SCBEngine; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -public class RawSpringMvcSimplifiedMappingAnnotationIntegrationTest extends SpringMvcIntegrationTestBase { - @BeforeClass - public static void init() throws Exception { - System.setProperty("spring.profiles.active", "SimplifiedMapping"); - System.setProperty("servicecomb.uploads.directory", "/tmp"); - setUpLocalRegistry(); - SpringMvcTestMain.main(new String[0]); - } - - @AfterClass - public static void shutdown() { - SCBEngine.getInstance().destroy(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java deleted file mode 100644 index 99d937049f5..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcTestMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.demo.springmvc.tests; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class SpringMvcTestMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/config/log4j.z.properties b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/config/log4j.z.properties deleted file mode 100644 index 02401e6e706..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/config/log4j.z.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.runLogger=WARN -log4j.rootLogger=WARN,paas,stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n diff --git a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/microservice.yaml b/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/microservice.yaml deleted file mode 100644 index a5d81f8712e..00000000000 --- a/integration-tests/springmvc-tests/springmvc-tests-simplified-mapping/src/test/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvctest-it -service_description: - name: springmvc-tests - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/integration-tests/test-common/pom.xml b/integration-tests/test-common/pom.xml deleted file mode 100644 index 127db2e161c..00000000000 --- a/integration-tests/test-common/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - test-common - Java Chassis::Integration Tests::Common - - - - com.github.tomakehurst - wiremock-standalone - test - - - io.zipkin.java - zipkin-junit - - - io.zipkin.zipkin2 - zipkin - - - com.squareup.okhttp3 - okhttp - test - - - io.zipkin.brave - brave-context-log4j12 - - - com.google.code.findbugs - jsr305 - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - diff --git a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/EmbeddedAppender.java b/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/EmbeddedAppender.java deleted file mode 100644 index 6d2a4637dc1..00000000000 --- a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/EmbeddedAppender.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import javax.annotation.Nonnull; - -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.PatternLayout; - -import com.seanyinx.github.unit.scaffolding.Poller; - -public class EmbeddedAppender extends ConsoleAppender { - - private Queue events; - - private final Poller poller = new Poller(5000, 200); - - public EmbeddedAppender() { - super(new PatternLayout("%d{ABSOLUTE} [%X{traceId}/%X{spanId}/%X{parentId}] %-5p [%t] %C{2} (%F:%L) - %m%n")); - } - - @Override - protected OutputStreamWriter createWriter(OutputStream os) { - events = new ConcurrentLinkedQueue<>(); - return super.createWriter(new InMemoryOutputStream(events, os)); - } - - public Collection pollLogs(String regex) { - final Set messages = new LinkedHashSet<>(); - - poller.assertEventually(() -> { - for (String event : events) { - if (event.trim().matches(regex)) { - messages.add(event); - } - } - return !messages.isEmpty(); - }); - - return messages; - } - - public void clear() { - events.clear(); - } - - private static class InMemoryOutputStream extends OutputStream { - - private final Queue events; - - private final OutputStream outputStream; - - InMemoryOutputStream(Queue events, OutputStream outputStream) { - this.events = events; - this.outputStream = outputStream; - } - - @Override - public void flush() throws IOException { - outputStream.flush(); - } - - @Override - public void write(int b) throws IOException { - outputStream.write(b); - events.add(String.valueOf(b)); - } - - @Override - public void write(@Nonnull byte[] b) throws IOException { - outputStream.write(b); - events.add(new String(b)); - } - - @Override - public void write(@Nonnull byte[] b, int off, int len) throws IOException { - outputStream.write(b, off, len); - events.add(new String(b, off, len)); - } - } -} diff --git a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/Log4jConfig.java b/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/Log4jConfig.java deleted file mode 100644 index 9f23b996dd5..00000000000 --- a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/Log4jConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests; - -import org.apache.log4j.Appender; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; - -public class Log4jConfig { - - private static final Logger rootLogger = Logger.getRootLogger(); - - public static Logger addAppender(Appender appender) { - rootLogger.removeAllAppenders(); - rootLogger.setLevel(Level.INFO); - rootLogger.addAppender(appender); - return rootLogger; - } - - public static Logger setLevel(Level level) { - rootLogger.setLevel(level); - return rootLogger; - } -} diff --git a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TraceContextConfig.java b/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TraceContextConfig.java deleted file mode 100644 index 8a01049d803..00000000000 --- a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TraceContextConfig.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import org.apache.log4j.MDC; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -import brave.internal.HexCodec; -import brave.propagation.CurrentTraceContext; -import brave.propagation.TraceContext; - -@Configuration -class TraceContextConfig { - - @Bean - @Primary - CurrentTraceContext traceContext() { - return ParentAwareMDCCurrentTraceContext.create(); - } - - private static class ParentAwareMDCCurrentTraceContext extends CurrentTraceContext { - @SuppressWarnings("deprecation") - static ParentAwareMDCCurrentTraceContext create() { - return new ParentAwareMDCCurrentTraceContext(new Default()); - } - - private final CurrentTraceContext delegate; - - ParentAwareMDCCurrentTraceContext(CurrentTraceContext delegate) { - if (delegate == null) { - throw new NullPointerException("delegate == null"); - } - this.delegate = delegate; - } - - @Override - public TraceContext get() { - return delegate.get(); - } - - @Override - public Scope newScope(TraceContext currentSpan) { - final Object previousTraceId = MDC.get("traceId"); - final Object previousSpanId = MDC.get("spanId"); - final Object previousParentId = MDC.get("parentId"); - - if (currentSpan != null) { - MDC.put("traceId", currentSpan.traceIdString()); - MDC.put("spanId", HexCodec.toLowerHex(currentSpan.spanId())); - if (currentSpan.parentId() != null) { - MDC.put("parentId", HexCodec.toLowerHex(currentSpan.parentId())); - } - } else { - MDC.remove("traceId"); - MDC.remove("spanId"); - MDC.remove("parentId"); - } - - Scope scope = delegate.newScope(currentSpan); - class MDCCurrentTraceContextScope implements Scope { - @Override - public void close() { - scope.close(); - if (previousTraceId != null) { - MDC.put("traceId", previousTraceId); - } else { - MDC.remove("traceId"); - } - - if (previousSpanId != null) { - MDC.put("spanId", previousSpanId); - } else { - MDC.remove("spanId"); - } - - if (previousParentId != null) { - MDC.put("parentId", previousParentId); - } else { - MDC.remove("parentId"); - } - } - } - return new MDCCurrentTraceContextScope(); - } - } -} diff --git a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestBase.java b/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestBase.java deleted file mode 100644 index df5063e7ba4..00000000000 --- a/integration-tests/test-common/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestBase.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_COLLECTOR_ADDRESS; -import static org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.springframework.http.HttpStatus.OK; - -import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.servicecomb.tests.EmbeddedAppender; -import org.apache.servicecomb.tests.Log4jConfig; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import zipkin.junit.ZipkinRule; -import zipkin2.Span; -import zipkin2.codec.SpanBytesDecoder; - -public class TracingTestBase { - - @ClassRule - public static final ZipkinRule zipkin = new ZipkinRule(); - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - protected static final EmbeddedAppender appender = new EmbeddedAppender(); - - final RestTemplate restTemplate = new RestTemplate(); - - @BeforeClass - public static void setUpClass() throws Exception { - System.setProperty(CONFIG_TRACING_COLLECTOR_ADDRESS, zipkin.httpUrl()); - setUpLocalRegistry(); - - Log4jConfig.addAppender(appender); - } - - private static void setUpLocalRegistry() { - System.setProperty(LOCAL_REGISTRY_FILE_KEY, "notExistJustForceLocal"); - } - - protected void assertThatSpansReceivedByZipkin(Collection logs, String... values) { - logs.forEach(message -> log.info("Received log: " + message)); - List loggedIds = logs.stream() - .map(this::extractIds) - .collect(Collectors.toList()); - - // Sleep for 5 seconds to wait the reporter finish posting to zipkin server. - // See SCB-293 - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - log.error("Thread interrupted, ", e.getMessage()); - Thread.currentThread().interrupt(); - } - - String url = zipkin.httpUrl() + "/api/v2/trace/{traceId}"; - log.info("rest url:" + url); - ResponseEntity responseEntity = restTemplate.getForEntity(url, String.class, traceId(loggedIds)); - - assertThat(responseEntity.getStatusCode(), is(OK)); - String body = responseEntity.getBody(); - log.info("Received trace json: {}", body); - List spans = new ArrayList<>(); - SpanBytesDecoder.JSON_V2.decodeList(body.getBytes(), spans); - - List tracedValues = tracedValues(spans); - tracedValues.forEach(value -> log.info("Received value {}", value)); - log.info("values: " + String.join(",", values)); - assertThat(tracedValues, containsInAnyOrder(values)); - } - - private List tracedValues(List spans) { - return spans.stream() - .filter(span -> span.tags() != null) - .map(span -> span.tags().entrySet()) - .flatMap(Collection::stream) - .filter(span -> "call.path".equals(span.getKey()) || "http.path".equals(span.getKey()) - || "http.status_code".equals(span.getKey())) - .filter(span -> span.getValue() != null) - .map(annotation -> new String(annotation.getValue())) - .distinct() - .collect(Collectors.toList()); - } - - private String extractIds(String message) { - return message.replaceFirst(".*\\[(\\w+/\\w+/\\w*)\\].*", "$1").trim(); - } - - private String traceId(List ids) { - return ids.get(0).split("/")[0]; - } -} diff --git a/integration-tests/tracing-tests/pom.xml b/integration-tests/tracing-tests/pom.xml deleted file mode 100644 index c663e75e06c..00000000000 --- a/integration-tests/tracing-tests/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - integration-tests - org.apache.servicecomb.tests - 1.2.0-SNAPSHOT - - 4.0.0 - - tracing-tests - Java Chassis::Integration Tests::Tracing - - - - org.apache.servicecomb.tests - test-common - test-jar - - - org.slf4j - slf4j-log4j12 - - - log4j - log4j - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - handler-tracing-zipkin - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - tracing-zipkin - - - io.zipkin.java - zipkin-junit - - - com.squareup.okhttp3 - okhttp - - - - diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepo.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepo.java deleted file mode 100644 index e1c270dbf10..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepo.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -public interface SlowRepo { - String crawl() throws InterruptedException; -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepoImpl.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepoImpl.java deleted file mode 100644 index 57b23a8c52b..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SlowRepoImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import java.util.Random; - -import org.apache.servicecomb.tracing.Span; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SlowRepoImpl implements SlowRepo { - private static final Logger logger = LoggerFactory.getLogger(SlowRepoImpl.class); - - private final Random random = new Random(); - - @Span - @Override - public String crawl() throws InterruptedException { - logger.info("in /crawl"); - Thread.sleep(random.nextInt(200)); - return "crawled"; - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SomeTracedController.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SomeTracedController.java deleted file mode 100644 index 0265f9ef5ae..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/SomeTracedController.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -@RestSchema(schemaId = "someTracedRestEndpoint") -@RestController -@RequestMapping("/") -public class SomeTracedController { - private static final Logger logger = LoggerFactory.getLogger(SomeTracedController.class); - - @Autowired - private RestTemplate template; - - @Autowired - private SlowRepo slowRepo; - - @RequestMapping(value = "/hello", method = GET, produces = TEXT_PLAIN_VALUE) - public String hello(HttpServletRequest request) throws InterruptedException { - logger.info("in /hello"); - - slowRepo.crawl(); - return "hello world, " + template.getForObject("cse://tracing-service/jaxrs/bonjour", String.class); - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedJaxrsController.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedJaxrsController.java deleted file mode 100644 index c600964ca5d..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedJaxrsController.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -import java.util.Random; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -@RestSchema(schemaId = "someTracedJaxrsRestEndpoint") -@Path("/jaxrs") -public class TracedJaxrsController { - private static final Logger logger = LoggerFactory.getLogger(TracedJaxrsController.class); - - private final Random random = new Random(); - - //@Autowired - //private RestTemplate template; - - @Autowired - private TracedPojo tracedPojo; - - @GET - @Path("/bonjour") - @Produces(TEXT_PLAIN) - public String bonjour(HttpServletRequest request) throws InterruptedException { - logger.info("in /bonjour"); - Thread.sleep(random.nextInt(100)); - - return "bonjour le monde, " + tracedPojo.pojo(); - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojo.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojo.java deleted file mode 100644 index f95e3b0eab2..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojo.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -interface TracedPojo { - - String pojo(); -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoConfig.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoConfig.java deleted file mode 100644 index 101d811a190..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.tracing.zipkin.EnableZipkinTracing; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@EnableZipkinTracing -@Configuration -class TracedPojoConfig { - - @RpcReference(microserviceName = "tracing-service", schemaId = "tracedPojo") - private TracedPojo tracedPojo; - - @Bean - TracedPojo tracedPojo() { - return tracedPojo; - } - - @Bean - SlowRepo slowRepo() { - return new SlowRepoImpl(); - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoImpl.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoImpl.java deleted file mode 100644 index 1b86123f7db..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracedPojoImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@RpcSchema(schemaId = "tracedPojo") -public class TracedPojoImpl implements TracedPojo { - - private static final Logger logger = LoggerFactory.getLogger(TracedPojoImpl.class); - - @Override - public String pojo() { - logger.info("in /pojo"); - return "hi pojo"; - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestMain.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestMain.java deleted file mode 100644 index ec12a81072a..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/TracingTestMain.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -public class TracingTestMain { - - public static void main(String[] args) { - BeanUtils.init(); - } -} diff --git a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/ZipkinTracingIntegrationTest.java b/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/ZipkinTracingIntegrationTest.java deleted file mode 100644 index fc307ec30a7..00000000000 --- a/integration-tests/tracing-tests/src/test/java/org/apache/servicecomb/tests/tracing/ZipkinTracingIntegrationTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.tests.tracing; - -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.springframework.http.HttpStatus.OK; - -import java.util.Collection; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.http.ResponseEntity; - -public class ZipkinTracingIntegrationTest extends TracingTestBase { - - @Before - public void setUp() throws Exception { - TracingTestMain.main(new String[0]); - } - - @Test - public void sendsTracingToConfiguredAddress() throws InterruptedException, NoSuchMethodException { - ResponseEntity entity = restTemplate.getForEntity("http://localhost:8080/hello", String.class); - - assertThat(entity.getStatusCode(), is(OK)); - assertThat(entity.getBody(), is("hello world, bonjour le monde, hi pojo")); - - TimeUnit.MILLISECONDS.sleep(1000); - - Collection tracingMessages = appender.pollLogs(".*\\[\\w+/\\w+/\\w*\\]\\s+INFO.*in /.*"); - assertThat(tracingMessages.size(), greaterThanOrEqualTo(2)); - - assertThatSpansReceivedByZipkin(tracingMessages, - "/hello", - SlowRepo.class.getMethod("crawl").toString(), - "/bonjour", - "/pojo"); - } -} diff --git a/integration-tests/tracing-tests/src/test/resources/log4j.properties b/integration-tests/tracing-tests/src/test/resources/log4j.properties deleted file mode 100644 index ff989feda5d..00000000000 --- a/integration-tests/tracing-tests/src/test/resources/log4j.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.logger.org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory=OFF -log4j.logger.org.apache.servicecomb.core.definition.schema.StaticSchemaFactory=OFF diff --git a/integration-tests/tracing-tests/src/test/resources/microservice.yaml b/integration-tests/tracing-tests/src/test/resources/microservice.yaml deleted file mode 100644 index b12e81a1ed4..00000000000 --- a/integration-tests/tracing-tests/src/test/resources/microservice.yaml +++ /dev/null @@ -1,41 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: tracing-app -service_description: - name: tracing-service - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080?sslEnabled=false - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: tracing-provider,bizkeeper-provider - Consumer: - default: tracing-consumer,loadbalance,bizkeeper-consumer - tracing: - collector: - address: http://localhost:9411 - executor: - default: - thread-per-group: 10 \ No newline at end of file diff --git a/java-chassis-dependencies-springboot2/pom.xml b/java-chassis-dependencies-springboot2/pom.xml deleted file mode 100644 index 7146d670b93..00000000000 --- a/java-chassis-dependencies-springboot2/pom.xml +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - java-chassis - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - java-chassis-dependencies-springboot2 - - Java Chassis::Dependencies::SpringBoot2 - pom - - - UTF-8 - 1.8 - - -Dfile.encoding=UTF-8 - UTF-8 - - 5.0.4.RELEASE - 2.0.0.RELEASE - Kay-RELEASE - 2.0.0.RELEASE - Finchley.RELEASE - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - org.springframework - spring-framework-bom - ${spring.version} - pom - import - - - - org.springframework.data - spring-data-releasetrain - ${spring.data.version} - pom - import - - - - org.apache.servicecomb - java-chassis-dependencies - ${project.version} - pom - import - - - - org.apache.servicecomb - spring-boot2-starter - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-servlet - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-standalone - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-discovery - ${project.version} - - - - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.maven.plugins - maven-remote-resources-plugin - [1.0,) - - process - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/java-chassis-dependencies/pom.xml b/java-chassis-dependencies/pom.xml deleted file mode 100644 index 699202dd6a9..00000000000 --- a/java-chassis-dependencies/pom.xml +++ /dev/null @@ -1,1097 +0,0 @@ - - - - - 4.0.0 - - - org.apache.servicecomb - java-chassis - 1.2.0-SNAPSHOT - - - java-chassis-dependencies - Java Chassis::Dependencies - pom - - - 2.9.6 - 3.5.3 - 0.8 - 4.3.16.RELEASE - 1.7.7 - 1.2.17 - 2.8.2 - 2.4 - 3.18.1-GA - 2.0.1 - 3.1.0 - 4.5.2 - 1.5.2 - 1.5.12 - 4.1.24.Final - 2.0.7.Final - ${basedir}/../.. - 5.3.2.Final - 3.1.6 - 1.1.7 - 4.13.1 - 2.4.2 - 2.2.2 - - - - - - javax.inject - javax.inject - 1 - - - com.netflix.ribbon - ribbon - 2.2.2 - - - com.netflix.ribbon - ribbon-core - 2.2.2 - - - com.google.code.findbugs - annotations - - - - - com.netflix.ribbon - ribbon-loadbalancer - 2.2.2 - - - com.google.code.findbugs - annotations - - - - - com.netflix.hystrix - hystrix-core - 1.5.10 - - - ch.qos.logback - logback-classic - ${logback.version} - - - ch.qos.logback - logback-core - ${logback.version} - - - junit - junit - 4.12 - test - - - io.reactivex - rxjava - 1.1.6 - - - org.mockito - mockito-core - 1.10.19 - test - - - org.mockito - mockito-all - 1.10.19 - test - - - org.jmockit - jmockit - 1.30 - test - - - org.hamcrest - hamcrest-core - 1.3 - test - - - org.hamcrest - hamcrest-all - 1.3 - test - - - com.dyuproject.protostuff - protostuff-api - 1.0.7.fixed.3500 - - - com.dyuproject.protostuff - protostuff-collectionschema - 1.0.7.fixed.3500 - - - com.dyuproject.protostuff - protostuff-core - 1.0.7.fixed.3500 - - - com.dyuproject.protostuff - protostuff-runtime - 1.0.7.fixed.3500 - - - javax.validation - validation-api - 2.0.0.Final - - - org.hibernate - hibernate-validator - 6.0.2.Final - - - - org.aspectj - aspectjweaver - 1.8.8 - - - com.google.guava - guava - 21.0 - - - - io.netty - netty-codec - ${netty.version} - - - io.netty - netty-codec-http - ${netty.version} - - - io.netty - netty-codec-http2 - ${netty.version} - - - io.netty - netty-common - ${netty.version} - - - io.netty - netty-handler - ${netty.version} - - - io.netty - netty-buffer - ${netty.version} - - - io.netty - netty-codec-dns - ${netty.version} - - - io.netty - netty-codec-socks - ${netty.version} - - - io.netty - netty-handler-proxy - ${netty.version} - - - io.netty - netty-resolver - ${netty.version} - - - io.netty - netty-resolver-dns - ${netty.version} - - - io.netty - netty-transport - ${netty.version} - - - io.netty - netty-tcnative-boringssl-static - ${tcnetty.version} - - - org.powermock - powermock-api-mockito - 1.6.2 - test - - - org.powermock - powermock-module-junit4 - 1.6.2 - test - - - - org.apache.tomcat.embed - tomcat-embed-core - 8.0.33 - - - org.apache.tomcat.embed - tomcat-embed-el - 8.0.33 - - - org.apache.tomcat.embed - tomcat-embed-logging-juli - 8.0.33 - - - org.apache.tomcat.embed - tomcat-embed-websocket - 8.0.33 - - - - com.squareup.okhttp3 - okhttp - 3.4.1 - - - - org.slf4j - log4j-over-slf4j - ${slf4j.version} - - - - commons-lang - commons-lang - 2.6 - - - - commons-logging - commons-logging - 1.2 - - - - javax.resource - connector-api - 1.5 - - - org.yaml - snakeyaml - 1.16 - - - org.hibernate - hibernate-validator-annotation-processor - 6.0.2.Final - - - javax.transaction - javax.transaction-api - 1.2 - - - - org.apache.commons - commons-lang3 - 3.6 - - - commons-beanutils - commons-beanutils - 1.9.2 - - - org.apache.cxf - cxf-rt-frontend-jaxws - ${cxf.version} - - - org.apache.cxf - cxf-rt-transports-http - ${cxf.version} - - - com.netflix.servo - servo-core - 0.10.1 - - - com.google.code.findbugs - annotations - - - - - com.netflix.spectator - spectator-reg-servo - 0.71.0 - - - com.google.inject - guice - 4.1.0 - - - org.glassfish.jersey.core - jersey-common - 2.22.2 - - - io.reactivex - rxnetty - 0.4.9 - - - - io.netty - netty-codec-http - - - io.netty - netty-handler - - - io.netty - netty-transport-native-epoll - - - - - - com.esotericsoftware - kryo-shaded - 3.0.3 - - - de.javakaffee - kryo-serializers - 0.26 - - - net.sf.json-lib - json-lib - 2.4 - jdk15 - - - com.netflix.governator - governator-api - 1.12.10 - - - org.codehaus.woodstox - woodstox-core-asl - 4.4.1 - provided - - - - org.codehaus.jettison - jettison - 1.3.8 - runtime - - - com.netflix.archaius - archaius-core - 0.7.3 - - - com.google.code.findbugs - annotations - - - - - com.google.code.findbugs - jsr305 - 3.0.1 - - - com.google.code.findbugs - annotations - 2.0.0 - - - commons-configuration - commons-configuration - 1.10 - - - - com.netflix.netflix-commons - netflix-eventbus - 0.3.0 - - - javax.servlet - servlet-api - - - - - com.thoughtworks.xstream - xstream - 1.4.9 - - - com.netflix.governator - governator-annotations - 1.14.2 - - - - com.netflix.netflix-commons - netflix-eventbus-rx - 0.3.0 - - - javax.servlet - servlet-api - - - com.netflix.rxjava - rxjava-core - - - - - - org.apache.zookeeper - zookeeper - 3.4.6 - provided - true - - - redis.clients - jedis - 2.8.0 - provided - true - - - org.mock-server - mockserver-netty - 3.10.4 - test - - - javax.annotation - javax.annotation-api - 1.2 - - - org.powermock - powermock-module-test-mockito-junit4-delegate - 1.6.2 - test - - - - org.apache.httpcomponents - httpclient - ${apache.httpclient} - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-ext - ${slf4j.version} - - - org.slf4j - slf4j-log4j12 - ${slf4j.version} - - - log4j - log4j - ${log4j.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - ${log4j2.version} - - - org.apache.logging.log4j - log4j-api - ${log4j2.version} - - - org.apache.logging.log4j - log4j-core - ${log4j2.version} - - - commons-io - commons-io - ${commons.io.version} - - - javax.ws.rs - javax.ws.rs-api - ${javax.ws.rs.version} - - - javax.servlet - javax.servlet-api - ${javax.servlet.version} - - - org.javassist - javassist - ${javassist.version} - - - org.springframework - spring-context - ${spring.version} - - - org.springframework - spring-web - ${spring.version} - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-aop - ${spring.version} - - - org.springframework - spring-aspects - ${spring.version} - - - org.springframework - spring-beans - ${spring.version} - - - org.springframework - spring-core - ${spring.version} - - - org.springframework - spring-expression - ${spring.version} - - - org.springframework - spring-jdbc - provided - true - ${spring.version} - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - io.vertx - vertx-codegen - ${vertx.version} - - - io.vertx - vertx-core - ${vertx.version} - - - io.vertx - vertx-web - ${vertx.version} - - - com.101tec - zkclient - ${tec.zkclient.version} - - - - org.springframework.boot - spring-boot-dependencies - 1.5.12.RELEASE - pom - import - - - - org.springframework.cloud - spring-cloud-dependencies - Edgware.SR3 - pom - import - - - - - io.zipkin.zipkin2 - zipkin - ${zipkin.version} - - - - io.zipkin.java - zipkin - ${zipkin.version} - test - - - io.zipkin.brave - brave - ${brave.version} - - - io.zipkin.brave - brave-spring-beans - ${brave.version} - - - io.zipkin.reporter2 - zipkin-sender-okhttp3 - ${zipkin-reporter.version} - - - io.zipkin.brave - brave-context-log4j12 - ${brave.version} - - - io.zipkin.brave - brave-instrumentation-servlet - ${brave.version} - - - io.zipkin.brave - brave-instrumentation-jaxrs2 - ${brave.version} - - - io.zipkin.brave - brave-instrumentation-spring-webmvc - ${brave.version} - - - io.zipkin.brave - brave-instrumentation-spring-web - ${brave.version} - - - - io.prometheus - simpleclient - 0.1.0 - - - io.prometheus - simpleclient_httpserver - 0.1.0 - - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - ${jackson.version} - - - com.fasterxml.jackson.dataformat - jackson-dataformat-protobuf - ${jackson.version} - - - com.fasterxml.jackson.dataformat - jackson-dataformat-xml - ${jackson.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-joda - ${jackson.version} - - - io.protostuff - protostuff-core - ${protostuff.version} - - - io.protostuff - protostuff-runtime - ${protostuff.version} - - - io.protostuff - protostuff-parser - 2.2.25 - - - io.swagger - swagger-core - ${swagger.version} - - - com.google.protobuf - protobuf-java - 3.5.1 - - - - - org.apache.servicecomb.archetypes - business-service-jaxrs-archetype - ${project.version} - - - org.apache.servicecomb.archetypes - business-service-pojo-archetype - ${project.version} - - - org.apache.servicecomb.archetypes - business-service-spring-boot-starter-archetype - ${project.version} - - - org.apache.servicecomb.archetypes - business-service-springmvc-archetype - ${project.version} - - - org.apache.servicecomb - common-javassist - ${project.version} - - - org.apache.servicecomb - common-protobuf - ${project.version} - - - org.apache.servicecomb - common-rest - ${project.version} - - - org.apache.servicecomb - java-chassis-core - ${project.version} - - - org.apache.servicecomb - deployment - ${project.version} - - - org.apache.servicecomb - config-apollo - ${project.version} - - - org.apache.servicecomb - config-cc - ${project.version} - - - org.apache.servicecomb - edge-core - ${project.version} - - - org.apache.servicecomb - foundation-common - ${project.version} - - - org.apache.servicecomb - foundation-config - ${project.version} - - - org.apache.servicecomb - foundation-metrics - ${project.version} - - - org.apache.servicecomb - foundation-protobuf - ${project.version} - - - org.apache.servicecomb - foundation-ssl - ${project.version} - - - org.apache.servicecomb - foundation-test-scaffolding - ${project.version} - test - - - org.apache.servicecomb - foundation-vertx - ${project.version} - - - org.apache.servicecomb - handler-bizkeeper - ${project.version} - - - org.apache.servicecomb - handler-fault-injection - ${project.version} - - - org.apache.servicecomb - handler-flowcontrol-qps - ${project.version} - - - org.apache.servicecomb - handler-loadbalance - ${project.version} - - - org.apache.servicecomb - handler-publickey-auth - ${project.version} - - - org.apache.servicecomb - handler-tracing-zipkin - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-discovery - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-servlet - ${project.version} - - - org.apache.servicecomb - spring-boot2-starter-standalone - ${project.version} - - - org.apache.servicecomb - spring-boot-common - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-configuration - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-discovery - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-provider - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-registry - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-servicecomb - ${project.version} - - - org.apache.servicecomb - spring-boot-starter-transport - ${project.version} - - - org.apache.servicecomb - spring-cloud-zuul - ${project.version} - - - org.apache.servicecomb - spring-cloud-zuul-zipkin - ${project.version} - - - org.apache.servicecomb - metrics-core - ${project.version} - - - org.apache.servicecomb - metrics-prometheus - ${project.version} - - - org.apache.servicecomb - provider-jaxrs - ${project.version} - - - org.apache.servicecomb - provider-pojo - ${project.version} - - - org.apache.servicecomb - provider-rest-common - ${project.version} - - - org.apache.servicecomb - provider-springmvc - ${project.version} - - - org.apache.servicecomb - service-registry - ${project.version} - - - org.apache.servicecomb - swagger-generator-core - ${project.version} - - - org.apache.servicecomb - swagger-generator-jaxrs - ${project.version} - - - org.apache.servicecomb - swagger-generator-springmvc - ${project.version} - - - org.apache.servicecomb - swagger-invocation-core - ${project.version} - - - org.apache.servicecomb - swagger-invocation-jaxrs - ${project.version} - - - org.apache.servicecomb - swagger-invocation-springmvc - ${project.version} - - - org.apache.servicecomb - swagger-invocation-validator - ${project.version} - - - org.apache.servicecomb - tracing-common - ${project.version} - - - org.apache.servicecomb - tracing-zipkin - ${project.version} - - - org.apache.servicecomb - transport-highway - ${project.version} - - - org.apache.servicecomb - transport-rest-client - ${project.version} - - - org.apache.servicecomb - transport-rest-servlet - ${project.version} - - - org.apache.servicecomb - transport-rest-vertx - ${project.version} - - - - diff --git a/java-chassis-distribution/pom.xml b/java-chassis-distribution/pom.xml deleted file mode 100644 index ed12fe39437..00000000000 --- a/java-chassis-distribution/pom.xml +++ /dev/null @@ -1,231 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - java-chassis-parent - 1.2.0-SNAPSHOT - ../parent - - apache-servicecomb-java-chassis-distribution - Java Chassis::Distribution - pom - - - org.apache.servicecomb - common-javassist - - - org.apache.servicecomb - common-protobuf - - - org.apache.servicecomb - common-rest - - - org.apache.servicecomb - java-chassis-core - - - org.apache.servicecomb - spring-boot-starter-configuration - - - org.apache.servicecomb - spring-boot-starter-provider - - - org.apache.servicecomb - spring-boot-starter-discovery - - - org.apache.servicecomb - spring-boot-starter-registry - - - org.apache.servicecomb - spring-boot-starter-transport - - - org.apache.servicecomb - swagger-generator-core - - - org.apache.servicecomb - swagger-generator-jaxrs - - - org.apache.servicecomb - swagger-generator-springmvc - - - org.apache.servicecomb - swagger-invocation-core - - - org.apache.servicecomb - swagger-invocation-jaxrs - - - org.apache.servicecomb - swagger-invocation-springmvc - - - org.apache.servicecomb - swagger-invocation-validator - - - org.apache.servicecomb - foundation-common - - - org.apache.servicecomb - foundation-config - - - org.apache.servicecomb - deployment - - - org.apache.servicecomb - foundation-metrics - - - org.apache.servicecomb - foundation-ssl - - - org.apache.servicecomb - foundation-vertx - - - org.apache.servicecomb - foundation-test-scaffolding - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - handler-tracing-zipkin - - - org.apache.servicecomb - handler-fault-injection - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-rest-common - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - service-registry - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-client - - - org.apache.servicecomb - transport-rest-servlet - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - tracing-zipkin - - - org.apache.servicecomb - tracing-common - - - org.apache.servicecomb - edge-core - - - - - - release - - - - maven-assembly-plugin - - - bin - package - - single - - - - src/assembly/bin.xml - - - - - src - package - - single - - - - src/assembly/src.xml - - - - - - - - - - diff --git a/java-chassis-distribution/src/assembly/bin.xml b/java-chassis-distribution/src/assembly/bin.xml deleted file mode 100644 index f5c56cac299..00000000000 --- a/java-chassis-distribution/src/assembly/bin.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - true - ${project.build.finalName}-bin - bin - - zip - - - - ../samples - samples - - **/*.iml - **/eclipse-classes/** - **/build/** - **/eclipse-classes/** - **/.* - **/.*/** - **/target - **/target/**/* - **/target - **/target/**/* - - - - ../ - / - - DISCLAIMER - README.md - - - - src/release - / - - NOTICE - LICENSE - licenses/** - - - - - - true - false - /libs - runtime - - - diff --git a/java-chassis-distribution/src/release/LICENSE b/java-chassis-distribution/src/release/LICENSE deleted file mode 100644 index 638a7a9bee2..00000000000 --- a/java-chassis-distribution/src/release/LICENSE +++ /dev/null @@ -1,521 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -======================================================================= -Apache ServiceComb Java Chassis Subcomponents: - -The Apache ServiceComb Java Chassis project contains subcomponents with -separate copyright notices and license terms. Your use of these -subcomponents is subject to the terms and conditions of the -following licenses. - - -================================================================ -For Stax2 API org.codehaus.woodstox:stax2-api:bundle:3.1.4 -================================================================ -This product bundles files from stax2 which is licensed under the -2-Clause BSD license. -For details, see http://wiki.fasterxml.com/WoodstoxStax2 -You can find a copy of the License at licenses/LICENSE-woodstox-stax2-api - -================================================================ -For org.aspectj:aspectjweaver:jar:1.8.8 -================================================================ -This product bundles AspectJ weaver which is licensed under the -Eclipse Public License v1.0. -For details, see http://www.aspectj.org -You can find a copy of the License at licenses/LICENSE-epl-v10 - -================================================================ -For ch.qos.logback:logback-core:jar:1.1.7, -ch.qos.logback:logback-classic:jar:1.1.7 -================================================================ -This product bundles Logback which is licensed under the -Eclipse Public License v1.0. -For details, see http://logback.qos.ch -You can find a copy of the License at licenses/LICENSE-logback - -================================================================ -For com.sun.jersey:jersey-core:jar:1.19.1, -com.sun.jersey.contribs:jersey-apache-client4:jar:1.19.1, -com.sun.jersey:jersey-client:jar:1.19.1 -================================================================ -This product bundles Jersey which is licensed under the -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1. -For details, see http://jersey.github.io -You can find a copy of the License at licenses/LICENSE-jersey - -================================================================ -For javax.ws.rs:javax.ws.rs-api:jar:2.0.1 -================================================================ -This product bundles jax-rs which is licensed under the -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1. -For details, see http://jax-rs-spec.java.net -You can find a copy of the License at licenses/LICENSE-jax-rs - -================================================================ -For javax.servlet:javax.el:jar:3.0.0 -================================================================ -This product bundles Java EL which is licensed under the -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1. -For details, see http://el-spec.java.net -You can find a copy of the License at licenses/LICENSE-javax-el - -================================================================ -For javax.servlet:javax.servlet-api:jar:3.1.0 -================================================================ -This product bundles Java Servlet API which is licensed under the -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1. -For details, see http://servlet-spec.java.net -You can find a copy of the License at licenses/LICENSE-javax-servlet - -================================================================ -For org.hdrhistogram:HdrHistogram:bundle:2.1.9 -================================================================ -This product bundles HdrHistogram which is licensed under the -Public domain. -For details, see https://github.com/HdrHistogram/HdrHistogram -You can find a copy of the License at licenses/LICENSE-hdrhistogram - -================================================================ -For org.bouncycastle:bcpkix-jdk15on:jar:1.55, -org.bouncycastle:bcprov-jdk15on:jar:1.55 -================================================================ -This product bundles bouncycastle libraries which is licensed under the -MIT license. -For details, see http://www.bouncycastle.org/java.html -You can find a copy of the License at licenses/LICENSE-bouncycastle - -================================================================ -For org.slf4j:jul-to-slf4j:jar:1.7.25, -org.slf4j:slf4j-api:jar:1.7.7, -org.slf4j:jcl-over-slf4j:jar:1.7.25 -================================================================ -This product bundles slf4j libraries which is licensed under the -MIT license. -For details, see http://www.slf4j.org -You can find a copy of the License at licenses/LICENSE-slf4j - -================================================================ -For javax.ws.rs:jsr311-api:jar:1.1.1 -================================================================ -This product bundles jsr311-api which is licensed under the -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1. -For details, see https://javaee.github.io/jsr311/ -You can find a copy of the License at licenses/LICENSE-jsr311 - -================================================================ -For org.ow2.asm:asm:jar:5.0.4 -================================================================ -This product bundles asm which is licensed under the -3-Clause BSD license. -For details, see http://asm.ow2.org/ -You can find a copy of the License at licenses/LICENSE-asm - -================================================================ -For protobuf-java com.google.protobuf:protobuf-java:jar:3.5.1 -================================================================ -This product bundles protobuf which is licensed under the -3-Clause BSD license. -For details, see https://github.com/protocolbuffers/protobuf -You can find a copy of the License at licenses/LICENSE-protobuf - -================================================================ -For antlr4 org.antlr:antlr4:jar:4.7, -org.antlr:antlr4-runtime:jar:4.7, -org.antlr:antlr-runtime:jar, -org.antlr:ST4:jar:4.0.8 -================================================================ -This product bundles antlr which is licensed under the -3-Clause BSD license. -For details, see https://www.antlr.org/ -You can find a copy of the License at licenses/LICENSE-antlr - -================================================================ -For aopalliance aopalliance:aopalliance:jar:1.0 -================================================================ -This product bundles aopalliance which is licensed under the -public domain. -For details, see http://aopalliance.sourceforge.net/ - -================================================================ -For icu4j com.ibm.icu:icu4j:jar:58.2 -================================================================ -This product bundles icu4j which is licensed under the -Unicode/ICU license. -For details, see http://site.icu-project.org/home -You can find a copy of the License at licenses/LICENSE-icu4j - -================================================================ -For javax.json org.glassfish:javax.json:bundle:1.0.4 -================================================================ -This product bundles javax.json which is licensed under the -CDDL license. -For details, see http://jsonp.java.net -You can find a copy of the License at licenses/LICENSE-jsonp - -================================================================ -For abego TreeLayout org.abego.treelayout:org.abego.treelayout.core:bundle:1.0.3 -================================================================ -This product bundles TreeLayout which is licensed under the -3-Clause BSD license. -For details, see http://treelayout.sourceforge.net -You can find a copy of the License at licenses/LICENSE-abego - -================================================================ -For foundations/foundation-vertx/src/main/java/io/vertx/ext/web/impl/MimeTypesUtils.java -transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java -================================================================ -This product bundles files from vertx which is licensed under the Apache License v2. -For details, see https://github.com/vert-x3/vertx-web - -================================================================ -For foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java -================================================================ -This product bundles files from vertx which is licensed under the Apache License v2. -For details, see https://github.com/eclipse-vertx/vert.x - -================================================================ -For swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java -================================================================ -This product bundles files from swagger which is licensed under the Apache License v2. -For details, see https://github.com/swagger-api/swagger-core - -================================================================ -For handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java -================================================================ -This product bundles files from Hystrix which is licensed under the Apache License v2. -For details, see https://github.com/Netflix/Hystrix - -================================================================ -This product bundles the following libraries which are licensed -under the Apache License v2. -For details, see their respective project links. - -Apache Commons BeanUtils (http://commons.apache.org/proper/commons-beanutils/) commons-beanutils:commons-beanutils:jar:1.9.2 -Apache Commons Codec (http://commons.apache.org/proper/commons-codec/) commons-codec:commons-codec:jar:1.10 -Apache Commons Collections (http://commons.apache.org/collections/) commons-collections:commons-collections:jar:3.2.2 -Apache Commons Configuration (http://commons.apache.org/configuration/) commons-configuration:commons-configuration:jar:1.10 -Apache Commons Lang (http://commons.apache.org/proper/commons-lang/) org.apache.commons:commons-lang3:jar:3.6 -Apache Commons Logging (http://commons.apache.org/proper/commons-logging/) commons-logging:commons-logging:jar:1.2 -Apache HttpClient (http://hc.apache.org/httpcomponents-client) org.apache.httpcomponents:httpclient:jar:4.5.2 -Apache HttpCore (http://hc.apache.org/httpcomponents-core-ga) org.apache.httpcomponents:httpcore:jar:4.4.9 -Apache Log4j (http://logging.apache.org/log4j/1.2/) log4j:log4j:bundle:1.2.17 -archaius-core (https://github.com/Netflix/archaius) com.netflix.archaius:archaius-core:jar:0.7.3 -Bean Validation API (http://beanvalidation.org) javax.validation:validation-api:jar:2.0.0.Final -brave (https://github.com/kristofa/brave/brave) io.zipkin.brave:brave:jar:4.13.1 -Brave Context: Log4J 1.2 (https://github.com/kristofa/brave/brave-context-parent/brave-context-log4j12) io.zipkin.brave:brave-context-log4j12:jar:4.13.1 -Brave Instrumentation: Http Adapters (https://github.com/kristofa/brave/brave-instrumentation-parent/brave-instrumentation-http) io.zipkin.brave:brave-instrumentation-http:jar:4.13.1 -Brave Instrumentation: Servlet (https://github.com/kristofa/brave/brave-instrumentation-parent/brave-instrumentation-servlet) io.zipkin.brave:brave-instrumentation-servlet:jar:4.13.1 -Brave Spring Factory Beans (https://github.com/kristofa/brave/brave-spring-beans) io.zipkin.brave:brave-spring-beans:jar:4.13.1 -ClassMate (http://github.com/cowtowncoder/java-classmate) com.fasterxml:classmate:bundle:1.3.4 -Commons IO (http://commons.apache.org/io/) commons-io:commons-io:jar:2.4 -Commons Lang (http://commons.apache.org/lang/) commons-lang:commons-lang:jar:2.6 -ezmorph (http://ezmorph.sourceforge.net) net.sf.ezmorph:ezmorph:jar:1.0.6 -FindBugs-jsr305 (http://findbugs.sourceforge.net/) com.google.code.findbugs:jsr305:jar:3.0.1 -Guava: Google Core Libraries for Java (http://code.google.com/p/guava-libraries/guava) com.google.guava:guava:bundle:21.0 -Guice (https://github.com/google/guice) com.google.inject:guice:jar:4.1.0 -Google Guice - Extensions - AssistedInject (https://github.com/google/guice/extensions-parent/guice-assistedinject) com.google.inject.extensions:guice-assistedinject:jar:4.1.0 -Google Guice - Extensions - MultiBindings (https://github.com/google/guice/extensions-parent/guice-multibindings) com.google.inject.extensions:guice-multibindings:jar:4.1.0 -Hibernate Validator Engine (http://hibernate.org/validator/hibernate-validator) org.hibernate:hibernate-validator:jar:6.0.2.Final -hystrix-core (https://github.com/Netflix/Hystrix) com.netflix.hystrix:hystrix-core:jar:1.5.10 -hystrix-javanica (https://github.com/Netflix/Hystrix) com.netflix.hystrix:hystrix-javanica:jar:1.5.12 -hystrix-metrics-event-stream (https://github.com/Netflix/Hystrix) com.netflix.hystrix:hystrix-metrics-event-stream:jar:1.5.12 -hystrix-serialization (https://github.com/Netflix/Hystrix) com.netflix.hystrix:hystrix-serialization:jar:1.5.12 -Jackson dataformat: protobuf (http://github.com/FasterXML/jackson-dataformats-binary) com.fasterxml.jackson.dataformat:jackson-dataformat-protobuf:bundle:2.9.6 -Jackson module: Afterburner (https://github.com/FasterXML/jackson-modules-base) com.fasterxml.jackson.module:jackson-module-afterburner:bundle:2.8.11 -Jackson module: JAXB-annotations (http://github.com/FasterXML/jackson-module-jaxb-annotations) com.fasterxml.jackson.module:jackson-module-jaxb-annotations:bundle:2.8.11 -Jackson-annotations (http://github.com/FasterXML/jackson) com.fasterxml.jackson.core:jackson-annotations:bundle:2.9.6 -Jackson-core (https://github.com/FasterXML/jackson-core) com.fasterxml.jackson.core:jackson-core:bundle:2.9.6 -jackson-databind (http://github.com/FasterXML/jackson) com.fasterxml.jackson.core:jackson-databind:bundle:2.9.6 -Jackson-dataformat-XML (http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding) com.fasterxml.jackson.dataformat:jackson-dataformat-xml:bundle:2.9.6 -Jackson-dataformat-YAML (https://github.com/FasterXML/jackson-dataformats-text) com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:bundle:2.9.6 -Javassist (http://www.javassist.org/) org.javassist:javassist:bundle:3.18.1-GA -javax.inject (http://code.google.com/p/atinject/) javax.inject:javax.inject:jar:1 -JBoss Logging 3 (http://www.jboss.org) org.jboss.logging:jboss-logging:jar:3.3.2.Final -json-lib (http://json-lib.sourceforge.net) net.sf.json-lib:json-lib:jar:2.4 -Log4j Implemented Over SLF4J (http://www.slf4j.org) org.slf4j:log4j-over-slf4j:jar:1.7.7 -netflix-commons-util (https://github.com/Netflix/netflix-commons) com.netflix.netflix-commons:netflix-commons-util:jar:0.1.1 -netflix-statistics (https://github.com/Netflix/netflix-commons) com.netflix.netflix-commons:netflix-statistics:jar:0.1.1 -Netty/Buffer (http://netty.io/netty-buffer/) io.netty:netty-buffer:jar:4.1.24.Final -Netty/Codec (http://netty.io/netty-codec/) io.netty:netty-codec:jar:4.1.24.Final -Netty/Codec/DNS (http://netty.io/netty-codec-dns/) io.netty:netty-codec-dns:jar:4.1.24.Final -Netty/Codec/HTTP (http://netty.io/netty-codec-http/) io.netty:netty-codec-http:jar:4.1.24.Final -Netty/Codec/HTTP2 (http://netty.io/netty-codec-http2/) io.netty:netty-codec-http2:jar:4.1.24.Final -Netty/Codec/Socks (http://netty.io/netty-codec-socks/) io.netty:netty-codec-socks:jar:4.1.24.Final -Netty/Common (http://netty.io/netty-common/) io.netty:netty-common:jar:4.1.24.Final -Netty/Handler (http://netty.io/netty-handler/) io.netty:netty-handler:jar:4.1.24.Final -Netty/Handler/Proxy (http://netty.io/netty-handler-proxy/) io.netty:netty-handler-proxy:jar:4.1.24.Final -Netty/Resolver (http://netty.io/netty-resolver/) io.netty:netty-resolver:jar:4.1.24.Final -Netty/Resolver/DNS (http://netty.io/netty-resolver-dns/) io.netty:netty-resolver-dns:jar:4.1.24.Final -Netty/TomcatNative(https://netty.io/wiki/forked-tomcat-native.html) io.netty:netty-tcnative-boringssl-static:2.0.7.Final -Netty/Transport (http://netty.io/netty-transport/) io.netty:netty-transport:jar:4.1.24.Final -OkHttp (https://github.com/square/okhttp/okhttp) com.squareup.okhttp3:okhttp:jar:3.4.1 -Okio (https://github.com/square/okio/okio) com.squareup.okio:okio:jar:1.9.0 -Prometheus Java Simpleclient (http://github.com/prometheus/client_java/simpleclient) io.prometheus:simpleclient:bundle:0.1.0 -Prometheus Java Simpleclient Common (http://github.com/prometheus/client_java/simpleclient_common) io.prometheus:simpleclient_common:bundle:0.1.0 -Prometheus Java Simpleclient Httpserver (http://github.com/prometheus/client_java/simpleclient_httpserver) io.prometheus:simpleclient_httpserver:bundle:0.1.0 -ProtoParser (http://github.com/square/protoparser/) com.squareup:protoparser:jar:4.0.3 -protostuff :: api (http://protostuff.io/protostuff-api) io.protostuff:protostuff-api:jar:1.5.2 -protostuff :: collectionschema (http://protostuff.io/protostuff-collectionschema) io.protostuff:protostuff-collectionschema:jar:1.5.2 -protostuff :: core (http://protostuff.io/protostuff-core) io.protostuff:protostuff-core:jar:1.5.2 -protostuff :: runtime (http://protostuff.io/protostuff-runtime) io.protostuff:protostuff-runtime:jar:1.5.2 -protostuff :: parser (https://github.com/protostuff/protostuff-compiler/tree/master/protostuff-parser) io.protostuff:protostuff-parser:jar:2.2.25 -ribbon (https://github.com/Netflix/ribbon) com.netflix.ribbon:ribbon:jar:2.2.2 -ribbon-core (https://github.com/Netflix/ribbon) com.netflix.ribbon:ribbon-core:jar:2.2.2 -ribbon-httpclient (https://github.com/Netflix/ribbon) com.netflix.ribbon:ribbon-httpclient:jar:2.2.5 -ribbon-loadbalancer (https://github.com/Netflix/ribbon) com.netflix.ribbon:ribbon-loadbalancer:jar:2.2.2 -ribbon-transport (https://github.com/Netflix/ribbon) com.netflix.ribbon:ribbon-transport:jar:2.2.2 -rxjava (https://github.com/ReactiveX/RxJava) io.reactivex:rxjava:jar:1.1.6 -rxnetty (https://github.com/ReactiveX/RxNetty) io.reactivex:rxnetty:jar:0.4.9 -rxnetty-contexts (https://github.com/ReactiveX/RxNetty) io.reactivex:rxnetty-contexts:jar:0.4.9 -rxnetty-servo (https://github.com/ReactiveX/RxNetty) io.reactivex:rxnetty-servo:jar:0.4.9 -servo-core (https://github.com/Netflix/servo) com.netflix.servo:servo-core:jar:0.10.1 -servo-internal (https://github.com/Netflix/servo) com.netflix.servo:servo-internal:jar:0.10.1 -SnakeYAML (http://www.snakeyaml.org) org.yaml:snakeyaml:bundle:1.16 -spectator-api (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-api:0.71.0 -spectator-reg-servo (https://github.com/Netflix/spectator) com.netflix.spectator:spectator-reg-servo:0.71.0 -Spring AOP (https://github.com/spring-projects/spring-framework) org.springframework:spring-aop:jar:4.3.16.RELEASE -Spring Aspects (https://github.com/spring-projects/spring-framework) org.springframework:spring-aspects:jar:4.3.16.RELEASE -Spring Beans (https://github.com/spring-projects/spring-framework) org.springframework:spring-beans:jar:4.3.16.RELEASE -Spring Boot (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot:jar:1.5.12.RELEASE -Spring Boot Actuator (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-actuator:jar:1.5.12.RELEASE -Spring Boot Actuator Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter-actuator:jar:1.5.12.RELEASE -Spring Boot AOP Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter-aop:jar:1.5.12.RELEASE -Spring Boot AutoConfigure (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-autoconfigure:jar:1.5.12.RELEASE -Spring Boot Logging Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter-logging:jar:1.5.12.RELEASE -Spring Boot Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter:jar:1.5.12.RELEASE -Spring Boot Tomcat Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.12.RELEASE -Spring Boot Web Starter (http://projects.spring.io/spring-boot/) org.springframework.boot:spring-boot-starter-web:jar:1.5.12.RELEASE -Spring Cloud Commons (https://projects.spring.io/spring-cloud/spring-cloud-commons/) org.springframework.cloud:spring-cloud-commons:jar:1.3.3.RELEASE -Spring Cloud Context (https://projects.spring.io/spring-cloud/spring-cloud-context/) org.springframework.cloud:spring-cloud-context:jar:1.3.3.RELEASE -Spring Cloud Netflix Core (https://spring.io/spring-cloud/spring-cloud-netflix/spring-cloud-netflix-core) org.springframework.cloud:spring-cloud-netflix-core:jar:1.4.4.RELEASE -Spring Context (https://github.com/spring-projects/spring-framework) org.springframework:spring-context:jar:4.3.16.RELEASE -Spring Core (https://github.com/spring-projects/spring-framework) org.springframework:spring-core:jar:4.3.16.RELEASE -Spring Expression Language (SpEL) (https://github.com/spring-projects/spring-framework) org.springframework:spring-expression:jar:4.3.16.RELEASE -Spring Web (https://github.com/spring-projects/spring-framework) org.springframework:spring-web:jar:4.3.16.RELEASE -Spring Web MVC (https://github.com/spring-projects/spring-framework) org.springframework:spring-webmvc:jar:4.3.16.RELEASE -spring-cloud-starter (https://projects.spring.io/spring-cloud) org.springframework.cloud:spring-cloud-starter:jar:1.3.3.RELEASE -spring-cloud-starter-archaius (https://projects.spring.io/spring-cloud) org.springframework.cloud:spring-cloud-starter-archaius:jar:1.4.4.RELEASE -spring-cloud-starter-hystrix (https://projects.spring.io/spring-cloud) org.springframework.cloud:spring-cloud-starter-hystrix:jar:1.4.4.RELEASE -spring-cloud-starter-ribbon (https://projects.spring.io/spring-cloud) org.springframework.cloud:spring-cloud-starter-ribbon:jar:1.4.4.RELEASE -spring-cloud-starter-zuul (https://projects.spring.io/spring-cloud) org.springframework.cloud:spring-cloud-starter-zuul:jar:1.4.4.RELEASE -spring-security-crypto (http://spring.io/spring-security) org.springframework.security:spring-security-crypto:jar:4.1.4.RELEASE -spring-security-rsa (http://github.com/spring-projects/spring-security-oauth) org.springframework.security:spring-security-rsa:jar:1.0.3.RELEASE -swagger-annotations (https://github.com/swagger-api/swagger-core/modules/swagger-annotations) io.swagger:swagger-annotations:bundle:1.5.12 -swagger-core (https://github.com/swagger-api/swagger-core/modules/swagger-core) io.swagger:swagger-core:bundle:1.5.12 -swagger-models (https://github.com/swagger-api/swagger-core/modules/swagger-models) io.swagger:swagger-models:bundle:1.5.12 -tomcat-embed-core (http://tomcat.apache.org/) org.apache.tomcat.embed:tomcat-embed-core:jar:8.0.33 -tomcat-embed-el (http://tomcat.apache.org/) org.apache.tomcat.embed:tomcat-embed-el:jar:8.0.33 -tomcat-embed-logging-juli (http://tomcat.apache.org/) org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:8.0.33 -tomcat-embed-websocket (http://tomcat.apache.org/) org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.0.33 -Vert.x Bridge Common (http://nexus.sonatype.org/oss-repository-hosting.html/vertx-parent/vertx-ext/vertx-ext-parent/vertx-bridge-common) io.vertx:vertx-bridge-common:jar:3.5.3 -Vert.x Core (http://nexus.sonatype.org/oss-repository-hosting.html/vertx-parent/vertx-core) io.vertx:vertx-core:jar:3.5.3 -vertx-auth-common (http://nexus.sonatype.org/oss-repository-hosting.html/vertx-parent/vertx-ext/vertx-ext-parent/vertx-auth/vertx-auth-common) io.vertx:vertx-auth-common:jar:3.5.3 -vertx-web (http://nexus.sonatype.org/oss-repository-hosting.html/vertx-parent/vertx-ext/vertx-ext-parent/vertx-web-parent/vertx-web) io.vertx:vertx-web:jar:3.5.3 -Woodstox (https://github.com/FasterXML/woodstox) com.fasterxml.woodstox:woodstox-core:bundle:5.0.3 -Zipkin Reporter Spring Factory Beans (https://github.com/openzipkin/zipkin-reporter-java/zipkin-reporter-spring-beans) io.zipkin.reporter2:zipkin-reporter-spring-beans:jar:2.2.2 -Zipkin Reporter: Core (https://github.com/openzipkin/zipkin-reporter-java/zipkin-reporter) io.zipkin.reporter2:zipkin-reporter:jar:2.5.0 -Zipkin Sender: OkHttp 3 (https://github.com/openzipkin/zipkin-reporter-java/zipkin-sender-okhttp3) io.zipkin.reporter2:zipkin-sender-okhttp3:jar:2.2.2 -Zipkin v1 (https://github.com/openzipkin/zipkin/) io.zipkin.java:zipkin:jar:2.4.2 -Zipkin v2 (https://github.com/openzipkin/zipkin/) io.zipkin.zipkin2:zipkin:jar:2.4.2 -zuul-core (https://github.com/Netflix/zuul) com.netflix.zuul:zuul-core:jar:1.3.0 diff --git a/java-chassis-distribution/src/release/NOTICE b/java-chassis-distribution/src/release/NOTICE deleted file mode 100644 index 6daa152caf0..00000000000 --- a/java-chassis-distribution/src/release/NOTICE +++ /dev/null @@ -1,63 +0,0 @@ -Apache ServiceComb Java Chassis -Copyright 2017-2018 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -================================================================ -Notice for Apache Commons Codec - -See licenses/NOTICE-apache-commons-codec - -================================================================ -Notice for Apache Commons Lang(Version 3) - -Apache Commons Lang -Copyright 2001-2014 The Apache Software Foundation - -This product includes software from the Spring Framework, -under the Apache License 2.0 (see: StringUtils.containsWhitespace()) - -================================================================ -Notice for Netty - -See licenses/NOTICE-netty - -================================================================ -Notice for Prometheus - -See licenses/NOTICE-prometheus - -================================================================ -Notice for Protostuff - -See licenses/NOTICE-protostuff - -================================================================ -Notice for Netflix servo - -Servo -Copyright 2011 Netflix, Inc. - -This product includes software developed by The Apache Software -Foundation (http://www.apache.org/). - -Alternative collection types provided by Google Guava from -http://code.google.com/p/guava-libraries/ -Copyright (C) 2007 Google Inc. - -================================================================ -Notice for Apache tomcat - -See licenses/NOTICE-tomcat - - -================================================================ -Notice for javax.jsonp - -The code released under the CDDL shall be governed by the laws of the -State of California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the jurisdiction -of the Federal Courts of the Northern District of California and the -state courts of the State of California, with venue lying in Santa Clara -County, California. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-javax-servlet b/java-chassis-distribution/src/release/licenses/LICENSE-javax-servlet deleted file mode 100644 index b1c74f95ede..00000000000 --- a/java-chassis-distribution/src/release/licenses/LICENSE-javax-servlet +++ /dev/null @@ -1,759 +0,0 @@ -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 - -1. Definitions. - - 1.1. "Contributor" means each individual or entity that creates or - contributes to the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Software, prior Modifications used by a Contributor (if any), and - the Modifications made by that particular Contributor. - - 1.3. "Covered Software" means (a) the Original Software, or (b) - Modifications, or (c) the combination of files containing Original - Software with files containing Modifications, in each case including - portions thereof. - - 1.4. "Executable" means the Covered Software in any form other than - Source Code. - - 1.5. "Initial Developer" means the individual or entity that first - makes Original Software available under this License. - - 1.6. "Larger Work" means a work which combines Covered Software or - portions thereof with code not governed by the terms of this License. - - 1.7. "License" means this document. - - 1.8. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means the Source Code and Executable form of - any of the following: - - A. Any file that results from an addition to, deletion from or - modification of the contents of a file containing Original Software - or previous Modifications; - - B. Any new file that contains any part of the Original Software or - previous Modification; or - - C. Any new file that is contributed or otherwise made available - under the terms of this License. - - 1.10. "Original Software" means the Source Code and Executable form - of computer software code that is originally released under this - License. - - 1.11. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.12. "Source Code" means (a) the common form of computer software - code in which modifications are made and (b) associated - documentation included in or with such code. - - 1.13. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, - this License. For legal entities, "You" includes any entity which - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants. - - 2.1. The Initial Developer Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, the Initial Developer - hereby grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer, to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Software (or portions thereof), with or without Modifications, - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using or selling of - Original Software, to make, have made, use, practice, sell, and - offer for sale, and/or otherwise dispose of the Original Software - (or portions thereof). - - (c) The licenses granted in Sections 2.1(a) and (b) are effective on - the date Initial Developer first distributes or otherwise makes the - Original Software available to a third party under the terms of this - License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: (1) for code that You delete from the Original Software, or - (2) for infringements caused by: (i) the modification of the - Original Software, or (ii) the combination of the Original Software - with other software or devices. - - 2.2. Contributor Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, each Contributor hereby - grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof), either on an - unmodified basis, with other Modifications, as Covered Software - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or selling - of Modifications made by that Contributor either alone and/or in - combination with its Contributor Version (or portions of such - combination), to make, use, sell, offer for sale, have made, and/or - otherwise dispose of: (1) Modifications made by that Contributor (or - portions thereof); and (2) the combination of Modifications made by - that Contributor with its Contributor Version (or portions of such - combination). - - (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective - on the date Contributor first distributes or otherwise makes the - Modifications available to a third party. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: (1) for any code that Contributor has deleted from the - Contributor Version; (2) for infringements caused by: (i) third - party modifications of Contributor Version, or (ii) the combination - of Modifications made by that Contributor with other software - (except as part of the Contributor Version) or other devices; or (3) - under Patent Claims infringed by Covered Software in the absence of - Modifications made by that Contributor. - -3. Distribution Obligations. - - 3.1. Availability of Source Code. - - Any Covered Software that You distribute or otherwise make available - in Executable form must also be made available in Source Code form - and that Source Code form must be distributed only under the terms - of this License. You must include a copy of this License with every - copy of the Source Code form of the Covered Software You distribute - or otherwise make available. You must inform recipients of any such - Covered Software in Executable form as to how they can obtain such - Covered Software in Source Code form in a reasonable manner on or - through a medium customarily used for software exchange. - - 3.2. Modifications. - - The Modifications that You create or to which You contribute are - governed by the terms of this License. You represent that You - believe Your Modifications are Your original creation(s) and/or You - have sufficient rights to grant the rights conveyed by this License. - - 3.3. Required Notices. - - You must include a notice in each of Your Modifications that - identifies You as the Contributor of the Modification. You may not - remove or alter any copyright, patent or trademark notices contained - within the Covered Software, or any notices of licensing or any - descriptive text giving attribution to any Contributor or the - Initial Developer. - - 3.4. Application of Additional Terms. - - You may not offer or impose any terms on any Covered Software in - Source Code form that alters or restricts the applicable version of - this License or the recipients' rights hereunder. You may choose to - offer, and to charge a fee for, warranty, support, indemnity or - liability obligations to one or more recipients of Covered Software. - However, you may do so only on Your own behalf, and not on behalf of - the Initial Developer or any Contributor. You must make it - absolutely clear that any such warranty, support, indemnity or - liability obligation is offered by You alone, and You hereby agree - to indemnify the Initial Developer and every Contributor for any - liability incurred by the Initial Developer or such Contributor as a - result of warranty, support, indemnity or liability terms You offer. - - 3.5. Distribution of Executable Versions. - - You may distribute the Executable form of the Covered Software under - the terms of this License or under the terms of a license of Your - choice, which may contain terms different from this License, - provided that You are in compliance with the terms of this License - and that the license for the Executable form does not attempt to - limit or alter the recipient's rights in the Source Code form from - the rights set forth in this License. If You distribute the Covered - Software in Executable form under a different license, You must make - it absolutely clear that any terms which differ from this License - are offered by You alone, not by the Initial Developer or - Contributor. You hereby agree to indemnify the Initial Developer and - every Contributor for any liability incurred by the Initial - Developer or such Contributor as a result of any such terms You offer. - - 3.6. Larger Works. - - You may create a Larger Work by combining Covered Software with - other code not governed by the terms of this License and distribute - the Larger Work as a single product. In such a case, You must make - sure the requirements of this License are fulfilled for the Covered - Software. - -4. Versions of the License. - - 4.1. New Versions. - - Oracle is the initial license steward and may publish revised and/or - new versions of this License from time to time. Each version will be - given a distinguishing version number. Except as provided in Section - 4.3, no one other than the license steward has the right to modify - this License. - - 4.2. Effect of New Versions. - - You may always continue to use, distribute or otherwise make the - Covered Software available under the terms of the version of the - License under which You originally received the Covered Software. If - the Initial Developer includes a notice in the Original Software - prohibiting it from being distributed or otherwise made available - under any subsequent version of the License, You must distribute and - make the Covered Software available under the terms of the version - of the License under which You originally received the Covered - Software. Otherwise, You may also choose to use, distribute or - otherwise make the Covered Software available under the terms of any - subsequent version of the License published by the license steward. - - 4.3. Modified Versions. - - When You are an Initial Developer and You want to create a new - license for Your Original Software, You may create and use a - modified version of this License if You: (a) rename the license and - remove any references to the name of the license steward (except to - note that the license differs from this License); and (b) otherwise - make it clear that the license contains terms which differ from this - License. - -5. DISCLAIMER OF WARRANTY. - - COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE - IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR - NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF - THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE - DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY - OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, - REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN - ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS - AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -6. TERMINATION. - - 6.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to - cure such breach within 30 days of becoming aware of the breach. - Provisions which, by their nature, must remain in effect beyond the - termination of this License shall survive. - - 6.2. If You assert a patent infringement claim (excluding - declaratory judgment actions) against Initial Developer or a - Contributor (the Initial Developer or Contributor against whom You - assert such claim is referred to as "Participant") alleging that the - Participant Software (meaning the Contributor Version where the - Participant is a Contributor or the Original Software where the - Participant is the Initial Developer) directly or indirectly - infringes any patent, then any and all rights granted directly or - indirectly to You by such Participant, the Initial Developer (if the - Initial Developer is not the Participant) and all Contributors under - Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice - from Participant terminate prospectively and automatically at the - expiration of such 60 day notice period, unless if within such 60 - day period You withdraw Your claim with respect to the Participant - Software against such Participant either unilaterally or pursuant to - a written agreement with Participant. - - 6.3. If You assert a patent infringement claim against Participant - alleging that the Participant Software directly or indirectly - infringes any patent where such claim is resolved (such as by - license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 6.4. In the event of termination under Sections 6.1 or 6.2 above, - all end user licenses that have been validly granted by You or any - distributor hereunder prior to termination (excluding licenses - granted to You by any distributor) shall survive termination. - -7. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE - INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF - COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE - TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT - LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER - FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR - LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE - POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT - APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH - PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH - LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR - LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION - AND LIMITATION MAY NOT APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - - The Covered Software is a "commercial item," as that term is defined - in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" (as that term is defined at 48 C.F.R. § - 252.227-7014(a)(1)) and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent - with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 - (June 1995), all U.S. Government End Users acquire Covered Software - with only those rights set forth herein. This U.S. Government Rights - clause is in lieu of, and supersedes, any other FAR, DFAR, or other - clause or provision that addresses Government rights in computer - software under this License. - -9. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - the law of the jurisdiction specified in a notice contained within - the Original Software (except to the extent applicable law, if any, - provides otherwise), excluding such jurisdiction's conflict-of-law - provisions. Any litigation relating to this License shall be subject - to the jurisdiction of the courts located in the jurisdiction and - venue specified in a notice contained within the Original Software, - with the losing party responsible for costs, including, without - limitation, court costs and reasonable attorneys' fees and expenses. - The application of the United Nations Convention on Contracts for - the International Sale of Goods is expressly excluded. Any law or - regulation which provides that the language of a contract shall be - construed against the drafter shall not apply to this License. You - agree that You alone are responsible for compliance with the United - States export administration regulations (and the export control - laws and regulation of any other countries) when You use, distribute - or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - ------------------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION -LICENSE (CDDL) - -The code released under the CDDL shall be governed by the laws of the -State of California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the jurisdiction -of the Federal Courts of the Northern District of California and the -state courts of the State of California, with venue lying in Santa Clara -County, California. - - - - The GNU General Public License (GPL) Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor -Boston, MA 02110-1335 -USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free software--to -make sure the software is free for all its users. This General Public -License applies to most of the Free Software Foundation's software and -to any other program whose authors commit to using it. (Some other Free -Software Foundation software is covered by the GNU Library General -Public License instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. -Our General Public Licenses are designed to make sure that you have the -freedom to distribute copies of free software (and charge for this -service if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone -to deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis -or for a fee, you must give the recipients all the rights that you have. -You must make sure that they, too, receive or can get the source code. -And you must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - -Finally, any free program is threatened constantly by software patents. -We wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must -be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and -modification follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a -notice placed by the copyright holder saying it may be distributed under -the terms of this General Public License. The "Program", below, refers -to any such program or work, and a "work based on the Program" means -either the Program or any derivative work under copyright law: that is -to say, a work containing the Program or a portion of it, either -verbatim or with modifications and/or translated into another language. -(Hereinafter, translation is included without limitation in the term -"modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of running -the Program is not restricted, and the output from the Program is -covered only if its contents constitute a work based on the Program -(independent of having been made by running the Program). Whether that -is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously -and appropriately publish on each copy an appropriate copyright notice -and disclaimer of warranty; keep intact all the notices that refer to -this License and to the absence of any warranty; and give any other -recipients of the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of -it, thus forming a work based on the Program, and copy and distribute -such modifications or work under the terms of Section 1 above, provided -that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this License. - (Exception: if the Program itself is interactive but does not - normally print such an announcement, your work based on the Program - is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, and -can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based on -the Program, the distribution of the whole must be on the terms of this -License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of a -storage or distribution medium does not bring the other work under the -scope of this License. - -3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your cost - of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source code -means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to control -compilation and installation of the executable. However, as a special -exception, the source code distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies the -executable. - -If distribution of executable or object code is made by offering access -to copy from a designated place, then offering equivalent access to copy -the source code from the same place counts as distribution of the source -code, even though third parties are not compelled to copy the source -along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt otherwise -to copy, modify, sublicense or distribute the Program is void, and will -automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will -not have their licenses terminated so long as such parties remain in -full compliance. - -5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and all -its terms and conditions for copying, distributing or modifying the -Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further restrictions -on the recipients' exercise of the rights granted herein. You are not -responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot distribute -so as to satisfy simultaneously your obligations under this License and -any other pertinent obligations, then as a consequence you may not -distribute the Program at all. For example, if a patent license would -not permit royalty-free redistribution of the Program by all those who -receive copies directly or indirectly through you, then the only way you -could satisfy both it and this License would be to refrain entirely from -distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is implemented -by public license practices. Many people have made generous -contributions to the wide range of software distributed through that -system in reliance on consistent application of that system; it is up to -the author/donor to decide if he or she is willing to distribute -software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be -a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License may -add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among countries -not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new -versions of the General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Program does not specify a version -number of this License, you may choose any version ever published by the -Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the -author to ask for permission. For software which is copyrighted by the -Free Software Foundation, write to the Free Software Foundation; we -sometimes make exceptions for this. Our decision will be guided by the -two goals of preserving the free status of all derivatives of our free -software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH -YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF -THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR -OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type - `show w'. This is free software, and you are welcome to redistribute - it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the commands -you use may be called something other than `show w' and `show c'; they -could even be mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (which makes passes at compilers) written by - James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications -with the library. If this is what you want to do, use the GNU Library -General Public License instead of this License. - -# - -Certain source files distributed by Oracle America, Inc. and/or its -affiliates are subject to the following clarification and special -exception to the GPLv2, based on the GNU Project exception for its -Classpath libraries, known as the GNU Classpath Exception, but only -where Oracle has expressly included in the particular source file's -header the words "Oracle designates this particular file as subject to -the "Classpath" exception as provided by Oracle in the LICENSE file -that accompanied this code." - -You should also note that Oracle includes multiple, independent -programs in this software package. Some of those programs are provided -under licenses deemed incompatible with the GPLv2 by the Free Software -Foundation and others. For example, the package includes programs -licensed under the Apache License, Version 2.0. Such programs are -licensed to you under their original licenses. - -Oracle facilitates your further distribution of this package by adding -the Classpath Exception to the necessary parts of its GPLv2 code, which -permits you to use that code in combination with other independent -modules not licensed under the GPLv2. However, note that this would -not permit you to commingle code under an incompatible license with -Oracle's GPLv2 licensed code by, for example, cutting and pasting such -code into a file also containing Oracle's GPLv2 licensed code and then -distributing the result. Additionally, if you were to remove the -Classpath Exception from any of the files to which it applies and -distribute the result, you would likely be required to license some or -all of the other code in that distribution under the GPLv2 as well, and -since the GPLv2 is incompatible with the license terms of some items -included in the distribution by Oracle, removing the Classpath -Exception could therefore effectively compromise your ability to -further distribute the package. - -Proceed with caution and we recommend that you obtain the advice of a -lawyer skilled in open source matters before removing the Classpath -Exception or making modifications to this package which may -subsequently be redistributed and/or involve the use of third party -software. - -CLASSPATH EXCEPTION -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License version 2 cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from or -based on this library. If you modify this library, you may extend this -exception to your version of the library, but you are not obligated to -do so. If you do not wish to do so, delete this exception statement -from your version. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-jax-rs b/java-chassis-distribution/src/release/licenses/LICENSE-jax-rs deleted file mode 100644 index b1c74f95ede..00000000000 --- a/java-chassis-distribution/src/release/licenses/LICENSE-jax-rs +++ /dev/null @@ -1,759 +0,0 @@ -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 - -1. Definitions. - - 1.1. "Contributor" means each individual or entity that creates or - contributes to the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Software, prior Modifications used by a Contributor (if any), and - the Modifications made by that particular Contributor. - - 1.3. "Covered Software" means (a) the Original Software, or (b) - Modifications, or (c) the combination of files containing Original - Software with files containing Modifications, in each case including - portions thereof. - - 1.4. "Executable" means the Covered Software in any form other than - Source Code. - - 1.5. "Initial Developer" means the individual or entity that first - makes Original Software available under this License. - - 1.6. "Larger Work" means a work which combines Covered Software or - portions thereof with code not governed by the terms of this License. - - 1.7. "License" means this document. - - 1.8. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means the Source Code and Executable form of - any of the following: - - A. Any file that results from an addition to, deletion from or - modification of the contents of a file containing Original Software - or previous Modifications; - - B. Any new file that contains any part of the Original Software or - previous Modification; or - - C. Any new file that is contributed or otherwise made available - under the terms of this License. - - 1.10. "Original Software" means the Source Code and Executable form - of computer software code that is originally released under this - License. - - 1.11. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.12. "Source Code" means (a) the common form of computer software - code in which modifications are made and (b) associated - documentation included in or with such code. - - 1.13. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, - this License. For legal entities, "You" includes any entity which - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants. - - 2.1. The Initial Developer Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, the Initial Developer - hereby grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer, to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Software (or portions thereof), with or without Modifications, - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using or selling of - Original Software, to make, have made, use, practice, sell, and - offer for sale, and/or otherwise dispose of the Original Software - (or portions thereof). - - (c) The licenses granted in Sections 2.1(a) and (b) are effective on - the date Initial Developer first distributes or otherwise makes the - Original Software available to a third party under the terms of this - License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: (1) for code that You delete from the Original Software, or - (2) for infringements caused by: (i) the modification of the - Original Software, or (ii) the combination of the Original Software - with other software or devices. - - 2.2. Contributor Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, each Contributor hereby - grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof), either on an - unmodified basis, with other Modifications, as Covered Software - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or selling - of Modifications made by that Contributor either alone and/or in - combination with its Contributor Version (or portions of such - combination), to make, use, sell, offer for sale, have made, and/or - otherwise dispose of: (1) Modifications made by that Contributor (or - portions thereof); and (2) the combination of Modifications made by - that Contributor with its Contributor Version (or portions of such - combination). - - (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective - on the date Contributor first distributes or otherwise makes the - Modifications available to a third party. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: (1) for any code that Contributor has deleted from the - Contributor Version; (2) for infringements caused by: (i) third - party modifications of Contributor Version, or (ii) the combination - of Modifications made by that Contributor with other software - (except as part of the Contributor Version) or other devices; or (3) - under Patent Claims infringed by Covered Software in the absence of - Modifications made by that Contributor. - -3. Distribution Obligations. - - 3.1. Availability of Source Code. - - Any Covered Software that You distribute or otherwise make available - in Executable form must also be made available in Source Code form - and that Source Code form must be distributed only under the terms - of this License. You must include a copy of this License with every - copy of the Source Code form of the Covered Software You distribute - or otherwise make available. You must inform recipients of any such - Covered Software in Executable form as to how they can obtain such - Covered Software in Source Code form in a reasonable manner on or - through a medium customarily used for software exchange. - - 3.2. Modifications. - - The Modifications that You create or to which You contribute are - governed by the terms of this License. You represent that You - believe Your Modifications are Your original creation(s) and/or You - have sufficient rights to grant the rights conveyed by this License. - - 3.3. Required Notices. - - You must include a notice in each of Your Modifications that - identifies You as the Contributor of the Modification. You may not - remove or alter any copyright, patent or trademark notices contained - within the Covered Software, or any notices of licensing or any - descriptive text giving attribution to any Contributor or the - Initial Developer. - - 3.4. Application of Additional Terms. - - You may not offer or impose any terms on any Covered Software in - Source Code form that alters or restricts the applicable version of - this License or the recipients' rights hereunder. You may choose to - offer, and to charge a fee for, warranty, support, indemnity or - liability obligations to one or more recipients of Covered Software. - However, you may do so only on Your own behalf, and not on behalf of - the Initial Developer or any Contributor. You must make it - absolutely clear that any such warranty, support, indemnity or - liability obligation is offered by You alone, and You hereby agree - to indemnify the Initial Developer and every Contributor for any - liability incurred by the Initial Developer or such Contributor as a - result of warranty, support, indemnity or liability terms You offer. - - 3.5. Distribution of Executable Versions. - - You may distribute the Executable form of the Covered Software under - the terms of this License or under the terms of a license of Your - choice, which may contain terms different from this License, - provided that You are in compliance with the terms of this License - and that the license for the Executable form does not attempt to - limit or alter the recipient's rights in the Source Code form from - the rights set forth in this License. If You distribute the Covered - Software in Executable form under a different license, You must make - it absolutely clear that any terms which differ from this License - are offered by You alone, not by the Initial Developer or - Contributor. You hereby agree to indemnify the Initial Developer and - every Contributor for any liability incurred by the Initial - Developer or such Contributor as a result of any such terms You offer. - - 3.6. Larger Works. - - You may create a Larger Work by combining Covered Software with - other code not governed by the terms of this License and distribute - the Larger Work as a single product. In such a case, You must make - sure the requirements of this License are fulfilled for the Covered - Software. - -4. Versions of the License. - - 4.1. New Versions. - - Oracle is the initial license steward and may publish revised and/or - new versions of this License from time to time. Each version will be - given a distinguishing version number. Except as provided in Section - 4.3, no one other than the license steward has the right to modify - this License. - - 4.2. Effect of New Versions. - - You may always continue to use, distribute or otherwise make the - Covered Software available under the terms of the version of the - License under which You originally received the Covered Software. If - the Initial Developer includes a notice in the Original Software - prohibiting it from being distributed or otherwise made available - under any subsequent version of the License, You must distribute and - make the Covered Software available under the terms of the version - of the License under which You originally received the Covered - Software. Otherwise, You may also choose to use, distribute or - otherwise make the Covered Software available under the terms of any - subsequent version of the License published by the license steward. - - 4.3. Modified Versions. - - When You are an Initial Developer and You want to create a new - license for Your Original Software, You may create and use a - modified version of this License if You: (a) rename the license and - remove any references to the name of the license steward (except to - note that the license differs from this License); and (b) otherwise - make it clear that the license contains terms which differ from this - License. - -5. DISCLAIMER OF WARRANTY. - - COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE - IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR - NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF - THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE - DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY - OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, - REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN - ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS - AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -6. TERMINATION. - - 6.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to - cure such breach within 30 days of becoming aware of the breach. - Provisions which, by their nature, must remain in effect beyond the - termination of this License shall survive. - - 6.2. If You assert a patent infringement claim (excluding - declaratory judgment actions) against Initial Developer or a - Contributor (the Initial Developer or Contributor against whom You - assert such claim is referred to as "Participant") alleging that the - Participant Software (meaning the Contributor Version where the - Participant is a Contributor or the Original Software where the - Participant is the Initial Developer) directly or indirectly - infringes any patent, then any and all rights granted directly or - indirectly to You by such Participant, the Initial Developer (if the - Initial Developer is not the Participant) and all Contributors under - Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice - from Participant terminate prospectively and automatically at the - expiration of such 60 day notice period, unless if within such 60 - day period You withdraw Your claim with respect to the Participant - Software against such Participant either unilaterally or pursuant to - a written agreement with Participant. - - 6.3. If You assert a patent infringement claim against Participant - alleging that the Participant Software directly or indirectly - infringes any patent where such claim is resolved (such as by - license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 6.4. In the event of termination under Sections 6.1 or 6.2 above, - all end user licenses that have been validly granted by You or any - distributor hereunder prior to termination (excluding licenses - granted to You by any distributor) shall survive termination. - -7. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE - INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF - COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE - TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT - LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER - FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR - LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE - POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT - APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH - PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH - LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR - LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION - AND LIMITATION MAY NOT APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - - The Covered Software is a "commercial item," as that term is defined - in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" (as that term is defined at 48 C.F.R. § - 252.227-7014(a)(1)) and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent - with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 - (June 1995), all U.S. Government End Users acquire Covered Software - with only those rights set forth herein. This U.S. Government Rights - clause is in lieu of, and supersedes, any other FAR, DFAR, or other - clause or provision that addresses Government rights in computer - software under this License. - -9. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - the law of the jurisdiction specified in a notice contained within - the Original Software (except to the extent applicable law, if any, - provides otherwise), excluding such jurisdiction's conflict-of-law - provisions. Any litigation relating to this License shall be subject - to the jurisdiction of the courts located in the jurisdiction and - venue specified in a notice contained within the Original Software, - with the losing party responsible for costs, including, without - limitation, court costs and reasonable attorneys' fees and expenses. - The application of the United Nations Convention on Contracts for - the International Sale of Goods is expressly excluded. Any law or - regulation which provides that the language of a contract shall be - construed against the drafter shall not apply to this License. You - agree that You alone are responsible for compliance with the United - States export administration regulations (and the export control - laws and regulation of any other countries) when You use, distribute - or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - ------------------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION -LICENSE (CDDL) - -The code released under the CDDL shall be governed by the laws of the -State of California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the jurisdiction -of the Federal Courts of the Northern District of California and the -state courts of the State of California, with venue lying in Santa Clara -County, California. - - - - The GNU General Public License (GPL) Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor -Boston, MA 02110-1335 -USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free software--to -make sure the software is free for all its users. This General Public -License applies to most of the Free Software Foundation's software and -to any other program whose authors commit to using it. (Some other Free -Software Foundation software is covered by the GNU Library General -Public License instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. -Our General Public Licenses are designed to make sure that you have the -freedom to distribute copies of free software (and charge for this -service if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone -to deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis -or for a fee, you must give the recipients all the rights that you have. -You must make sure that they, too, receive or can get the source code. -And you must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - -Finally, any free program is threatened constantly by software patents. -We wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must -be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and -modification follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a -notice placed by the copyright holder saying it may be distributed under -the terms of this General Public License. The "Program", below, refers -to any such program or work, and a "work based on the Program" means -either the Program or any derivative work under copyright law: that is -to say, a work containing the Program or a portion of it, either -verbatim or with modifications and/or translated into another language. -(Hereinafter, translation is included without limitation in the term -"modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of running -the Program is not restricted, and the output from the Program is -covered only if its contents constitute a work based on the Program -(independent of having been made by running the Program). Whether that -is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously -and appropriately publish on each copy an appropriate copyright notice -and disclaimer of warranty; keep intact all the notices that refer to -this License and to the absence of any warranty; and give any other -recipients of the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of -it, thus forming a work based on the Program, and copy and distribute -such modifications or work under the terms of Section 1 above, provided -that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this License. - (Exception: if the Program itself is interactive but does not - normally print such an announcement, your work based on the Program - is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, and -can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based on -the Program, the distribution of the whole must be on the terms of this -License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of a -storage or distribution medium does not bring the other work under the -scope of this License. - -3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your cost - of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source code -means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to control -compilation and installation of the executable. However, as a special -exception, the source code distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies the -executable. - -If distribution of executable or object code is made by offering access -to copy from a designated place, then offering equivalent access to copy -the source code from the same place counts as distribution of the source -code, even though third parties are not compelled to copy the source -along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt otherwise -to copy, modify, sublicense or distribute the Program is void, and will -automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will -not have their licenses terminated so long as such parties remain in -full compliance. - -5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and all -its terms and conditions for copying, distributing or modifying the -Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further restrictions -on the recipients' exercise of the rights granted herein. You are not -responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot distribute -so as to satisfy simultaneously your obligations under this License and -any other pertinent obligations, then as a consequence you may not -distribute the Program at all. For example, if a patent license would -not permit royalty-free redistribution of the Program by all those who -receive copies directly or indirectly through you, then the only way you -could satisfy both it and this License would be to refrain entirely from -distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is implemented -by public license practices. Many people have made generous -contributions to the wide range of software distributed through that -system in reliance on consistent application of that system; it is up to -the author/donor to decide if he or she is willing to distribute -software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be -a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License may -add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among countries -not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new -versions of the General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Program does not specify a version -number of this License, you may choose any version ever published by the -Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the -author to ask for permission. For software which is copyrighted by the -Free Software Foundation, write to the Free Software Foundation; we -sometimes make exceptions for this. Our decision will be guided by the -two goals of preserving the free status of all derivatives of our free -software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH -YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF -THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR -OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type - `show w'. This is free software, and you are welcome to redistribute - it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the commands -you use may be called something other than `show w' and `show c'; they -could even be mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (which makes passes at compilers) written by - James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications -with the library. If this is what you want to do, use the GNU Library -General Public License instead of this License. - -# - -Certain source files distributed by Oracle America, Inc. and/or its -affiliates are subject to the following clarification and special -exception to the GPLv2, based on the GNU Project exception for its -Classpath libraries, known as the GNU Classpath Exception, but only -where Oracle has expressly included in the particular source file's -header the words "Oracle designates this particular file as subject to -the "Classpath" exception as provided by Oracle in the LICENSE file -that accompanied this code." - -You should also note that Oracle includes multiple, independent -programs in this software package. Some of those programs are provided -under licenses deemed incompatible with the GPLv2 by the Free Software -Foundation and others. For example, the package includes programs -licensed under the Apache License, Version 2.0. Such programs are -licensed to you under their original licenses. - -Oracle facilitates your further distribution of this package by adding -the Classpath Exception to the necessary parts of its GPLv2 code, which -permits you to use that code in combination with other independent -modules not licensed under the GPLv2. However, note that this would -not permit you to commingle code under an incompatible license with -Oracle's GPLv2 licensed code by, for example, cutting and pasting such -code into a file also containing Oracle's GPLv2 licensed code and then -distributing the result. Additionally, if you were to remove the -Classpath Exception from any of the files to which it applies and -distribute the result, you would likely be required to license some or -all of the other code in that distribution under the GPLv2 as well, and -since the GPLv2 is incompatible with the license terms of some items -included in the distribution by Oracle, removing the Classpath -Exception could therefore effectively compromise your ability to -further distribute the package. - -Proceed with caution and we recommend that you obtain the advice of a -lawyer skilled in open source matters before removing the Classpath -Exception or making modifications to this package which may -subsequently be redistributed and/or involve the use of third party -software. - -CLASSPATH EXCEPTION -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License version 2 cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from or -based on this library. If you modify this library, you may extend this -exception to your version of the library, but you are not obligated to -do so. If you do not wish to do so, delete this exception statement -from your version. diff --git a/java-chassis-distribution/src/release/licenses/LICENSE-jersey b/java-chassis-distribution/src/release/licenses/LICENSE-jersey deleted file mode 100644 index 80babca1e16..00000000000 --- a/java-chassis-distribution/src/release/licenses/LICENSE-jersey +++ /dev/null @@ -1,759 +0,0 @@ -COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 - -1. Definitions. - - 1.1. "Contributor" means each individual or entity that creates or - contributes to the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Software, prior Modifications used by a Contributor (if any), and - the Modifications made by that particular Contributor. - - 1.3. "Covered Software" means (a) the Original Software, or (b) - Modifications, or (c) the combination of files containing Original - Software with files containing Modifications, in each case including - portions thereof. - - 1.4. "Executable" means the Covered Software in any form other than - Source Code. - - 1.5. "Initial Developer" means the individual or entity that first - makes Original Software available under this License. - - 1.6. "Larger Work" means a work which combines Covered Software or - portions thereof with code not governed by the terms of this License. - - 1.7. "License" means this document. - - 1.8. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means the Source Code and Executable form of - any of the following: - - A. Any file that results from an addition to, deletion from or - modification of the contents of a file containing Original Software - or previous Modifications; - - B. Any new file that contains any part of the Original Software or - previous Modification; or - - C. Any new file that is contributed or otherwise made available - under the terms of this License. - - 1.10. "Original Software" means the Source Code and Executable form - of computer software code that is originally released under this - License. - - 1.11. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.12. "Source Code" means (a) the common form of computer software - code in which modifications are made and (b) associated - documentation included in or with such code. - - 1.13. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, - this License. For legal entities, "You" includes any entity which - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants. - - 2.1. The Initial Developer Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, the Initial Developer - hereby grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer, to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Software (or portions thereof), with or without Modifications, - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using or selling of - Original Software, to make, have made, use, practice, sell, and - offer for sale, and/or otherwise dispose of the Original Software - (or portions thereof). - - (c) The licenses granted in Sections 2.1(a) and (b) are effective on - the date Initial Developer first distributes or otherwise makes the - Original Software available to a third party under the terms of this - License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: (1) for code that You delete from the Original Software, or - (2) for infringements caused by: (i) the modification of the - Original Software, or (ii) the combination of the Original Software - with other software or devices. - - 2.2. Contributor Grant. - - Conditioned upon Your compliance with Section 3.1 below and subject - to third party intellectual property claims, each Contributor hereby - grants You a world-wide, royalty-free, non-exclusive license: - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof), either on an - unmodified basis, with other Modifications, as Covered Software - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or selling - of Modifications made by that Contributor either alone and/or in - combination with its Contributor Version (or portions of such - combination), to make, use, sell, offer for sale, have made, and/or - otherwise dispose of: (1) Modifications made by that Contributor (or - portions thereof); and (2) the combination of Modifications made by - that Contributor with its Contributor Version (or portions of such - combination). - - (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective - on the date Contributor first distributes or otherwise makes the - Modifications available to a third party. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: (1) for any code that Contributor has deleted from the - Contributor Version; (2) for infringements caused by: (i) third - party modifications of Contributor Version, or (ii) the combination - of Modifications made by that Contributor with other software - (except as part of the Contributor Version) or other devices; or (3) - under Patent Claims infringed by Covered Software in the absence of - Modifications made by that Contributor. - -3. Distribution Obligations. - - 3.1. Availability of Source Code. - - Any Covered Software that You distribute or otherwise make available - in Executable form must also be made available in Source Code form - and that Source Code form must be distributed only under the terms - of this License. You must include a copy of this License with every - copy of the Source Code form of the Covered Software You distribute - or otherwise make available. You must inform recipients of any such - Covered Software in Executable form as to how they can obtain such - Covered Software in Source Code form in a reasonable manner on or - through a medium customarily used for software exchange. - - 3.2. Modifications. - - The Modifications that You create or to which You contribute are - governed by the terms of this License. You represent that You - believe Your Modifications are Your original creation(s) and/or You - have sufficient rights to grant the rights conveyed by this License. - - 3.3. Required Notices. - - You must include a notice in each of Your Modifications that - identifies You as the Contributor of the Modification. You may not - remove or alter any copyright, patent or trademark notices contained - within the Covered Software, or any notices of licensing or any - descriptive text giving attribution to any Contributor or the - Initial Developer. - - 3.4. Application of Additional Terms. - - You may not offer or impose any terms on any Covered Software in - Source Code form that alters or restricts the applicable version of - this License or the recipients' rights hereunder. You may choose to - offer, and to charge a fee for, warranty, support, indemnity or - liability obligations to one or more recipients of Covered Software. - However, you may do so only on Your own behalf, and not on behalf of - the Initial Developer or any Contributor. You must make it - absolutely clear that any such warranty, support, indemnity or - liability obligation is offered by You alone, and You hereby agree - to indemnify the Initial Developer and every Contributor for any - liability incurred by the Initial Developer or such Contributor as a - result of warranty, support, indemnity or liability terms You offer. - - 3.5. Distribution of Executable Versions. - - You may distribute the Executable form of the Covered Software under - the terms of this License or under the terms of a license of Your - choice, which may contain terms different from this License, - provided that You are in compliance with the terms of this License - and that the license for the Executable form does not attempt to - limit or alter the recipient's rights in the Source Code form from - the rights set forth in this License. If You distribute the Covered - Software in Executable form under a different license, You must make - it absolutely clear that any terms which differ from this License - are offered by You alone, not by the Initial Developer or - Contributor. You hereby agree to indemnify the Initial Developer and - every Contributor for any liability incurred by the Initial - Developer or such Contributor as a result of any such terms You offer. - - 3.6. Larger Works. - - You may create a Larger Work by combining Covered Software with - other code not governed by the terms of this License and distribute - the Larger Work as a single product. In such a case, You must make - sure the requirements of this License are fulfilled for the Covered - Software. - -4. Versions of the License. - - 4.1. New Versions. - - Oracle is the initial license steward and may publish revised and/or - new versions of this License from time to time. Each version will be - given a distinguishing version number. Except as provided in Section - 4.3, no one other than the license steward has the right to modify - this License. - - 4.2. Effect of New Versions. - - You may always continue to use, distribute or otherwise make the - Covered Software available under the terms of the version of the - License under which You originally received the Covered Software. If - the Initial Developer includes a notice in the Original Software - prohibiting it from being distributed or otherwise made available - under any subsequent version of the License, You must distribute and - make the Covered Software available under the terms of the version - of the License under which You originally received the Covered - Software. Otherwise, You may also choose to use, distribute or - otherwise make the Covered Software available under the terms of any - subsequent version of the License published by the license steward. - - 4.3. Modified Versions. - - When You are an Initial Developer and You want to create a new - license for Your Original Software, You may create and use a - modified version of this License if You: (a) rename the license and - remove any references to the name of the license steward (except to - note that the license differs from this License); and (b) otherwise - make it clear that the license contains terms which differ from this - License. - -5. DISCLAIMER OF WARRANTY. - - COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE - IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR - NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF - THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE - DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY - OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, - REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN - ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS - AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -6. TERMINATION. - - 6.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to - cure such breach within 30 days of becoming aware of the breach. - Provisions which, by their nature, must remain in effect beyond the - termination of this License shall survive. - - 6.2. If You assert a patent infringement claim (excluding - declaratory judgment actions) against Initial Developer or a - Contributor (the Initial Developer or Contributor against whom You - assert such claim is referred to as "Participant") alleging that the - Participant Software (meaning the Contributor Version where the - Participant is a Contributor or the Original Software where the - Participant is the Initial Developer) directly or indirectly - infringes any patent, then any and all rights granted directly or - indirectly to You by such Participant, the Initial Developer (if the - Initial Developer is not the Participant) and all Contributors under - Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice - from Participant terminate prospectively and automatically at the - expiration of such 60 day notice period, unless if within such 60 - day period You withdraw Your claim with respect to the Participant - Software against such Participant either unilaterally or pursuant to - a written agreement with Participant. - - 6.3. If You assert a patent infringement claim against Participant - alleging that the Participant Software directly or indirectly - infringes any patent where such claim is resolved (such as by - license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 6.4. In the event of termination under Sections 6.1 or 6.2 above, - all end user licenses that have been validly granted by You or any - distributor hereunder prior to termination (excluding licenses - granted to You by any distributor) shall survive termination. - -7. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE - INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF - COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE - TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT - LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER - FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR - LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE - POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT - APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH - PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH - LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR - LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION - AND LIMITATION MAY NOT APPLY TO YOU. - -8. U.S. GOVERNMENT END USERS. - - The Covered Software is a "commercial item," as that term is defined - in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" (as that term is defined at 48 C.F.R. ß - 252.227-7014(a)(1)) and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent - with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 - (June 1995), all U.S. Government End Users acquire Covered Software - with only those rights set forth herein. This U.S. Government Rights - clause is in lieu of, and supersedes, any other FAR, DFAR, or other - clause or provision that addresses Government rights in computer - software under this License. - -9. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - the law of the jurisdiction specified in a notice contained within - the Original Software (except to the extent applicable law, if any, - provides otherwise), excluding such jurisdiction's conflict-of-law - provisions. Any litigation relating to this License shall be subject - to the jurisdiction of the courts located in the jurisdiction and - venue specified in a notice contained within the Original Software, - with the losing party responsible for costs, including, without - limitation, court costs and reasonable attorneys' fees and expenses. - The application of the United Nations Convention on Contracts for - the International Sale of Goods is expressly excluded. Any law or - regulation which provides that the language of a contract shall be - construed against the drafter shall not apply to this License. You - agree that You alone are responsible for compliance with the United - States export administration regulations (and the export control - laws and regulation of any other countries) when You use, distribute - or otherwise make available any Covered Software. - -10. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - ------------------------------------------------------------------------- - -NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION -LICENSE (CDDL) - -The code released under the CDDL shall be governed by the laws of the -State of California (excluding conflict-of-law provisions). Any -litigation relating to this License shall be subject to the jurisdiction -of the Federal Courts of the Northern District of California and the -state courts of the State of California, with venue lying in Santa Clara -County, California. - - - - The GNU General Public License (GPL) Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor -Boston, MA 02110-1335 -USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free software--to -make sure the software is free for all its users. This General Public -License applies to most of the Free Software Foundation's software and -to any other program whose authors commit to using it. (Some other Free -Software Foundation software is covered by the GNU Library General -Public License instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. -Our General Public Licenses are designed to make sure that you have the -freedom to distribute copies of free software (and charge for this -service if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone -to deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis -or for a fee, you must give the recipients all the rights that you have. -You must make sure that they, too, receive or can get the source code. -And you must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - -Finally, any free program is threatened constantly by software patents. -We wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must -be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and -modification follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a -notice placed by the copyright holder saying it may be distributed under -the terms of this General Public License. The "Program", below, refers -to any such program or work, and a "work based on the Program" means -either the Program or any derivative work under copyright law: that is -to say, a work containing the Program or a portion of it, either -verbatim or with modifications and/or translated into another language. -(Hereinafter, translation is included without limitation in the term -"modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of running -the Program is not restricted, and the output from the Program is -covered only if its contents constitute a work based on the Program -(independent of having been made by running the Program). Whether that -is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously -and appropriately publish on each copy an appropriate copyright notice -and disclaimer of warranty; keep intact all the notices that refer to -this License and to the absence of any warranty; and give any other -recipients of the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of -it, thus forming a work based on the Program, and copy and distribute -such modifications or work under the terms of Section 1 above, provided -that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this License. - (Exception: if the Program itself is interactive but does not - normally print such an announcement, your work based on the Program - is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, and -can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based on -the Program, the distribution of the whole must be on the terms of this -License, whose permissions for other licensees extend to the entire -whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of a -storage or distribution medium does not bring the other work under the -scope of this License. - -3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your cost - of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source code -means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to control -compilation and installation of the executable. However, as a special -exception, the source code distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies the -executable. - -If distribution of executable or object code is made by offering access -to copy from a designated place, then offering equivalent access to copy -the source code from the same place counts as distribution of the source -code, even though third parties are not compelled to copy the source -along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt otherwise -to copy, modify, sublicense or distribute the Program is void, and will -automatically terminate your rights under this License. However, parties -who have received copies, or rights, from you under this License will -not have their licenses terminated so long as such parties remain in -full compliance. - -5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and all -its terms and conditions for copying, distributing or modifying the -Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further restrictions -on the recipients' exercise of the rights granted herein. You are not -responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot distribute -so as to satisfy simultaneously your obligations under this License and -any other pertinent obligations, then as a consequence you may not -distribute the Program at all. For example, if a patent license would -not permit royalty-free redistribution of the Program by all those who -receive copies directly or indirectly through you, then the only way you -could satisfy both it and this License would be to refrain entirely from -distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is implemented -by public license practices. Many people have made generous -contributions to the wide range of software distributed through that -system in reliance on consistent application of that system; it is up to -the author/donor to decide if he or she is willing to distribute -software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be -a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License may -add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among countries -not thus excluded. In such case, this License incorporates the -limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new -versions of the General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Program does not specify a version -number of this License, you may choose any version ever published by the -Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the -author to ask for permission. For software which is copyrighted by the -Free Software Foundation, write to the Free Software Foundation; we -sometimes make exceptions for this. Our decision will be guided by the -two goals of preserving the free status of all derivatives of our free -software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH -YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL -NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR -DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL -DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF -THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR -OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - One line to give the program's name and a brief idea of what it does. - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type - `show w'. This is free software, and you are welcome to redistribute - it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the commands -you use may be called something other than `show w' and `show c'; they -could even be mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (which makes passes at compilers) written by - James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications -with the library. If this is what you want to do, use the GNU Library -General Public License instead of this License. - -# - -Certain source files distributed by Oracle America, Inc. and/or its -affiliates are subject to the following clarification and special -exception to the GPLv2, based on the GNU Project exception for its -Classpath libraries, known as the GNU Classpath Exception, but only -where Oracle has expressly included in the particular source file's -header the words "Oracle designates this particular file as subject to -the "Classpath" exception as provided by Oracle in the LICENSE file -that accompanied this code." - -You should also note that Oracle includes multiple, independent -programs in this software package. Some of those programs are provided -under licenses deemed incompatible with the GPLv2 by the Free Software -Foundation and others. For example, the package includes programs -licensed under the Apache License, Version 2.0. Such programs are -licensed to you under their original licenses. - -Oracle facilitates your further distribution of this package by adding -the Classpath Exception to the necessary parts of its GPLv2 code, which -permits you to use that code in combination with other independent -modules not licensed under the GPLv2. However, note that this would -not permit you to commingle code under an incompatible license with -Oracle's GPLv2 licensed code by, for example, cutting and pasting such -code into a file also containing Oracle's GPLv2 licensed code and then -distributing the result. Additionally, if you were to remove the -Classpath Exception from any of the files to which it applies and -distribute the result, you would likely be required to license some or -all of the other code in that distribution under the GPLv2 as well, and -since the GPLv2 is incompatible with the license terms of some items -included in the distribution by Oracle, removing the Classpath -Exception could therefore effectively compromise your ability to -further distribute the package. - -Proceed with caution and we recommend that you obtain the advice of a -lawyer skilled in open source matters before removing the Classpath -Exception or making modifications to this package which may -subsequently be redistributed and/or involve the use of third party -software. - -CLASSPATH EXCEPTION -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License version 2 cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from or -based on this library. If you modify this library, you may extend this -exception to your version of the library, but you are not obligated to -do so. If you do not wish to do so, delete this exception statement -from your version. diff --git a/java-chassis-distribution/src/release/licenses/NOTICE-protostuff b/java-chassis-distribution/src/release/licenses/NOTICE-protostuff deleted file mode 100644 index e1c9c379777..00000000000 --- a/java-chassis-distribution/src/release/licenses/NOTICE-protostuff +++ /dev/null @@ -1,27 +0,0 @@ -============================================================== - protostuff - Copyright 2009 David Yu dyuproject@gmail.com -============================================================== - -protobuf is copyright Google inc unless otherwise noted. -It is licensed under the BSD license. - -jackson-core-asl is copyright FasterXml unless otherwise noted. -It is licensed under the apache 2.0 license. - -antlr is copyright Terence Parr unless otherwise noted. -It is licensed under the BSD license. - -stringtemplate is copyright Terence Parr unless otherwise noted. -It is licensed under the BSD license. - -velocity is licensed under the apache 2.0 license. - -B64Code.java is copyright Mort Bay Consulting Pty Ltd unless otherwise noted. -It is licensed under the apache 2.0 license. - -jarjar is copyright Google inc unless otherwise noted. -It is licensed under the apache 2.0 license. - -guava is copyright Google inc unless otherwise noted. -It is licensed under the apache 2.0 license. diff --git a/java-chassis-spring-boot/pom.xml b/java-chassis-spring-boot/pom.xml deleted file mode 100644 index 39514ecd876..00000000000 --- a/java-chassis-spring-boot/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - java-chassis - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - pom - java-chassis-spring-boot - - - spring-boot-common - spring-boot-starter - spring-boot2-starter-parent - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot-common/pom.xml b/java-chassis-spring-boot/spring-boot-common/pom.xml deleted file mode 100644 index 525e689a3ce..00000000000 --- a/java-chassis-spring-boot/spring-boot-common/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - java-chassis-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - ../../parent - - 4.0.0 - - spring-boot-common - - - org.apache.servicecomb - service-registry - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java b/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java deleted file mode 100644 index f114439c757..00000000000 --- a/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.common; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; - -public abstract class AbstractDiscoveryClient { - - private Map discoveryTrees = new ConcurrentHashMapEx<>(); - private DiscoveryFilter filter = null; - - public AbstractDiscoveryClient(DiscoveryFilter filter){ - this.filter = filter; - } - - public List doGetInstances(final String serviceId) { - DiscoveryContext context = new DiscoveryContext(); - context.setInputParameters(serviceId); - - DiscoveryTree discoveryTree = discoveryTrees.computeIfAbsent(serviceId, key -> { - DiscoveryTree tree = new DiscoveryTree(); - tree.addFilter(filter); - return tree; - }); - - VersionedCache serversVersionedCache = discoveryTree.discovery(context, - RegistryUtils.getAppId(), - serviceId, - DefinitionConst.VERSION_RULE_ALL); - - return serversVersionedCache.data(); - } - - public List getServices() { - ServiceRegistryClient client = RegistryUtils.getServiceRegistryClient(); - List services = client.getAllMicroservices(); - List serviceIDList = new ArrayList<>(); - if (null != services && !services.isEmpty()) { - for (Microservice service : services) { - serviceIDList.add(service.getServiceName()); - } - } - return serviceIDList; - } -} diff --git a/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/InstanceDiscoveryFilter.java b/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/InstanceDiscoveryFilter.java deleted file mode 100644 index 86f84a968cb..00000000000 --- a/java-chassis-spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/InstanceDiscoveryFilter.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.common; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InstanceDiscoveryFilter implements DiscoveryFilter { - - private static final Logger LOGGER = LoggerFactory.getLogger(InstanceDiscoveryFilter.class); - - public interface InstanceFactory { - Object createInstance(String name, URIEndpointObject uri); - } - - InstanceFactory instanceFactory; - - public InstanceDiscoveryFilter(InstanceFactory factory){ - instanceFactory = factory; - } - - @Override - public int getOrder() { - return Short.MAX_VALUE; - } - - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - return parent.children() - .computeIfAbsent(context.getInputParameters(), etn -> createDiscoveryTreeNode(context, parent)); - } - - @SuppressWarnings("unchecked") - protected DiscoveryTreeNode createDiscoveryTreeNode(DiscoveryContext context, - DiscoveryTreeNode parent) { - String serviceName = context.getInputParameters(); - - List instances = new ArrayList<>(); - for (MicroserviceInstance instance : ((Map) parent.data()).values()) { - for (String endpoint : instance.getEndpoints()) { - String scheme = endpoint.split(":", 2)[0]; - if (!scheme.equalsIgnoreCase("rest")) { - LOGGER.info("Endpoint {} is not supported in Spring Cloud, ignoring.", endpoint); - continue; - } - URIEndpointObject uri = new URIEndpointObject(endpoint); - instances.add(instanceFactory.createInstance(serviceName, uri)); - } - } - - return new DiscoveryTreeNode() - .subName(parent, serviceName) - .data(instances); - } -}; \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot-starter/pom.xml b/java-chassis-spring-boot/spring-boot-starter/pom.xml deleted file mode 100644 index 8d579389b1a..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - java-chassis-parent - 1.2.0-SNAPSHOT - ../../parent - - spring-boot-starter-parent - Java Chassis::Spring Boot Starter::Parent - - pom - - spring-boot-starter-configuration - spring-boot-starter-provider - spring-boot-starter-transport - spring-boot-starter-discovery - spring-boot-starter-registry - spring-cloud-zuul - spring-cloud-zuul-zipkin - spring-boot-starter-servicecomb - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-configuration/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-configuration/pom.xml deleted file mode 100644 index f039ffbd0f8..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-configuration/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - spring-boot-starter-parent - 1.2.0-SNAPSHOT - - - spring-boot-starter-configuration - Java Chassis::Spring Boot Starter::Configuration - - - - org.apache.servicecomb - foundation-config - - - org.apache.servicecomb - config-cc - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/pom.xml deleted file mode 100644 index d67d7531dd7..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - spring-boot-starter-parent - 1.2.0-SNAPSHOT - - spring-boot-starter-discovery - Java Chassis::Spring Boot Starter::Discovery - - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - logback-classic - - - org.slf4j - log4j-over-slf4j - - - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - org.springframework.cloud - spring-cloud-starter-zuul - - - org.springframework.cloud - spring-cloud-starter-ribbon - - - javax.ws.rs - jsr311-api - - - - - org.springframework.cloud - spring-cloud-starter-hystrix - - - org.apache.servicecomb - service-registry - - - org.apache.servicecomb - spring-boot-common - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClient.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClient.java deleted file mode 100644 index 22565b60b6a..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClient.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.springboot.common.AbstractDiscoveryClient; -import org.apache.servicecomb.springboot.common.InstanceDiscoveryFilter; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; - -public class ScbDiscoveryClient extends AbstractDiscoveryClient implements DiscoveryClient { - - public ScbDiscoveryClient() { - super(new InstanceDiscoveryFilter((String name, URIEndpointObject uri) -> - new DefaultServiceInstance(name, uri.getHostOrIp(), uri.getPort(), uri.isSslEnabled()))); - } - - @Override - public String description() { - return "Spring Cloud CSE Discovery Client"; - } - - @Override - @Deprecated - public ServiceInstance getLocalServiceInstance() { - return null; - } - - public List getInstances(String serviceId) { - return super.doGetInstances(serviceId); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClientConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClientConfiguration.java deleted file mode 100644 index b26f4597433..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbDiscoveryClientConfiguration.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class) -@Configuration -public class ScbDiscoveryClientConfiguration { - @Bean - @Order(5000) - @ConditionalOnProperty(value = "servicecomb.discoveryClient.enabled", havingValue = "true", matchIfMissing = true) - public DiscoveryClient cseDiscoveryClient() { - return new ScbDiscoveryClient(); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonClientConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonClientConfiguration.java deleted file mode 100644 index d93dd08ccf0..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonClientConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import org.springframework.context.annotation.Bean; - -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.ServerList; - -/** - * Custom {@link org.springframework.cloud.netflix.ribbon.RibbonClient} configuration must not be - * scanned by spring. - * - * @see - * Customizing the Ribbon Client - */ -public class ScbRibbonClientConfiguration { - @Bean - public ServerList ribbonServerList( - IClientConfig config) { - ServiceCombServerList serverList = new ServiceCombServerList(); - serverList.initWithNiwsConfig(config); - return serverList; - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonConfiguration.java deleted file mode 100644 index 4cabac6143f..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; -import org.springframework.cloud.netflix.ribbon.RibbonClients; -import org.springframework.cloud.netflix.ribbon.SpringClientFactory; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableConfigurationProperties -@ConditionalOnBean(SpringClientFactory.class) -@AutoConfigureAfter(RibbonAutoConfiguration.class) -@RibbonClients(defaultConfiguration = ScbRibbonClientConfiguration.class) -public class ScbRibbonConfiguration { - -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java deleted file mode 100644 index a9a4de57c3c..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.starter.discovery; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.AbstractEndpointDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; - -import com.netflix.loadbalancer.Server; - -public class ScbRibbonEndpointDiscoveryFilter extends AbstractEndpointDiscoveryFilter { - @Override - protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { - //only need rest endpoints - return "rest"; - } - - @Override - protected Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance) { - URIEndpointObject uri = new URIEndpointObject(endpoint); - return new Server(uri.getHostOrIp(), uri.getPort()); - } - - @Override - public int getOrder() { - return (int) Short.MAX_VALUE - 1; - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ServiceCombServerList.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ServiceCombServerList.java deleted file mode 100644 index aa20b39aaa5..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/ServiceCombServerList.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; - -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.AbstractServerList; -import com.netflix.loadbalancer.Server; - -public class ServiceCombServerList extends AbstractServerList { - - private DiscoveryTree discoveryTree = new DiscoveryTree(); - - private String serviceId; - - public ServiceCombServerList() { - discoveryTree.addFilter(new ScbRibbonEndpointDiscoveryFilter()); - } - - @Override - public List getInitialListOfServers() { - DiscoveryContext context = new DiscoveryContext(); - context.setInputParameters(serviceId); - VersionedCache serversVersionedCache = discoveryTree.discovery(context, - RegistryUtils.getAppId(), - serviceId, - DefinitionConst.VERSION_RULE_ALL); - return serversVersionedCache.data(); - } - - @Override - public List getUpdatedListOfServers() { - return getInitialListOfServers(); - } - - @Override - public void initWithNiwsConfig(IClientConfig iClientConfig) { - this.serviceId = iClientConfig.getClientName(); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/package-info.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/package-info.java deleted file mode 100644 index 7521e304509..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/java/org/apache/servicecomb/springboot/starter/discovery/package-info.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/resources/META-INF/spring.factories b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 92267e7acf4..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,24 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -org.apache.servicecomb.springboot.starter.provider.EnableServiceComb=\ - org.apache.servicecomb.springboot.starter.discovery.ScbDiscoveryClientConfiguration,\ - org.apache.servicecomb.springboot.starter.discovery.ScbRibbonConfiguration -org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ - org.apache.servicecomb.springboot.starter.discovery.ScbDiscoveryClientConfiguration -org.springframework.cloud.netflix.ribbon.RibbonClient=\ - org.apache.servicecomb.springboot.starter.discovery.ScbRibbonConfiguration \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClient.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClient.java deleted file mode 100644 index 786fd0eba07..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClient.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.cloud.client.discovery.DiscoveryClient; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; - -public class TestScbDiscoveryClient { - @Test - public void testCseDiscoveryClient(@Mocked RegistryUtils registryUtils, - @Injectable InstanceCacheManager instanceCacheManager, - @Injectable ServiceRegistryClient serviceRegistryClient) { - List microserviceList = new ArrayList<>(); - Microservice service1 = new Microservice(); - service1.setServiceName("service1"); - microserviceList.add(service1); - Microservice server2 = new Microservice(); - microserviceList.add(server2); - server2.setServiceName("server2"); - - - List endpoints = new ArrayList<>(); - endpoints.add("rest://localhost:3333"); - endpoints.add("rest://localhost:4444"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setServiceId("service1"); - instance1.setInstanceId("service1-instance1"); - instance1.setEndpoints(endpoints); - - Map data = new HashMap<>(); - data.put("service1-instance1", instance1); - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent").data(data); - new Expectations() { - { - instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); - result = parent; - serviceRegistryClient.getAllMicroservices(); - result = microserviceList; - } - }; - - DiscoveryClient client = new ScbDiscoveryClient(); - Assert.assertEquals("Spring Cloud CSE Discovery Client", client.description()); - Assert.assertEquals(2, client.getServices().size()); - Assert.assertEquals("server2", client.getServices().get(1)); - Assert.assertEquals(2, client.getInstances("service1-instance1").size()); - Assert.assertEquals(4444, client.getInstances("service1-instance1").get(1).getPort()); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClientConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClientConfiguration.java deleted file mode 100644 index 455c95e58dc..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbDiscoveryClientConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import org.junit.Assert; -import org.junit.Test; - -public class TestScbDiscoveryClientConfiguration { - @Test - public void testCseDiscoveryClientConfiguration() { - ScbDiscoveryClientConfiguration discoveryClientConfiguration = new ScbDiscoveryClientConfiguration(); - Assert.assertTrue(discoveryClientConfiguration.cseDiscoveryClient() instanceof ScbDiscoveryClient); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbRibbonClientConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbRibbonClientConfiguration.java deleted file mode 100644 index d833dd76965..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestScbRibbonClientConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.starter.discovery; - -import org.junit.Assert; -import org.junit.Test; - -import com.netflix.client.config.IClientConfig; - -import mockit.Injectable; - -public class TestScbRibbonClientConfiguration { - @Test - public void testCseRibbonClientConfiguration(@Injectable IClientConfig clientConfig) { - ScbRibbonClientConfiguration config = new ScbRibbonClientConfiguration(); - Assert.assertTrue(config.ribbonServerList(clientConfig) instanceof ServiceCombServerList); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestServiceCombServerList.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestServiceCombServerList.java deleted file mode 100644 index 8201641d37f..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery/src/test/java/org/apache/servicecomb/springboot/starter/discovery/TestServiceCombServerList.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.discovery; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.collect.Lists; -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.Server; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; - -public class TestServiceCombServerList { - @Test - public void testServiceCombServerList(@Injectable IClientConfig iClientConfig, - @Mocked RegistryUtils registryUtils, - @Mocked DiscoveryTree discoveryTree, - @Injectable DiscoveryTreeNode versionedCache) { - List endpoints = new ArrayList<>(); - endpoints.add("rest://localhost:3333"); - endpoints.add("highway://localhost:4444"); - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setServiceId("service1"); - instance1.setInstanceId("service1-instance1"); - instance1.setEndpoints(endpoints); - - new Expectations() { - { - iClientConfig.getClientName(); - result = "serviceId1"; - - RegistryUtils.getAppId(); - result = "app"; - discoveryTree.discovery((DiscoveryContext) any, anyString, anyString, anyString); - result = versionedCache; - versionedCache.data(); - result = Lists.newArrayList(new Server("localhost", 3333)); - } - }; - - ServiceCombServerList list = new ServiceCombServerList(); - list.initWithNiwsConfig(iClientConfig); - List serverList = list.getInitialListOfServers(); - Assert.assertEquals(1, serverList.size()); - Assert.assertEquals(3333, serverList.get(0).getPort()); - Assert.assertEquals(serverList.size(), list.getUpdatedListOfServers().size()); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/pom.xml deleted file mode 100644 index 6dfe75d57a5..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - spring-boot-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-boot-starter-provider - Java Chassis::Spring Boot Starter::Provider - - - - org.apache.servicecomb - spring-boot-starter-servicecomb - - - org.apache.servicecomb - transport-rest-vertx - - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/src/main/resources/application.properties b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/src/main/resources/application.properties deleted file mode 100644 index 6a7dfb45b01..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-provider/src/main/resources/application.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -spring.main.web-environment=false diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/pom.xml deleted file mode 100644 index 0fa2353d8ff..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - spring-boot-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-boot-starter-registry - Java Chassis::Spring Boot Starter::Registry - - - - org.apache.servicecomb - service-registry - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/RegistryIntializer.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/RegistryIntializer.java deleted file mode 100644 index f14180e1ccc..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/RegistryIntializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.registry; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; - -/** - * Initialize and Register the services with service center - */ -public class RegistryIntializer { - private static final Logger LOG = LoggerFactory.getLogger(RegistryIntializer.class); - - private RegistryIntializer() { - - } - - public static void initRegistry() { - String address = DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.rest.address", null).get(); - if (null != address) { - try { - RegistryUtils.init(); - RegistryUtils.getMicroserviceInstance().getEndpoints().add(RegistryUtils.getPublishAddress("rest", address)); - RegistryUtils.run(); - } catch (Exception e) { - LOG.error("init registry error.", e); - } - } else { - LOG.info("rest address is null.Service is not registered to service center"); - } - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/ServiceCenterRegistryConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/ServiceCenterRegistryConfiguration.java deleted file mode 100644 index 83c55ba333d..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/java/org/apache/servicecomb/springboot/starter/registry/ServiceCenterRegistryConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.registry; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -/** - * Initialize and Register the services with service center - */ -@Configuration -@ImportResource(BeanUtils.DEFAULT_BEAN_RESOURCE) -public class ServiceCenterRegistryConfiguration { - public ServiceCenterRegistryConfiguration() { - RegistryIntializer.initRegistry(); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/resources/META-INF/spring.factories b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/resources/META-INF/spring.factories deleted file mode 100644 index d7c1d768f1b..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,18 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.apache.servicecomb.springboot.starter.registry.ServiceCenterRegistryConfiguration diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/test/java/org/apache/servicecomb/springboot/starter/registry/TestServiceCenterRegistryConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/test/java/org/apache/servicecomb/springboot/starter/registry/TestServiceCenterRegistryConfiguration.java deleted file mode 100644 index e0088e10bb1..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-registry/src/test/java/org/apache/servicecomb/springboot/starter/registry/TestServiceCenterRegistryConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.registry; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import mockit.Expectations; - -public class TestServiceCenterRegistryConfiguration { - - @Test - public void testInitRegistry() { - MicroserviceInstance microserviceInstance = Mockito.mock(MicroserviceInstance.class); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.init(); - RegistryUtils.run(); - RegistryUtils.getMicroserviceInstance(); - result = microserviceInstance; - } - }; - System.setProperty("servicecomb.rest.address", "127.0.0.1:8081"); - new ServiceCenterRegistryConfiguration(); - Assert.assertEquals("rest://127.0.0.1:8081", RegistryUtils.getPublishAddress("rest", "127.0.0.1:8081")); - } - - @Test - public void testInitRegistryException() { - MicroserviceInstance microserviceInstance = Mockito.mock(MicroserviceInstance.class); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getMicroserviceInstance(); - result = microserviceInstance; - } - }; - RegistryIntializer.initRegistry(); - Assert.assertEquals(0, RegistryUtils.getMicroserviceInstance().getEndpoints().size()); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/pom.xml deleted file mode 100644 index fd583de898c..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - spring-boot-starter-parent - 1.2.0-SNAPSHOT - - spring-boot-starter-servicecomb - Java Chassis::Spring Boot Starter::ServiceComb - - - - org.apache.tomcat.embed - tomcat-embed-logging-juli - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - logback-classic - - - org.slf4j - log4j-over-slf4j - - - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - handler-flowcontrol-qps - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/EnableServiceComb.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/EnableServiceComb.java deleted file mode 100644 index d96b6e02f82..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/EnableServiceComb.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.provider; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Import; - -/** - * This annotation enables auto-configuration of Spring beans to integrate with ServiceComb modules. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Import(ServiceCombSpringConfiguration.class) -public @interface EnableServiceComb { - -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/ServiceCombSpringConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/ServiceCombSpringConfiguration.java deleted file mode 100644 index 447388921be..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/ServiceCombSpringConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.provider; - -import javax.inject.Inject; - -import org.apache.servicecomb.core.CseApplicationListener; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -@Configuration -@ImportResource(BeanUtils.DEFAULT_BEAN_RESOURCE) -class ServiceCombSpringConfiguration { - @Inject - public void setCseApplicationListener(CseApplicationListener cseApplicationListener) { - cseApplicationListener.setInitEventClass(ApplicationReadyEvent.class); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/package-info.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/package-info.java deleted file mode 100644 index d8b740578c8..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-servicecomb/src/main/java/org/apache/servicecomb/springboot/starter/provider/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * - */ -/** - * - * - */ -package org.apache.servicecomb.springboot.starter.provider; diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/pom.xml deleted file mode 100644 index 3a5904da5af..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - spring-boot-starter-parent - 1.2.0-SNAPSHOT - - - spring-boot-starter-transport - Java Chassis::Spring Boot Starter::Transport - - - - org.apache.servicecomb - spring-boot-starter-servicecomb - - - org.apache.servicecomb - transport-rest-servlet - - - javax.servlet - javax.servlet-api - compile - - - org.apache.servicecomb - foundation-test-scaffolding - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/RestServletInitializer.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/RestServletInitializer.java deleted file mode 100644 index 974b84c6568..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/RestServletInitializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot.starter.transport; - -import java.io.IOException; -import java.net.ServerSocket; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.transport.rest.servlet.ServletConfig; -import org.apache.servicecomb.transport.rest.servlet.ServletUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicPropertyFactory; - -@Component -// extends from AbstractConfigurableEmbeddedServletContainer, only want to get embed web container's port and address -// when org.springframework.web.context.ServletContextAware invoked, ServletContext already rejected to addServlet -// should implements org.springframework.boot.web.servlet.ServletContextInitializer to inject servlet -public class RestServletInitializer extends AbstractConfigurableEmbeddedServletContainer - implements ServletContextInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(RestServletInitializer.class); - - @SuppressWarnings("try") - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - if (getPort() == 0) { - LOGGER.warn( - "spring boot embed web container listen port is 0, serviceComb will not use container's port to handler RESTful request."); - return; - } - - // web container did not did listen now. - // so mock to listen, and then close. - try (ServerSocket ss = new ServerSocket(getPort(), 0, getAddress())) { - if (StringUtils.isEmpty(ServletConfig.getServletUrlPattern())) { - // ensure the servlet will be instantiated - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.setProperty(ServletConfig.KEY_SERVLET_URL_PATTERN, ServletConfig.DEFAULT_URL_PATTERN); - } - - ServletUtils.init(servletContext); - } catch (IOException e) { - throw new ServletException(e); - } - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/package-info.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/package-info.java deleted file mode 100644 index d42491b4800..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/main/java/org/apache/servicecomb/springboot/starter/transport/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * - */ -/** - * - * - */ -package org.apache.servicecomb.springboot.starter.transport; diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java b/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java deleted file mode 100644 index 878934a9356..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-transport/src/test/java/org/apache/servicecomb/springboot/starter/transport/TestRestServletInitializer.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot.starter.transport; - -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration.Dynamic; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.transport.rest.servlet.RestServlet; -import org.apache.servicecomb.transport.rest.servlet.RestServletInjector; -import org.apache.servicecomb.transport.rest.servlet.ServletConfig; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.netflix.config.DynamicPropertyFactory; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({NetUtils.class}) -public class TestRestServletInitializer { - - private static final String LISTEN_ADDRESS = "127.0.0.1"; - - private static final int TEST_PORT = 8582; - - @BeforeClass - public static void beforeClass() { - ArchaiusUtils.resetConfig(); - - DynamicPropertyFactory.getInstance(); - } - - @AfterClass - public static void afterClass() { - ArchaiusUtils.resetConfig(); - } - - @Before - public void setUp() throws Exception { - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.clearProperty(ServletConfig.KEY_SERVLET_URL_PATTERN); - configuration.setProperty(ServletConfig.SERVICECOMB_REST_ADDRESS, LISTEN_ADDRESS); - - PowerMockito.mockStatic(NetUtils.class); - PowerMockito.when(NetUtils.parseIpPortFromURI(anyString())).thenReturn(new IpPort(LISTEN_ADDRESS, TEST_PORT)); - PowerMockito.when(NetUtils.canTcpListen(anyObject(), anyInt())).thenReturn(false); - } - - @Test - public void testOnStartup() throws Exception { - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - String urlPattern = "/rest/*"; - configuration.setProperty(ServletConfig.KEY_SERVLET_URL_PATTERN, urlPattern); - - ServletContext servletContext = mock(ServletContext.class); - Dynamic dynamic = mock(Dynamic.class); - when(servletContext.addServlet(RestServletInjector.SERVLET_NAME, RestServlet.class)).thenReturn(dynamic); - - RestServletInitializer restServletInitializer = new RestServletInitializer(); - restServletInitializer.setPort(TEST_PORT); - restServletInitializer.onStartup(servletContext); - - verify(dynamic).setAsyncSupported(true); - verify(dynamic).addMapping(urlPattern); - verify(dynamic).setLoadOnStartup(0); - } - - @Test - public void testOnStartupWhenUrlPatternNotSet() throws ServletException { - ServletContext servletContext = mock(ServletContext.class); - Dynamic dynamic = mock(Dynamic.class); - when(servletContext.addServlet(RestServletInjector.SERVLET_NAME, RestServlet.class)).thenReturn(dynamic); - - RestServletInitializer restServletInitializer = new RestServletInitializer(); - restServletInitializer.setPort(TEST_PORT); - restServletInitializer.onStartup(servletContext); - - verify(dynamic).setAsyncSupported(true); - verify(dynamic).addMapping(ServletConfig.DEFAULT_URL_PATTERN); - verify(dynamic).setLoadOnStartup(0); - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/pom.xml deleted file mode 100644 index 28b891a4a8a..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - spring-boot-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-cloud-zuul-zipkin - Java Chassis::Spring Boot Starter::Spring Cloud Zuul Zipkin - - - - - org.springframework.cloud - spring-cloud-starter-zuul - - - org.apache.servicecomb - handler-tracing-zipkin - - - io.zipkin.brave - brave-instrumentation-servlet - - - - io.zipkin.java - zipkin - provided - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfiguration.java b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfiguration.java deleted file mode 100644 index 7048fffd0d5..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfiguration.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static javax.servlet.DispatcherType.ASYNC; -import static javax.servlet.DispatcherType.ERROR; -import static javax.servlet.DispatcherType.FORWARD; -import static javax.servlet.DispatcherType.INCLUDE; -import static javax.servlet.DispatcherType.REQUEST; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_ENABLED_KEY; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; - -import com.netflix.zuul.context.RequestContext; - -import brave.http.HttpClientAdapter; -import brave.http.HttpClientHandler; -import brave.http.HttpTracing; -import brave.servlet.TracingFilter; - -@Configuration -@ConditionalOnProperty(value = CONFIG_TRACING_ENABLED_KEY, havingValue = "true", matchIfMissing = true) -public class SpringTracingConfiguration { - - @Bean - FilterRegistrationBean traceWebFilter(HttpTracing httpTracing) { - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(TracingFilter.create(httpTracing)); - filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, REQUEST); - filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); - return filterRegistrationBean; - } - - @SuppressWarnings("unchecked") - @Bean - HttpClientHandler httpClientHandler(HttpTracing httpTracing) { - return HttpClientHandler.create(httpTracing, new ZuulHttpClientAdapter()); - } - - @Bean - TracePreZuulFilter tracePreZuulFilter( - HttpTracing tracing, - HttpClientHandler handler) { - - return new TracePreZuulFilter(tracing, handler); - } - - @Bean - TracePostZuulFilter tracePostZuulFilter( - HttpTracing tracing, - HttpClientHandler handler) { - - return new TracePostZuulFilter(tracing, handler); - } - - private static class ZuulHttpClientAdapter extends HttpClientAdapter { - - @Nullable - @Override - public String method(@Nonnull RequestContext request) { - return request.getRequest().getMethod(); - } - - @Nullable - @Override - public String url(@Nonnull RequestContext request) { - return request.getRequest().getRequestURI(); - } - - @Nullable - @Override - public String requestHeader(@Nonnull RequestContext request, @Nonnull String name) { - return request.getRequest().getHeader(name); - } - - @Nullable - @Override - public Integer statusCode(@Nonnull HttpServletResponse response) { - return response.getStatus() == 0 ? 500 : response.getStatus(); - } - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePostZuulFilter.java b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePostZuulFilter.java deleted file mode 100644 index 57a4e1c63b1..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePostZuulFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import java.lang.invoke.MethodHandles; - -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; - -import brave.Tracer; -import brave.Tracer.SpanInScope; -import brave.http.HttpClientHandler; -import brave.http.HttpTracing; - -class TracePostZuulFilter extends ZuulFilter { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Tracer tracer; - - private final HttpClientHandler clientHandler; - - TracePostZuulFilter(HttpTracing tracer, HttpClientHandler clientHandler) { - this.tracer = tracer.tracing().tracer(); - this.clientHandler = clientHandler; - } - - @Override - public boolean shouldFilter() { - return tracer.currentSpan() != null; - } - - @Override - public Object run() { - RequestContext context = RequestContext.getCurrentContext(); - ((SpanInScope) context.getRequest().getAttribute(SpanInScope.class.getName())).close(); - - clientHandler.handleReceive(context.getResponse(), null, tracer.currentSpan()); - log.debug("Closed span {} for {}", tracer.currentSpan(), context.getRequest().getMethod()); - - return null; - } - - @Override - public String filterType() { - return "post"; - } - - @Override - public int filterOrder() { - return 0; - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePreZuulFilter.java b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePreZuulFilter.java deleted file mode 100644 index ce30fdbbf56..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/main/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracePreZuulFilter.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static org.apache.servicecomb.core.Const.CSE_CONTEXT; - -import java.lang.invoke.MethodHandles; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.netflix.zuul.ExecutionStatus; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.ZuulFilterResult; -import com.netflix.zuul.context.RequestContext; - -import brave.Span; -import brave.Tracer; -import brave.Tracer.SpanInScope; -import brave.http.HttpClientHandler; -import brave.http.HttpTracing; -import brave.propagation.TraceContext.Injector; - -class TracePreZuulFilter extends ZuulFilter { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Tracer tracer; - - private final HttpClientHandler clientHandler; - - private final Injector injector; - - TracePreZuulFilter( - HttpTracing tracing, - HttpClientHandler clientHandler) { - - this.tracer = tracing.tracing().tracer(); - this.injector = tracing.tracing().propagation().injector( - (requestContext, name, value) -> requestContext.getZuulRequestHeaders().put(name, value)); - this.clientHandler = clientHandler; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - return null; - } - - @Override - public ZuulFilterResult runFilter() { - RequestContext ctx = RequestContext.getCurrentContext(); - - Span span = clientHandler.handleSend(injector, ctx); - saveHeadersAsInvocationContext(ctx, span); - - SpanInScope scope = tracer.withSpanInScope(span); - log.debug("Generated tracing span {} for {}", span, ctx.getRequest().getMethod()); - - ctx.getRequest().setAttribute(SpanInScope.class.getName(), scope); - - ZuulFilterResult result = super.runFilter(); - log.debug("Result of Zuul filter is [{}]", result.getStatus()); - - if (ExecutionStatus.SUCCESS != result.getStatus()) { - log.debug("The result of Zuul filter execution was not successful thus will close the current span {}", span); - clientHandler.handleReceive(ctx.getResponse(), result.getException(), span); - scope.close(); - } - return result; - } - - private void saveHeadersAsInvocationContext(RequestContext ctx, Span span) { - try { - ctx.addZuulRequestHeader(CSE_CONTEXT, JsonUtils.writeValueAsString(ctx.getZuulRequestHeaders())); - } catch (JsonProcessingException e) { - clientHandler.handleReceive(ctx.getResponse(), e, span); - throw new IllegalStateException("Unable to write request headers as json to " + CSE_CONTEXT, e); - } - } - - - @Override - public String filterType() { - return "pre"; - } - - @Override - public int filterOrder() { - return Integer.MAX_VALUE; - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfigurationTest.java b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfigurationTest.java deleted file mode 100644 index 50d52d5015c..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul-zipkin/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringTracingConfigurationTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul.tracing; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_TRACING_ENABLED_KEY; -import static org.junit.Assert.fail; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.UnsatisfiedDependencyException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - - -public class SpringTracingConfigurationTest { - - private AnnotationConfigApplicationContext context; - - @Before - public void setUp() { - context = new AnnotationConfigApplicationContext(); - } - - @After - public void tearDown() { - context.close(); - System.clearProperty(CONFIG_TRACING_ENABLED_KEY); - } - - @Test - public void ensureTracingDisabled() { - System.setProperty(CONFIG_TRACING_ENABLED_KEY, "false"); - context.register(SpringTracingConfiguration.class); - context.refresh(); - try { - context.getBean(SpringTracingConfiguration.class); - fail("Expect to throw BeansException, but got none"); - } catch (BeansException ignored) { - } - } - - @Test - public void ensureTracingEnabledByDefault() { - tracingEnabledCheck(); - } - - @Test - public void ensureTracingEnabledByProperty() { - System.setProperty(CONFIG_TRACING_ENABLED_KEY, "true"); - tracingEnabledCheck(); - } - - private void tracingEnabledCheck() { - context.register(SpringTracingConfiguration.class); - try { - context.refresh(); - fail("Expect to throw UnsatisfiedDependencyException, but got none"); - } catch (UnsatisfiedDependencyException ignored) { - } catch (Exception e) { - fail("Expect to throw UnsatisfiedDependencyException, but got Exception: " + e); - } - } -} diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/pom.xml b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/pom.xml deleted file mode 100644 index e1d15974a16..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - spring-boot-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-cloud-zuul - Java Chassis::Spring Boot Starter::Spring Cloud Zuul - - - - org.apache.servicecomb - java-chassis-core - - - org.apache.servicecomb - foundation-config - - - org.apache.servicecomb - service-registry - - - org.springframework.cloud - spring-cloud-starter-zuul - - - diff --git a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/src/main/java/org/apache/servicecomb/spring/cloud/zuul/ContextHeaderZuulFilter.java b/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/src/main/java/org/apache/servicecomb/spring/cloud/zuul/ContextHeaderZuulFilter.java deleted file mode 100644 index 92850970ea7..00000000000 --- a/java-chassis-spring-boot/spring-boot-starter/spring-cloud-zuul/src/main/java/org/apache/servicecomb/spring/cloud/zuul/ContextHeaderZuulFilter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.spring.cloud.zuul; - -import static org.apache.servicecomb.core.Const.CSE_CONTEXT; -import static org.apache.servicecomb.core.Const.SRC_MICROSERVICE; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.springframework.stereotype.Component; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; - -@Component -public class ContextHeaderZuulFilter extends ZuulFilter { - - private static String microserviceName; - - static { - MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(); - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels()); - microserviceName = microserviceDefinition.getMicroserviceName(); - } - - @Override - public String filterType() { - return "pre"; - } - - @Override - public int filterOrder() { - return 0; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - RequestContext ctx = RequestContext.getCurrentContext(); - ctx.addZuulRequestHeader(SRC_MICROSERVICE, microserviceName); - saveHeadersAsInvocationContext(ctx); - return null; - } - - private void saveHeadersAsInvocationContext(RequestContext ctx) { - try { - ctx.addZuulRequestHeader(CSE_CONTEXT, JsonUtils.writeValueAsString(ctx.getZuulRequestHeaders())); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Unable to write request headers as json to " + CSE_CONTEXT, e); - } - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/pom.xml b/java-chassis-spring-boot/spring-boot2-starter-parent/pom.xml deleted file mode 100644 index 83b3d276af1..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/pom.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - org.apache.servicecomb - java-chassis-dependencies-springboot2 - 1.2.0-SNAPSHOT - ../../java-chassis-dependencies-springboot2 - - 4.0.0 - - spring-boot2-starter-parent - pom - - - UTF-8 - 1.8 - -Dfile.encoding=UTF-8 - - - - spring-boot2-starter - spring-boot2-starter-servlet - spring-boot2-starter-standalone - spring-boot2-starter-discovery - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/pom.xml b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/pom.xml deleted file mode 100644 index e1446c2f679..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb - spring-boot2-starter-parent - 1.2.0-SNAPSHOT - - spring-boot2-starter-discovery - Java Chassis::Spring Boot2 Starter::Discovery - - - - org.springframework.boot - spring-boot-starter - - - ch.qos.logback - logback-classic - - - org.slf4j - log4j-over-slf4j - - - - - org.springframework.cloud - spring-cloud-commons - - - org.springframework.cloud - spring-cloud-context - - - org.springframework.cloud - spring-cloud-netflix-core - - - org.springframework.cloud - spring-cloud-starter-netflix-zuul - - - org.springframework.cloud - spring-cloud-starter-netflix-ribbon - - - javax.ws.rs - jsr311-api - - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - - - junit - junit - test - - - org.jmockit - jmockit - test - - - org.mockito - mockito-core - test - - - org.apache.servicecomb - service-registry - - - org.apache.servicecomb - spring-boot2-starter - - - org.apache.servicecomb - spring-boot-common - - - diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClient.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClient.java deleted file mode 100644 index eddafc3f171..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClient.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.springboot.common.AbstractDiscoveryClient; -import org.apache.servicecomb.springboot.common.InstanceDiscoveryFilter; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; - -public class ScbDiscoveryClient extends AbstractDiscoveryClient implements DiscoveryClient { - - public ScbDiscoveryClient() { - super(new InstanceDiscoveryFilter((String name, URIEndpointObject uri) -> - new DefaultServiceInstance(name, uri.getHostOrIp(), uri.getPort(), uri.isSslEnabled()))); - } - - @Override - public String description() { - return "Spring Cloud 2 CSE Discovery Client"; - } - - public List getInstances(String serviceId) { - return super.doGetInstances(serviceId); - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClientConfiguration.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClientConfiguration.java deleted file mode 100644 index 75730b77b39..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbDiscoveryClientConfiguration.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; - -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; - -@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class) -@Configuration -public class ScbDiscoveryClientConfiguration { - @Bean - @Order(5000) - @ConditionalOnProperty(value = "servicecomb.discoveryClient.enabled", havingValue = "true", matchIfMissing = true) - public DiscoveryClient cseDiscoveryClient() { - return new ScbDiscoveryClient(); - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonClientConfiguration.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonClientConfiguration.java deleted file mode 100644 index fa896dc8890..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonClientConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; - -import org.springframework.context.annotation.Bean; - -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.Server; -import com.netflix.loadbalancer.ServerList; - -/** - * Custom {@link org.springframework.cloud.netflix.ribbon.RibbonClient} configuration must not be - * scanned by spring. - * - * @see - * Customizing the Ribbon Client - */ -public class ScbRibbonClientConfiguration { - @Bean - public ServerList ribbonServerList( - IClientConfig config) { - ServiceCombServerList serverList = new ServiceCombServerList(); - serverList.initWithNiwsConfig(config); - return serverList; - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonConfiguration.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonConfiguration.java deleted file mode 100644 index 0ffeab3a22d..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; -import org.springframework.cloud.netflix.ribbon.RibbonClients; -import org.springframework.cloud.netflix.ribbon.SpringClientFactory; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableConfigurationProperties -@ConditionalOnBean(SpringClientFactory.class) -@AutoConfigureAfter(RibbonAutoConfiguration.class) -@RibbonClients(defaultConfiguration = ScbRibbonClientConfiguration.class) -public class ScbRibbonConfiguration { - -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java deleted file mode 100644 index 1f17df56d0e..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ScbRibbonEndpointDiscoveryFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot2.starter.discovery; - -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.discovery.AbstractEndpointDiscoveryFilter; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode; - -import com.netflix.loadbalancer.Server; - -public class ScbRibbonEndpointDiscoveryFilter extends AbstractEndpointDiscoveryFilter { - @Override - protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { - //only need rest endpoints - return "rest"; - } - - @Override - protected Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance) { - URIEndpointObject uri = new URIEndpointObject(endpoint); - return new Server(uri.getHostOrIp(), uri.getPort()); - } - - @Override - public int getOrder() { - return (int) Short.MAX_VALUE - 1; - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ServiceCombServerList.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ServiceCombServerList.java deleted file mode 100644 index 61ac3eadc30..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/ServiceCombServerList.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; - -import java.util.List; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; -import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree; - -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.AbstractServerList; -import com.netflix.loadbalancer.Server; - -public class ServiceCombServerList extends AbstractServerList { - - private DiscoveryTree discoveryTree = new DiscoveryTree(); - - private String serviceId; - - public ServiceCombServerList() { - discoveryTree.addFilter(new ScbRibbonEndpointDiscoveryFilter()); - } - - @Override - public List getInitialListOfServers() { - DiscoveryContext context = new DiscoveryContext(); - context.setInputParameters(serviceId); - VersionedCache serversVersionedCache = discoveryTree.discovery(context, - RegistryUtils.getAppId(), - serviceId, - DefinitionConst.VERSION_RULE_ALL); - return serversVersionedCache.data(); - } - - @Override - public List getUpdatedListOfServers() { - return getInitialListOfServers(); - } - - @Override - public void initWithNiwsConfig(IClientConfig iClientConfig) { - this.serviceId = iClientConfig.getClientName(); - } -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/package-info.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/package-info.java deleted file mode 100644 index 0feb6131179..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/java/org/apache/servicecomb/springboot2/starter/discovery/package-info.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter.discovery; diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/resources/META-INF/spring.factories b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/resources/META-INF/spring.factories deleted file mode 100644 index de5a9fc177f..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-discovery/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,24 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -org.apache.servicecomb.springboot.starter.provider.EnableServiceComb=\ - org.apache.servicecomb.springboot2.starter.discovery.ScbDiscoveryClientConfiguration,\ - org.apache.servicecomb.springboot2.starter.discovery.ScbRibbonConfiguration -org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ - org.apache.servicecomb.springboot2.starter.discovery.ScbDiscoveryClientConfiguration -org.springframework.cloud.netflix.ribbon.RibbonClient=\ - org.apache.servicecomb.springboot2.starter.discovery.ScbRibbonConfiguration \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/pom.xml b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/pom.xml deleted file mode 100644 index c29700d84d9..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - spring-boot2-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-boot2-starter-servlet - - - - org.apache.servicecomb - spring-boot2-starter - - - org.springframework.boot - spring-boot-starter-web - - - org.apache.servicecomb - transport-rest-servlet - - - javax.servlet - javax.servlet-api - compile - - - org.apache.servicecomb - foundation-test-scaffolding - - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/RestServletInitializer.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/RestServletInitializer.java deleted file mode 100644 index 8d518ef2f5b..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/RestServletInitializer.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot2.starter.servlet; - -import java.io.IOException; -import java.net.ServerSocket; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.transport.rest.servlet.ServletConfig; -import org.apache.servicecomb.transport.rest.servlet.ServletUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicPropertyFactory; - -@Component -public class RestServletInitializer - implements WebServerFactoryCustomizer, ServletContextInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(RestServletInitializer.class); - - private AbstractConfigurableWebServerFactory factory; - - @Override - public void customize(AbstractConfigurableWebServerFactory factory) { - this.factory = factory; - } - - @Override - @SuppressWarnings("try") - public void onStartup(ServletContext servletContext) throws ServletException { - if (factory.getPort() == 0) { - LOGGER.warn( - "spring boot embed web container listen port is 0, serviceComb will not use container's port to handler RESTful request."); - return; - } - - // web container did not did listen now. - // so mock to listen, and then close. - try (ServerSocket ss = new ServerSocket(factory.getPort(), 0, factory.getAddress())) { - if (StringUtils.isEmpty(ServletConfig.getServletUrlPattern())) { - // ensure the servlet will be instantiated - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.setProperty(ServletConfig.KEY_SERVLET_URL_PATTERN, ServletConfig.DEFAULT_URL_PATTERN); - } - - ServletUtils.init(servletContext); - } catch (IOException e) { - throw new ServletException(e); - } - } -} \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/package-info.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/package-info.java deleted file mode 100644 index 041302864db..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-servlet/src/main/java/org/apache/servicecomb/springboot2/starter/servlet/package-info.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.springboot2.starter.servlet; \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-standalone/pom.xml b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-standalone/pom.xml deleted file mode 100644 index e60a2687e82..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter-standalone/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - spring-boot2-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-boot2-starter-standalone - - - - org.apache.servicecomb - spring-boot2-starter - - - org.apache.servicecomb - transport-rest-vertx - - - - - org.hibernate - hibernate-validator - - - - org.apache.servicecomb - foundation-test-scaffolding - - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/pom.xml b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/pom.xml deleted file mode 100644 index 83e9b594e55..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - spring-boot2-starter-parent - org.apache.servicecomb - 1.2.0-SNAPSHOT - - 4.0.0 - - spring-boot2-starter - - - - org.springframework.boot - spring-boot-starter - - - org.slf4j - log4j-over-slf4j - - - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - transport-highway - - - - \ No newline at end of file diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/EnableServiceComb.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/EnableServiceComb.java deleted file mode 100644 index dd09d68c3cf..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/EnableServiceComb.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Import; - -/** - * This annotation enables auto-configuration of Spring beans to integrate with ServiceComb modules. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Import(ServiceCombSpringConfiguration.class) -public @interface EnableServiceComb { - -} diff --git a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ServiceCombSpringConfiguration.java b/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ServiceCombSpringConfiguration.java deleted file mode 100644 index 6b39f7cfea0..00000000000 --- a/java-chassis-spring-boot/spring-boot2-starter-parent/spring-boot2-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ServiceCombSpringConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.springboot2.starter; - -import javax.inject.Inject; - -import org.apache.servicecomb.core.CseApplicationListener; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -@Configuration -@ImportResource(BeanUtils.DEFAULT_BEAN_RESOURCE) -class ServiceCombSpringConfiguration { - @Inject - public void setCseApplicationListener(CseApplicationListener cseApplicationListener) { - cseApplicationListener.setInitEventClass(ApplicationReadyEvent.class); - } -} diff --git a/metrics/metrics-core/pom.xml b/metrics/metrics-core/pom.xml index c324e613476..c68b483fde9 100644 --- a/metrics/metrics-core/pom.xml +++ b/metrics/metrics-core/pom.xml @@ -21,7 +21,7 @@ metrics org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -41,23 +41,33 @@ org.apache.servicecomb swagger-generator-jaxrs - + + org.apache.servicecomb + common-rest + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.apache.servicecomb + registry-service-center + test + io.vertx vertx-codegen provided - - org.slf4j - slf4j-log4j12 + org.mockito + mockito-inline test - org.apache.servicecomb - foundation-test-scaffolding + org.jmockit + jmockit + test - - diff --git a/metrics/metrics-core/src/main/java/com/netflix/spectator/api/patterns/ThreadPoolMonitorPublishModelFactory.java b/metrics/metrics-core/src/main/java/com/netflix/spectator/api/patterns/ThreadPoolMonitorPublishModelFactory.java deleted file mode 100644 index 0ffb5a1bcf0..00000000000 --- a/metrics/metrics-core/src/main/java/com/netflix/spectator/api/patterns/ThreadPoolMonitorPublishModelFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.spectator.api.patterns; - -import java.util.Map; - -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; -import org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel; - -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Utils; - -public class ThreadPoolMonitorPublishModelFactory { - interface Setter { - void set(ThreadPoolPublishModel model, Measurement measurement); - } - - private MeasurementTree tree; - - private Map threadPools; - - public ThreadPoolMonitorPublishModelFactory(MeasurementTree tree, - Map threadPools) { - this.tree = tree; - this.threadPools = threadPools; - } - - public static void create(MeasurementTree tree, - Map threadPools) { - new ThreadPoolMonitorPublishModelFactory(tree, threadPools).create(); - } - - public void create() { - readMeasurement(ThreadPoolMonitor.TASK_COUNT, - (model, measurement) -> { - model.setAvgTaskCount(measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.COMPLETED_TASK_COUNT, - (model, measurement) -> { - model.setAvgCompletedTaskCount(measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.CURRENT_THREADS_BUSY, - (model, measurement) -> { - model.setCurrentThreadsBusy((int) measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.MAX_THREADS, - (model, measurement) -> { - model.setMaxThreads((int) measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.POOL_SIZE, - (model, measurement) -> { - model.setPoolSize((int) measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.CORE_POOL_SIZE, - (model, measurement) -> { - model.setCorePoolSize((int) measurement.value()); - }); - readMeasurement(ThreadPoolMonitor.QUEUE_SIZE, - (model, measurement) -> { - model.setQueueSize((int) measurement.value()); - }); - } - - protected void readMeasurement(String name, Setter setter) { - MeasurementNode node = tree.findChild(name); - if (node == null) { - return; - } - - for (Measurement measurement : node.getMeasurements()) { - String threadPoolName = Utils.getTagValue(measurement.id(), ThreadPoolMonitor.ID_TAG_NAME); - if (threadPoolName == null) { - continue; - } - - ThreadPoolPublishModel model = threadPools.computeIfAbsent(threadPoolName, tpn -> { - return new ThreadPoolPublishModel(); - }); - - setter.set(model, measurement); - } - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/DefaultRegistryInitializer.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/DefaultRegistryInitializer.java deleted file mode 100644 index a01675fba67..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/DefaultRegistryInitializer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core; - -import java.time.Duration; - -import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; - -import com.google.common.eventbus.EventBus; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.spectator.servo.ServoRegistry; - -public class DefaultRegistryInitializer implements MetricsInitializer { - public static final String SERVO_POLLERS = "servo.pollers"; - - private GlobalRegistry globalRegistry; - - private ServoRegistry registry; - - // create registry before init meters - @Override - public int getOrder() { - return -10; - } - - @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - this.globalRegistry = globalRegistry; - - // spectator move poll gauges from inline to background executor - // we need to set the interval to unify value - System.setProperty("spectator.api.gaugePollingFrequency", Duration.ofMillis(config.getMsPollInterval()).toString()); - - System.setProperty(SERVO_POLLERS, String.valueOf(config.getMsPollInterval())); - registry = new ServoRegistry(); - globalRegistry.add(registry); - } - - @Override - public void destroy() { - if (registry != null) { - DefaultMonitorRegistry.getInstance().unregister(registry); - globalRegistry.remove(registry); - } - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/InvocationMetersInitializer.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/InvocationMetersInitializer.java index d265434678d..25bc9b62e71 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/InvocationMetersInitializer.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/InvocationMetersInitializer.java @@ -21,7 +21,6 @@ import org.apache.servicecomb.core.event.InvocationStartEvent; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; import org.apache.servicecomb.metrics.core.meter.ConsumerMeters; import org.apache.servicecomb.metrics.core.meter.EdgeMeters; import org.apache.servicecomb.metrics.core.meter.ProducerMeters; @@ -30,7 +29,8 @@ import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import com.netflix.spectator.api.Registry; + +import io.micrometer.core.instrument.MeterRegistry; public class InvocationMetersInitializer implements MetricsInitializer { private ConsumerMeters consumerMeters; @@ -40,23 +40,20 @@ public class InvocationMetersInitializer implements MetricsInitializer { private EdgeMeters edgeMeters; @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - Registry registry = globalRegistry.getDefaultRegistry(); - - consumerMeters = new ConsumerMeters(registry); - producerMeters = new ProducerMeters(registry); - edgeMeters = new EdgeMeters(registry); + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + consumerMeters = new ConsumerMeters(meterRegistry, config); + producerMeters = new ProducerMeters(meterRegistry, config); + edgeMeters = new EdgeMeters(meterRegistry, config); eventBus.register(this); } protected AbstractInvocationMeters findInvocationMeters(Invocation invocation) { if (invocation.isConsumer()) { - if (invocation.isEdge()) { - return edgeMeters.getInvocationMeters(); - } else { - return consumerMeters.getInvocationMeters(); - } + return consumerMeters.getInvocationMeters(); + } + if (invocation.isEdge()) { + return edgeMeters.getInvocationMeters(); } return producerMeters.getInvocationMeters(); } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsBootListener.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsBootListener.java index 376c502bcea..eb9e4347544 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsBootListener.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsBootListener.java @@ -16,56 +16,33 @@ */ package org.apache.servicecomb.metrics.core; -import javax.inject.Inject; - import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.metrics.MetricsBootstrap; -import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.metrics.core.publish.HealthCheckerRestPublisher; -import org.apache.servicecomb.metrics.core.publish.MetricsRestPublisher; -import org.springframework.stereotype.Component; -@Component public class MetricsBootListener implements BootListener { - private MetricsBootstrap metricsBootstrap = new MetricsBootstrap(); + private final MetricsBootstrap metricsBootstrap; + + public MetricsBootListener(MetricsBootstrap metricsBootstrap) { + this.metricsBootstrap = metricsBootstrap; + } + + @Override + public void onBeforeProducerProvider(BootEvent event) { - @Inject - private ProducerSchemaFactory producerSchemaFactory; + } public MetricsBootstrap getMetricsBootstrap() { return metricsBootstrap; } @Override - public void onBootEvent(BootEvent event) { - switch (event.getEventType()) { - case BEFORE_PRODUCER_PROVIDER: - registerSchemas(); - break; - case AFTER_REGISTRY: - metricsBootstrap.start(new GlobalRegistry(), EventManager.getEventBus()); - break; - case BEFORE_CLOSE: - metricsBootstrap.shutdown(); - break; - default: - break; - } + public void onAfterRegistry(BootEvent event) { + metricsBootstrap.start(EventManager.getEventBus()); } - private void registerSchemas() { - producerSchemaFactory.getOrCreateProducerSchema("healthEndpoint", - HealthCheckerRestPublisher.class, - new HealthCheckerRestPublisher()); - - MetricsRestPublisher metricsRestPublisher = - SPIServiceUtils.getTargetService(MetricsInitializer.class, MetricsRestPublisher.class); - producerSchemaFactory.getOrCreateProducerSchema("metricsEndpoint", - metricsRestPublisher.getClass(), - metricsRestPublisher); + @Override + public void onBeforeClose(BootEvent event) { + metricsBootstrap.shutdown(); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsCoreConfiguration.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsCoreConfiguration.java new file mode 100644 index 00000000000..338b2183d02 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsCoreConfiguration.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core; + +import java.time.Duration; + +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrap; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher; +import org.apache.servicecomb.metrics.core.publish.SlowInvocationLogger; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.CountingMode; + +@Configuration +public class MetricsCoreConfiguration { + @Bean + public MetricsBootstrapConfig metricsBootstrapConfig(Environment environment) { + return new MetricsBootstrapConfig(environment); + } + + @Bean + @ConditionalOnMissingBean + public MeterRegistry meterRegistry(MetricsBootstrapConfig config) { + return new SimpleMeterRegistryExt(s -> { + if ("simple.step".equals(s)) { + return Duration.ofMillis(config.getMsPollInterval()).toString(); + } + if ("simple.mode".equals(s)) { + return CountingMode.STEP.name(); + } + return null; + }, Clock.SYSTEM); + } + + @Bean + public MetricsBootListener metricsBootListener(MetricsBootstrap metricsBootstrap) { + return new MetricsBootListener(metricsBootstrap); + } + + @Bean + public MetricsBootstrap metricsBootstrap(MetricsBootstrapConfig config) { + return new MetricsBootstrap(config); + } + + // Begin MetricsInitializers + + @Bean + public DefaultLogPublisher defaultLogPublisher() { + return new DefaultLogPublisher(); + } + + @Bean + public InvocationMetersInitializer invocationMetersInitializer() { + return new InvocationMetersInitializer(); + } + + @Bean + public ThreadPoolMetersInitializer threadPoolMetersInitializer() { + return new ThreadPoolMetersInitializer(); + } + + @Bean + public VertxMetersInitializer vertxMetersInitializer() { + return new VertxMetersInitializer(); + } + + @Bean + public OsMetersInitializer osMetersInitializer() { + return new OsMetersInitializer(); + } + + @Bean + public SlowInvocationLogger slowInvocationLogger(SCBEngine scbEngine) { + return new SlowInvocationLogger(scbEngine); + } + + // End MetricsInitializers +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java index 783d0cce68e..f5486f78089 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java @@ -16,36 +16,31 @@ */ package org.apache.servicecomb.metrics.core; -import org.apache.commons.lang3.SystemUtils; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.SpectatorUtils; -public class OsMetersInitializer implements MetricsInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(OsMetersInitializer.class); +import io.micrometer.core.instrument.MeterRegistry; +public class OsMetersInitializer implements MetricsInitializer, PeriodMeter { private OsMeter osMeter; @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - if (!SystemUtils.IS_OS_LINUX) { - LOGGER.info("only support linux os to collect cpu and net info"); - return; - } - - Registry registry = globalRegistry.getDefaultRegistry(); - osMeter = new OsMeter(registry); - SpectatorUtils.registerMeter(registry, osMeter); + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + osMeter = new OsMeter(meterRegistry); } public OsMeter getOsMeter() { return osMeter; } + + @Override + public void poll(long msNow, long secondInterval) { + if (osMeter != null) { + osMeter.poll(msNow, secondInterval); + } + } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/SimpleMeterRegistryExt.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/SimpleMeterRegistryExt.java new file mode 100644 index 00000000000..592ec2af113 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/SimpleMeterRegistryExt.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.cumulative.CumulativeDistributionSummary; +import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; +import io.micrometer.core.instrument.distribution.HistogramGauges; +import io.micrometer.core.instrument.distribution.StepBucketHistogram; +import io.micrometer.core.instrument.simple.SimpleConfig; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; + +/** + * Custom SimpleMeterRegistry to support StepDistributionSummary + */ +public class SimpleMeterRegistryExt extends SimpleMeterRegistry { + private final SimpleConfig config; + + public SimpleMeterRegistryExt(SimpleConfig config, Clock clock) { + super(config, clock); + this.config = config; + } + + @Override + protected DistributionSummary newDistributionSummary(Meter.Id id, + DistributionStatisticConfig distributionStatisticConfig, double scale) { + DistributionStatisticConfig merged = distributionStatisticConfig + .merge(DistributionStatisticConfig.builder().expiry(config.step()).build()); + + DistributionSummary summary; + switch (config.mode()) { + case CUMULATIVE: + summary = new CumulativeDistributionSummary(id, clock, merged, scale, false); + break; + case STEP: + default: + summary = new StepDistributionSummaryExt(id, clock, merged, scale, config.step().toMillis(), + new StepBucketHistogram(clock, config.step().toMillis(), distributionStatisticConfig, + false, false)); + break; + } + + HistogramGauges.registerWithCommonFormat(summary, this); + + return summary; + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/StepDistributionSummaryExt.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/StepDistributionSummaryExt.java new file mode 100644 index 00000000000..519f903a76e --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/StepDistributionSummaryExt.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; +import io.micrometer.core.instrument.distribution.Histogram; +import io.micrometer.core.instrument.step.StepDistributionSummary; + +public class StepDistributionSummaryExt extends StepDistributionSummary { + public StepDistributionSummaryExt(Id id, Clock clock, + DistributionStatisticConfig distributionStatisticConfig, double scale, long stepMillis, + Histogram histogram) { + super(id, clock, distributionStatisticConfig, scale, stepMillis, histogram); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/ThreadPoolMetersInitializer.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/ThreadPoolMetersInitializer.java index 621fd0fe2ff..9ada122585b 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/ThreadPoolMetersInitializer.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/ThreadPoolMetersInitializer.java @@ -16,6 +16,7 @@ */ package org.apache.servicecomb.metrics.core; +import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; import java.util.Map.Entry; @@ -25,22 +26,25 @@ import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.executor.FixedThreadExecutor; +import org.apache.servicecomb.core.executor.GroupExecutor; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; +import org.apache.servicecomb.metrics.core.meter.pool.ThreadPoolMeter; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.patterns.ThreadPoolMonitor; -public class ThreadPoolMetersInitializer implements MetricsInitializer { - private Registry registry; +import io.micrometer.core.instrument.MeterRegistry; + +public class ThreadPoolMetersInitializer implements MetricsInitializer, PeriodMeter { + private MeterRegistry meterRegistry; + + private Map threadPoolMeters = new HashMap<>(); @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - registry = globalRegistry.getDefaultRegistry(); + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + this.meterRegistry = meterRegistry; createThreadPoolMeters(); } @@ -56,8 +60,8 @@ public void createThreadPoolMeters() { continue; } - if (FixedThreadExecutor.class.isInstance(executor)) { - createThreadPoolMeters(entry.getKey(), (FixedThreadExecutor) executor); + if (executor instanceof GroupExecutor) { + createThreadPoolMeters(entry.getKey(), (GroupExecutor) executor); continue; } @@ -75,18 +79,24 @@ protected Map collectionOperationExecutors() { return operationExecutors; } - protected void createThreadPoolMeters(String threadPoolName, FixedThreadExecutor fixedThreadExecutor) { - for (int idx = 0; idx < fixedThreadExecutor.getExecutorList().size(); idx++) { - Executor executor = fixedThreadExecutor.getExecutorList().get(idx); + protected void createThreadPoolMeters(String threadPoolName, GroupExecutor groupExecutor) { + for (int idx = 0; idx < groupExecutor.getExecutorList().size(); idx++) { + Executor executor = groupExecutor.getExecutorList().get(idx); createThreadPoolMeters(threadPoolName + "-group" + idx, executor); } } - protected void createThreadPoolMeters(String threadPoolName, Executor executor) { - if (!ThreadPoolExecutor.class.isInstance(executor)) { + public void createThreadPoolMeters(String threadPoolName, Executor executor) { + if (!(executor instanceof ThreadPoolExecutor threadPoolExecutor)) { return; } - ThreadPoolMonitor.attach(registry, (ThreadPoolExecutor) executor, threadPoolName); + threadPoolMeters.computeIfAbsent(threadPoolName, + (key) -> new ThreadPoolMeter(meterRegistry, threadPoolName, threadPoolExecutor)); + } + + @Override + public void poll(long msNow, long secondInterval) { + threadPoolMeters.forEach((key, value) -> value.poll(msNow, secondInterval)); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/VertxMetersInitializer.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/VertxMetersInitializer.java index fc8b4df6fa9..8240fabd4f2 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/VertxMetersInitializer.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/VertxMetersInitializer.java @@ -16,48 +16,49 @@ */ package org.apache.servicecomb.metrics.core; -import org.apache.servicecomb.core.transport.AbstractTransport; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.metrics.core.meter.vertx.VertxEndpointsMeter; -import org.apache.servicecomb.metrics.core.meter.vertx.VertxServerEndpointsMeter; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; +import org.apache.servicecomb.foundation.vertx.SharedVertxFactory; +import org.apache.servicecomb.metrics.core.meter.vertx.HttpClientEndpointsMeter; +import org.apache.servicecomb.metrics.core.meter.vertx.ServerEndpointsMeter; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.SpectatorUtils; -public class VertxMetersInitializer implements MetricsInitializer { +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; + +public class VertxMetersInitializer implements MetricsInitializer, PeriodMeter { public static final String VERTX_ENDPOINTS = "servicecomb.vertx.endpoints"; public static final String ENDPOINTS_TYPE = "type"; - public static final String ENDPOINTS_CLINET = "client"; + public static final String ENDPOINTS_CLIENT = "client"; public static final String ENDPOINTS_SERVER = "server"; + private HttpClientEndpointsMeter httpClientEndpointsMeter; + + private ServerEndpointsMeter serverEndpointsMeter; + @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - Registry registry = globalRegistry.getDefaultRegistry(); - - Id endpointsId = registry.createId(VERTX_ENDPOINTS); - VertxEndpointsMeter clientMeter = new VertxEndpointsMeter(endpointsId.withTag(ENDPOINTS_TYPE, ENDPOINTS_CLINET), - AbstractTransport - .getTransportVertxFactory() - .getMetricsFactory() + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + httpClientEndpointsMeter = new HttpClientEndpointsMeter(meterRegistry, VERTX_ENDPOINTS, + Tags.of(ENDPOINTS_TYPE, ENDPOINTS_CLIENT), + SharedVertxFactory.getMetricsFactory(config.getEnvironment()) .getVertxMetrics() - .getClientEndpointMetricManager() - .getClientEndpointMetricMap()); - SpectatorUtils.registerMeter(registry, clientMeter); - - VertxEndpointsMeter serverMeter = new VertxServerEndpointsMeter( - endpointsId.withTag(ENDPOINTS_TYPE, ENDPOINTS_SERVER), - AbstractTransport - .getTransportVertxFactory() - .getMetricsFactory() + .getClientEndpointMetricManager()); + + serverEndpointsMeter = new ServerEndpointsMeter(meterRegistry, VERTX_ENDPOINTS, + Tags.of(ENDPOINTS_TYPE, ENDPOINTS_SERVER), + SharedVertxFactory.getMetricsFactory(config.getEnvironment()) .getVertxMetrics() .getServerEndpointMetricMap()); - SpectatorUtils.registerMeter(registry, serverMeter); + } + + @Override + public void poll(long msNow, long secondInterval) { + httpClientEndpointsMeter.poll(msNow, secondInterval); + serverEndpointsMeter.poll(msNow, secondInterval); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ConsumerMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ConsumerMeters.java index b249fdcd6aa..ccd7f49f6a3 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ConsumerMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ConsumerMeters.java @@ -16,16 +16,17 @@ */ package org.apache.servicecomb.metrics.core.meter; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.metrics.core.meter.invocation.AbstractInvocationMeters; import org.apache.servicecomb.metrics.core.meter.invocation.ConsumerInvocationMeters; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; public class ConsumerMeters { - private AbstractInvocationMeters invocationMeters; + private final AbstractInvocationMeters invocationMeters; - public ConsumerMeters(Registry registry) { - invocationMeters = new ConsumerInvocationMeters(registry); + public ConsumerMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + invocationMeters = new ConsumerInvocationMeters(meterRegistry, metricsBootstrapConfig); } public AbstractInvocationMeters getInvocationMeters() { diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/EdgeMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/EdgeMeters.java index 8efc1419d1a..b81403e89a3 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/EdgeMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/EdgeMeters.java @@ -17,17 +17,18 @@ package org.apache.servicecomb.metrics.core.meter; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.metrics.core.meter.invocation.AbstractInvocationMeters; import org.apache.servicecomb.metrics.core.meter.invocation.EdgeInvocationMeters; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; public class EdgeMeters { - private AbstractInvocationMeters invocationMeters; + private final AbstractInvocationMeters invocationMeters; - public EdgeMeters(Registry registry) { - this.invocationMeters = new EdgeInvocationMeters(registry); + public EdgeMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + this.invocationMeters = new EdgeInvocationMeters(meterRegistry, metricsBootstrapConfig); } public AbstractInvocationMeters getInvocationMeters() { diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ProducerMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ProducerMeters.java index e867f8ed9a7..1822b940f06 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ProducerMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ProducerMeters.java @@ -16,16 +16,17 @@ */ package org.apache.servicecomb.metrics.core.meter; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.metrics.core.meter.invocation.AbstractInvocationMeters; import org.apache.servicecomb.metrics.core.meter.invocation.ProducerInvocationMeters; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; public class ProducerMeters { - private AbstractInvocationMeters invocationMeters; + private final AbstractInvocationMeters invocationMeters; - public ProducerMeters(Registry registry) { - invocationMeters = new ProducerInvocationMeters(registry); + public ProducerMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + invocationMeters = new ProducerInvocationMeters(meterRegistry, metricsBootstrapConfig); } public AbstractInvocationMeters getInvocationMeters() { diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ThreadPoolMonitorPublishModelFactory.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ThreadPoolMonitorPublishModelFactory.java new file mode 100644 index 00000000000..d0474142cca --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/ThreadPoolMonitorPublishModelFactory.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; +import org.apache.servicecomb.metrics.core.meter.pool.ThreadPoolMeter; +import org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel; + +import io.micrometer.core.instrument.Measurement; + +public class ThreadPoolMonitorPublishModelFactory { + interface Setter { + void set(ThreadPoolPublishModel model, Measurement measurement); + } + + public static Map create(MeasurementTree tree) { + Map result = new HashMap<>(8); + readMeasurement(result, tree, ThreadPoolMeter.TASK_COUNT, + (model, measurement) -> model.setAvgTaskCount(measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.COMPLETED_TASK_COUNT, + (model, measurement) -> model.setAvgCompletedTaskCount(measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.CURRENT_THREADS_BUSY, + (model, measurement) -> model.setCurrentThreadsBusy((int) measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.MAX_THREADS, + (model, measurement) -> model.setMaxThreads((int) measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.POOL_SIZE, + (model, measurement) -> model.setPoolSize((int) measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.CORE_POOL_SIZE, + (model, measurement) -> model.setCorePoolSize((int) measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.QUEUE_SIZE, + (model, measurement) -> model.setQueueSize((int) measurement.getValue())); + readMeasurement(result, tree, ThreadPoolMeter.REJECTED_COUNT, + (model, measurement) -> model.setRejected(measurement.getValue())); + return result; + } + + protected static void readMeasurement(Map threadPools, MeasurementTree tree, + String name, Setter setter) { + MeasurementNode node = tree.findChild(ThreadPoolMeter.THREAD_POOL_METER); + if (node == null) { + return; + } + + for (String threadPoolName : node.getChildren().keySet()) { + MeasurementNode measure = node.findChild(threadPoolName, name); + if (measure == null) { + continue; + } + ThreadPoolPublishModel model = threadPools.computeIfAbsent(threadPoolName, tpn -> new ThreadPoolPublishModel()); + setter.set(model, measure.getMeasurements().get(0)); + } + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeter.java index 3023602bc0d..dbaf875ba81 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeter.java @@ -16,84 +16,90 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import java.util.ArrayList; -import java.util.List; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.metrics.meter.AbstractPeriodMeter; -import org.apache.servicecomb.foundation.metrics.meter.SimpleTimer; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.apache.servicecomb.foundation.metrics.meter.LatencyDistributionConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.Timer; -public abstract class AbstractInvocationMeter extends AbstractPeriodMeter { - private final Registry registry; +public abstract class AbstractInvocationMeter { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractInvocationMeter.class); + + // total time distribution + private final DistributionSummary totalSummary; //total time - private SimpleTimer totalTimer; + private final Timer totalTimer; // prepare time - private SimpleTimer prepareTimer; - - // handler request - private SimpleTimer handlersRequestTimer; - - // handler response - private SimpleTimer handlersResponseTimer; - - private long lastUpdated; - - public AbstractInvocationMeter(Registry registry, Id id) { - this.registry = registry; - this.id = id; - - totalTimer = creatStageTimer(MeterInvocationConst.STAGE_TOTAL); - prepareTimer = creatStageTimer(MeterInvocationConst.STAGE_PREPARE); - handlersRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_HANDLERS_REQUEST); - handlersResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_HANDLERS_RESPONSE); - } - - protected SimpleTimer creatStageTimer(String stageValue) { - return createTimer(id.withTag(MeterInvocationConst.TAG_STAGE, stageValue)); + private final Timer prepareTimer; + + protected final MetricsBootstrapConfig metricsBootstrapConfig; + + public AbstractInvocationMeter(MeterRegistry meterRegistry, String name, Tags tags, + MetricsBootstrapConfig metricsBootstrapConfig) { + this.metricsBootstrapConfig = metricsBootstrapConfig; + + double[] sla = toSla(metricsBootstrapConfig.getLatencyDistribution()); + if (sla != null) { + totalSummary = DistributionSummary.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_DISTRIBUTION)) + .distributionStatisticExpiry(Duration.ofMillis(metricsBootstrapConfig.getMsPollInterval())) + .serviceLevelObjectives(sla).register(meterRegistry); + } else { + totalSummary = null; + } + this.totalTimer = Timer.builder(name).tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE + , MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_TOTAL)).register(meterRegistry); + this.prepareTimer = Timer.builder(name).tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE + , MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PREPARE)).register(meterRegistry); } - protected SimpleTimer createTimer(String tagKey, String tagValue) { - return createTimer(id.withTag(tagKey, tagValue)); - } - - protected SimpleTimer createTimer(Id timerId) { - return new SimpleTimer(timerId); + private static double[] toSla(String config) { + if (StringUtils.isEmpty(config)) { + return null; + } + config = config.trim() + "," + LatencyDistributionConfig.MAX_LATENCY; + String[] array = config.split("\\s*,+\\s*"); + double[] result = new double[array.length]; + + for (int idx = 0; idx < array.length - 1; idx++) { + long msMin = Long.parseLong(array[idx]); + long msMax = Long.parseLong(array[idx + 1]); + if (msMin >= msMax) { + LOGGER.error("invalid latency scope, min={}, max={}.", array[idx], array[idx + 1]); + return null; + } + + result[idx] = msMin; + } + result[array.length - 1] = LatencyDistributionConfig.MAX_LATENCY; + + if (Double.compare(0, result[0]) == 0) { + double[] target = new double[result.length - 1]; + System.arraycopy(result, 1, target, 0, target.length); + return target; + } + + return result; } public void onInvocationFinish(InvocationFinishEvent event) { - lastUpdated = registry.clock().wallTime(); - InvocationStageTrace stageTrace = event.getInvocation().getInvocationStageTrace(); - totalTimer.record((long) stageTrace.calcTotalTime()); - handlersRequestTimer.record((long) stageTrace.calcHandlersRequestTime()); - handlersResponseTimer.record((long) stageTrace.calcHandlersResponseTime()); - prepareTimer.record((long) stageTrace.calcInvocationPrepareTime()); - } - - @Override - public void calcMeasurements(long msNow, long secondInterval) { - List measurements = new ArrayList<>(3); - calcMeasurements(measurements, msNow, secondInterval); - allMeasurements = measurements; - } - - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - totalTimer.calcMeasurements(measurements, msNow, secondInterval); - handlersRequestTimer.calcMeasurements(measurements, msNow, secondInterval); - handlersResponseTimer.calcMeasurements(measurements, msNow, secondInterval); - prepareTimer.calcMeasurements(measurements, msNow, secondInterval); - } - - @Override - public boolean hasExpired() { - return super.hasExpired(); + totalTimer.record(stageTrace.calcTotal(), TimeUnit.NANOSECONDS); + prepareTimer.record(stageTrace.calcPrepare(), TimeUnit.NANOSECONDS); + if (totalSummary != null) { + totalSummary.record(TimeUnit.NANOSECONDS.toMillis(stageTrace.calcTotal())); + } } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeters.java index e9114804b78..30e8e2987ca 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/AbstractInvocationMeters.java @@ -22,34 +22,31 @@ import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.event.InvocationStartEvent; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.swagger.invocation.Response; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.SpectatorUtils; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; public abstract class AbstractInvocationMeters { - protected Registry registry; + protected MeterRegistry registry; - private Map metersMap = new ConcurrentHashMapEx<>(); + private final Map metersMap = new ConcurrentHashMapEx<>(); - // not care for concurrency, just for make build key faster + // not care for concurrency, just for make build key faster private int maxKeyLen = 64; - public AbstractInvocationMeters(Registry registry) { + protected MetricsBootstrapConfig metricsBootstrapConfig; + + public AbstractInvocationMeters(MeterRegistry registry, MetricsBootstrapConfig metricsBootstrapConfig) { this.registry = registry; + this.metricsBootstrapConfig = metricsBootstrapConfig; } protected AbstractInvocationMeter getOrCreateMeters(Invocation invocation, Response response) { - // build string key is faster then use Id to locate timer directly + // build string key is faster than use Id to locate timer directly StringBuilder keyBuilder = new StringBuilder(maxKeyLen); - String invocationName; - //check edge - if (invocation.isConsumer() && invocation.isEdge()) { - invocationName = MeterInvocationConst.EDGE_INVOCATION_NAME; - } else { - invocationName = invocation.getInvocationType().name(); - } + String invocationName = invocation.getInvocationType().name(); keyBuilder .append(invocationName) @@ -61,23 +58,16 @@ protected AbstractInvocationMeter getOrCreateMeters(Invocation invocation, Respo } return metersMap.computeIfAbsent(keyBuilder.toString(), k -> { - Id id = registry.createId(MeterInvocationConst.INVOCATION_NAME, - MeterInvocationConst.TAG_ROLE, - invocationName, - MeterInvocationConst.TAG_TRANSPORT, - invocation.getRealTransportName(), - MeterInvocationConst.TAG_OPERATION, - invocation.getMicroserviceQualifiedName(), - MeterInvocationConst.TAG_STATUS, - String.valueOf(response.getStatusCode())); - - AbstractInvocationMeter meter = createMeter(id); - SpectatorUtils.registerMeter(registry, meter); + AbstractInvocationMeter meter = createMeter(MeterInvocationConst.INVOCATION_NAME, Tags.empty() + .and(MeterInvocationConst.TAG_ROLE, invocationName) + .and(MeterInvocationConst.TAG_TRANSPORT, invocation.getRealTransportName()) + .and(MeterInvocationConst.TAG_OPERATION, invocation.getMicroserviceQualifiedName()) + .and(MeterInvocationConst.TAG_STATUS, String.valueOf(response.getStatusCode()))); return meter; }); } - protected abstract AbstractInvocationMeter createMeter(Id id); + protected abstract AbstractInvocationMeter createMeter(String name, Tags tags); public void onInvocationStart(InvocationStartEvent event) { } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeter.java index a82624fe945..d0b4c08f75d 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeter.java @@ -16,40 +16,47 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.metrics.meter.SimpleTimer; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.Timer; public class ConsumerInvocationMeter extends AbstractInvocationMeter { - private SimpleTimer clientFiltersRequestTimer; + private final Timer consumerEncodeRequestTimer; - private SimpleTimer consumerSendRequestTimer; + private final Timer consumerDecodeResponseTimer; - private SimpleTimer consumerGetConnectionTimer; + private final Timer consumerGetConnectionTimer; - private SimpleTimer consumerWriteToBufTimer; + private final Timer consumerSendRequestTimer; - private SimpleTimer consumerWaitResponseTimer; + private final Timer consumerWaitResponseTimer; - private SimpleTimer consumerWakeConsumerTimer; - - private SimpleTimer clientFiltersResponseTimer; - - public ConsumerInvocationMeter(Registry registry, Id id) { - super(registry, id); - clientFiltersRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_CLIENT_FILTERS_REQUEST); - consumerSendRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_CONSUMER_SEND_REQUEST); - consumerGetConnectionTimer = creatStageTimer(MeterInvocationConst.STAGE_CONSUMER_GET_CONNECTION); - consumerWriteToBufTimer = creatStageTimer(MeterInvocationConst.STAGE_CONSUMER_WRITE_TO_BUF); - consumerWakeConsumerTimer = creatStageTimer(MeterInvocationConst.STAGE_CONSUMER_WAKE_CONSUMER); - clientFiltersResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_CLIENT_FILTERS_RESPONSE); - consumerWaitResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_CONSUMER_WAIT_RESPONSE); + public ConsumerInvocationMeter(MeterRegistry meterRegistry, String name, Tags tags, + MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, name, tags, metricsBootstrapConfig); + consumerSendRequestTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_CONSUMER_SEND)).register(meterRegistry); + consumerGetConnectionTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_CONSUMER_CONNECTION)).register(meterRegistry); + consumerEncodeRequestTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST)) + .register(meterRegistry); + consumerDecodeResponseTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE)) + .register(meterRegistry); + consumerWaitResponseTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_CONSUMER_WAIT)).register(meterRegistry); } @Override @@ -57,25 +64,10 @@ public void onInvocationFinish(InvocationFinishEvent event) { super.onInvocationFinish(event); InvocationStageTrace invocationStageTrace = event.getInvocation().getInvocationStageTrace(); - clientFiltersRequestTimer.record((long) invocationStageTrace.calcClientFiltersRequestTime()); - consumerSendRequestTimer.record((long) invocationStageTrace.calcSendRequestTime()); - consumerGetConnectionTimer.record((long) invocationStageTrace.calcGetConnectionTime()); - consumerWriteToBufTimer.record((long) invocationStageTrace.calcWriteToBufferTime()); - consumerWaitResponseTimer.record((long) invocationStageTrace.calcReceiveResponseTime()); - consumerWakeConsumerTimer.record((long) invocationStageTrace.calcWakeConsumer()); - clientFiltersResponseTimer.record((long) invocationStageTrace.calcClientFiltersResponseTime()); - } - - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - super.calcMeasurements(measurements, msNow, secondInterval); - - clientFiltersRequestTimer.calcMeasurements(measurements, msNow, secondInterval); - consumerSendRequestTimer.calcMeasurements(measurements, msNow, secondInterval); - consumerGetConnectionTimer.calcMeasurements(measurements, msNow, secondInterval); - consumerWriteToBufTimer.calcMeasurements(measurements, msNow, secondInterval); - consumerWaitResponseTimer.calcMeasurements(measurements, msNow, secondInterval); - consumerWakeConsumerTimer.calcMeasurements(measurements, msNow, secondInterval); - clientFiltersResponseTimer.calcMeasurements(measurements, msNow, secondInterval); + consumerEncodeRequestTimer.record(invocationStageTrace.calcConsumerEncodeRequest(), TimeUnit.NANOSECONDS); + consumerSendRequestTimer.record(invocationStageTrace.calcConsumerSendRequest(), TimeUnit.NANOSECONDS); + consumerGetConnectionTimer.record(invocationStageTrace.calcConnection(), TimeUnit.NANOSECONDS); + consumerWaitResponseTimer.record(invocationStageTrace.calcWait(), TimeUnit.NANOSECONDS); + consumerDecodeResponseTimer.record(invocationStageTrace.calcConsumerDecodeResponse(), TimeUnit.NANOSECONDS); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeters.java index 5543c9f54fe..842122e08db 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ConsumerInvocationMeters.java @@ -16,16 +16,18 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Registry; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; public class ConsumerInvocationMeters extends AbstractInvocationMeters { - public ConsumerInvocationMeters(Registry registry) { - super(registry); + public ConsumerInvocationMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, metricsBootstrapConfig); } @Override - protected AbstractInvocationMeter createMeter(Id id) { - return new ConsumerInvocationMeter(registry, id); + protected AbstractInvocationMeter createMeter(String name, Tags tags) { + return new ConsumerInvocationMeter(registry, name, tags, this.metricsBootstrapConfig); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeter.java index ca41a2f6b38..32fe7aa926a 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeter.java @@ -17,31 +17,37 @@ package org.apache.servicecomb.metrics.core.meter.invocation; -import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.metrics.meter.SimpleTimer; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.Timer; public class EdgeInvocationMeter extends ConsumerInvocationMeter { - private SimpleTimer executorQueueTimer; - - private SimpleTimer serverFiltersRequestTimer; - - private SimpleTimer serverFiltersResponseTimer; - - private SimpleTimer sendResponseTimer; - - public EdgeInvocationMeter(Registry registry, Id id) { - super(registry, id); - executorQueueTimer = creatStageTimer(MeterInvocationConst.STAGE_EXECUTOR_QUEUE); - serverFiltersRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_SERVER_FILTERS_REQUEST); - serverFiltersResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_SERVER_FILTERS_RESPONSE); - sendResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_PRODUCER_SEND_RESPONSE); + private final Timer providerDecodeRequestTimer; + + private final Timer providerEncodeResponseTimer; + + private final Timer sendResponseTimer; + + public EdgeInvocationMeter(MeterRegistry meterRegistry, String name, Tags tags, + MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, name, tags, metricsBootstrapConfig); + providerDecodeRequestTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST)) + .register(meterRegistry); + providerEncodeResponseTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE)) + .register(meterRegistry); + sendResponseTimer = Timer.builder(name).tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_SEND)) + .register(meterRegistry); } @Override @@ -49,19 +55,8 @@ public void onInvocationFinish(InvocationFinishEvent event) { super.onInvocationFinish(event); InvocationStageTrace invocationStageTrace = event.getInvocation().getInvocationStageTrace(); - executorQueueTimer.record((long) invocationStageTrace.calcThreadPoolQueueTime()); - serverFiltersRequestTimer.record((long) invocationStageTrace.calcServerFiltersRequestTime()); - serverFiltersResponseTimer.record((long) invocationStageTrace.calcServerFiltersResponseTime()); - sendResponseTimer.record((long) invocationStageTrace.calcSendResponseTime()); - } - - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - super.calcMeasurements(measurements, msNow, secondInterval); - - executorQueueTimer.calcMeasurements(measurements, msNow, secondInterval); - serverFiltersRequestTimer.calcMeasurements(measurements, msNow, secondInterval); - serverFiltersResponseTimer.calcMeasurements(measurements, msNow, secondInterval); - sendResponseTimer.calcMeasurements(measurements, msNow, secondInterval); + providerDecodeRequestTimer.record(invocationStageTrace.calcProviderDecodeRequest(), TimeUnit.NANOSECONDS); + providerEncodeResponseTimer.record(invocationStageTrace.calcProviderEncodeResponse(), TimeUnit.NANOSECONDS); + sendResponseTimer.record(invocationStageTrace.calcProviderSendResponse(), TimeUnit.NANOSECONDS); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeters.java index b7db74c27c0..ecdbd3670b0 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/EdgeInvocationMeters.java @@ -17,16 +17,18 @@ package org.apache.servicecomb.metrics.core.meter.invocation; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Registry; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; public class EdgeInvocationMeters extends ConsumerInvocationMeters { - public EdgeInvocationMeters(Registry registry) { - super(registry); + public EdgeInvocationMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, metricsBootstrapConfig); } @Override - protected AbstractInvocationMeter createMeter(Id id) { - return new EdgeInvocationMeter(registry, id); + protected AbstractInvocationMeter createMeter(String name, Tags tags) { + return new EdgeInvocationMeter(registry, name, tags, metricsBootstrapConfig); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/MeterInvocationConst.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/MeterInvocationConst.java index e09da9b5e4a..2a377e43260 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/MeterInvocationConst.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/MeterInvocationConst.java @@ -16,8 +16,6 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import com.netflix.spectator.api.Statistic; - public interface MeterInvocationConst { String INVOCATION_NAME = "servicecomb.invocation"; @@ -28,46 +26,13 @@ public interface MeterInvocationConst { String TAG_TRANSPORT = "transport"; - String TAG_STAGE = "stage"; - - String TAG_STATUS = "status"; - - String TAG_STATISTIC = Statistic.count.key(); - - String STAGE_TOTAL = "total"; + String TAG_TYPE = "type"; - String STAGE_PREPARE = "prepare"; + String TAG_STAGE = "stage"; - String STAGE_EXECUTOR_QUEUE = "queue"; + String TAG_DISTRIBUTION = "distribution"; - String STAGE_EXECUTION = "execution"; + String TAG_STATUS = "status"; String EDGE_INVOCATION_NAME = "EDGE"; - - String STAGE_HANDLERS_REQUEST = "handlers_request"; - - String STAGE_HANDLERS_RESPONSE = "handlers_response"; - - // producer only - String STAGE_SERVER_FILTERS_REQUEST = "server_filters_request"; - - String STAGE_SERVER_FILTERS_RESPONSE = "server_filters_response"; - - String STAGE_PRODUCER_SEND_RESPONSE = "producer_send_response"; - - //consumer only - - String STAGE_CLIENT_FILTERS_REQUEST = "client_filters_request"; - - String STAGE_CONSUMER_SEND_REQUEST = "consumer_send_request"; - - String STAGE_CONSUMER_GET_CONNECTION = "consumer_get_connection"; - - String STAGE_CONSUMER_WRITE_TO_BUF = "consumer_write_to_buf"; - - String STAGE_CONSUMER_WAIT_RESPONSE = "consumer_wait_response"; - - String STAGE_CONSUMER_WAKE_CONSUMER = "consumer_wake_consumer"; - - String STAGE_CLIENT_FILTERS_RESPONSE = "client_filters_response"; } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeter.java index 79b89e51fd2..2ed55e5e0ef 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeter.java @@ -16,35 +16,49 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import java.util.List; +import java.util.concurrent.TimeUnit; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.metrics.meter.SimpleTimer; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.Timer; public class ProducerInvocationMeter extends AbstractInvocationMeter { - private SimpleTimer executorQueueTimer; + private final Timer executorQueueTimer; - private SimpleTimer executionTimer; + private final Timer executionTimer; - private SimpleTimer serverFiltersRequestTimer; + private final Timer providerDecodeRequestTimer; - private SimpleTimer serverFiltersResponseTimer; + private final Timer providerEncodeResponseTimer; - private SimpleTimer sendResponseTimer; + private final Timer sendResponseTimer; - public ProducerInvocationMeter(Registry registry, Id id) { - super(registry, id); - - executorQueueTimer = creatStageTimer(MeterInvocationConst.STAGE_EXECUTOR_QUEUE); - executionTimer = creatStageTimer(MeterInvocationConst.STAGE_EXECUTION); - serverFiltersRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_SERVER_FILTERS_REQUEST); - serverFiltersResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_SERVER_FILTERS_RESPONSE); - sendResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_PRODUCER_SEND_RESPONSE); + public ProducerInvocationMeter(MeterRegistry meterRegistry, String name, Tags tags, + MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, name, tags, metricsBootstrapConfig); + executorQueueTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_QUEUE)) + .register(meterRegistry); + executionTimer = Timer.builder(name).tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_BUSINESS)) + .register(meterRegistry); + providerDecodeRequestTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST)) + .register(meterRegistry); + providerEncodeResponseTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE)) + .register(meterRegistry); + sendResponseTimer = Timer.builder(name) + .tags(tags.and(MeterInvocationConst.TAG_TYPE, MeterInvocationConst.TAG_STAGE, + MeterInvocationConst.TAG_STAGE, InvocationStageTrace.STAGE_PROVIDER_SEND)) + .register(meterRegistry); } @Override @@ -52,21 +66,10 @@ public void onInvocationFinish(InvocationFinishEvent event) { super.onInvocationFinish(event); InvocationStageTrace invocationStageTrace = event.getInvocation().getInvocationStageTrace(); - executorQueueTimer.record((long) invocationStageTrace.calcThreadPoolQueueTime()); - executionTimer.record((long) invocationStageTrace.calcBusinessTime()); - serverFiltersRequestTimer.record((long) invocationStageTrace.calcServerFiltersRequestTime()); - serverFiltersResponseTimer.record((long) invocationStageTrace.calcServerFiltersResponseTime()); - sendResponseTimer.record((long) invocationStageTrace.calcSendResponseTime()); - } - - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - super.calcMeasurements(measurements, msNow, secondInterval); - - executorQueueTimer.calcMeasurements(measurements, msNow, secondInterval); - executionTimer.calcMeasurements(measurements, msNow, secondInterval); - serverFiltersRequestTimer.calcMeasurements(measurements, msNow, secondInterval); - serverFiltersResponseTimer.calcMeasurements(measurements, msNow, secondInterval); - sendResponseTimer.calcMeasurements(measurements, msNow, secondInterval); + executorQueueTimer.record(invocationStageTrace.calcQueue(), TimeUnit.NANOSECONDS); + executionTimer.record(invocationStageTrace.calcBusinessExecute(), TimeUnit.NANOSECONDS); + providerDecodeRequestTimer.record(invocationStageTrace.calcProviderDecodeRequest(), TimeUnit.NANOSECONDS); + providerEncodeResponseTimer.record(invocationStageTrace.calcProviderEncodeResponse(), TimeUnit.NANOSECONDS); + sendResponseTimer.record(invocationStageTrace.calcProviderSendResponse(), TimeUnit.NANOSECONDS); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeters.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeters.java index f8e88148a45..bf4f84104f9 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeters.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/invocation/ProducerInvocationMeters.java @@ -16,16 +16,18 @@ */ package org.apache.servicecomb.metrics.core.meter.invocation; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Registry; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; public class ProducerInvocationMeters extends AbstractInvocationMeters { - public ProducerInvocationMeters(Registry registry) { - super(registry); + public ProducerInvocationMeters(MeterRegistry meterRegistry, MetricsBootstrapConfig metricsBootstrapConfig) { + super(meterRegistry, metricsBootstrapConfig); } @Override - protected AbstractInvocationMeter createMeter(Id id) { - return new ProducerInvocationMeter(registry, id); + protected AbstractInvocationMeter createMeter(String name, Tags tags) { + return new ProducerInvocationMeter(registry, name, tags, metricsBootstrapConfig); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java deleted file mode 100644 index 6edcf1b46fd..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.os; - -import java.util.List; - -import org.apache.servicecomb.metrics.core.meter.os.cpu.OsCpuUsage; -import org.apache.servicecomb.metrics.core.meter.os.cpu.ProcessCpuUsage; - -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; - -public class CpuMeter { - - // read from /proc/stat - private OsCpuUsage allCpuUsage; - - // read from /proc/{pid}/stat - private ProcessCpuUsage processCpuUsage; - - public CpuMeter(Id id) { - allCpuUsage = new OsCpuUsage(id.withTag(OsMeter.OS_TYPE, OsMeter.OS_TYPE_ALL_CPU)); - processCpuUsage = new ProcessCpuUsage(id.withTag(OsMeter.OS_TYPE, OsMeter.OS_TYPE_PROCESS_CPU)); - - //must refresh all first - update(); - allCpuUsage.setUsage(0); - processCpuUsage.setUsage(0); - } - - public void calcMeasurements(List measurements, long msNow) { - update(); - measurements.add(new Measurement(allCpuUsage.getId(), msNow, allCpuUsage.getUsage())); - measurements.add(new Measurement(processCpuUsage.getId(), msNow, processCpuUsage.getUsage())); - } - - public void update() { - allCpuUsage.update(); - processCpuUsage.setPeriodTotalTime(allCpuUsage.getPeriodTotalTime()); - processCpuUsage.update(); - } - - public OsCpuUsage getAllCpuUsage() { - return allCpuUsage; - } - - public ProcessCpuUsage getProcessCpuUsage() { - return processCpuUsage; - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java index e6fa13e29cf..882fb6bf5de 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java @@ -19,59 +19,66 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.SystemUtils; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; import org.apache.servicecomb.metrics.core.meter.os.net.InterfaceUsage; -import org.apache.servicecomb.metrics.core.meter.os.net.NetStat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.netflix.spectator.api.BasicTag; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Tag; +import com.google.common.annotations.VisibleForTesting; -public class NetMeter { +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; + +public class NetMeter implements PeriodMeter { private static final Logger LOGGER = LoggerFactory.getLogger(NetMeter.class); public static final String STATISTIC = "statistic"; public static final String INTERFACE = "interface"; - public static final Tag TAG_RECEIVE = new BasicTag(STATISTIC, "receive"); + public static final Tag TAG_RECEIVE = Tag.of(STATISTIC, "receive"); - public static final Tag TAG_PACKETS_RECEIVE = new BasicTag(STATISTIC, "receivePackets"); + public static final Tag TAG_PACKETS_RECEIVE = Tag.of(STATISTIC, "receivePackets"); - public static final Tag TAG_SEND = new BasicTag(STATISTIC, "send"); + public static final Tag TAG_SEND = Tag.of(STATISTIC, "send"); - public static final Tag TAG_PACKETS_SEND = new BasicTag(STATISTIC, "sendPackets"); + public static final Tag TAG_PACKETS_SEND = Tag.of(STATISTIC, "sendPackets"); - private final Id id; + private final Map interfaceUsageMap = new ConcurrentHashMap<>(); - private Map interfaceUsageMap = new ConcurrentHashMap<>(); + private boolean isOsLinux = SystemUtils.IS_OS_LINUX; - public NetMeter(Id id) { - this.id = id; - // init lastRxBytes, lastRxPackets, lastTxBytes, lastTxPackets - refreshNet(1); - interfaceUsageMap.values().forEach(interfaceUsage -> { - interfaceUsage.getNetStats().forEach(NetStat::clearRate); - }); - } + protected final MeterRegistry meterRegistry; + + protected final String name; - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - refreshNet(secondInterval); + protected final Tags tags; + + public NetMeter(MeterRegistry meterRegistry, String name, Tags tags) { + this.meterRegistry = meterRegistry; + this.name = name; + this.tags = tags; + poll(0, 0); + } - interfaceUsageMap.values().forEach(interfaceUsage -> { - interfaceUsage.calcMeasurements(measurements, msNow); - }); + @VisibleForTesting + public void setOsLinux(boolean osLinux) { + isOsLinux = osLinux; } + @Override + public void poll(long msNow, long secondInterval) { + if (isOsLinux) { + refreshNet(secondInterval); + } + } /* * Inter-| Receive | Transmit @@ -83,7 +90,6 @@ protected void refreshNet(long secondInterval) { try { File file = new File("/proc/net/dev"); List netInfo = FileUtils.readLines(file, StandardCharsets.UTF_8); - Set nameSet = new HashSet<>(); //the first two lines is useless for (int i = 2; i < netInfo.size(); i++) { @@ -94,19 +100,12 @@ protected void refreshNet(long secondInterval) { continue; } - String name = strings[0].trim(); - nameSet.add(name); + String interfaceName = strings[0].trim(); - InterfaceUsage interfaceUsage = interfaceUsageMap.computeIfAbsent(name, key -> new InterfaceUsage(id, key)); + InterfaceUsage interfaceUsage = interfaceUsageMap.computeIfAbsent(interfaceName, + key -> new InterfaceUsage(meterRegistry, name, tags, key)); interfaceUsage.update(strings[1], secondInterval); } - - // clear deleted interfaces - for (String interfaceName : interfaceUsageMap.keySet()) { - if (!nameSet.contains(interfaceName)) { - this.interfaceUsageMap.remove(interfaceName); - } - } } catch (IOException e) { LOGGER.error("Failed to read net info/", e); } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java index b435665479a..9b74fd199de 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java @@ -16,14 +16,12 @@ */ package org.apache.servicecomb.metrics.core.meter.os; -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.foundation.metrics.meter.AbstractPeriodMeter; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; import com.google.common.annotations.VisibleForTesting; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; /** * name=os type=cpu value = 0 @@ -33,43 +31,31 @@ * name=os type=net interface=eth0 statistic=sendPackets value=100 * name=os type=net interface=eth0 statistic=receivePackets value=100 */ -public class OsMeter extends AbstractPeriodMeter { +public class OsMeter implements PeriodMeter { public static final String OS_NAME = "os"; public static final String OS_TYPE = "type"; - public static final String OS_TYPE_ALL_CPU = "cpu"; - - public static final String OS_TYPE_PROCESS_CPU = "processCpu"; - public static final String OS_TYPE_NET = "net"; - private CpuMeter cpuMeter; + private final SystemMeter systemMeter; - private NetMeter netMeter; + private final NetMeter netMeter; - public OsMeter(Registry registry) { - this.id = registry.createId(OS_NAME); - cpuMeter = new CpuMeter(id); - netMeter = new NetMeter(id.withTag(OS_TYPE, OS_TYPE_NET)); - } - - @Override - public void calcMeasurements(long msNow, long secondInterval) { - List measurements = new ArrayList<>(); - calcMeasurements(measurements, msNow, secondInterval); - allMeasurements = measurements; + public OsMeter(MeterRegistry meterRegistry) { + systemMeter = new SystemMeter(meterRegistry, OS_NAME); + netMeter = new NetMeter(meterRegistry, OS_NAME, Tags.of(OS_TYPE, OS_TYPE_NET)); } @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - cpuMeter.calcMeasurements(measurements, msNow); - netMeter.calcMeasurements(measurements, msNow, secondInterval); + public void poll(long msNow, long secondInterval) { + systemMeter.poll(msNow, secondInterval); + netMeter.poll(msNow, secondInterval); } @VisibleForTesting - public CpuMeter getCpuMeter() { - return cpuMeter; + public SystemMeter getCpuMeter() { + return systemMeter; } @VisibleForTesting diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/SystemMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/SystemMeter.java new file mode 100644 index 00000000000..2b9ce7d471e --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/SystemMeter.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.os; + +import java.lang.management.ManagementFactory; + +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; + +import com.google.common.annotations.VisibleForTesting; +import com.sun.management.OperatingSystemMXBean; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; + +public class SystemMeter implements PeriodMeter { + public static final String SYSTEM_LOAD_AVERAGE = "sla"; + + public static final String CPU_USAGE = "cpu"; + + public static final String PROCESS_CPU_USAGE = "processCpu"; + + public static final String MEMORY_USAGE = "memory"; + + private OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); + + public SystemMeter(MeterRegistry meterRegistry, String name) { + Gauge.builder(name, () -> getOsBean().getSystemLoadAverage()) + .tags(Tags.of(OsMeter.OS_TYPE, SYSTEM_LOAD_AVERAGE)) + .register(meterRegistry); + + Gauge.builder(name, () -> getOsBean().getCpuLoad()) + .tags(Tags.of(OsMeter.OS_TYPE, CPU_USAGE)) + .register(meterRegistry); + + Gauge.builder(name, () -> getOsBean().getProcessCpuLoad()) + .tags(Tags.of(OsMeter.OS_TYPE, PROCESS_CPU_USAGE)) + .register(meterRegistry); + + Gauge.builder(name, () -> (getOsBean().getTotalMemorySize() - getOsBean().getFreeMemorySize()) + / (double) getOsBean().getTotalMemorySize()) + .tags(Tags.of(OsMeter.OS_TYPE, MEMORY_USAGE)) + .register(meterRegistry); + } + + @VisibleForTesting + public void setOsBean(OperatingSystemMXBean mock) { + this.osBean = mock; + } + + private OperatingSystemMXBean getOsBean() { + return this.osBean; + } + + @Override + public void poll(long msNow, long secondInterval) { + + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java deleted file mode 100644 index af4f514409f..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.os.cpu; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.spectator.api.Id; - -public abstract class AbstractCpuUsage { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCpuUsage.class); - - protected String filePath; - - protected Id id; - - protected long lastBusyTime; - - protected long periodTotalTime; - - protected double usage; - - public AbstractCpuUsage(Id id, String filePath) { - this.id = id; - this.filePath = filePath; - } - - public Id getId() { - return id; - } - - public long getPeriodTotalTime() { - return periodTotalTime; - } - - public long getLastBusyTime() { - return lastBusyTime; - } - - public String getFilePath() { - return filePath; - } - - public double getUsage() { - return usage; - } - - public void setUsage(double usage) { - this.usage = usage; - } - - public void setPeriodTotalTime(long periodTotalTime) { - this.periodTotalTime = periodTotalTime; - } - - protected String[] readAndSplitStat() throws IOException { - File file = new File(filePath); - String stat = FileUtils.readLines(file, StandardCharsets.UTF_8).get(0); - return stat.trim().split("\\s+"); - } - - public void update() { - String[] stats; - try { - stats = readAndSplitStat(); - } catch (IOException e) { - LOGGER.error(String.format("Failed to read cpu info/%s.", filePath), e); - return; - } - - update(stats); - } - - protected void update(String[] stats) { - long currentBusyTime = readCurrentBusyTime(stats); - - usage = periodTotalTime == 0 ? 0 : (double) (currentBusyTime - lastBusyTime) / periodTotalTime; - usage *= Runtime.getRuntime().availableProcessors(); - - lastBusyTime = currentBusyTime; - } - - protected abstract long readCurrentBusyTime(String[] stats); -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java deleted file mode 100644 index 48b9a8ce790..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.os.cpu; - -import com.netflix.spectator.api.Id; - -/* - * unit : 1 jiffies = 10ms = 0.01 s - * more details : - * http://man7.org/linux/man-pages/man5/proc.5.html - * CMD : /proc/stat - * cpu 2445171 599297 353967 24490633 11242 0 10780 2993 0 0 - * cpu user nice system idle iowait irq softirq stealstolen guest guest_nice - * 0 1 2 3 4 5 6 7 8 - * total = user + nice + system + idle + iowait + irq + softirq + stealstolen - * busy = total - idle - */ -public class OsCpuUsage extends AbstractCpuUsage { - private long lastTotalTime; - - private long currentTotalTime; - - public OsCpuUsage(Id id) { - super(id, "/proc/stat"); - } - - @Override - protected void update(String[] stats) { - currentTotalTime = readCurrentTotalTime(stats); - periodTotalTime = currentTotalTime - lastTotalTime; - lastTotalTime = currentTotalTime; - - super.update(stats); - } - - private long readCurrentTotalTime(String[] stats) { - long total = 0L; - for (int i = 1; i <= 8; i++) { - total += Long.parseLong(stats[i]); - } - return total; - } - - @Override - protected long readCurrentBusyTime(String[] stats) { - return currentTotalTime - Long.parseLong(stats[4]); - } - - public long getLastTotalTime() { - return lastTotalTime; - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java deleted file mode 100644 index 57efd85796c..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.os.cpu; - -import java.lang.management.ManagementFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.spectator.api.Id; - -/* - * unit : 1 jiffies = 10ms = 0.01 s - * more details : - * http://man7.org/linux/man-pages/man5/proc.5.html - * CMD : /proc/[pid]/stat - * 6754 (kubelet) S 1 995 995 0 -1 4202752 193281 592501546 0 12 1152076 907044 87991 113319 .. - * pid comm state ppid pgrp session tty_nr tpgid flags minflt cminflt majflt cmajflt utime stime cutime cstime - * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - * busy = utime + stime + cutime + cstime - * - */ -public class ProcessCpuUsage extends AbstractCpuUsage { - private static final Logger LOGGER = LoggerFactory.getLogger(ProcessCpuUsage.class); - - public ProcessCpuUsage(Id id) { - super(id, String.format("/proc/%s/stat", getCurrentPid())); - } - - private static String getCurrentPid() { - String name = ManagementFactory.getRuntimeMXBean().getName(); - int idx = name.indexOf('@'); - if (idx > 0) { - return name.substring(0, idx); - } - - LOGGER.error("Failed to get current process id. {}", name); - throw new IllegalStateException("Failed to get current process Id"); - } - - @Override - protected long readCurrentBusyTime(String[] stats) { - long busy = 0L; - for (int i = 13; i <= 16; i++) { - busy += Long.parseLong(stats[i]); - } - return busy; - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/InterfaceUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/InterfaceUsage.java index 1fa8a7b03ce..b3d40a1bbf5 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/InterfaceUsage.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/InterfaceUsage.java @@ -22,51 +22,71 @@ import static org.apache.servicecomb.metrics.core.meter.os.NetMeter.TAG_RECEIVE; import static org.apache.servicecomb.metrics.core.meter.os.NetMeter.TAG_SEND; -import java.util.ArrayList; -import java.util.List; +import com.google.common.annotations.VisibleForTesting; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; public class InterfaceUsage { - private final String name; + private final String interfaceName; - private List netStats = new ArrayList<>(); + private final NetStat receive; - public InterfaceUsage(Id id, String name) { - this.name = name; - id = id.withTag(INTERFACE, name); - init(id); - } + private final NetStat send; + + private final NetStat packetsReceive; + + private final NetStat packetsSend; + + public InterfaceUsage(MeterRegistry meterRegistry, String name, Tags tags, String interfaceName) { + this.interfaceName = interfaceName; + tags = tags.and(Tag.of(INTERFACE, interfaceName)); - private void init(Id id) { // recv/Bps - netStats.add(new NetStat(id.withTag(TAG_RECEIVE), 0)); + receive = new NetStat(0); + Gauge.builder(name, receive::getRate).tags(tags.and(TAG_RECEIVE)).register(meterRegistry); // send/Bps - netStats.add(new NetStat(id.withTag(TAG_SEND), 8)); - + send = new NetStat(8); + Gauge.builder(name, send::getRate).tags(tags.and(TAG_SEND)).register(meterRegistry); // recv/pps - netStats.add(new NetStat(id.withTag(TAG_PACKETS_RECEIVE), 1)); + packetsReceive = new NetStat(1); + Gauge.builder(name, packetsReceive::getRate).tags(tags.and(TAG_PACKETS_RECEIVE)).register(meterRegistry); // send/pps - netStats.add(new NetStat(id.withTag(TAG_PACKETS_SEND), 9)); - } - - public void calcMeasurements(List measurements, long msNow) { - netStats.forEach(netStat -> { - measurements.add(new Measurement(netStat.getId(), msNow, netStat.getRate())); - }); + packetsSend = new NetStat(9); + Gauge.builder(name, packetsSend::getRate).tags(tags.and(TAG_PACKETS_SEND)).register(meterRegistry); } public void update(String interfaceData, long secondInterval) { String[] netInfo = interfaceData.trim().split("\\s+"); - netStats.forEach(netStat -> netStat.update(netInfo, secondInterval)); + receive.update(netInfo, secondInterval); + send.update(netInfo, secondInterval); + packetsReceive.update(netInfo, secondInterval); + packetsSend.update(netInfo, secondInterval); } - public String getName() { - return name; + @VisibleForTesting + public NetStat getReceive() { + return receive; } - public List getNetStats() { - return netStats; + @VisibleForTesting + public NetStat getSend() { + return send; + } + + @VisibleForTesting + public NetStat getPacketsReceive() { + return packetsReceive; + } + + @VisibleForTesting + public NetStat getPacketsSend() { + return packetsSend; + } + + public String getName() { + return interfaceName; } -} \ No newline at end of file +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/NetStat.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/NetStat.java index f80a9088b8e..fac707dce6d 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/NetStat.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/net/NetStat.java @@ -16,21 +16,17 @@ */ package org.apache.servicecomb.metrics.core.meter.os.net; -import com.netflix.spectator.api.Id; public class NetStat { private final int index; - private Id id; - // send/recv bytes/packets private long lastValue; // Bps/pps private double rate; - public NetStat(Id id, int index) { - this.id = id; + public NetStat(int index) { this.index = index; } @@ -55,8 +51,4 @@ public double getRate() { public int getIndex() { return index; } - - public Id getId() { - return id; - } -} \ No newline at end of file +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/pool/ThreadPoolMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/pool/ThreadPoolMeter.java new file mode 100644 index 00000000000..1267bc53e6f --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/pool/ThreadPoolMeter.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.pool; + +import java.util.concurrent.ThreadPoolExecutor; + +import org.apache.servicecomb.core.executor.ThreadPoolExecutorEx; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; + +public class ThreadPoolMeter implements PeriodMeter { + public static final String THREAD_POOL_METER = "servicecomb.threadpool"; + + public static final String ID = "id"; + + public static final String STAGE = "stage"; + + public static final String REJECTED_COUNT = "rejectedCount"; + + public static final String TASK_COUNT = "taskCount"; + + public static final String COMPLETED_TASK_COUNT = "completedTaskCount"; + + public static final String CURRENT_THREADS_BUSY = "currentThreadsBusy"; + + public static final String MAX_THREADS = "maxThreads"; + + public static final String POOL_SIZE = "poolSize"; + + public static final String CORE_POOL_SIZE = "corePoolSize"; + + public static final String QUEUE_SIZE = "queueSize"; + + private final ThreadPoolExecutor threadPoolExecutor; + + private long currentTask; + + private long lastTask; + + private long currentCompletedTask; + + private long lastCompletedTask; + + public ThreadPoolMeter(MeterRegistry meterRegistry, String threadPoolName, ThreadPoolExecutor threadPoolExecutor) { + this.threadPoolExecutor = threadPoolExecutor; + + Gauge.builder(THREAD_POOL_METER, () -> currentTask) + .tags(ID, threadPoolName, STAGE, TASK_COUNT) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, () -> currentCompletedTask) + .tags(ID, threadPoolName, STAGE, COMPLETED_TASK_COUNT) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, threadPoolExecutor::getActiveCount) + .tags(ID, threadPoolName, STAGE, CURRENT_THREADS_BUSY) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, threadPoolExecutor::getMaximumPoolSize) + .tags(ID, threadPoolName, STAGE, MAX_THREADS) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, threadPoolExecutor::getPoolSize) + .tags(ID, threadPoolName, STAGE, POOL_SIZE) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, threadPoolExecutor::getCorePoolSize) + .tags(ID, threadPoolName, STAGE, CORE_POOL_SIZE) + .register(meterRegistry); + Gauge.builder(THREAD_POOL_METER, () -> threadPoolExecutor.getQueue().size()) + .tags(ID, threadPoolName, STAGE, QUEUE_SIZE) + .register(meterRegistry); + + if (threadPoolExecutor instanceof ThreadPoolExecutorEx) { + Gauge.builder(THREAD_POOL_METER, () -> ((ThreadPoolExecutorEx) (threadPoolExecutor)).getRejectedCount()) + .tags(ID, threadPoolName, STAGE, REJECTED_COUNT) + .register(meterRegistry); + } + } + + @Override + public void poll(long msNow, long secondInterval) { + long temp = threadPoolExecutor.getTaskCount(); + currentTask = temp - lastTask; + lastTask = temp; + + temp = threadPoolExecutor.getCompletedTaskCount(); + currentCompletedTask = temp - lastCompletedTask; + lastCompletedTask = temp; + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/EndpointMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/EndpointMeter.java index 8789a610763..e7f960b6d6d 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/EndpointMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/EndpointMeter.java @@ -16,14 +16,19 @@ */ package org.apache.servicecomb.metrics.core.meter.vertx; -import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; + +public class EndpointMeter implements PeriodMeter { + private static final double SNV_MILLI_SECONDS = 1.0 / TimeUnit.MILLISECONDS.toNanos(1L); -public class EndpointMeter { public static final String ADDRESS = "address"; public static final String STATISTIC = "statistic"; @@ -38,62 +43,126 @@ public class EndpointMeter { public static final String BYTES_WRITTEN = "bytesWritten"; - protected Id id; + public static final String REQUESTS = "requests"; - private Id idConnect; + public static final String LATENCY = "latency"; - private Id idDisconnect; + protected DefaultEndpointMetric metric; - private Id idConnections; + protected final MeterRegistry meterRegistry; - private Id idBytesRead; + private final Gauge connectCount; - private Id idBytesWritten; + private final Gauge disconnectCount; - protected DefaultEndpointMetric metric; + private final Gauge connections; + + private final Gauge bytesRead; + + private final Gauge bytesWritten; + + private final Gauge requests; + + private final Gauge latency; + + private long currentConnectCount; private long lastConnectCount; + private long currentDisconnectCount; + private long lastDisconnectCount; + private long currentBytesRead; + private long lastBytesRead; + private long currentBytesWritten; + private long lastBytesWritten; - public EndpointMeter(Id id, DefaultEndpointMetric metric) { - id = id.withTag(ADDRESS, metric.getAddress().toString()); - this.id = id; - idConnect = id.withTag(STATISTIC, CONNECT_COUNT); - idDisconnect = id.withTag(STATISTIC, DISCONNECT_COUNT); - idConnections = id.withTag(STATISTIC, CONNECTIONS); - idBytesRead = id.withTag(STATISTIC, BYTES_READ); - idBytesWritten = id.withTag(STATISTIC, BYTES_WRITTEN); + private long currentRequests; + + private long lastRequests; + + private long currentRequestsForLatency; + + private long lastRequestsForLatency; + + private long currentLatency; + + private long lastLatency; + + public EndpointMeter(MeterRegistry meterRegistry, String name, Tags tags, DefaultEndpointMetric metric) { + this.meterRegistry = meterRegistry; this.metric = metric; + + tags = tags.and(Tag.of(ADDRESS, metric.getAddress())); + connectCount = Gauge.builder(name, () -> currentConnectCount) + .tags(tags.and(Tag.of(STATISTIC, CONNECT_COUNT))) + .register(meterRegistry); + disconnectCount = Gauge.builder(name, () -> currentDisconnectCount) + .tags(tags.and(Tag.of(STATISTIC, DISCONNECT_COUNT))) + .register(meterRegistry); + connections = Gauge.builder(name, () -> this.metric.getConnectCount() - this.metric.getDisconnectCount()) + .tags(tags.and(Tag.of(STATISTIC, CONNECTIONS))) + .register(meterRegistry); + bytesRead = Gauge.builder(name, () -> currentBytesRead) + .tags(tags.and(Tag.of(STATISTIC, BYTES_READ))) + .register(meterRegistry); + bytesWritten = Gauge.builder(name, () -> currentBytesWritten) + .tags(tags.and(Tag.of(STATISTIC, BYTES_WRITTEN))) + .register(meterRegistry); + requests = Gauge.builder(name, () -> currentRequests) + .tags(tags.and(Tag.of(STATISTIC, REQUESTS))) + .register(meterRegistry); + latency = Gauge.builder(name, () -> currentRequestsForLatency == 0 ? 0 : + (currentLatency) / ((double) (currentRequestsForLatency)) * SNV_MILLI_SECONDS) + .tags(tags.and(Tag.of(STATISTIC, LATENCY))) + .register(meterRegistry); } public DefaultEndpointMetric getMetric() { return metric; } - protected Measurement newMeasurement(Id id, long timestamp, Number n) { - return new Measurement(id, timestamp, n.doubleValue()); + public void destroy() { + this.meterRegistry.remove(connectCount); + this.meterRegistry.remove(disconnectCount); + this.meterRegistry.remove(connections); + this.meterRegistry.remove(bytesRead); + this.meterRegistry.remove(bytesWritten); + this.meterRegistry.remove(requests); + this.meterRegistry.remove(latency); } - public void calcMeasurements(List measurements, long msNow, double secondInterval) { - long connectCount = metric.getConnectCount(); - long disconnectCount = metric.getDisconnectCount(); - long bytesRead = metric.getBytesRead(); - long bytesWritten = metric.getBytesWritten(); - - measurements.add(newMeasurement(idConnect, msNow, connectCount - lastConnectCount)); - measurements.add(newMeasurement(idDisconnect, msNow, disconnectCount - lastDisconnectCount)); - measurements.add(newMeasurement(idConnections, msNow, connectCount - disconnectCount)); - measurements.add(newMeasurement(idBytesRead, msNow, (bytesRead - lastBytesRead) / secondInterval)); - measurements.add(newMeasurement(idBytesWritten, msNow, (bytesWritten - lastBytesWritten) / secondInterval)); - - this.lastConnectCount = connectCount; - this.lastDisconnectCount = disconnectCount; - this.lastBytesRead = bytesRead; - this.lastBytesWritten = bytesWritten; + @Override + public void poll(long msNow, long secondInterval) { + long temp = metric.getConnectCount(); + currentConnectCount = temp - lastConnectCount; + lastConnectCount = temp; + + temp = metric.getDisconnectCount(); + currentDisconnectCount = temp - lastDisconnectCount; + lastDisconnectCount = temp; + + temp = metric.getBytesRead(); + currentBytesRead = temp - lastBytesRead; + lastBytesRead = temp; + + temp = metric.getBytesWritten(); + currentBytesWritten = temp - lastBytesWritten; + lastBytesWritten = temp; + + temp = metric.getRequests(); + currentRequests = temp - lastRequests; + lastRequests = temp; + + temp = metric.getRequests(); + currentRequestsForLatency = temp - lastRequestsForLatency; + lastRequestsForLatency = temp; + temp = metric.getLatency(); + currentLatency = temp - lastLatency; + lastLatency = temp; } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointMeter.java new file mode 100644 index 00000000000..a8e75dc013f --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointMeter.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.vertx; + +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetric; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; + +public class HttpClientEndpointMeter extends EndpointMeter { + public static final String QUEUE_COUNT = "queueCount"; + + private final Gauge queueCount; + + private long currentQueueCount; + + public HttpClientEndpointMeter(MeterRegistry meterRegistry, String name, Tags tags, DefaultEndpointMetric metric) { + super(meterRegistry, name, tags, metric); + queueCount = Gauge.builder(name, () -> currentQueueCount) + .tags(tags.and(Tag.of(STATISTIC, QUEUE_COUNT), Tag.of(ADDRESS, metric.getAddress()))) + .register(meterRegistry); + } + + @Override + public void destroy() { + super.destroy(); + this.meterRegistry.remove(queueCount); + } + + @Override + public void poll(long msNow, long secondInterval) { + super.poll(msNow, secondInterval); + + currentQueueCount = ((DefaultClientEndpointMetric) metric).getQueueCount(); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointsMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointsMeter.java new file mode 100644 index 00000000000..f68f8413cc5 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/HttpClientEndpointsMeter.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.vertx; + +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultClientEndpointMetricManager; +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; + +public class HttpClientEndpointsMeter extends VertxEndpointsMeter { + public HttpClientEndpointsMeter(MeterRegistry meterRegistry, String name, Tags tags, + DefaultClientEndpointMetricManager clientEndpointMetricManager) { + super(meterRegistry, name, tags, clientEndpointMetricManager.getClientEndpointMetricMap()); + } + + @Override + protected EndpointMeter createEndpointMeter(DefaultEndpointMetric metric) { + return new HttpClientEndpointMeter(meterRegistry, name, tags, metric); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointMeter.java index 300fe0398cc..bee385ef9b5 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointMeter.java @@ -16,33 +16,42 @@ */ package org.apache.servicecomb.metrics.core.meter.vertx; -import java.util.List; - import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; public class ServerEndpointMeter extends EndpointMeter { public static final String REJECT_BY_CONNECTION_LIMIT = "rejectByConnectionLimit"; - private Id idRejectByConnectionLimit; + private final Gauge rejectByConnectionLimit; private long lastRejectByConnectionLimit; - public ServerEndpointMeter(Id id, DefaultEndpointMetric metric) { - super(id, metric); - idRejectByConnectionLimit = this.id.withTag(STATISTIC, REJECT_BY_CONNECTION_LIMIT); + private long currentRejectByConnectionLimit; + + public ServerEndpointMeter(MeterRegistry meterRegistry, String name, Tags tags, DefaultEndpointMetric metric) { + super(meterRegistry, name, tags, metric); + rejectByConnectionLimit = Gauge.builder(name, () -> currentRejectByConnectionLimit) + .tags(tags.and(Tag.of(STATISTIC, REJECT_BY_CONNECTION_LIMIT), Tag.of(ADDRESS, metric.getAddress()))) + .register(meterRegistry); + } + + @Override + public void destroy() { + super.destroy(); + this.meterRegistry.remove(rejectByConnectionLimit); } @Override - public void calcMeasurements(List measurements, long msNow, double secondInterval) { - super.calcMeasurements(measurements, msNow, secondInterval); + public void poll(long msNow, long secondInterval) { + super.poll(msNow, secondInterval); - long rejectByConnectionLimit = ((DefaultServerEndpointMetric) metric).getRejectByConnectionLimitCount(); - measurements - .add(newMeasurement(idRejectByConnectionLimit, msNow, rejectByConnectionLimit - lastRejectByConnectionLimit)); - this.lastRejectByConnectionLimit = rejectByConnectionLimit; + long current = ((DefaultServerEndpointMetric) metric).getRejectByConnectionLimitCount(); + currentRejectByConnectionLimit = current - lastRejectByConnectionLimit; + lastRejectByConnectionLimit = current; } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointsMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointsMeter.java new file mode 100644 index 00000000000..11f5a706523 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/ServerEndpointsMeter.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.vertx; + +import java.util.Map; + +import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; + +public class ServerEndpointsMeter extends VertxEndpointsMeter { + public ServerEndpointsMeter(MeterRegistry meterRegistry, String name, Tags tags, + Map endpointMetricMap) { + super(meterRegistry, name, tags, endpointMetricMap); + } + + @Override + protected EndpointMeter createEndpointMeter(DefaultEndpointMetric metric) { + return new ServerEndpointMeter(meterRegistry, name, tags, metric); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxEndpointsMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxEndpointsMeter.java index abf25d187f8..fd4d10f0d41 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxEndpointsMeter.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxEndpointsMeter.java @@ -16,68 +16,55 @@ */ package org.apache.servicecomb.metrics.core.meter.vertx; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.metrics.meter.AbstractPeriodMeter; +import org.apache.servicecomb.foundation.metrics.meter.PeriodMeter; import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; -import io.vertx.core.net.SocketAddress; +public class VertxEndpointsMeter implements PeriodMeter { + private final Map endpointMetricMap; -public class VertxEndpointsMeter extends AbstractPeriodMeter { - private Map endpointMetricMap; + protected final MeterRegistry meterRegistry; - private Map endpointMeterMap = new ConcurrentHashMapEx<>(); + protected final String name; - @SuppressWarnings("unchecked") - public VertxEndpointsMeter(Id id, Map endpointMetricMap) { - this.id = id; - this.endpointMetricMap = (Map) endpointMetricMap; - } - - @Override - public void calcMeasurements(long msNow, long secondInterval) { - List measurements = new ArrayList<>(); - calcMeasurements(measurements, msNow, secondInterval); - allMeasurements = measurements; - } + protected final Tags tags; - @Override - public void calcMeasurements(List measurements, long msNow, long secondInterval) { - syncMeters(); + private final Map endpointMeterMap = new ConcurrentHashMapEx<>(); - for (EndpointMeter meter : endpointMeterMap.values()) { - meter.calcMeasurements(measurements, msNow, secondInterval); - } + @SuppressWarnings("unchecked") + public VertxEndpointsMeter(MeterRegistry meterRegistry, String name, Tags tags, + Map endpointMetricMap) { + this.meterRegistry = meterRegistry; + this.name = name; + this.tags = tags; + this.endpointMetricMap = (Map) endpointMetricMap; } - private void syncMeters() { + private void syncMeters(long msNow, long secondInterval) { for (EndpointMeter meter : endpointMeterMap.values()) { if (!endpointMetricMap.containsKey(meter.getMetric().getAddress())) { - endpointMeterMap.remove(meter.getMetric().getAddress()); + EndpointMeter removed = endpointMeterMap.remove(meter.getMetric().getAddress()); + removed.destroy(); } } for (DefaultEndpointMetric metric : endpointMetricMap.values()) { - endpointMeterMap.computeIfAbsent(metric.getAddress(), addr -> createEndpointMeter(id, metric)); + EndpointMeter updated = endpointMeterMap.computeIfAbsent(metric.getAddress(), + address -> createEndpointMeter(metric)); + updated.poll(msNow, secondInterval); } } - protected EndpointMeter createEndpointMeter(Id id, DefaultEndpointMetric metric) { - return new EndpointMeter(id, metric); - } - - @Override - public Iterable measure() { - return allMeasurements; + protected EndpointMeter createEndpointMeter(DefaultEndpointMetric metric) { + return new EndpointMeter(meterRegistry, name, tags, metric); } @Override - public boolean hasExpired() { - return false; + public void poll(long msNow, long secondInterval) { + syncMeters(msNow, secondInterval); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxServerEndpointsMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxServerEndpointsMeter.java deleted file mode 100644 index 1def3b23200..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/vertx/VertxServerEndpointsMeter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.vertx; - -import java.util.Map; - -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; - -import com.netflix.spectator.api.Id; - -import io.vertx.core.net.SocketAddress; - -public class VertxServerEndpointsMeter extends VertxEndpointsMeter { - public VertxServerEndpointsMeter( - Id id, Map endpointMetricMap) { - super(id, endpointMetricMap); - } - - @Override - protected EndpointMeter createEndpointMeter(Id id, DefaultEndpointMetric metric) { - return new ServerEndpointMeter(id, metric); - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java index 960c7b692c9..cba8e334ce9 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java @@ -16,15 +16,15 @@ */ package org.apache.servicecomb.metrics.core.publish; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; public abstract class AbstractMeasurementNodeLogPublisher { protected StringBuilder sb; protected MeasurementNode measurementNode; - private boolean exists; + private final boolean exists; public AbstractMeasurementNodeLogPublisher(MeasurementTree tree, StringBuilder sb, String... childNames) { this.sb = sb; diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ClientEndpointsLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ClientEndpointsLogPublisher.java index c49d4f0548f..0669283fc73 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ClientEndpointsLogPublisher.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ClientEndpointsLogPublisher.java @@ -18,11 +18,15 @@ import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; +import java.util.ArrayList; +import java.util.List; + import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.VertxMetersInitializer; import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; +import org.apache.servicecomb.metrics.core.meter.vertx.HttpClientEndpointMeter; public class ClientEndpointsLogPublisher extends AbstractMeasurementNodeLogPublisher { public ClientEndpointsLogPublisher(MeasurementTree tree, StringBuilder sb, String meterName) { @@ -31,40 +35,28 @@ public ClientEndpointsLogPublisher(MeasurementTree tree, StringBuilder sb, Strin @Override public void print(boolean printDetail) { + if (!printDetail) { + return; + } appendLine(sb, " client.endpoints:"); - appendLine(sb, " remote connectCount disconnectCount connections send(Bps) receive(Bps)"); + appendLine(sb, + " connectCount disconnectCount queue connections requests latency send(Bps) receive(Bps) remote"); - double connect = 0; - double disconnect = 0; - double connections = 0; - double readSize = 0; - double writeSize = 0; - for (MeasurementNode address : measurementNode.getChildren().values()) { - connect += address.findChild(EndpointMeter.CONNECT_COUNT).summary(); - disconnect += address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(); - connections += address.findChild(EndpointMeter.CONNECTIONS).summary(); - readSize += address.findChild(EndpointMeter.BYTES_READ).summary(); - writeSize += address.findChild(EndpointMeter.BYTES_WRITTEN).summary(); - - if (printDetail) { - appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12s %-12s", - address.getName(), - address.findChild(EndpointMeter.CONNECT_COUNT).summary(), - address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(), - address.findChild(EndpointMeter.CONNECTIONS).summary(), - NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_WRITTEN).summary()), - NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_READ).summary()) - ); - } + List measurements = new ArrayList<>(measurementNode.getChildren().size()); + measurements.addAll(measurementNode.getChildren().values()); + measurements.sort(MeasurementNode::compareTo); + for (MeasurementNode address : measurements) { + appendLine(sb, " %-12.0f %-15.0f %-13.0f %-11.0f %-8.0f %-7.0f %-9s %-12s %s", + address.findChild(EndpointMeter.CONNECT_COUNT).summary(), + address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(), + address.findChild(HttpClientEndpointMeter.QUEUE_COUNT).summary(), + address.findChild(EndpointMeter.CONNECTIONS).summary(), + address.findChild(EndpointMeter.REQUESTS).summary(), + address.findChild(EndpointMeter.LATENCY).summary(), + NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_WRITTEN).summary()), + NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_READ).summary()), + address.getName() + ); } - - appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12s %-12s", - "(summary)", - connect, - disconnect, - connections, - NetUtils.humanReadableBytes((long) writeSize), - NetUtils.humanReadableBytes((long) readSize) - ); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java index 7b3b48841ed..73327df1385 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java @@ -22,19 +22,20 @@ import java.util.Map; import java.util.Map.Entry; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; import org.apache.servicecomb.foundation.common.net.NetUtils; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; import org.apache.servicecomb.foundation.metrics.PolledEvent; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.foundation.metrics.meter.LatencyDistributionConfig; +import org.apache.servicecomb.foundation.metrics.meter.LatencyScopeConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.metrics.core.VertxMetersInitializer; -import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; -import org.apache.servicecomb.metrics.core.meter.os.CpuMeter; import org.apache.servicecomb.metrics.core.meter.os.NetMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; +import org.apache.servicecomb.metrics.core.meter.os.SystemMeter; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; import org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf; @@ -43,57 +44,95 @@ import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import com.google.common.base.Strings; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.spectator.api.Meter; -import io.vertx.core.impl.VertxImplEx; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; +import io.vertx.core.Vertx; public class DefaultLogPublisher implements MetricsInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLogPublisher.class); + private static final Logger LOGGER = LoggerFactory.getLogger("scb-metrics"); public static final String ENABLED = "servicecomb.metrics.publisher.defaultLog.enabled"; // for a client, maybe will connect to too many endpoints, so default not print detail, just print summary public static final String ENDPOINTS_CLIENT_DETAIL_ENABLED = "servicecomb.metrics.publisher.defaultLog.endpoints.client.detail.enabled"; - //sample - private static final String SIMPLE_HEADER = "%s:\n simple:\n" - + " status tps latency operation\n"; + private static final String FIRST_LINE_SIMPLE_FORMAT = " %-11s\n"; - private static final String FIRST_LINE_SIMPLE_FORMAT = " %-15s %-8s %-19s %s\n"; - - private static final String SIMPLE_FORMAT = " %-8s %-19s %s\n"; + private static final String SIMPLE_FORMAT = " %-8.1f %-18s %s%s\n"; //details private static final String PRODUCER_DETAILS_FORMAT = "" - + " prepare: %-19s queue : %-19s filtersReq : %-19s handlersReq: %s\n" - + " execute: %-19s handlersResp: %-19s filtersResp: %-19s sendResp : %s\n"; + + " prepare: %-18s decode-request : %-18s queue : %-18s business-execute: %s\n" + + " encode-response: %-18s send: %-18s\n"; private static final String CONSUMER_DETAILS_FORMAT = "" - + " prepare : %-19s handlersReq : %-19s cFiltersReq: %-19s sendReq : %s\n" - + " getConnect : %-19s writeBuf : %-19s waitResp : %-19s wakeConsumer: %s\n" - + " cFiltersResp: %-19s handlersResp: %s\n"; + + " prepare : %-18s connection : %-18s encode-request: %-18s send : %s\n" + + " wait : %-18s decode-response : %-18s\n"; private static final String EDGE_DETAILS_FORMAT = "" - + " prepare : %-19s queue : %-19s sFiltersReq : %-19s handlersReq : %s\n" - + " cFiltersReq : %-19s sendReq : %-19s getConnect : %-19s writeBuf : %s\n" - + " waitResp : %-19s wakeConsumer: %-19s cFiltersResp: %-19s handlersResp: %s\n" - + " sFiltersResp: %-19s sendResp : %s\n"; + + " prepare : %-18s provider-decode : %-18s connection : %-18s consumer-encode : %s\n" + + " consumer-send : %-18s wait : %-18s consumer-decode : %-18s provider-encode : %s\n" + + " provider-send : %-18s\n"; + + private LatencyDistributionConfig latencyDistributionConfig; + + /** + * if config is 0,1,10,100 then header will be:
+ * [0,1) [1,10) [10,100) [100,) + */ + private String latencyDistributionHeader = ""; + + /** + * if config is 0,1,10,100 then format will be:
+ * %-7d %-7d %-9d %-7d + */ + private String latencyDistributionFormat = ""; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - if (!DynamicPropertyFactory.getInstance() - .getBooleanProperty(ENABLED, false) - .get()) { + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + if (!environment.getProperty(ENABLED, boolean.class, false)) { return; } + initLatencyDistribution(config); + eventBus.register(this); } + private void initLatencyDistribution(MetricsBootstrapConfig config) { + // default length is 7 which include a space, one minute 999999 requests, TPS is 16666, mostly it's enough + int leastLatencyScopeStrLength = config.getMinScopeLength(); + + latencyDistributionConfig = new LatencyDistributionConfig(config.getLatencyDistribution()); + String header; + for (LatencyScopeConfig scopeConfig : latencyDistributionConfig.getScopeConfigs()) { + if (scopeConfig.getMsMax() == LatencyDistributionConfig.MAX_LATENCY) { + header = String.format("[%d,) ", scopeConfig.getMsMin()); + } else { + header = String.format("[%d,%d) ", scopeConfig.getMsMin(), scopeConfig.getMsMax()); + } + header = Strings.padEnd(header, leastLatencyScopeStrLength, ' '); + latencyDistributionHeader += header; + + String format = "%-" + (header.length() - 1) + "d "; + latencyDistributionFormat += format; + } + } + @Subscribe public void onPolledEvent(PolledEvent event) { try { @@ -107,7 +146,6 @@ public void onPolledEvent(PolledEvent event) { protected void printLog(List meters) { StringBuilder sb = new StringBuilder(); sb.append("\n"); - PublishModelFactory factory = new PublishModelFactory(meters); DefaultPublishModel model = factory.createDefaultPublishModel(); @@ -144,14 +182,13 @@ private void printNetLog(StringBuilder sb, MeasurementNode osNode) { StringBuilder tmpSb = new StringBuilder(); for (MeasurementNode interfaceNode : netNode.getChildren().values()) { - double sendRate = interfaceNode.findChild(NetMeter.TAG_SEND.value()).summary(); - double sendPacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_SEND.value()).summary(); - double receiveRate = interfaceNode.findChild(NetMeter.TAG_RECEIVE.value()).summary(); - double receivePacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_RECEIVE.value()).summary(); + double sendRate = interfaceNode.findChild(NetMeter.TAG_SEND.getValue()).summary(); + double sendPacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_SEND.getValue()).summary(); + double receiveRate = interfaceNode.findChild(NetMeter.TAG_RECEIVE.getValue()).summary(); + double receivePacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_RECEIVE.getValue()).summary(); if (sendRate == 0 && receiveRate == 0 && receivePacketsRate == 0 && sendPacketsRate == 0) { continue; } - appendLine(tmpSb, " %-12s %-12s %-12s %-12s %s", NetUtils.humanReadableBytes((long) sendRate), NetUtils.humanReadableBytes((long) receiveRate), @@ -160,40 +197,35 @@ private void printNetLog(StringBuilder sb, MeasurementNode osNode) { interfaceNode.getName()); } if (tmpSb.length() != 0) { - sb.append(tmpSb.toString()); + sb.append(tmpSb); } } private void printCpuLog(StringBuilder sb, MeasurementNode osNode) { - MeasurementNode cpuNode = osNode.findChild(OsMeter.OS_TYPE_ALL_CPU); - MeasurementNode processNode = osNode.findChild(OsMeter.OS_TYPE_PROCESS_CPU); - if (cpuNode == null || cpuNode.getMeasurements().isEmpty() || - processNode == null || processNode.getMeasurements().isEmpty()) { - return; - } - - double allRate = cpuNode.summary(); - double processRate = processNode.summary(); - + MeasurementNode cpuNode = osNode.findChild(SystemMeter.CPU_USAGE); + MeasurementNode processNode = osNode.findChild(SystemMeter.PROCESS_CPU_USAGE); + MeasurementNode memoryNode = osNode.findChild(SystemMeter.MEMORY_USAGE); + MeasurementNode slaNode = osNode.findChild(SystemMeter.SYSTEM_LOAD_AVERAGE); appendLine(sb, " cpu:"); - appendLine(sb, " all: %.2f%% process: %.2f%%", allRate * 100, processRate * 100); + appendLine(sb, " all usage: %.2f%% process usage: %.2f%% sla: %.2f memory usage: %.2f%%", + cpuNode.summary() * 100, processNode.summary() * 100, + slaNode.summary(), memoryNode.summary() * 100); } - protected void printThreadPoolMetrics(DefaultPublishModel model, StringBuilder sb) { if (model.getThreadPools().isEmpty()) { return; } - sb.append("threadPool:\n"); - sb.append(" corePoolSize maxThreads poolSize currentThreadsBusy queueSize taskCount completedTaskCount name\n"); + sb.append(" coreSize maxThreads poolSize currentBusy rejected queueSize taskCount taskFinished name\n"); for (Entry entry : model.getThreadPools().entrySet()) { ThreadPoolPublishModel threadPoolPublishModel = entry.getValue(); - sb.append(String.format(" %-12d %-10d %-8d %-18d %-9d %-9.1f %-18.1f %s\n", + sb.append(String.format(" %-8d %-10d %-8d %-11d %-8.0f %-9d %-9.1f %-12.1f %s\n", threadPoolPublishModel.getCorePoolSize(), threadPoolPublishModel.getMaxThreads(), threadPoolPublishModel.getPoolSize(), threadPoolPublishModel.getCurrentThreadsBusy(), + threadPoolPublishModel.getRejected(), threadPoolPublishModel.getQueueSize(), threadPoolPublishModel.getAvgTaskCount(), threadPoolPublishModel.getAvgCompletedTaskCount(), @@ -206,8 +238,12 @@ protected void printEdgeLog(DefaultPublishModel model, StringBuilder sb) { if (edgePerf == null) { return; } - sb.append(String.format(SIMPLE_HEADER, "edge")); - + sb.append("" + + "edge:\n" + + " simple:\n" + + " status requests latency ") + .append(latencyDistributionHeader) + .append("operation\n"); StringBuilder detailsBuilder = new StringBuilder(); //print sample for (Map statusMap : edgePerf.getGroups().values()) { @@ -218,20 +254,20 @@ protected void printEdgeLog(DefaultPublishModel model, StringBuilder sb) { detailsBuilder.append(printEdgeDetailsPerf(perfGroup)); } } - - sb.append(" details:\n") - .append(detailsBuilder); + sb.append(" details:\n").append(detailsBuilder); } - protected void printConsumerLog(DefaultPublishModel model, StringBuilder sb) { OperationPerfGroups consumerPerf = model.getConsumer().getOperationPerfGroups(); if (consumerPerf == null) { return; } - - sb.append(String.format(SIMPLE_HEADER, "consumer")); - + sb.append("" + + "consumer:\n" + + " simple:\n" + + " status requests latency ") + .append(latencyDistributionHeader) + .append("operation\n"); StringBuilder detailsBuilder = new StringBuilder(); //print sample for (Map statusMap : consumerPerf.getGroups().values()) { @@ -242,18 +278,20 @@ protected void printConsumerLog(DefaultPublishModel model, StringBuilder sb) { detailsBuilder.append(printConsumerDetailsPerf(perfGroup)); } } - sb.append(" details:\n") - .append(detailsBuilder); + sb.append(" details:\n").append(detailsBuilder); } - protected void printProducerLog(DefaultPublishModel model, StringBuilder sb) { OperationPerfGroups producerPerf = model.getProducer().getOperationPerfGroups(); - if (producerPerf == null) { return; } - sb.append(String.format(SIMPLE_HEADER, "producer")); + sb.append("" + + "producer:\n" + + " simple:\n" + + " status requests latency ") + .append(latencyDistributionHeader) + .append("operation\n"); // use detailsBuilder, we can traverse the map only once StringBuilder detailsBuilder = new StringBuilder(); //print sample @@ -266,65 +304,68 @@ protected void printProducerLog(DefaultPublishModel model, StringBuilder sb) { } } //print details - sb.append(" details:\n") - .append(detailsBuilder); + sb.append(" details:\n").append(detailsBuilder); } - private StringBuilder printSamplePerf(OperationPerfGroup perfGroup) { StringBuilder sb = new StringBuilder(); + String status = perfGroup.getTransport() + "." + perfGroup.getStatus() + ":"; + sb.append(String.format(FIRST_LINE_SIMPLE_FORMAT, status)); + for (int i = 0; i < perfGroup.getOperationPerfs().size(); i++) { OperationPerf operationPerf = perfGroup.getOperationPerfs().get(i); - PerfInfo stageTotal = operationPerf.findStage(MeterInvocationConst.STAGE_TOTAL); - if (i == 0) { - // first line - String status = perfGroup.getTransport() + "." + perfGroup.getStatus(); - sb.append(String.format(FIRST_LINE_SIMPLE_FORMAT, status, stageTotal.getTps(), - getDetailsFromPerf(stageTotal), operationPerf.getOperation())); - } else { - sb.append(String - .format(SIMPLE_FORMAT, stageTotal.getTps(), getDetailsFromPerf(stageTotal), operationPerf.getOperation())); + if (isIgnoreEmptyPerf(operationPerf)) { + continue; } + PerfInfo stageTotal = operationPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + sb.append(String.format(SIMPLE_FORMAT, stageTotal.getTotalRequests(), + getDetailsFromPerf(stageTotal), + formatLatencyDistribution(operationPerf), + operationPerf.getOperation())); } - //print summary OperationPerf summaryOperation = perfGroup.getSummary(); - PerfInfo stageSummaryTotal = summaryOperation.findStage(MeterInvocationConst.STAGE_TOTAL); - sb.append( - String.format(SIMPLE_FORMAT, stageSummaryTotal.getTps(), getDetailsFromPerf(stageSummaryTotal), "(summary)")); + PerfInfo stageSummaryTotal = summaryOperation.findStage(InvocationStageTrace.STAGE_TOTAL); + //print summary + sb.append(String.format(SIMPLE_FORMAT, stageSummaryTotal.getTotalRequests(), + getDetailsFromPerf(stageSummaryTotal), + formatLatencyDistribution(summaryOperation), + "(summary)")); return sb; } + private String formatLatencyDistribution(OperationPerf operationPerf) { + return String.format(latencyDistributionFormat, (Object[]) operationPerf.getLatencyDistribution()); + } + private StringBuilder printProducerDetailsPerf(OperationPerfGroup perfGroup) { StringBuilder sb = new StringBuilder(); - //append rest.200: + //append rest."200": sb.append(" ") .append(perfGroup.getTransport()) .append(".") .append(perfGroup.getStatus()) .append(":\n"); - PerfInfo prepare, queue, filtersReq, handlersReq, execute, handlersResp, filtersResp, sendResp; + PerfInfo prepare, queue, providerDecode, providerEncode, execute, sendResp; for (OperationPerf operationPerf : perfGroup.getOperationPerfs()) { - - prepare = operationPerf.findStage(MeterInvocationConst.STAGE_PREPARE); - queue = operationPerf.findStage(MeterInvocationConst.STAGE_EXECUTOR_QUEUE); - filtersReq = operationPerf.findStage(MeterInvocationConst.STAGE_SERVER_FILTERS_REQUEST); - handlersReq = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_REQUEST); - execute = operationPerf.findStage(MeterInvocationConst.STAGE_EXECUTION); - handlersResp = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_RESPONSE); - filtersResp = operationPerf.findStage(MeterInvocationConst.STAGE_SERVER_FILTERS_RESPONSE); - sendResp = operationPerf.findStage(MeterInvocationConst.STAGE_PRODUCER_SEND_RESPONSE); + if (isIgnoreEmptyPerf(operationPerf)) { + continue; + } + prepare = operationPerf.findStage(InvocationStageTrace.STAGE_PREPARE); + queue = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_QUEUE); + providerDecode = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST); + providerEncode = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE); + execute = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_BUSINESS); + sendResp = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_SEND); sb.append(" ") .append(operationPerf.getOperation()) .append(":\n") .append(String.format(PRODUCER_DETAILS_FORMAT, getDetailsFromPerf(prepare), + getDetailsFromPerf(providerDecode), getDetailsFromPerf(queue), - getDetailsFromPerf(filtersReq), - getDetailsFromPerf(handlersReq), getDetailsFromPerf(execute), - getDetailsFromPerf(handlersResp), - getDetailsFromPerf(filtersResp), + getDetailsFromPerf(providerEncode), getDetailsFromPerf(sendResp) )); } @@ -334,42 +375,36 @@ private StringBuilder printProducerDetailsPerf(OperationPerfGroup perfGroup) { private StringBuilder printConsumerDetailsPerf(OperationPerfGroup perfGroup) { StringBuilder sb = new StringBuilder(); - //append rest.200: + //append rest."200": sb.append(" ") .append(perfGroup.getTransport()) .append(".") .append(perfGroup.getStatus()) .append(":\n"); - PerfInfo prepare, handlersReq, clientFiltersReq, sendReq, getConnect, writeBuf, - waitResp, wakeConsumer, clientFiltersResp, handlersResp; + PerfInfo prepare, encodeRequest, decodeResponse, sendReq, getConnect, + waitResp; for (OperationPerf operationPerf : perfGroup.getOperationPerfs()) { - - prepare = operationPerf.findStage(MeterInvocationConst.STAGE_PREPARE); - handlersReq = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_REQUEST); - clientFiltersReq = operationPerf.findStage(MeterInvocationConst.STAGE_CLIENT_FILTERS_REQUEST); - sendReq = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_SEND_REQUEST); - getConnect = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_GET_CONNECTION); - writeBuf = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WRITE_TO_BUF); - waitResp = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WAIT_RESPONSE); - wakeConsumer = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WAKE_CONSUMER); - clientFiltersResp = operationPerf.findStage(MeterInvocationConst.STAGE_CLIENT_FILTERS_RESPONSE); - handlersResp = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_RESPONSE); + if (isIgnoreEmptyPerf(operationPerf)) { + continue; + } + prepare = operationPerf.findStage(InvocationStageTrace.STAGE_PREPARE); + encodeRequest = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST); + decodeResponse = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE); + sendReq = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_SEND); + getConnect = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_CONNECTION); + waitResp = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_WAIT); sb.append(" ") .append(operationPerf.getOperation()) .append(":\n") .append(String.format(CONSUMER_DETAILS_FORMAT, getDetailsFromPerf(prepare), - getDetailsFromPerf(handlersReq), - getDetailsFromPerf(clientFiltersReq), - getDetailsFromPerf(sendReq), getDetailsFromPerf(getConnect), - getDetailsFromPerf(writeBuf), + getDetailsFromPerf(encodeRequest), + getDetailsFromPerf(sendReq), getDetailsFromPerf(waitResp), - getDetailsFromPerf(wakeConsumer), - getDetailsFromPerf(clientFiltersResp), - getDetailsFromPerf(handlersResp) + getDetailsFromPerf(decodeResponse) )); } @@ -378,48 +413,42 @@ private StringBuilder printConsumerDetailsPerf(OperationPerfGroup perfGroup) { private StringBuilder printEdgeDetailsPerf(OperationPerfGroup perfGroup) { StringBuilder sb = new StringBuilder(); - //append rest.200: + //append rest."200": sb.append(" ") .append(perfGroup.getTransport()) .append(".") .append(perfGroup.getStatus()) .append(":\n"); - PerfInfo prepare, queue, serverFiltersReq, handlersReq, clientFiltersReq, sendReq, getConnect, writeBuf, - waitResp, wakeConsumer, clientFiltersResp, handlersResp, serverFiltersResp, sendResp; + PerfInfo prepare, connection, decodeProviderRequest, encodeProviderResponse, + encodeConsumerRequest, decodeConsumerResponse, sendReq, getConnect, + waitResp, sendResp; for (OperationPerf operationPerf : perfGroup.getOperationPerfs()) { - prepare = operationPerf.findStage(MeterInvocationConst.STAGE_PREPARE); - queue = operationPerf.findStage(MeterInvocationConst.STAGE_EXECUTOR_QUEUE); - serverFiltersReq = operationPerf.findStage(MeterInvocationConst.STAGE_SERVER_FILTERS_REQUEST); - handlersReq = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_REQUEST); - clientFiltersReq = operationPerf.findStage(MeterInvocationConst.STAGE_CLIENT_FILTERS_REQUEST); - sendReq = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_SEND_REQUEST); - getConnect = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_GET_CONNECTION); - writeBuf = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WRITE_TO_BUF); - waitResp = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WAIT_RESPONSE); - wakeConsumer = operationPerf.findStage(MeterInvocationConst.STAGE_CONSUMER_WAKE_CONSUMER); - clientFiltersResp = operationPerf.findStage(MeterInvocationConst.STAGE_CLIENT_FILTERS_RESPONSE); - handlersResp = operationPerf.findStage(MeterInvocationConst.STAGE_HANDLERS_RESPONSE); - serverFiltersResp = operationPerf.findStage(MeterInvocationConst.STAGE_SERVER_FILTERS_RESPONSE); - sendResp = operationPerf.findStage(MeterInvocationConst.STAGE_PRODUCER_SEND_RESPONSE); + if (isIgnoreEmptyPerf(operationPerf)) { + continue; + } + prepare = operationPerf.findStage(InvocationStageTrace.STAGE_PREPARE); + connection = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_CONNECTION); + decodeProviderRequest = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST); + encodeProviderResponse = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE); + encodeConsumerRequest = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST); + sendReq = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_SEND); + decodeConsumerResponse = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE); + waitResp = operationPerf.findStage(InvocationStageTrace.STAGE_CONSUMER_WAIT); + sendResp = operationPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_SEND); sb.append(" ") .append(operationPerf.getOperation()) .append(":\n") .append(String.format(EDGE_DETAILS_FORMAT, getDetailsFromPerf(prepare), - getDetailsFromPerf(queue), - getDetailsFromPerf(serverFiltersReq), - getDetailsFromPerf(handlersReq), - getDetailsFromPerf(clientFiltersReq), + getDetailsFromPerf(decodeProviderRequest), + getDetailsFromPerf(connection), + getDetailsFromPerf(encodeConsumerRequest), getDetailsFromPerf(sendReq), - getDetailsFromPerf(getConnect), - getDetailsFromPerf(writeBuf), getDetailsFromPerf(waitResp), - getDetailsFromPerf(wakeConsumer), - getDetailsFromPerf(clientFiltersResp), - getDetailsFromPerf(handlersResp), - getDetailsFromPerf(serverFiltersResp), + getDetailsFromPerf(decodeConsumerResponse), + getDetailsFromPerf(encodeProviderResponse), getDetailsFromPerf(sendResp) )); } @@ -427,28 +456,36 @@ private StringBuilder printEdgeDetailsPerf(OperationPerfGroup perfGroup) { return sb; } + private boolean isIgnoreEmptyPerf(OperationPerf operationPerf) { + PerfInfo stageTotal = operationPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + // max latency is calculated in ring algorithm, maybe not 0 + if (Double.compare(0D, stageTotal.getTotalRequests()) == 0 + && Double.compare(0D, stageTotal.getMsMaxLatency()) == 0) { + return true; + } + return false; + } + protected void printVertxMetrics(MeasurementTree tree, StringBuilder sb) { appendLine(sb, "vertx:"); appendLine(sb, " instances:"); appendLine(sb, " name eventLoopContext-created"); - for (Entry entry : VertxUtils.getVertxMap().entrySet()) { + for (Entry entry : VertxUtils.getVertxMap().entrySet()) { appendLine(sb, " %-10s %d", entry.getKey(), - entry.getValue().getEventLoopContextCreatedCount()); + // TODO will be fixed by next vertx update.entry.getValue().getEventLoopContextCreatedCount() + 0); } ClientEndpointsLogPublisher client = new ClientEndpointsLogPublisher(tree, sb, - VertxMetersInitializer.ENDPOINTS_CLINET); + VertxMetersInitializer.ENDPOINTS_CLIENT); ServerEndpointsLogPublisher server = new ServerEndpointsLogPublisher(tree, sb, VertxMetersInitializer.ENDPOINTS_SERVER); if (client.isExists() || server.isExists()) { appendLine(sb, " transport:"); if (client.isExists()) { - client.print(DynamicPropertyFactory - .getInstance() - .getBooleanProperty(ENDPOINTS_CLIENT_DETAIL_ENABLED, false) - .get()); + client.print(environment.getProperty(ENDPOINTS_CLIENT_DETAIL_ENABLED, boolean.class, true)); } if (server.isExists()) { diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/HealthCheckerRestPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/HealthCheckerRestPublisher.java deleted file mode 100644 index ccc76438ef8..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/HealthCheckerRestPublisher.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.metrics.core.publish; - -import java.util.Map; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; -import org.apache.servicecomb.foundation.metrics.health.HealthCheckerManager; - -@Path("/health") -public class HealthCheckerRestPublisher { - @Path("/") - @GET - public boolean checkHealth() { - Map results = HealthCheckerManager.getInstance().check(); - for (HealthCheckResult result : results.values()) { - if (!result.isHealthy()) { - return false; - } - } - return true; - } - - @Path("/details") - @GET - public Map checkHealthDetails() { - return HealthCheckerManager.getInstance().check(); - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/MetricsRestPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/MetricsRestPublisher.java deleted file mode 100644 index 629b171b7b7..00000000000 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/MetricsRestPublisher.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.metrics.core.publish; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; - -import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Registry; - -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Path("/metrics") -public class MetricsRestPublisher implements MetricsInitializer { - private GlobalRegistry globalRegistry; - - @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - this.globalRegistry = globalRegistry; - } - - @ApiResponses({ - @ApiResponse(code = 400, response = String.class, message = "illegal request content"), - }) - @GET - @Path("/") - public Map measure() { - Map measurements = new LinkedHashMap<>(); - if (globalRegistry == null) { - return measurements; - } - - StringBuilder sb = new StringBuilder(); - for (Registry registry : globalRegistry.getRegistries()) { - for (Meter meter : registry) { - meter.measure().forEach(measurement -> { - String key = idToString(measurement.id(), sb); - measurements.put(key, measurement.value()); - }); - } - } - - return measurements; - } - - // format id to string: - // idName(tag1=value1,tag2=value2) - protected String idToString(Id id, StringBuilder sb) { - sb.setLength(0); - sb.append(id.name()).append('('); - sb.append(StreamSupport - .stream(id - .tags() - .spliterator(), false) - .map(Object::toString) - .collect( - Collectors.joining(","))); - sb.append(')'); - - return sb.toString(); - } -} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java index 9b94ba3f33e..7fb9ad43cda 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java @@ -18,24 +18,25 @@ import java.util.List; -import org.apache.servicecomb.foundation.metrics.publish.spectator.DefaultTagFinder; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementGroupConfig; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.foundation.metrics.publish.DefaultTagFinder; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.VertxMetersInitializer; +import org.apache.servicecomb.metrics.core.meter.ThreadPoolMonitorPublishModelFactory; import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.meter.os.NetMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; +import org.apache.servicecomb.metrics.core.meter.pool.ThreadPoolMeter; import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; import org.apache.servicecomb.swagger.invocation.InvocationType; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.patterns.ThreadPoolMonitorPublishModelFactory; +import io.micrometer.core.instrument.Meter; public class PublishModelFactory { - private MeasurementTree tree; + private final MeasurementTree tree; public PublishModelFactory(List meters) { tree = createMeasurementTree(meters); @@ -60,19 +61,20 @@ protected MeasurementGroupConfig createMeasurementGroupConfig() { MeterInvocationConst.TAG_TRANSPORT, MeterInvocationConst.TAG_OPERATION, MeterInvocationConst.TAG_STATUS, - MeterInvocationConst.TAG_STAGE, - MeterInvocationConst.TAG_STATISTIC); + MeterInvocationConst.TAG_TYPE, + new DefaultTagFinder(MeterInvocationConst.TAG_STAGE, true)); - //os config groupConfig.addGroup(OsMeter.OS_NAME, OsMeter.OS_TYPE, new DefaultTagFinder(NetMeter.INTERFACE, true), - NetMeter.STATISTIC); + new DefaultTagFinder(NetMeter.STATISTIC, true)); groupConfig.addGroup(VertxMetersInitializer.VERTX_ENDPOINTS, VertxMetersInitializer.ENDPOINTS_TYPE, - EndpointMeter.ADDRESS, - EndpointMeter.STATISTIC); + EndpointMeter.ADDRESS, EndpointMeter.STATISTIC); + + groupConfig.addGroup(ThreadPoolMeter.THREAD_POOL_METER, + ThreadPoolMeter.ID, ThreadPoolMeter.STAGE); return groupConfig; } @@ -106,12 +108,12 @@ public DefaultPublishModel createDefaultPublishModel() { .setOperationPerfGroups(generateOperationPerfGroups(tree, InvocationType.CONSUMER.name())); model.getProducer() - .setOperationPerfGroups(generateOperationPerfGroups(tree, InvocationType.PRODUCER.name())); - //edge + .setOperationPerfGroups(generateOperationPerfGroups(tree, InvocationType.PROVIDER.name())); + model.getEdge() .setOperationPerfGroups(generateOperationPerfGroups(tree, MeterInvocationConst.EDGE_INVOCATION_NAME)); - ThreadPoolMonitorPublishModelFactory.create(tree, model.getThreadPools()); + model.setThreadPools(ThreadPoolMonitorPublishModelFactory.create(tree)); return model; } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishUtils.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishUtils.java index 16680c7a114..9c761aaa5d4 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishUtils.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishUtils.java @@ -19,13 +19,14 @@ import java.util.HashMap; import java.util.Map; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroup; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo; -import com.netflix.spectator.api.Statistic; +import io.micrometer.core.instrument.Statistic; public final class PublishUtils { private PublishUtils() { @@ -33,15 +34,9 @@ private PublishUtils() { public static PerfInfo createPerfInfo(MeasurementNode stageNode) { PerfInfo perfInfo = new PerfInfo(); - - perfInfo.setTps((int) stageNode.findChild(Statistic.count.name()).summary()); - perfInfo.setMsTotalTime(stageNode.findChild(Statistic.totalTime.name()).summary() * 1000); - // when UT with DefaultRegistry, there is no max value - MeasurementNode maxNode = stageNode.findChild(Statistic.max.name()); - if (maxNode != null) { - perfInfo.setMsMaxLatency(maxNode.summary() * 1000); - } - + perfInfo.setTotalRequests(stageNode.findChild(Statistic.COUNT.name()).summary()); + perfInfo.setMsTotalTime(stageNode.findChild(Statistic.TOTAL_TIME.name()).summary() * 1000); + perfInfo.setMsMaxLatency(stageNode.findChild(Statistic.MAX.name()).summary() * 1000); return perfInfo; } @@ -49,11 +44,18 @@ public static OperationPerf createOperationPerf(String operation, MeasurementNod OperationPerf operationPerf = new OperationPerf(); operationPerf.setOperation(operation); - for (MeasurementNode stageNode : statusNode.getChildren().values()) { - PerfInfo perfInfo = createPerfInfo(stageNode); - operationPerf.getStages().put(stageNode.getName(), perfInfo); - } + MeasurementNode stageNode = statusNode.findChild(MeterInvocationConst.TAG_STAGE); + stageNode.getChildren().values().forEach(mNode -> { + PerfInfo perfInfo = createPerfInfo(mNode); + operationPerf.getStages().put(mNode.getName(), perfInfo); + }); + MeasurementNode latencyNode = statusNode.findChild(MeterInvocationConst.TAG_DISTRIBUTION); + if (latencyNode != null && latencyNode.getMeasurements() != null) { + operationPerf.setLatencyDistribution(latencyNode.getMeasurements().stream() + .map(m -> (int) m.getValue()) + .toArray(Integer[]::new)); + } return operationPerf; } @@ -61,13 +63,9 @@ public static void addOperationPerfGroups(OperationPerfGroups operationPerfGroup MeasurementNode statusNode) { Map statusMap = operationPerfGroups .getGroups() - .computeIfAbsent(transport, tn -> { - return new HashMap<>(); - }); - OperationPerfGroup group = statusMap.computeIfAbsent(statusNode.getName(), status -> { - return new OperationPerfGroup(transport, status); - }); - + .computeIfAbsent(transport, tn -> new HashMap<>()); + OperationPerfGroup group = statusMap + .computeIfAbsent(statusNode.getName(), status -> new OperationPerfGroup(transport, status)); OperationPerf operationPerf = createOperationPerf(operation, statusNode); group.addOperationPerf(operationPerf); } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ServerEndpointsLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ServerEndpointsLogPublisher.java index 5dc461a4bee..115e9660009 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ServerEndpointsLogPublisher.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/ServerEndpointsLogPublisher.java @@ -19,8 +19,8 @@ import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.VertxMetersInitializer; import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; import org.apache.servicecomb.metrics.core.meter.vertx.ServerEndpointMeter; @@ -32,45 +32,27 @@ public ServerEndpointsLogPublisher(MeasurementTree tree, StringBuilder sb, Strin @Override public void print(boolean printDetail) { + if (!printDetail) { + return; + } appendLine(sb, " server.endpoints:"); appendLine(sb, - " listen connectCount disconnectCount rejectByLimit connections send(Bps) receive(Bps)"); + " connectCount disconnectCount rejectByLimit connections requests latency send(Bps) receive(Bps) listen"); - double connect = 0; - double disconnect = 0; - double reject = 0; - double connections = 0; - double readSize = 0; - double writeSize = 0; for (MeasurementNode address : measurementNode.getChildren().values()) { - connect += address.findChild(EndpointMeter.CONNECT_COUNT).summary(); - disconnect += address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(); - reject += address.findChild(ServerEndpointMeter.REJECT_BY_CONNECTION_LIMIT).summary(); - connections += address.findChild(EndpointMeter.CONNECTIONS).summary(); - readSize += address.findChild(EndpointMeter.BYTES_READ).summary(); - writeSize += address.findChild(EndpointMeter.BYTES_WRITTEN).summary(); - if (printDetail) { - appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12.0f %-12s %-12s", - address.getName(), + appendLine(sb, " %-12.0f %-15.0f %-13.0f %-11.0f %-8.0f %-7.0f %-9s %-12s %s", address.findChild(EndpointMeter.CONNECT_COUNT).summary(), address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(), address.findChild(ServerEndpointMeter.REJECT_BY_CONNECTION_LIMIT).summary(), address.findChild(EndpointMeter.CONNECTIONS).summary(), + address.findChild(EndpointMeter.REQUESTS).summary(), + address.findChild(EndpointMeter.LATENCY).summary(), NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_WRITTEN).summary()), - NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_READ).summary()) + NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_READ).summary()), + address.getName() ); } } - - appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12.0f %-12s %-12s", - "(summary)", - connect, - disconnect, - reject, - connections, - NetUtils.humanReadableBytes((long) writeSize), - NetUtils.humanReadableBytes((long) readSize) - ); } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/SlowInvocationLogger.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/SlowInvocationLogger.java new file mode 100644 index 00000000000..797876aafb6 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/SlowInvocationLogger.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.publish; + +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_CONSUMER_CONNECTION; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_CONSUMER_SEND; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_CONSUMER_WAIT; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PREPARE; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PROVIDER_BUSINESS; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PROVIDER_QUEUE; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_PROVIDER_SEND; +import static org.apache.servicecomb.core.invocation.InvocationStageTrace.STAGE_TOTAL; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.OperationConfig; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.AllowConcurrentEvents; +import com.google.common.eventbus.Subscribe; + +public class SlowInvocationLogger { + private static final Logger LOGGER = LoggerFactory.getLogger("scb-slow"); + + public SlowInvocationLogger(SCBEngine scbEngine) { + scbEngine.getEventBus().register(this); + } + + @Subscribe + @AllowConcurrentEvents + public void onInvocationFinish(InvocationFinishEvent event) { + Invocation invocation = event.getInvocation(); + OperationConfig operationConfig = invocation.getOperationMeta().getConfig(); + if (!operationConfig.isSlowInvocationEnabled() || + invocation.getInvocationStageTrace().calcTotal() < operationConfig.getNanoSlowInvocation()) { + return; + } + + if (invocation.isProducer()) { + logSlowProvider(invocation, event.getResponse(), operationConfig); + return; + } + + if (invocation.isEdge()) { + logSlowEdge(invocation, event.getResponse(), operationConfig); + return; + } + + logSlowConsumer(invocation, event.getResponse(), operationConfig); + } + + private static String collectClientAddress(Invocation invocation) { + HttpServletRequestEx requestEx = invocation.getRequestEx(); + return requestEx == null ? "unknown" : requestEx.getRemoteAddr() + ":" + requestEx.getRemotePort(); + } + + private static String collectTargetAddress(Invocation invocation) { + Endpoint endpoint = invocation.getEndpoint(); + return endpoint == null ? "unknown" : endpoint.getEndpoint(); + } + + private static String formatTime(long doubleNano) { + long micros = TimeUnit.NANOSECONDS.toMicros(doubleNano); + return micros / 1000 + "." + micros % 1000; + } + + private static void logSlowProvider(Invocation invocation, Response response, OperationConfig operationConfig) { + RestOperationMeta restOperationMeta = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); + InvocationStageTrace stageTrace = invocation.getInvocationStageTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Slow Provider invocation [").append(invocation.getInvocationQualifiedName()) + .append("](").append(operationConfig.getMsSlowInvocation()).append(" ms") + .append(")[").append(invocation.getTraceId()).append("]\n") + .append(formatPair(" ", "http method", restOperationMeta.getHttpMethod())) + .append(formatPair(" ", "url", restOperationMeta.getAbsolutePath())) + .append(formatPair(" ", "endpoint", collectClientAddress(invocation))) + .append(formatPair(" ", "status code", String.valueOf(response.getStatusCode()))) + + .append(formatPair(" ", STAGE_TOTAL, stageTrace.calcTotal())) + .append(formatPair(" ", STAGE_PREPARE, stageTrace.calcPrepare())) + .append(formatPair(" ", STAGE_PROVIDER_DECODE_REQUEST, stageTrace.calcProviderDecodeRequest())) + .append(formatPair(" ", STAGE_PROVIDER_QUEUE, stageTrace.calcQueue())) + .append(formatPair(" ", STAGE_PROVIDER_BUSINESS, stageTrace.calcBusinessExecute())) + .append(formatPair(" ", STAGE_PROVIDER_ENCODE_RESPONSE, stageTrace.calcProviderEncodeResponse())) + .append(formatPair(" ", STAGE_PROVIDER_SEND, stageTrace.calcProviderSendResponse())); + + List sorted = new ArrayList<>(stageTrace.getStages().keySet()); + sorted.stream().sorted().forEach(key -> { + sb.append(formatPair(" ", key, + InvocationStageTrace.calc(stageTrace.getStages().get(key).getEndTime(), + stageTrace.getStages().get(key).getBeginTime()))); + }); + + LOGGER.warn(sb.toString()); + } + + protected static String formatPair(String padding, String name, String value) { + return String.format("%-20s: %20s\n", padding + name, value); + } + + protected static String formatPair(String padding, String name, long time) { + return String.format("%-20s: %8sms\n", padding + name, formatTime(time)); + } + + private static void logSlowConsumer(Invocation invocation, Response response, OperationConfig operationConfig) { + RestOperationMeta restOperationMeta = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); + InvocationStageTrace stageTrace = invocation.getInvocationStageTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Slow Consumer invocation [").append(invocation.getInvocationQualifiedName()) + .append("](").append(operationConfig.getMsSlowInvocation()).append(" ms") + .append(")[").append(invocation.getTraceId()).append("]\n") + .append(formatPair(" ", "http method", restOperationMeta.getHttpMethod())) + .append(formatPair(" ", "url", restOperationMeta.getAbsolutePath())) + .append(formatPair(" ", "endpoint", collectTargetAddress(invocation))) + .append(formatPair(" ", "status code", String.valueOf(response.getStatusCode()))) + .append(formatPair(" ", STAGE_TOTAL, stageTrace.calcTotal())) + .append(formatPair(" ", STAGE_PREPARE, stageTrace.calcPrepare())) + .append(formatPair(" ", STAGE_CONSUMER_CONNECTION, stageTrace.calcConnection())) + .append(formatPair(" ", STAGE_CONSUMER_ENCODE_REQUEST, stageTrace.calcConsumerEncodeRequest())) + .append(formatPair(" ", STAGE_CONSUMER_SEND, stageTrace.calcConsumerSendRequest())) + .append(formatPair(" ", STAGE_CONSUMER_WAIT, stageTrace.calcWait())) + .append(formatPair(" ", STAGE_CONSUMER_DECODE_RESPONSE, stageTrace.calcConsumerDecodeResponse())); + + List sorted = new ArrayList<>(stageTrace.getStages().keySet()); + sorted.stream().sorted().forEach(key -> { + sb.append(formatPair(" ", key, + InvocationStageTrace.calc(stageTrace.getStages().get(key).getEndTime(), + stageTrace.getStages().get(key).getBeginTime()))); + }); + + LOGGER.warn(sb.toString()); + } + + private static void logSlowEdge(Invocation invocation, Response response, OperationConfig operationConfig) { + RestOperationMeta restOperationMeta = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); + InvocationStageTrace stageTrace = invocation.getInvocationStageTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Slow Edge invocation [").append(invocation.getInvocationQualifiedName()) + .append("](").append(operationConfig.getMsSlowInvocation()).append(" ms") + .append(")[").append(invocation.getTraceId()).append("]\n") + .append(formatPair(" ", "http method", restOperationMeta.getHttpMethod())) + .append(formatPair(" ", "url", restOperationMeta.getAbsolutePath())) + .append(formatPair(" ", "endpoint", collectTargetAddress(invocation))) + .append(formatPair(" ", "status code", String.valueOf(response.getStatusCode()))) + .append(formatPair(" ", STAGE_TOTAL, stageTrace.calcTotal())) + .append(formatPair(" ", STAGE_PREPARE, stageTrace.calcPrepare())) + .append(formatPair(" ", STAGE_PROVIDER_DECODE_REQUEST, stageTrace.calcProviderDecodeRequest())) + .append(formatPair(" ", STAGE_CONSUMER_CONNECTION, stageTrace.calcConnection())) + .append(formatPair(" ", STAGE_CONSUMER_ENCODE_REQUEST, stageTrace.calcConsumerEncodeRequest())) + .append(formatPair(" ", STAGE_CONSUMER_SEND, stageTrace.calcConsumerSendRequest())) + .append(formatPair(" ", STAGE_CONSUMER_WAIT, stageTrace.calcWait())) + .append(formatPair(" ", STAGE_CONSUMER_DECODE_RESPONSE, stageTrace.calcConsumerDecodeResponse())) + .append(formatPair(" ", STAGE_PROVIDER_ENCODE_RESPONSE, stageTrace.calcProviderEncodeResponse())) + .append(formatPair(" ", STAGE_PROVIDER_SEND, stageTrace.calcProviderSendResponse())) + ; + + List sorted = new ArrayList<>(stageTrace.getStages().keySet()); + sorted.stream().sorted().forEach(key -> { + sb.append(formatPair(" ", key, + InvocationStageTrace.calc(stageTrace.getStages().get(key).getEndTime(), + stageTrace.getStages().get(key).getBeginTime()))); + }); + + LOGGER.warn(sb.toString()); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/ThreadPoolPublishModel.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/ThreadPoolPublishModel.java index 70c288b68dc..eb4aee56dc1 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/ThreadPoolPublishModel.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/ThreadPoolPublishModel.java @@ -31,6 +31,8 @@ public class ThreadPoolPublishModel { private int queueSize; + private double rejected = Double.NaN; + public double getAvgTaskCount() { return avgTaskCount; } @@ -86,4 +88,12 @@ public int getQueueSize() { public void setQueueSize(int queueSize) { this.queueSize = queueSize; } + + public double getRejected() { + return rejected; + } + + public void setRejected(double rejected) { + this.rejected = rejected; + } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerf.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerf.java index 4679d9c0dfb..28ddd5a5915 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerf.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerf.java @@ -16,15 +16,17 @@ */ package org.apache.servicecomb.metrics.core.publish.model.invocation; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; public class OperationPerf { private String operation; private Map stages = new HashMap<>(); + private Integer[] latencyDistribution; + public String getOperation() { return operation; } @@ -37,6 +39,14 @@ public Map getStages() { return stages; } + public Integer[] getLatencyDistribution() { + return latencyDistribution; + } + + public void setLatencyDistribution(Integer[] latencyDistribution) { + this.latencyDistribution = latencyDistribution; + } + public void setStages(Map stages) { this.stages = stages; } @@ -46,11 +56,21 @@ public PerfInfo findStage(String stage) { } public void add(OperationPerf operationPerf) { - for (Entry entry : operationPerf.stages.entrySet()) { - PerfInfo perfInfo = stages.computeIfAbsent(entry.getKey(), n -> { - return new PerfInfo(); - }); - perfInfo.add(entry.getValue()); + operationPerf.stages.forEach((key, value) -> { + PerfInfo perfInfo = stages.computeIfAbsent(key, n -> new PerfInfo()); + perfInfo.add(value); + }); + + if (operationPerf.getLatencyDistribution() == null) { + return; + } + + if (latencyDistribution == null) { + latencyDistribution = new Integer[operationPerf.getLatencyDistribution().length]; + Arrays.fill(latencyDistribution, 0); + } + for (int idx = 0; idx < operationPerf.getLatencyDistribution().length; idx++) { + latencyDistribution[idx] += operationPerf.getLatencyDistribution()[idx]; } } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerfGroup.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerfGroup.java index 01e0fb8dcb0..eca0baa5a44 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerfGroup.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/OperationPerfGroup.java @@ -20,11 +20,11 @@ import java.util.List; public class OperationPerfGroup { - private String transport; + private final String transport; - private String status; + private final String status; - private List operationPerfs = new ArrayList<>(); + private final List operationPerfs = new ArrayList<>(); private OperationPerf summary; diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/PerfInfo.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/PerfInfo.java index 6ab8b4d1e05..e9e3afbee5b 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/PerfInfo.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/model/invocation/PerfInfo.java @@ -17,18 +17,18 @@ package org.apache.servicecomb.metrics.core.publish.model.invocation; public class PerfInfo { - private int tps; + private double totalRequests; private double msTotalTime; private double msMaxLatency; - public int getTps() { - return tps; + public double getTotalRequests() { + return totalRequests; } - public void setTps(int tps) { - this.tps = tps; + public void setTotalRequests(double totalRequests) { + this.totalRequests = totalRequests; } public double getMsTotalTime() { @@ -48,7 +48,7 @@ public void setMsMaxLatency(double msMaxLatency) { } public void add(PerfInfo other) { - tps += other.tps; + totalRequests += other.totalRequests; msTotalTime += other.msTotalTime; if (msMaxLatency < other.msMaxLatency) { msMaxLatency = other.msMaxLatency; @@ -56,12 +56,12 @@ public void add(PerfInfo other) { } public double calcMsLatency() { - return (tps != 0) ? msTotalTime / tps : 0; + return (totalRequests != 0) ? msTotalTime / totalRequests : 0; } @Override public String toString() { - return "PerfInfo [tps=" + tps + ", msTotalTime=" + msTotalTime + ", msLatency=" + calcMsLatency() + return "PerfInfo [tps=" + totalRequests + ", msTotalTime=" + msTotalTime + ", msLatency=" + calcMsLatency() + ", msMaxLatency=" + msMaxLatency + "]"; } diff --git a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer b/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer deleted file mode 100644 index a8d82d03ee5..00000000000 --- a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer +++ /dev/null @@ -1,24 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.metrics.core.DefaultRegistryInitializer -org.apache.servicecomb.metrics.core.InvocationMetersInitializer -org.apache.servicecomb.metrics.core.ThreadPoolMetersInitializer -org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher -org.apache.servicecomb.metrics.core.VertxMetersInitializer -org.apache.servicecomb.metrics.core.OsMetersInitializer -org.apache.servicecomb.metrics.core.publish.MetricsRestPublisher diff --git a/metrics/metrics-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/metrics/metrics-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..87677909bd6 --- /dev/null +++ b/metrics/metrics-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.metrics.core.MetricsCoreConfiguration diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/AssertUtil.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/AssertUtil.java new file mode 100644 index 00000000000..f154ba65449 --- /dev/null +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/AssertUtil.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; + +import io.micrometer.core.instrument.Measurement; + +public class AssertUtil { + + public static void assertMeasure(List measurements, int index, String expected) { + Assertions.assertEquals(String.format("Measurement{%s}", expected), measurements.get(index).toString()); + } +} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestDefaultRegistryInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestDefaultRegistryInitializer.java deleted file mode 100644 index c18aed91b7c..00000000000 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestDefaultRegistryInitializer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core; - -import java.util.List; - -import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.servo.ServoRegistry; - -import mockit.Deencapsulation; - -public class TestDefaultRegistryInitializer { - GlobalRegistry globalRegistry = new GlobalRegistry(); - - List registries = Deencapsulation.getField(globalRegistry, "registries"); - - DefaultRegistryInitializer registryInitializer = new DefaultRegistryInitializer(); - - @Test - public void init() { - registryInitializer.init(globalRegistry, new EventBus(), new MetricsBootstrapConfig()); - - Assert.assertEquals(-10, registryInitializer.getOrder()); - Assert.assertThat(globalRegistry.getDefaultRegistry(), Matchers.instanceOf(ServoRegistry.class)); - Assert.assertEquals(1, registries.size()); - Assert.assertEquals(1, DefaultMonitorRegistry.getInstance().getRegisteredMonitors().size()); - - registryInitializer.destroy(); - - Assert.assertEquals(0, registries.size()); - Assert.assertEquals(0, DefaultMonitorRegistry.getInstance().getRegisteredMonitors().size()); - } - - @Test - public void destroy_notInit() { - // should not throw exception - registryInitializer.destroy(); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestInvocationMetersInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestInvocationMetersInitializer.java index 6bb57ad54aa..316b9bf9b53 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestInvocationMetersInitializer.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestInvocationMetersInitializer.java @@ -16,306 +16,397 @@ */ package org.apache.servicecomb.metrics.core; -import static org.junit.Assert.assertEquals; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; -import org.apache.servicecomb.core.Const; +import java.util.List; + +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementGroupConfig; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.env.Environment; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; -import mockit.Expectations; -import mockit.Mocked; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +@ExtendWith(MockitoExtension.class) public class TestInvocationMetersInitializer { EventBus eventBus = new EventBus(); - GlobalRegistry globalRegistry = new GlobalRegistry(new ManualClock()); - - Registry registry = new DefaultRegistry(globalRegistry.getClock()); + MeterRegistry registry = new SimpleMeterRegistry(); InvocationMetersInitializer invocationMetersInitializer = new InvocationMetersInitializer(); - @Mocked + @Mock Invocation invocation; - @Mocked - Response response; + Environment environment = Mockito.mock(Environment.class); - @Before + @BeforeEach public void setup() { - globalRegistry.add(registry); - invocationMetersInitializer.init(globalRegistry, eventBus, null); + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + invocationMetersInitializer.init(registry, eventBus, new MetricsBootstrapConfig(environment)); } @Test - public void consumerInvocation(@Mocked InvocationFinishEvent event) { - new Expectations() { - { - invocation.isConsumer(); - result = true; - invocation.getInvocationType(); - result = InvocationType.CONSUMER; - invocation.getRealTransportName(); - result = Const.RESTFUL; - invocation.getMicroserviceQualifiedName(); - result = "m.s.o"; - invocation.getInvocationStageTrace().calcTotalTime(); - result = 9; - invocation.getInvocationStageTrace().calcClientFiltersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcSendRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcGetConnectionTime(); - result = 4; - invocation.getInvocationStageTrace().calcWriteToBufferTime(); - result = 5; - invocation.getInvocationStageTrace().calcWakeConsumer(); - result = 9; - invocation.getInvocationStageTrace().calcReceiveResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcClientFiltersResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcInvocationPrepareTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersResponseTime(); - result = 9; - - event.getInvocation(); - result = invocation; - } - }; + public void consumerInvocation() { + InvocationFinishEvent event = Mockito.mock(InvocationFinishEvent.class); + Mockito.when(invocation.isConsumer()).thenReturn(true); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER); + Mockito.when(invocation.getRealTransportName()).thenReturn(CoreConst.RESTFUL); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("m.s.o"); + InvocationStageTrace invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + Mockito.when(invocationStageTrace.calcTotal()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcPrepare()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcConnection()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcConsumerEncodeRequest()).thenReturn(4L); + Mockito.when(invocationStageTrace.calcConsumerSendRequest()).thenReturn(5L); + Mockito.when(invocationStageTrace.calcWait()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcConsumerDecodeResponse()).thenReturn(9L); + Mockito.when(event.getInvocation()).thenReturn(invocation); + Response mockResponse = Mockito.spy(Response.class); + Mockito.when(event.getResponse()).thenReturn(mockResponse); + Mockito.doReturn(0).when(mockResponse).getStatusCode(); eventBus.post(event); eventBus.post(event); - globalRegistry.poll(1); - MeasurementTree tree = new MeasurementTree(); - tree.from(registry.iterator(), new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME)); - assertEquals("" - + "[Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=total:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=total:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=total:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=handlers_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=prepare:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=prepare:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=prepare:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_send_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_send_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_send_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_get_connection:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_get_connection:statistic=totalTime:status=0:transport=rest,0,8.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_get_connection:statistic=max:status=0:transport=rest,0,4.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_write_to_buf:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_write_to_buf:statistic=totalTime:status=0:transport=rest,0,1.0E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_write_to_buf:statistic=max:status=0:transport=rest,0,5.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wait_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wait_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wait_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wake_consumer:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wake_consumer:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=consumer_wake_consumer:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=CONSUMER:stage=client_filters_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9)]", - tree.findChild(MeterInvocationConst.INVOCATION_NAME).getMeasurements().toString()); + tree.from(registry.getMeters().iterator(), + new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME, "stage")); + List measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "total") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "prepare") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-send") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.0E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=5.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "connection") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-encode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=8.0E-9"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=4.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "connection") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "wait") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-decode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); } @Test - public void edgeInvocation(@Mocked InvocationFinishEvent event) { - new Expectations() { - { - invocation.isConsumer(); - result = true; - invocation.isEdge(); - result = true; - invocation.getRealTransportName(); - result = Const.RESTFUL; - invocation.getMicroserviceQualifiedName(); - result = "m.s.o"; - invocation.getInvocationStageTrace().calcTotalTime(); - result = 9; - invocation.getInvocationStageTrace().calcThreadPoolQueueTime(); - result = 9; - invocation.getInvocationStageTrace().calcClientFiltersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcSendRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcGetConnectionTime(); - result = 4; - invocation.getInvocationStageTrace().calcWriteToBufferTime(); - result = 5; - invocation.getInvocationStageTrace().calcWakeConsumer(); - result = 9; - invocation.getInvocationStageTrace().calcReceiveResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcClientFiltersResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcInvocationPrepareTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcSendResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcServerFiltersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcServerFiltersResponseTime(); - result = 9; - event.getInvocation(); - result = invocation; - } - }; + public void edgeInvocation() { + InvocationFinishEvent event = Mockito.mock(InvocationFinishEvent.class); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.EDGE); + Mockito.when(invocation.isEdge()).thenReturn(true); + Mockito.when(invocation.getRealTransportName()).thenReturn(CoreConst.RESTFUL); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("m.s.o"); + InvocationStageTrace invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + Mockito.when(invocationStageTrace.calcTotal()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcPrepare()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderDecodeRequest()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcConnection()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcConsumerEncodeRequest()).thenReturn(4L); + Mockito.when(invocationStageTrace.calcConsumerSendRequest()).thenReturn(5L); + Mockito.when(invocationStageTrace.calcConsumerDecodeResponse()).thenReturn(8L); + Mockito.when(invocationStageTrace.calcWait()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderEncodeResponse()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderSendResponse()).thenReturn(9L); + Mockito.when(event.getInvocation()).thenReturn(invocation); + Response mockResponse = Mockito.spy(Response.class); + Mockito.when(event.getResponse()).thenReturn(mockResponse); + Mockito.doReturn(0).when(mockResponse).getStatusCode(); eventBus.post(event); eventBus.post(event); - globalRegistry.poll(1); - MeasurementTree tree = new MeasurementTree(); - tree.from(registry.iterator(), new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME)); - assertEquals("" - + "[Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=total:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=total:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=total:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=handlers_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=prepare:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=prepare:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=prepare:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_send_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_send_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_send_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_get_connection:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_get_connection:statistic=totalTime:status=0:transport=rest,0,8.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_get_connection:statistic=max:status=0:transport=rest,0,4.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_write_to_buf:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_write_to_buf:statistic=totalTime:status=0:transport=rest,0,1.0E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_write_to_buf:statistic=max:status=0:transport=rest,0,5.0E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wait_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wait_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wait_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wake_consumer:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wake_consumer:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=consumer_wake_consumer:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=client_filters_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=queue:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=queue:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=queue:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=server_filters_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=producer_send_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=producer_send_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=EDGE:stage=producer_send_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9)]", - tree.findChild(MeterInvocationConst.INVOCATION_NAME).getMeasurements().toString()); + tree.from(registry.getMeters().iterator(), + new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME, "stage")); + + List measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "total") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "prepare") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-send") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.0E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=5.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "connection") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-encode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=8.0E-9"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=4.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "wait") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "consumer-decode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.6E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=8.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-decode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-encode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-send") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); } @Test - public void producerInvocation(@Mocked InvocationFinishEvent event) { - new Expectations() { - { - invocation.isConsumer(); - result = false; - invocation.getInvocationType(); - result = InvocationType.PRODUCER; - invocation.getRealTransportName(); - result = Const.RESTFUL; - invocation.getMicroserviceQualifiedName(); - result = "m.s.o"; - invocation.getInvocationStageTrace().calcTotalTime(); - result = 9; - invocation.getInvocationStageTrace().calcInvocationPrepareTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcHandlersResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcThreadPoolQueueTime(); - result = 9; - invocation.getInvocationStageTrace().calcBusinessTime(); - result = 9; - invocation.getInvocationStageTrace().calcServerFiltersRequestTime(); - result = 9; - invocation.getInvocationStageTrace().calcServerFiltersResponseTime(); - result = 9; - invocation.getInvocationStageTrace().calcSendResponseTime(); - result = 9; - event.getInvocation(); - result = invocation; - } - }; + public void producerInvocation() { + InvocationFinishEvent event = Mockito.mock(InvocationFinishEvent.class); + Mockito.when(invocation.isConsumer()).thenReturn(false); + Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PROVIDER); + Mockito.when(invocation.getRealTransportName()).thenReturn(CoreConst.RESTFUL); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("m.s.o"); + InvocationStageTrace invocationStageTrace = Mockito.mock(InvocationStageTrace.class); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + Mockito.when(invocationStageTrace.calcTotal()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcPrepare()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderDecodeRequest()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcQueue()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcBusinessExecute()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderEncodeResponse()).thenReturn(9L); + Mockito.when(invocationStageTrace.calcProviderSendResponse()).thenReturn(9L); + Mockito.when(event.getInvocation()).thenReturn(invocation); + Response mockResponse = Mockito.spy(Response.class); + Mockito.when(event.getResponse()).thenReturn(mockResponse); + Mockito.doReturn(0).when(mockResponse).getStatusCode(); eventBus.post(event); eventBus.post(event); - globalRegistry.poll(1); - MeasurementTree tree = new MeasurementTree(); - tree.from(registry.iterator(), new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME)); - assertEquals("" - + "[Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=total:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=total:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=total:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=handlers_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=prepare:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=prepare:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=prepare:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=queue:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=queue:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=queue:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=execution:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=execution:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=execution:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_request:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_request:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_request:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=server_filters_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=producer_send_response:statistic=count:status=0:transport=rest,0,2.0), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=producer_send_response:statistic=totalTime:status=0:transport=rest,0,1.8000000000000002E-8), " - + "Measurement(servicecomb.invocation:operation=m.s.o:role=PRODUCER:stage=producer_send_response:statistic=max:status=0:transport=rest,0,9.000000000000001E-9)]", - tree.findChild(MeterInvocationConst.INVOCATION_NAME).getMeasurements().toString()); + tree.from(registry.getMeters().iterator(), + new MeasurementGroupConfig(MeterInvocationConst.INVOCATION_NAME, "stage")); + + List measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "total") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "prepare") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "queue") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "execute") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-decode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-encode") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); + + measurements = tree.findChild(MeterInvocationConst.INVOCATION_NAME, "provider-send") + .getMeasurements(); + Assertions.assertEquals(3, measurements.size()); + AssertUtil.assertMeasure(measurements, 0, + "statistic='COUNT', value=2.0"); + AssertUtil.assertMeasure(measurements, 1, + "statistic='TOTAL_TIME', value=1.8E-8"); + AssertUtil.assertMeasure(measurements, 2, + "statistic='MAX', value=9.0E-9"); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestMetricsBootListener.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestMetricsBootListener.java deleted file mode 100644 index 75eabe80dae..00000000000 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestMetricsBootListener.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.core.BootListener.BootEvent; -import org.apache.servicecomb.core.BootListener.EventType; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.metrics.core.publish.HealthCheckerRestPublisher; -import org.apache.servicecomb.metrics.core.publish.MetricsRestPublisher; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class TestMetricsBootListener { - MetricsBootListener listener = new MetricsBootListener(); - - @Test - public void registerSchemas() { - List argsList = new ArrayList<>(); - - ProducerSchemaFactory producerSchemaFactory = new MockUp() { - @Mock - SchemaMeta getOrCreateProducerSchema(String schemaId, - Class producerClass, - Object producerInstance) { - argsList.add(new Object[] {schemaId, producerClass, producerInstance}); - return null; - } - }.getMockInstance(); - Deencapsulation.setField(listener, "producerSchemaFactory", producerSchemaFactory); - - Microservice microservice = new Microservice(); - microservice.setServiceName("name"); - - BootEvent event = new BootEvent(); - event.setEventType(EventType.BEFORE_PRODUCER_PROVIDER); - listener.onBootEvent(event); - - Object[] args = argsList.get(0); - //we have remove parameter microserviceName - Assert.assertEquals("healthEndpoint", args[0]); - Assert.assertEquals(HealthCheckerRestPublisher.class, args[1]); - Assert.assertEquals(HealthCheckerRestPublisher.class, args[2].getClass()); - - MetricsRestPublisher metricsRestPublisher = - SPIServiceUtils.getTargetService(MetricsInitializer.class, MetricsRestPublisher.class); - args = argsList.get(1); - //we have remove parameter microserviceName - Assert.assertEquals("metricsEndpoint", args[0]); - Assert.assertEquals(MetricsRestPublisher.class, args[1]); - Assert.assertSame(metricsRestPublisher, args[2]); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java index 8f2f60f86f1..c9461668da1 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java @@ -17,138 +17,95 @@ package org.apache.servicecomb.metrics.core; import java.io.File; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.SystemUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.metrics.core.meter.os.CpuMeter; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.meter.os.NetMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; +import org.apache.servicecomb.metrics.core.meter.os.SystemMeter; import org.apache.servicecomb.metrics.core.meter.os.net.InterfaceUsage; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; +import com.sun.management.OperatingSystemMXBean; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.mockito.junit.jupiter.MockitoExtension; +@ExtendWith(MockitoExtension.class) public class TestOsMeterInitializer { - GlobalRegistry globalRegistry = new GlobalRegistry(new ManualClock()); + MeterRegistry registry = new SimpleMeterRegistry(); - Registry registry = new DefaultRegistry(globalRegistry.getClock()); - - private boolean isLinux; - - @Mocked + @Mock EventBus eventBus; - @Before - public void beforeTest() { - isLinux = SystemUtils.IS_OS_LINUX; - } - @Test - public void init(@Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) { - ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", true); + public void init() { List list = new ArrayList<>(); - list.add("cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1"); + list.add("13 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1"); list.add("useless"); list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - new MockUp() { - @Mock - RuntimeMXBean getRuntimeMXBean() { - return mxBean; - } - }; - - new MockUp() { - @Mock - public Runtime getRuntime() { - return runtime; - } - }; - new Expectations() { - { - runtime.availableProcessors(); - result = 2; - mxBean.getName(); - result = "6666@desktop111"; - } - }; - globalRegistry.add(registry); - OsMetersInitializer osMetersInitializer = new OsMetersInitializer(); - osMetersInitializer.init(globalRegistry, eventBus, null); - OsMeter osMeter = osMetersInitializer.getOsMeter(); - Assert.assertNotNull(osMeter); - Assert.assertNotNull(osMeter.getCpuMeter()); - Assert.assertNotNull(osMeter.getNetMeter()); - CpuMeter cpuMeter = osMeter.getCpuMeter(); - NetMeter netMeter = osMeter.getNetMeter(); - Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0); - Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath()); - Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime()); - Assert.assertEquals(8L, cpuMeter.getProcessCpuUsage().getPeriodTotalTime()); - - Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime()); - Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime()); - Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath()); - - Map interfaceInfoMap = netMeter.getInterfaceUsageMap(); - Assert.assertEquals(1, interfaceInfoMap.size()); - InterfaceUsage eth0 = interfaceInfoMap.get("eth0"); - Assert.assertEquals(4, eth0.getNetStats().size()); - // recv Bps - Assert.assertEquals(0L, eth0.getNetStats().get(0).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, eth0.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(0L, eth0.getNetStats().get(1).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, eth0.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(0L, eth0.getNetStats().get(2).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, eth0.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(0L, eth0.getNetStats().get(3).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, eth0.getNetStats().get(3).getIndex()); - } - - @Test - public void initFail() { - OsMetersInitializer osMetersInitializer = new OsMetersInitializer(); - ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", false); - osMetersInitializer.init(null, eventBus, null); - Assert.assertNull(osMetersInitializer.getOsMeter()); - } - @After - public void afterTest() { - ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", isLinux); + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + OsMetersInitializer osMetersInitializer = new OsMetersInitializer(); + osMetersInitializer.init(registry, eventBus, null); + + OsMeter osMeter = osMetersInitializer.getOsMeter(); + SystemMeter systemMeter = osMeter.getCpuMeter(); + OperatingSystemMXBean osBean = Mockito.mock(OperatingSystemMXBean.class); + Mockito.when(osBean.getCpuLoad()).thenReturn(3.2D); + Mockito.when(osBean.getProcessCpuLoad()).thenReturn(1.2D); + systemMeter.setOsBean(osBean); + NetMeter netMeter = osMeter.getNetMeter(); + netMeter.setOsLinux(true); + + osMetersInitializer.poll(System.currentTimeMillis(), 1000); + + MeasurementTree tree = new MeasurementTree(); + MeasurementGroupConfig group = new MeasurementGroupConfig(); + group.addGroup(OsMeter.OS_NAME, OsMeter.OS_TYPE); + tree.from(registry.getMeters().iterator(), group); + + Assertions.assertEquals(1.2D, + tree.findChild(OsMeter.OS_NAME, SystemMeter.PROCESS_CPU_USAGE).summary(), 0.0); + Assertions.assertEquals(3.2D, + tree.findChild(OsMeter.OS_NAME, SystemMeter.CPU_USAGE).summary(), 0.0); + + Map interfaceInfoMap = netMeter.getInterfaceUsageMap(); + Assertions.assertEquals(1, interfaceInfoMap.size()); + InterfaceUsage eth0 = interfaceInfoMap.get("eth0"); + // recv Bps + Assertions.assertEquals(0L, eth0.getReceive().getLastValue()); + Assertions.assertEquals(0, eth0.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, eth0.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(0L, eth0.getSend().getLastValue()); + Assertions.assertEquals(0, eth0.getSend().getRate(), 0.0); + Assertions.assertEquals(8, eth0.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(0L, eth0.getPacketsReceive().getLastValue()); + Assertions.assertEquals(0, eth0.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, eth0.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(0L, eth0.getPacketsSend().getLastValue()); + Assertions.assertEquals(0, eth0.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, eth0.getPacketsSend().getIndex()); + } } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestThreadPoolMetersInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestThreadPoolMetersInitializer.java index 4942ccfbf03..9c9698aed2b 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestThreadPoolMetersInitializer.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestThreadPoolMetersInitializer.java @@ -16,62 +16,55 @@ */ package org.apache.servicecomb.metrics.core; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.RunnableScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; -import org.apache.servicecomb.core.CseContext; import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.definition.MicroserviceMeta; import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.executor.FixedThreadExecutor; +import org.apache.servicecomb.core.executor.GroupExecutor; +import org.apache.servicecomb.core.executor.ThreadPoolExecutorEx; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.hamcrest.Matchers; -import org.junit.Assert; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; +import org.apache.servicecomb.metrics.core.meter.pool.ThreadPoolMeter; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.patterns.PolledMeter; - +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import mockit.Expectations; import mockit.Mock; import mockit.MockUp; import mockit.Mocked; public class TestThreadPoolMetersInitializer { - GlobalRegistry globalRegistry = new GlobalRegistry(); - - Registry registry = new DefaultRegistry(new ManualClock()); + MeterRegistry registry = new SimpleMeterRegistry(); ThreadPoolMetersInitializer threadPoolMetersInitializer = new ThreadPoolMetersInitializer(); - ThreadPoolExecutor threadPoolExecutor = Mockito.mock(ThreadPoolExecutor.class); + ThreadPoolExecutorEx threadPoolExecutor = Mockito.mock(ThreadPoolExecutorEx.class); @Mocked BlockingQueue queue; @Mocked - FixedThreadExecutor fixedThreadExecutor; + GroupExecutor groupExecutor; ExecutorService executor = Mockito.mock(ExecutorService.class); @Mocked ApplicationContext applicationContext; - @Mocked MicroserviceMeta microserviceMeta; @@ -94,7 +87,7 @@ public void init() { }; Map beanExecutors = new HashMap<>(); beanExecutors.put("executor", executor); - beanExecutors.put("fixedThreadExecutor", fixedThreadExecutor); + beanExecutors.put("groupExecutor", groupExecutor); beanExecutors.put("threadPoolExecutor", threadPoolExecutor); new Expectations(BeanUtils.class) { { @@ -106,7 +99,7 @@ public void init() { }; Mockito.when(threadPoolExecutor.getQueue()).thenReturn(queue); - new Expectations(CseContext.getInstance()) { + new Expectations() { { microserviceMeta.getOperations(); result = Arrays.asList(operationMetaExecutor, operationMetaSameExecutor, operationMetaFixedThreadExecutor); @@ -115,9 +108,9 @@ public void init() { operationMetaSameExecutor.getExecutor(); result = executor; operationMetaFixedThreadExecutor.getExecutor(); - result = fixedThreadExecutor; + result = groupExecutor; - fixedThreadExecutor.getExecutorList(); + groupExecutor.getExecutorList(); result = Arrays.asList(threadPoolExecutor); queue.size(); @@ -132,22 +125,22 @@ void delayedExecute(RunnableScheduledFuture task) { } }; - globalRegistry.add(registry); - threadPoolMetersInitializer.init(globalRegistry, null, null); - - PolledMeter.update(registry); - List result = new ArrayList<>(); - registry.iterator().forEachRemaining(meter -> { - result.add(meter.measure().toString()); - }); - - Assert.assertThat(result, - Matchers.containsInAnyOrder("[Measurement(threadpool.maxThreads:id=fixedThreadExecutor-group0,0,0.0)]", - "[Measurement(threadpool.completedTaskCount:id=fixedThreadExecutor-group0,0,0.0)]", - "[Measurement(threadpool.currentThreadsBusy:id=fixedThreadExecutor-group0,0,0.0)]", - "[Measurement(threadpool.corePoolSize:id=fixedThreadExecutor-group0,0,0.0)]", - "[Measurement(threadpool.poolSize:id=fixedThreadExecutor-group0,0,0.0)]", - "[Measurement(threadpool.queueSize:id=fixedThreadExecutor-group0,0,10.0)]", - "[Measurement(threadpool.taskCount:id=fixedThreadExecutor-group0,0,0.0)]")); + threadPoolMetersInitializer.init(registry, null, null); + + MeasurementTree tree = new MeasurementTree(); + MeasurementGroupConfig group = new MeasurementGroupConfig(); + group.addGroup(ThreadPoolMeter.THREAD_POOL_METER, ThreadPoolMeter.ID, + ThreadPoolMeter.STAGE); + tree.from(registry.getMeters().iterator(), group); + + MeasurementNode node = tree.findChild(ThreadPoolMeter.THREAD_POOL_METER); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "maxThreads").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "rejectedCount").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "completedTaskCount").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "currentThreadsBusy").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "corePoolSize").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "poolSize").summary(), 0, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "queueSize").summary(), 10, 0); + Assertions.assertEquals(node.findChild("groupExecutor-group0", "taskCount").summary(), 0, 0); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java index ad5573fd187..35ba63b3bdc 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java @@ -16,137 +16,158 @@ */ package org.apache.servicecomb.metrics.core; -import java.util.ArrayList; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; +import static org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher.ENDPOINTS_CLIENT_DETAIL_ENABLED; + import java.util.List; -import org.apache.servicecomb.core.transport.AbstractTransport; -import org.apache.servicecomb.core.transport.TransportVertxFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.PolledEvent; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.apache.servicecomb.foundation.vertx.SharedVertxFactory; import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; import org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import com.google.common.collect.Lists; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.vertx.core.AbstractVerticle; import io.vertx.core.DeploymentOptions; import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServer; +import io.vertx.core.impl.SysProps; import io.vertx.ext.web.Router; -import mockit.Expectations; public class TestVertxMetersInitializer { - GlobalRegistry globalRegistry = new GlobalRegistry(new ManualClock()); - - Registry registry = new DefaultRegistry(globalRegistry.getClock()); + MeterRegistry registry = new SimpleMeterRegistry(); EventBus eventBus = new EventBus(); - TransportVertxFactory transportVertxFactory; - VertxMetersInitializer vertxMetersInitializer = new VertxMetersInitializer(); DefaultLogPublisher logPublisher = new DefaultLogPublisher(); + Environment environment = Mockito.mock(Environment.class); + + LogCollector logCollector = new LogCollector(); + + static HttpClient client; + + static HttpServer server; + static int port; static String body = "body"; public static class TestServerVerticle extends AbstractVerticle { @Override - public void start(Future startFuture) { + public void start(Promise startPromise) { Router mainRouter = Router.router(vertx); - mainRouter.route("/").handler(context -> { - context.response().end(context.getBody()); - }); - - HttpServer server = vertx.createHttpServer(); - server.requestHandler(mainRouter::accept); - server.listen(0, "0.0.0.0", ar -> { - if (ar.succeeded()) { - port = ar.result().actualPort(); - startFuture.complete(); + mainRouter.route("/").handler(context -> context.response().end(body)); + + server = vertx.createHttpServer(); + server.requestHandler(mainRouter); + Future future = server.listen(0, "0.0.0.0"); + future.onComplete((s, f) -> { + if (f == null) { + port = s.actualPort(); + startPromise.complete(); return; } - startFuture.fail(ar.cause()); + startPromise.fail(f); }); } } public static class TestClientVerticle extends AbstractVerticle { @Override - public void start(Future startFuture) { - HttpClient client = vertx.createHttpClient(); - client.post(port, "127.0.0.1", "/").handler(resp -> { - resp.bodyHandler((buffer) -> { - startFuture.complete(); - }); - }).end(body); + public void start(Promise startPromise) { + client = vertx.createHttpClient(); + Future future = client.request(HttpMethod.GET, port, "127.0.0.1", "/"); + future.onComplete((s, f) -> { + if (f == null) { + Future responseFuture = s.send(body); + responseFuture.onComplete((rs, rf) -> { + if (rf == null) { + rs.bodyHandler((buffer) -> startPromise.complete()); + } else { + startPromise.fail(f); + } + }); + } + }); } } - @Before + @BeforeEach public void setup() { - VertxUtils.blockCloseVertxByName("transport"); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + HttpClients.load(); } - @After - public void teardown() { - VertxUtils.blockCloseVertxByName("transport"); + @AfterEach + public void tearDown() { + logCollector.clear(); + HttpClients.destroy(); + if (client != null) { + client.shutdown(); + } + if (server != null) { + server.shutdown(); + } } @Test public void init() throws InterruptedException { - transportVertxFactory = new TransportVertxFactory(); - new Expectations(AbstractTransport.class) { - { - AbstractTransport.getTransportVertxFactory(); - result = transportVertxFactory; - } - }; - - globalRegistry.add(registry); - vertxMetersInitializer.init(globalRegistry, eventBus, null); - logPublisher.init(null, eventBus, null); + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + Mockito.when(environment.getProperty(DefaultLogPublisher.ENABLED, boolean.class, false)).thenReturn(false); VertxUtils - .blockDeploy(transportVertxFactory.getTransportVertx(), TestServerVerticle.class, new DeploymentOptions()); + .blockDeploy(SharedVertxFactory.getSharedVertx(environment), TestServerVerticle.class, new DeploymentOptions()); VertxUtils - .blockDeploy(transportVertxFactory.getTransportVertx(), TestClientVerticle.class, new DeploymentOptions()); + .blockDeploy(SharedVertxFactory.getSharedVertx(environment), TestClientVerticle.class, new DeploymentOptions()); - globalRegistry.poll(1); - List meters = Lists.newArrayList(registry.iterator()); - List measurements = new ArrayList<>(); - for (Meter meter : meters) { - meter.measure().forEach(measurements::add); - } + vertxMetersInitializer.init(registry, eventBus, new MetricsBootstrapConfig(environment)); + logPublisher.setEnvironment(environment); + logPublisher.init(registry, eventBus, null); - LogCollector logCollector = new LogCollector(); + vertxMetersInitializer.poll(0, 1); + List meters = registry.getMeters(); - testLog(logCollector, meters, measurements, true); + testLog(logCollector, meters, true); logCollector.clear(); - testLog(logCollector, meters, measurements, false); - logCollector.teardown(); + testLog(logCollector, meters, false); } - private void testLog(LogCollector logCollector, List meters, List measurements, - boolean printDetail) { - ArchaiusUtils.setProperty(DefaultLogPublisher.ENDPOINTS_CLIENT_DETAIL_ENABLED, String.valueOf(printDetail)); - logPublisher.onPolledEvent(new PolledEvent(meters, measurements)); + private void testLog(LogCollector logCollector, List meters, boolean printDetail) { + Mockito.when(environment.getProperty(ENDPOINTS_CLIENT_DETAIL_ENABLED, boolean.class, true)).thenReturn(printDetail); + logPublisher.onPolledEvent(new PolledEvent(meters)); StringBuilder sb = new StringBuilder(); logCollector.getEvents().forEach(event -> sb.append(event.getMessage()).append("\n")); @@ -154,24 +175,42 @@ private void testLog(LogCollector logCollector, List meters, List list = new ArrayList<>(); - list.add("cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - new MockUp() { - @Mock - RuntimeMXBean getRuntimeMXBean() { - return mxBean; - } - }; - - new MockUp() { - @Mock - public Runtime getRuntime() { - return runtime; - } - }; - new Expectations() { - { - runtime.availableProcessors(); - result = 2; - mxBean.getName(); - result = "6666@desktop111"; - } - }; - CpuMeter cpuMeter = new CpuMeter(id); - Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0); - Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0); - - Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime()); - Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime()); - - Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath()); - Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath()); - - list.add(0, "cpu 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2"); - cpuMeter.update(); - Assert.assertEquals(1.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0); - Assert.assertEquals(1.75, cpuMeter.getAllCpuUsage().getUsage(), 0.0); - - Assert.assertEquals(8L, cpuMeter.getProcessCpuUsage().getLastBusyTime()); - Assert.assertEquals(16L, cpuMeter.getAllCpuUsage().getLastTotalTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime()); - Assert.assertEquals(14L, cpuMeter.getAllCpuUsage().getLastBusyTime()); - } - - @Test - public void testRefreshError(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) { - List list = new ArrayList<>(); - list.add("cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - - new MockUp() { - @Mock - RuntimeMXBean getRuntimeMXBean() { - return mxBean; - } - }; - new MockUp() { - @Mock - public Runtime getRuntime() { - return runtime; - } - }; - new Expectations() { - { - runtime.availableProcessors(); - result = 2; - mxBean.getName(); - result = "6666@desktop111"; - } - }; - CpuMeter cpuMeter = new CpuMeter(id); - Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0); - Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0); - - Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime()); - Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime()); - - Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath()); - Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath()); - - list.add(0, "cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1"); - cpuMeter.update(); - - Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0); - Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0); - - Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime()); - Assert.assertEquals(0L, cpuMeter.getAllCpuUsage().getPeriodTotalTime()); - Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime()); - Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime()); - } - - @Test - public void testCalcMeasurements(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) { - List measurements = new ArrayList<>(); - List list = new ArrayList<>(); - list.add("cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - - new MockUp() { - @Mock - RuntimeMXBean getRuntimeMXBean() { - return mxBean; - } - }; - new MockUp() { - @Mock - public Runtime getRuntime() { - return runtime; - } - }; - new Expectations() { - { - runtime.availableProcessors(); - result = 2; - mxBean.getName(); - result = "6666@desktop111"; - } - }; - CpuMeter cpuMeter = new CpuMeter(id); - list.add(0, "cpu 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2"); - cpuMeter.calcMeasurements(measurements, 0); - Assert.assertEquals(2, measurements.size()); - Measurement measurement = measurements.get(0); - Assert.assertEquals(0, measurement.timestamp()); - Assert.assertEquals(1.75, measurement.value(), 0.0); - measurement = measurements.get(1); - Assert.assertEquals(0, measurement.timestamp()); - Assert.assertEquals(1.0, measurement.value(), 0.0); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java index b692c7a2f2a..8ed2a920de7 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java @@ -16,6 +16,9 @@ */ package org.apache.servicecomb.metrics.core.meter.os; +import static org.apache.servicecomb.metrics.core.meter.os.OsMeter.OS_TYPE; +import static org.apache.servicecomb.metrics.core.meter.os.OsMeter.OS_TYPE_NET; + import java.io.File; import java.nio.charset.Charset; import java.util.ArrayList; @@ -23,243 +26,280 @@ import java.util.Map; import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.foundation.metrics.publish.DefaultTagFinder; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.metrics.core.meter.os.net.InterfaceUsage; -import org.junit.Assert; -import org.junit.Test; - -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; +import org.junit.jupiter.api.Assertions; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; public class TestNetMeter { @Test - public void testNetRefreshUnchanged(@Mocked Id id) { + public void testNetRefreshUnchanged() { List list = new ArrayList<>(); list.add("useless"); list.add("useless"); list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; + + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + + MeterRegistry meterRegistry = new SimpleMeterRegistry(); + NetMeter netMeter = new NetMeter(meterRegistry, "os", Tags.of(OS_TYPE, OS_TYPE_NET)); + list.remove(2); + list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); + netMeter.refreshNet(1); + + Map meterInterfaceInfoMap = netMeter.getInterfaceUsageMap(); + Assertions.assertTrue(meterInterfaceInfoMap.containsKey("eth0")); + + InterfaceUsage eth0 = meterInterfaceInfoMap.get("eth0"); + + Assertions.assertEquals("eth0", eth0.getName()); + + // recv Bps + Assertions.assertEquals(1L, eth0.getReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, eth0.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(1L, eth0.getSend().getLastValue()); + Assertions.assertEquals(1, eth0.getSend().getRate(), 0.0); + Assertions.assertEquals(8, eth0.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(1L, eth0.getPacketsReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, eth0.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(1L, eth0.getPacketsSend().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, eth0.getPacketsSend().getIndex()); + + // measurement tree test + MeasurementGroupConfig group = new MeasurementGroupConfig(); + group.addGroup(OsMeter.OS_NAME, + OS_TYPE, + new DefaultTagFinder(NetMeter.INTERFACE, true), + new DefaultTagFinder(NetMeter.STATISTIC, true)); + + MeasurementTree tree = new MeasurementTree(); + tree.from(meterRegistry.getMeters().iterator(), group); + MeasurementNode osNode = tree.findChild(OsMeter.OS_NAME); + MeasurementNode netNode = osNode.findChild(OS_TYPE_NET); + Assertions.assertEquals(1, netNode.getChildren().size()); + for (MeasurementNode interfaceNode : netNode.getChildren().values()) { + double sendRate = interfaceNode.findChild(NetMeter.TAG_SEND.getValue()).summary(); + double sendPacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_SEND.getValue()).summary(); + double receiveRate = interfaceNode.findChild(NetMeter.TAG_RECEIVE.getValue()).summary(); + double receivePacketsRate = interfaceNode.findChild(NetMeter.TAG_PACKETS_RECEIVE.getValue()).summary(); + Assertions.assertEquals(1, sendRate, 0); + Assertions.assertEquals(1, sendPacketsRate, 0); + Assertions.assertEquals(1, receiveRate, 0); + Assertions.assertEquals(1, receivePacketsRate, 0); } - }; - NetMeter netMeter = new NetMeter(id); - list.remove(2); - list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); - netMeter.refreshNet(1); - Map meterInterfaceInfoMap = netMeter.getInterfaceUsageMap(); - Assert.assertTrue(meterInterfaceInfoMap.containsKey("eth0")); - - InterfaceUsage eth0 = meterInterfaceInfoMap.get("eth0"); - - Assert.assertEquals("eth0", eth0.getName()); - - Assert.assertEquals(4, eth0.getNetStats().size()); - // recv Bps - Assert.assertEquals(1L, eth0.getNetStats().get(0).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, eth0.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(1L, eth0.getNetStats().get(1).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, eth0.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(1L, eth0.getNetStats().get(2).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, eth0.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(1L, eth0.getNetStats().get(3).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, eth0.getNetStats().get(3).getIndex()); + } } @Test - public void testNetRefreshAdd(@Mocked Id id) { + public void testNetRefreshAdd() { List list = new ArrayList<>(); list.add("useless"); list.add("useless"); list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - NetMeter netMeter = new NetMeter(id); - Map netMap = netMeter.getInterfaceUsageMap(); - Assert.assertEquals(1, netMap.size()); - list.remove(2); - list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); - list.add("lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - netMeter.refreshNet(1); - Assert.assertEquals(2, netMap.size()); - InterfaceUsage eth0 = netMap.get("eth0"); - Assert.assertEquals("eth0", eth0.getName()); - Assert.assertEquals(4, eth0.getNetStats().size()); - // recv Bps - Assert.assertEquals(1L, eth0.getNetStats().get(0).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, eth0.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(1L, eth0.getNetStats().get(1).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, eth0.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(1L, eth0.getNetStats().get(2).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, eth0.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(1L, eth0.getNetStats().get(3).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, eth0.getNetStats().get(3).getIndex()); - - InterfaceUsage lo = netMap.get("lo"); - Assert.assertEquals("lo", lo.getName()); - - Assert.assertEquals(4, lo.getNetStats().size()); - // recv Bps - Assert.assertEquals(0L, lo.getNetStats().get(0).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, lo.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(0L, lo.getNetStats().get(1).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, lo.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(0L, lo.getNetStats().get(2).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, lo.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(0L, lo.getNetStats().get(3).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, lo.getNetStats().get(3).getIndex()); + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + + MeterRegistry meterRegistry = new SimpleMeterRegistry(); + NetMeter netMeter = new NetMeter(meterRegistry, "net", Tags.empty()); + netMeter.setOsLinux(true); + netMeter.poll(0, 0); + Map netMap = netMeter.getInterfaceUsageMap(); + Assertions.assertEquals(1, netMap.size()); + list.remove(2); + list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); + list.add("lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); + netMeter.refreshNet(1); + Assertions.assertEquals(2, netMap.size()); + InterfaceUsage eth0 = netMap.get("eth0"); + Assertions.assertEquals("eth0", eth0.getName()); + + // recv Bps + Assertions.assertEquals(1L, eth0.getReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, eth0.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(1L, eth0.getSend().getLastValue()); + Assertions.assertEquals(1, eth0.getSend().getRate(), 0.0); + Assertions.assertEquals(8, eth0.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(1L, eth0.getPacketsReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, eth0.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(1L, eth0.getPacketsSend().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, eth0.getPacketsSend().getIndex()); + + InterfaceUsage lo = netMap.get("lo"); + Assertions.assertEquals("lo", lo.getName()); + + // recv Bps + Assertions.assertEquals(0L, lo.getReceive().getLastValue()); + Assertions.assertEquals(0, lo.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, lo.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(0L, lo.getSend().getLastValue()); + Assertions.assertEquals(0, lo.getSend().getRate(), 0.0); + Assertions.assertEquals(8, lo.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(0L, lo.getPacketsReceive().getLastValue()); + Assertions.assertEquals(0, lo.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, lo.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(0L, lo.getPacketsSend().getLastValue()); + Assertions.assertEquals(0, lo.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, lo.getPacketsSend().getIndex()); + } } @Test - public void testNetRefreshRemove(@Mocked Id id) { + public void testNetRefreshRemove() { List list = new ArrayList<>(); list.add("useless"); list.add("useless"); list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); list.add("lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - NetMeter netMeter = new NetMeter(id); - Map netMap = netMeter.getInterfaceUsageMap(); - Assert.assertEquals(2, netMap.size()); - InterfaceUsage lo = netMap.get("lo"); - InterfaceUsage eth0 = netMap.get("eth0"); - Assert.assertEquals("lo", lo.getName()); - Assert.assertEquals(4, lo.getNetStats().size()); - // recv Bps - Assert.assertEquals(0L, lo.getNetStats().get(0).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, lo.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(0L, lo.getNetStats().get(1).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, lo.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(0L, lo.getNetStats().get(2).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, lo.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(0L, lo.getNetStats().get(3).getLastValue()); - Assert.assertEquals(0, lo.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, lo.getNetStats().get(3).getIndex()); - - Assert.assertEquals("eth0", eth0.getName()); - Assert.assertEquals(4, eth0.getNetStats().size()); - // recv Bps - Assert.assertEquals(0L, eth0.getNetStats().get(0).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, eth0.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(0L, eth0.getNetStats().get(1).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, eth0.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(0L, eth0.getNetStats().get(2).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, eth0.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(0L, eth0.getNetStats().get(3).getLastValue()); - Assert.assertEquals(0, eth0.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, eth0.getNetStats().get(3).getIndex()); - list.remove(2); - list.remove(2); - list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); - netMeter.refreshNet(1); - Assert.assertNull(netMap.get("lo")); - Assert.assertEquals(1, netMap.size()); - Assert.assertEquals("eth0", eth0.getName()); - Assert.assertEquals(4, eth0.getNetStats().size()); - // recv Bps - Assert.assertEquals(1L, eth0.getNetStats().get(0).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(0).getRate(), 0.0); - Assert.assertEquals(0, eth0.getNetStats().get(0).getIndex()); - // send Bps - Assert.assertEquals(1L, eth0.getNetStats().get(1).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(1).getRate(), 0.0); - Assert.assertEquals(8, eth0.getNetStats().get(1).getIndex()); - - // recv pps - Assert.assertEquals(1L, eth0.getNetStats().get(2).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(2).getRate(), 0.0); - Assert.assertEquals(1, eth0.getNetStats().get(2).getIndex()); - - // send pps - Assert.assertEquals(1L, eth0.getNetStats().get(3).getLastValue()); - Assert.assertEquals(1, eth0.getNetStats().get(3).getRate(), 0.0); - Assert.assertEquals(9, eth0.getNetStats().get(3).getIndex()); - } + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + + MeterRegistry meterRegistry = new SimpleMeterRegistry(); + NetMeter netMeter = new NetMeter(meterRegistry, "net", Tags.empty()); + netMeter.setOsLinux(true); + netMeter.poll(0, 1); + + Map netMap = netMeter.getInterfaceUsageMap(); + Assertions.assertEquals(2, netMap.size()); + InterfaceUsage lo = netMap.get("lo"); + InterfaceUsage eth0 = netMap.get("eth0"); + Assertions.assertEquals("lo", lo.getName()); + // recv Bps + Assertions.assertEquals(0L, lo.getReceive().getLastValue()); + Assertions.assertEquals(0, lo.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, lo.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(0L, lo.getSend().getLastValue()); + Assertions.assertEquals(0, lo.getSend().getRate(), 0.0); + Assertions.assertEquals(8, lo.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(0L, lo.getPacketsReceive().getLastValue()); + Assertions.assertEquals(0, lo.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, lo.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(0L, lo.getPacketsSend().getLastValue()); + Assertions.assertEquals(0, lo.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, lo.getPacketsSend().getIndex()); + + Assertions.assertEquals("eth0", eth0.getName()); + // recv Bps + Assertions.assertEquals(0L, eth0.getReceive().getLastValue()); + Assertions.assertEquals(0, eth0.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, eth0.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(0L, eth0.getSend().getLastValue()); + Assertions.assertEquals(0, eth0.getSend().getRate(), 0.0); + Assertions.assertEquals(8, eth0.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(0L, eth0.getPacketsReceive().getLastValue()); + Assertions.assertEquals(0, eth0.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, eth0.getPacketsReceive().getIndex()); + // send pps + Assertions.assertEquals(0L, eth0.getPacketsSend().getLastValue()); + Assertions.assertEquals(0, eth0.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, eth0.getPacketsSend().getIndex()); + list.remove(2); + list.remove(2); + list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); + netMeter.refreshNet(1); + + Assertions.assertEquals("eth0", eth0.getName()); + + // recv Bps + Assertions.assertEquals(1L, eth0.getReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getReceive().getRate(), 0.0); + Assertions.assertEquals(0, eth0.getReceive().getIndex()); + // send Bps + Assertions.assertEquals(1L, eth0.getSend().getLastValue()); + Assertions.assertEquals(1, eth0.getSend().getRate(), 0.0); + Assertions.assertEquals(8, eth0.getSend().getIndex()); + + // recv pps + Assertions.assertEquals(1L, eth0.getPacketsReceive().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsReceive().getRate(), 0.0); + Assertions.assertEquals(1, eth0.getPacketsReceive().getIndex()); + + // send pps + Assertions.assertEquals(1L, eth0.getPacketsSend().getLastValue()); + Assertions.assertEquals(1, eth0.getPacketsSend().getRate(), 0.0); + Assertions.assertEquals(9, eth0.getPacketsSend().getIndex()); + } + + } @Test - public void testCalcMeasurements(@Mocked Id id) { + public void testCalcMeasurements() { List list = new ArrayList<>(); list.add("useless"); list.add("useless"); list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - NetMeter netMeter = new NetMeter(id); - list.remove(2); - list.add("eth0: 3 1 0 0 0 0 0 1 3 1 1 0 0 0 0 0"); - List measurements = new ArrayList<>(); - netMeter.calcMeasurements(measurements, 0L, 1); - Assert.assertEquals(4, measurements.size()); - Measurement receive = measurements.get(0); - Measurement send = measurements.get(1); - Measurement receivePackets = measurements.get(2); - Measurement sendPackets = measurements.get(3); - Assert.assertEquals(3.0, send.value(), 0.0); - Assert.assertEquals(1.0, sendPackets.value(), 0.0); - Assert.assertEquals(3.0, receive.value(), 0.0); - Assert.assertEquals(1.0, receivePackets.value(), 0.0); + MeterRegistry meterRegistry = new SimpleMeterRegistry(); + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + + NetMeter netMeter = new NetMeter(meterRegistry, "net", Tags.empty()); + netMeter.setOsLinux(true); + list.remove(2); + list.add("eth0: 3 1 0 0 0 0 0 1 3 1 1 0 0 0 0 0"); + netMeter.poll(0, 1); + MeasurementTree tree = new MeasurementTree(); + tree.from(meterRegistry.getMeters().iterator(), + new MeasurementGroupConfig("net", "statistic")); + + Measurement receive = tree.findChild("net", "receive").getMeasurements().get(0); + Measurement send = tree.findChild("net", "send").getMeasurements().get(0); + Measurement receivePackets = tree.findChild("net", "receivePackets").getMeasurements().get(0); + Measurement sendPackets = tree.findChild("net", "sendPackets").getMeasurements().get(0); + Assertions.assertEquals(3.0, send.getValue(), 0.0); + Assertions.assertEquals(1.0, sendPackets.getValue(), 0.0); + Assertions.assertEquals(3.0, receive.getValue(), 0.0); + Assertions.assertEquals(1.0, receivePackets.getValue(), 0.0); + } + } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java deleted file mode 100644 index 79b20a71896..00000000000 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.meter.os; - - -import java.io.File; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.collect.Lists; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestOsMeter { - Registry registry = new DefaultRegistry(new ManualClock()); - - @Test - public void testCalcMeasurement(@Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) { - List list = new ArrayList<>(); - list.add("cpu 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1"); - list.add("useless"); - list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); - new MockUp() { - @Mock - public List readLines(File file, Charset encoding) { - return list; - } - }; - new MockUp() { - @Mock - RuntimeMXBean getRuntimeMXBean() { - return mxBean; - } - }; - new MockUp() { - @Mock - public Runtime getRuntime() { - return runtime; - } - }; - new Expectations() { - { - runtime.availableProcessors(); - result = 2; - mxBean.getName(); - result = "6666@desktop111"; - } - }; - OsMeter osMeter = new OsMeter(registry); - list.clear(); - list.add("cpu 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2"); - list.add("useless"); - list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); - - osMeter.calcMeasurements(1, 1); - ArrayList measurements = Lists.newArrayList(osMeter.measure()); - Assert.assertEquals(6, measurements.size()); - Assert.assertEquals(1.75, measurements.get(0).value(), 0.0); - Assert.assertEquals(1.0, measurements.get(1).value(), 0.0); - Assert.assertEquals(1.0, measurements.get(2).value(), 0.0); - Assert.assertEquals(1.0, measurements.get(3).value(), 0.0); - Assert.assertEquals(1.0, measurements.get(4).value(), 0.0); - Assert.assertEquals(1.0, measurements.get(5).value(), 0.0); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestSystemMeter.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestSystemMeter.java new file mode 100644 index 00000000000..05d32250dbf --- /dev/null +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestSystemMeter.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.meter.os; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementGroupConfig; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import com.google.common.io.CharSource; +import com.google.common.io.Files; +import com.sun.management.OperatingSystemMXBean; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; + +public class TestSystemMeter { + @Test + public void testCalcMeasurement() throws IOException { + MeterRegistry meterRegistry = new SimpleMeterRegistry(); + CharSource charSource = Mockito.mock(CharSource.class); + List list = new ArrayList<>(); + list.add("useless"); + list.add("useless"); + list.add("eth0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"); + + try (MockedStatic fileUtilsMockedStatic = Mockito.mockStatic(FileUtils.class); + MockedStatic filesMockedStatic = Mockito.mockStatic(Files.class)) { + fileUtilsMockedStatic.when(() -> { + FileUtils.readLines(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(list); + filesMockedStatic.when(() -> { + Files.asCharSource(Mockito.any(File.class), Mockito.any(Charset.class)); + }).thenReturn(charSource); + + OsMeter osMeter = new OsMeter(meterRegistry); + list.clear(); + list.add("useless"); + list.add("useless"); + list.add("eth0: 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0"); + + SystemMeter systemMeter = osMeter.getCpuMeter(); + OperatingSystemMXBean osBean = Mockito.mock(OperatingSystemMXBean.class); + Mockito.when(osBean.getSystemLoadAverage()).thenReturn(0.775); + Mockito.when(osBean.getCpuLoad()).thenReturn(0.875); + Mockito.when(osBean.getProcessCpuLoad()).thenReturn(0.5); + Mockito.when(osBean.getTotalMemorySize()).thenReturn(1000000000L); + Mockito.when(osBean.getFreeMemorySize()).thenReturn(300000000L); + systemMeter.setOsBean(osBean); + NetMeter netMeter = osMeter.getNetMeter(); + netMeter.setOsLinux(true); + + osMeter.poll(0, 1); + + MeasurementTree tree = new MeasurementTree(); + tree.from(meterRegistry.getMeters().iterator(), + new MeasurementGroupConfig("os", "type")); + + Assertions.assertEquals(0.875, tree.findChild("os", "cpu").getMeasurements().get(0).getValue(), 0.0); + Assertions.assertEquals(0.5, tree.findChild("os", "processCpu").getMeasurements().get(0).getValue(), 0.0); + Assertions.assertEquals(0.7, tree.findChild("os", "memory").getMeasurements().get(0).getValue(), 0.0); + Assertions.assertEquals(0.775, tree.findChild("os", "sla").getMeasurements().get(0).getValue(), 0.0); + Assertions.assertEquals(1.0, tree.findChild("os", "net").getMeasurements().get(0).getValue(), 0.0); + Assertions.assertEquals(1.0, tree.findChild("os", "net").getMeasurements().get(1).getValue(), 0.0); + Assertions.assertEquals(1.0, tree.findChild("os", "net").getMeasurements().get(2).getValue(), 0.0); + Assertions.assertEquals(1.0, tree.findChild("os", "net").getMeasurements().get(3).getValue(), 0.0); + } + } +} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java index 81f29dc35b1..a1867955a60 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java @@ -16,25 +16,24 @@ */ package org.apache.servicecomb.metrics.core.publish; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; + import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; - -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; -import org.apache.log4j.spi.LoggingEvent; -import org.apache.servicecomb.core.Const; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.PolledEvent; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; import org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel; @@ -43,21 +42,33 @@ import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo; import org.junit.After; -import org.junit.Assert; import org.junit.Before; +import org.junit.FixMethodOrder; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Measurement; -import io.vertx.core.impl.VertxImplEx; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Meter.Type; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.vertx.core.impl.VertxImpl; +import jakarta.ws.rs.core.Response.Status; import mockit.Expectations; +import mockit.Injectable; import mockit.Mock; import mockit.MockUp; -import mockit.Mocked; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestDefaultLogPublisher { - GlobalRegistry globalRegistry = new GlobalRegistry(); + MeterRegistry meterRegistry = new SimpleMeterRegistry(); EventBus eventBus = new EventBus(); @@ -65,19 +76,26 @@ public class TestDefaultLogPublisher { LogCollector collector = new LogCollector(); + Environment environment = Mockito.mock(Environment.class); + @Before public void setup() { - + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + publisher.setEnvironment(environment); } @After - public void teardown() { - collector.teardown(); - ArchaiusUtils.resetConfig(); + public void tearDown() { + collector.tearDown(); } @Test public void init_enabled_default() { + Mockito.when(environment.getProperty(DefaultLogPublisher.ENABLED, boolean.class, false)).thenReturn(false); Holder registered = new Holder<>(false); new MockUp(eventBus) { @Mock @@ -86,12 +104,13 @@ void register(Object object) { } }; - publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig()); - Assert.assertFalse(registered.value); + publisher.init(meterRegistry, eventBus, new MetricsBootstrapConfig(environment)); + Assertions.assertFalse(registered.value); } @Test public void init_enabled_true() { + Mockito.when(environment.getProperty(DefaultLogPublisher.ENABLED, boolean.class, false)).thenReturn(true); Holder registered = new Holder<>(); new MockUp(eventBus) { @Mock @@ -100,14 +119,13 @@ void register(Object object) { } }; - ArchaiusUtils.setProperty(DefaultLogPublisher.ENABLED, true); - - publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig()); - Assert.assertTrue(registered.value); + publisher.init(meterRegistry, eventBus, new MetricsBootstrapConfig(environment)); + Assertions.assertTrue(registered.value); } @Test public void init_enabled_false() { + Mockito.when(environment.getProperty(DefaultLogPublisher.ENABLED, boolean.class, false)).thenReturn(false); Holder registered = new Holder<>(); new MockUp(eventBus) { @Mock @@ -116,160 +134,179 @@ void register(Object object) { } }; - ArchaiusUtils.setProperty(DefaultLogPublisher.ENABLED, false); - - publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig()); - Assert.assertNull(registered.value); + publisher.init(meterRegistry, eventBus, new MetricsBootstrapConfig(environment)); + Assertions.assertNull(registered.value); } @Test public void onPolledEvent_failed() { publisher.onPolledEvent(null); - LoggingEvent event = collector.getEvents().get(0); - Assert.assertEquals("Failed to print perf log.", event.getMessage()); - Assert.assertEquals(NullPointerException.class, event.getThrowableInformation().getThrowable().getClass()); + LogEvent event = collector.getEvents().get(0); + Assertions.assertEquals("Failed to print perf log.", event.getMessage().getFormattedMessage()); + Assertions.assertEquals(NullPointerException.class, event.getThrown().getClass()); } @Test - public void onPolledEvent(@Mocked VertxImplEx vertxImplEx, @Mocked MeasurementTree tree) { - new Expectations(VertxUtils.class) { - { - VertxUtils.getVertxMap(); - result = Collections.singletonMap("v", vertxImplEx); - vertxImplEx.getEventLoopContextCreatedCount(); - result = 1; - } - }; - - DefaultPublishModel model = new DefaultPublishModel(); - - PerfInfo perfTotal = new PerfInfo(); - perfTotal.setTps(100_0000); - perfTotal.setMsTotalTime(30000L * 100_0000); - perfTotal.setMsMaxLatency(30000); - - OperationPerf operationPerf = new OperationPerf(); - operationPerf.setOperation("op"); - operationPerf.getStages().put(MeterInvocationConst.STAGE_TOTAL, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_EXECUTOR_QUEUE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_EXECUTION, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_PREPARE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_HANDLERS_REQUEST, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_HANDLERS_RESPONSE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CLIENT_FILTERS_REQUEST, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CLIENT_FILTERS_RESPONSE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CONSUMER_SEND_REQUEST, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_PRODUCER_SEND_RESPONSE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CONSUMER_GET_CONNECTION, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CONSUMER_WRITE_TO_BUF, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CONSUMER_WAIT_RESPONSE, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_CONSUMER_WAKE_CONSUMER, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_SERVER_FILTERS_REQUEST, perfTotal); - operationPerf.getStages().put(MeterInvocationConst.STAGE_SERVER_FILTERS_RESPONSE, perfTotal); - - OperationPerfGroup operationPerfGroup = new OperationPerfGroup(Const.RESTFUL, Status.OK.name()); - operationPerfGroup.addOperationPerf(operationPerf); - - OperationPerfGroups operationPerfGroups = new OperationPerfGroups(); - operationPerfGroups.getGroups().put(operationPerfGroup.getTransport(), - Collections.singletonMap(operationPerfGroup.getStatus(), operationPerfGroup)); - model.getConsumer().setOperationPerfGroups(operationPerfGroups); - model.getProducer().setOperationPerfGroups(operationPerfGroups); - - model.getThreadPools().put("test", new ThreadPoolPublishModel()); - Measurement measurement = new Measurement(null, 0L, 1.0); - - MeasurementNode measurementNodeCpuAll = new MeasurementNode("allProcess", new HashMap<>()); - MeasurementNode measurementNodeCpuProcess = new MeasurementNode("currentProcess", new HashMap<>()); - MeasurementNode measurementNodeSend = new MeasurementNode("send", new HashMap<>()); - MeasurementNode measurementNodeSendPacket = new MeasurementNode("sendPackets", new HashMap<>()); - MeasurementNode measurementNodeRecv = new MeasurementNode("receive", new HashMap<>()); - MeasurementNode measurementNodeRecvPacket = new MeasurementNode("receivePackets", new HashMap<>()); - MeasurementNode measurementNodeEth0 = new MeasurementNode("eth0", new HashMap<>()); - MeasurementNode measurementNodeNet = new MeasurementNode("net", new HashMap<>()); - MeasurementNode measurementNodeOs = new MeasurementNode("os", new HashMap<>()); - - measurementNodeSend.getMeasurements().add(measurement); - measurementNodeRecv.getMeasurements().add(measurement); - measurementNodeCpuAll.getMeasurements().add(measurement); - measurementNodeCpuProcess.getMeasurements().add(measurement); - measurementNodeRecvPacket.getMeasurements().add(measurement); - measurementNodeSendPacket.getMeasurements().add(measurement); - - measurementNodeEth0.getChildren().put("send", measurementNodeSend); - measurementNodeEth0.getChildren().put("receive", measurementNodeRecv); - measurementNodeEth0.getChildren().put("receivePackets", measurementNodeRecvPacket); - measurementNodeEth0.getChildren().put("sendPackets", measurementNodeSendPacket); - - measurementNodeNet.getChildren().put("eth0", measurementNodeEth0); - measurementNodeOs.getChildren().put("cpu", measurementNodeCpuAll); - measurementNodeOs.getChildren().put("processCpu", measurementNodeCpuProcess); - measurementNodeOs.getChildren().put("net", measurementNodeNet); - - measurementNodeOs.getMeasurements().add(measurement); - measurementNodeNet.getMeasurements().add(measurement); - measurementNodeEth0.getMeasurements().add(measurement); - - new MockUp() { - @Mock - DefaultPublishModel createDefaultPublishModel() { - return model; - } - - @Mock - MeasurementTree getTree() { - return tree; - } - }; - new Expectations() { - { - tree.findChild(OsMeter.OS_NAME); - result = measurementNodeOs; - } - }; - publisher.onPolledEvent(new PolledEvent(Collections.emptyList(), Collections.emptyList())); - - List events = collector.getEvents().stream().filter(e -> { - return DefaultLogPublisher.class.getName().equals(e.getLoggerName()); - }).collect(Collectors.toList()); - - LoggingEvent event = events.get(0); - Assert.assertEquals("\n" - + "os:\n" - + " cpu:\n" - + " all: 100.00% process: 100.00%\n" - + " net:\n" - + " send(Bps) recv(Bps) send(pps) recv(pps) interface\n" - + " 1 1 1 1 eth0\n" - + "vertx:\n" - + " instances:\n" - + " name eventLoopContext-created\n" - + " v 1\n" - + "threadPool:\n" - + " corePoolSize maxThreads poolSize currentThreadsBusy queueSize taskCount completedTaskCount name\n" - + " 0 0 0 0 0 0.0 0.0 test\n" - + "consumer:\n" - + " simple:\n" - + " status tps latency operation\n" - + " rest.OK 1000000 30000.000/30000.000 op\n" - + " 1000000 30000.000/30000.000 (summary)\n" - + " details:\n" - + " rest.OK:\n" - + " op:\n" - + " prepare : 30000.000/30000.000 handlersReq : 30000.000/30000.000 cFiltersReq: 30000.000/30000.000 sendReq : 30000.000/30000.000\n" - + " getConnect : 30000.000/30000.000 writeBuf : 30000.000/30000.000 waitResp : 30000.000/30000.000 wakeConsumer: 30000.000/30000.000\n" - + " cFiltersResp: 30000.000/30000.000 handlersResp: 30000.000/30000.000\n" - + "producer:\n" - + " simple:\n" - + " status tps latency operation\n" - + " rest.OK 1000000 30000.000/30000.000 op\n" - + " 1000000 30000.000/30000.000 (summary)\n" - + " details:\n" - + " rest.OK:\n" - + " op:\n" - + " prepare: 30000.000/30000.000 queue : 30000.000/30000.000 filtersReq : 30000.000/30000.000 handlersReq: 30000.000/30000.000\n" - + " execute: 30000.000/30000.000 handlersResp: 30000.000/30000.000 filtersResp: 30000.000/30000.000 sendResp : 30000.000/30000.000\n", - event.getMessage()); + public void onPolledEvent(@Injectable VertxImpl vertxImpl, @Injectable MeasurementTree tree, + @Injectable EventBus eventBus) { + MetricsBootstrapConfig config = Mockito.mock(MetricsBootstrapConfig.class); + try { + Mockito.when(environment.getProperty(DefaultLogPublisher.ENABLED, boolean.class, false)).thenReturn(true); + Mockito.when(config.getLatencyDistribution()).thenReturn("0,1,100"); + publisher.init(meterRegistry, eventBus, config); + new Expectations(VertxUtils.class) { + { + VertxUtils.getVertxMap(); + result = Collections.singletonMap("v", vertxImpl); + } + }; + DefaultPublishModel model = new DefaultPublishModel(); + PerfInfo perfTotal = new PerfInfo(); + perfTotal.setTotalRequests(10_0000); + perfTotal.setMsTotalTime(30000L * 1_0000); + perfTotal.setMsMaxLatency(30000); + OperationPerf operationPerf = new OperationPerf(); + operationPerf.setOperation("op"); + operationPerf.setLatencyDistribution(new Integer[] {12, 120, 1200}); + operationPerf.getStages().put(InvocationStageTrace.STAGE_TOTAL, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PROVIDER_QUEUE, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PROVIDER_BUSINESS, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PREPARE, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_CONSUMER_WAIT, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_CONSUMER_SEND, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_PROVIDER_SEND, perfTotal); + operationPerf.getStages().put(InvocationStageTrace.STAGE_CONSUMER_CONNECTION, perfTotal); + + OperationPerfGroup operationPerfGroup = new OperationPerfGroup(CoreConst.RESTFUL, Status.OK.name()); + operationPerfGroup.addOperationPerf(operationPerf); + + OperationPerfGroups operationPerfGroups = new OperationPerfGroups(); + operationPerfGroups.getGroups().put(operationPerfGroup.getTransport(), + Collections.singletonMap(operationPerfGroup.getStatus(), operationPerfGroup)); + model.getConsumer().setOperationPerfGroups(operationPerfGroups); + model.getProducer().setOperationPerfGroups(operationPerfGroups); + model.getEdge().setOperationPerfGroups(operationPerfGroups); + + model.getThreadPools().put("test", new ThreadPoolPublishModel()); + Id id = new Id("test", Tags.empty(), null, null, Type.OTHER); + Measurement measurement = new Measurement(() -> 1.0, Statistic.VALUE); + + MeasurementNode measurementNodeCpuAll = new MeasurementNode("allProcess", id, new HashMap<>()); + MeasurementNode measurementNodeCpuProcess = new MeasurementNode("currentProcess", id, new HashMap<>()); + MeasurementNode measurementNodeSla = new MeasurementNode("sla", id, new HashMap<>()); + MeasurementNode measurementNodeMemory = new MeasurementNode("memory", id, new HashMap<>()); + MeasurementNode measurementNodeSend = new MeasurementNode("send", id, new HashMap<>()); + MeasurementNode measurementNodeSendPacket = new MeasurementNode("sendPackets", id, new HashMap<>()); + MeasurementNode measurementNodeRecv = new MeasurementNode("receive", id, new HashMap<>()); + MeasurementNode measurementNodeRecvPacket = new MeasurementNode("receivePackets", id, new HashMap<>()); + MeasurementNode measurementNodeEth0 = new MeasurementNode("eth0", id, new HashMap<>()); + MeasurementNode measurementNodeNet = new MeasurementNode("net", id, new HashMap<>()); + MeasurementNode measurementNodeOs = new MeasurementNode("os", id, new HashMap<>()); + + measurementNodeSend.getMeasurements().add(measurement); + measurementNodeRecv.getMeasurements().add(measurement); + measurementNodeCpuAll.getMeasurements().add(measurement); + measurementNodeCpuProcess.getMeasurements().add(measurement); + measurementNodeSla.getMeasurements().add(measurement); + measurementNodeMemory.getMeasurements().add(measurement); + measurementNodeRecvPacket.getMeasurements().add(measurement); + measurementNodeSendPacket.getMeasurements().add(measurement); + + measurementNodeEth0.getChildren().put("send", measurementNodeSend); + measurementNodeEth0.getChildren().put("receive", measurementNodeRecv); + measurementNodeEth0.getChildren().put("receivePackets", measurementNodeRecvPacket); + measurementNodeEth0.getChildren().put("sendPackets", measurementNodeSendPacket); + + measurementNodeNet.getChildren().put("eth0", measurementNodeEth0); + measurementNodeOs.getChildren().put("cpu", measurementNodeCpuAll); + measurementNodeOs.getChildren().put("processCpu", measurementNodeCpuProcess); + measurementNodeOs.getChildren().put("sla", measurementNodeSla); + measurementNodeOs.getChildren().put("memory", measurementNodeMemory); + measurementNodeOs.getChildren().put("net", measurementNodeNet); + + measurementNodeOs.getMeasurements().add(measurement); + measurementNodeNet.getMeasurements().add(measurement); + measurementNodeEth0.getMeasurements().add(measurement); + + new MockUp() { + @Mock + DefaultPublishModel createDefaultPublishModel() { + return model; + } + + @Mock + MeasurementTree getTree() { + return tree; + } + }; + new Expectations() { + { + tree.findChild(OsMeter.OS_NAME); + result = measurementNodeOs; + } + }; + publisher.onPolledEvent(new PolledEvent(Collections.emptyList())); + List events = collector.getEvents().stream() + .filter(e -> "scb-metrics".equals(e.getLoggerName())).toList(); + LogEvent event = events.get(0); + Assertions.assertEquals(""" + os: + cpu: + all usage: 100.00% process usage: 100.00% sla: 1.00 memory usage: 100.00% + net: + send(Bps) recv(Bps) send(pps) recv(pps) interface + 1 1 1 1 eth0 + vertx: + instances: + name eventLoopContext-created + v 0 + threadPool: + coreSize maxThreads poolSize currentBusy rejected queueSize taskCount taskFinished name + 0 0 0 0 NaN 0 0.0 0.0 test + consumer: + simple: + status requests latency [0,1) [1,100) [100,) operation + rest.OK: \s + 100000.0 3000.000/30000.000 12 120 1200 op + 100000.0 3000.000/30000.000 12 120 1200 (summary) + details: + rest.OK: + op: + prepare : 3000.000/30000.000 connection : 3000.000/30000.000 encode-request: 3000.000/30000.000 send : 3000.000/30000.000 + wait : 3000.000/30000.000 decode-response : 3000.000/30000.000 + producer: + simple: + status requests latency [0,1) [1,100) [100,) operation + rest.OK: \s + 100000.0 3000.000/30000.000 12 120 1200 op + 100000.0 3000.000/30000.000 12 120 1200 (summary) + details: + rest.OK: + op: + prepare: 3000.000/30000.000 decode-request : 3000.000/30000.000 queue : 3000.000/30000.000 business-execute: 3000.000/30000.000 + encode-response: 3000.000/30000.000 send: 3000.000/30000.000 + edge: + simple: + status requests latency [0,1) [1,100) [100,) operation + rest.OK: \s + 100000.0 3000.000/30000.000 12 120 1200 op + 100000.0 3000.000/30000.000 12 120 1200 (summary) + details: + rest.OK: + op: + prepare : 3000.000/30000.000 provider-decode : 3000.000/30000.000 connection : 3000.000/30000.000 consumer-encode : 3000.000/30000.000 + consumer-send : 3000.000/30000.000 wait : 3000.000/30000.000 consumer-decode : 3000.000/30000.000 provider-encode : 3000.000/30000.000 + provider-send : 3000.000/30000.000 + """.trim(), + event.getMessage().getFormattedMessage().trim()); + } catch (Exception e) { + e.printStackTrace(); + Assertions.fail("unexpected error happen. " + e.getMessage()); + } } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestHealthCheckerPublisher.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestHealthCheckerPublisher.java deleted file mode 100644 index 3a747d49751..00000000000 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestHealthCheckerPublisher.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.metrics.core.publish; - -import java.util.Map; - -import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; -import org.apache.servicecomb.foundation.metrics.health.HealthChecker; -import org.apache.servicecomb.foundation.metrics.health.HealthCheckerManager; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestHealthCheckerPublisher { - private HealthChecker good = new HealthChecker() { - @Override - public String getName() { - return "test"; - } - - @Override - public HealthCheckResult check() { - return new HealthCheckResult(true, "info", "extra data"); - } - }; - - private HealthChecker bad = new HealthChecker() { - @Override - public String getName() { - return "test2"; - } - - @Override - public HealthCheckResult check() { - return new HealthCheckResult(false, "info2", "extra data 2"); - } - }; - - - @Before - public void reset() { - HealthCheckerManager.getInstance().unregister(good.getName()); - HealthCheckerManager.getInstance().unregister(bad.getName()); - } - - @Test - public void checkHealthGood() { - HealthCheckerManager.getInstance().register(good); - HealthCheckerRestPublisher publisher = new HealthCheckerRestPublisher(); - Assert.assertEquals(true, publisher.checkHealth()); - } - - @Test - public void checkHealthBad() { - HealthCheckerManager.getInstance().register(good); - HealthCheckerManager.getInstance().register(bad); - HealthCheckerRestPublisher publisher = new HealthCheckerRestPublisher(); - Assert.assertEquals(false, publisher.checkHealth()); - } - - @Test - public void checkHealthDetails() { - HealthCheckerManager.getInstance().register(good); - HealthCheckerManager.getInstance().register(bad); - HealthCheckerRestPublisher publisher = new HealthCheckerRestPublisher(); - Map content = publisher.checkHealthDetails(); - Assert.assertEquals(true, content.get("test").isHealthy()); - Assert.assertEquals("info", content.get("test").getInformation()); - Assert.assertEquals("extra data", content.get("test").getExtraData()); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestInvocationPublishModelFactory.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestInvocationPublishModelFactory.java index fadabdc1157..483aa6ab75d 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestInvocationPublishModelFactory.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestInvocationPublishModelFactory.java @@ -16,370 +16,287 @@ */ package org.apache.servicecomb.metrics.core.publish; -import org.apache.servicecomb.core.Const; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; + +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.event.InvocationFinishEvent; import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.metrics.core.InvocationMetersInitializer; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import com.google.common.collect.Lists; import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.vertx.core.json.Json; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; + +import org.skyscreamer.jsonassert.JSONAssert; public class TestInvocationPublishModelFactory { EventBus eventBus = new EventBus(); - GlobalRegistry globalRegistry = new GlobalRegistry(); - - Registry registry = new DefaultRegistry(new ManualClock()); + // not step mode. + MeterRegistry meterRegistry = new SimpleMeterRegistry(); InvocationMetersInitializer invocationMetersInitializer = new InvocationMetersInitializer(); - @Mocked - Invocation invocation; + Invocation invocation = Mockito.mock(Invocation.class); - InvocationStageTrace invocationStageTrace = new InvocationStageTrace(invocation); + InvocationStageTrace invocationStageTrace = Mockito.mock(InvocationStageTrace.class); - @Mocked - Response response; + Response response = Mockito.mock(Response.class); InvocationType invocationType; + Environment environment = Mockito.mock(Environment.class); + @Test - public void createDefaultPublishModel() { - globalRegistry.add(registry); - invocationMetersInitializer.init(globalRegistry, eventBus, null); + public void createDefaultPublishModel() throws Exception { + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + Mockito.when(environment.getProperty(CONFIG_LATENCY_DISTRIBUTION, String.class)).thenReturn("0,1,100"); + + invocationMetersInitializer.init(meterRegistry, eventBus, new MetricsBootstrapConfig(environment)); prepareInvocation(); - globalRegistry.poll(1); - PublishModelFactory factory = new PublishModelFactory(Lists.newArrayList(registry.iterator())); + PublishModelFactory factory = new PublishModelFactory(meterRegistry.getMeters()); DefaultPublishModel model = factory.createDefaultPublishModel(); - String expect = "{\n" - + " \"operationPerfGroups\" : {\n" - + " \"groups\" : {\n" - + " \"rest\" : {\n" - + " \"200\" : {\n" - + " \"transport\" : \"rest\",\n" - + " \"status\" : \"200\",\n" - + " \"operationPerfs\" : [ {\n" - + " \"operation\" : \"m.s.o\",\n" - + " \"stages\" : {\n" - + " \"client_filters_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"prepare\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_send_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 2.0000000000000003E-6,\n" - + " \"msMaxLatency\" : 2.0000000000000003E-6\n" - + " },\n" - + " \"total\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.4000000000000001E-5,\n" - + " \"msMaxLatency\" : 1.4000000000000001E-5\n" - + " },\n" - + " \"handlers_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"client_filters_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_wait_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"handlers_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 3.0000000000000005E-6,\n" - + " \"msMaxLatency\" : 3.0000000000000005E-6\n" - + " },\n" - + " \"consumer_get_connection\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_wake_consumer\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_write_to_buf\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " }\n" - + " }\n" - + " } ],\n" - + " \"summary\" : {\n" - + " \"operation\" : \"\",\n" - + " \"stages\" : {\n" - + " \"prepare\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"client_filters_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"total\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.4000000000000001E-5,\n" - + " \"msMaxLatency\" : 1.4000000000000001E-5\n" - + " },\n" - + " \"consumer_send_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 2.0000000000000003E-6,\n" - + " \"msMaxLatency\" : 2.0000000000000003E-6\n" - + " },\n" - + " \"handlers_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"handlers_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 3.0000000000000005E-6,\n" - + " \"msMaxLatency\" : 3.0000000000000005E-6\n" - + " },\n" - + " \"consumer_wait_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"client_filters_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_get_connection\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_write_to_buf\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"consumer_wake_consumer\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "}"; - Assert.assertEquals(Json.encodePrettily(Json.decodeValue(expect, Object.class)), - Json.encodePrettily(model.getConsumer())); + String expect = """ + { + "operationPerfGroups" : { + "groups" : { + "rest" : { + "200" : { + "transport" : "rest", + "status" : "200", + "operationPerfs" : [ { + "operation" : "m.s.o", + "stages" : { + "consumer-encode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "prepare" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "wait" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "total" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.4E-5, + "msMaxLatency" : 1.4E-5 + }, + "consumer-send" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "connection" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-decode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + } + }, + "latencyDistribution" : [ 1, 1, 1 ] + } ], + "summary" : { + "operation" : "", + "stages" : { + "consumer-encode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "prepare" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "total" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.4E-5, + "msMaxLatency" : 1.4E-5 + }, + "wait" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-send" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "connection" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-decode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + } + }, + "latencyDistribution" : [ 1, 1, 1 ] + } + } + } + } + } + } + """; + JSONAssert.assertEquals(Json.encodePrettily(Json.decodeValue(expect, Object.class)), + Json.encodePrettily(model.getConsumer()), false); - expect = "{\n" - + " \"operationPerfGroups\" : {\n" - + " \"groups\" : {\n" - + " \"rest\" : {\n" - + " \"200\" : {\n" - + " \"transport\" : \"rest\",\n" - + " \"status\" : \"200\",\n" - + " \"operationPerfs\" : [ {\n" - + " \"operation\" : \"m.s.o\",\n" - + " \"stages\" : {\n" - + " \"server_filters_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 0.0,\n" - + " \"msMaxLatency\" : 0.0\n" - + " },\n" - + " \"execution\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 3.0000000000000005E-6,\n" - + " \"msMaxLatency\" : 3.0000000000000005E-6\n" - + " },\n" - + " \"prepare\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 5.0E-6,\n" - + " \"msMaxLatency\" : 5.0E-6\n" - + " },\n" - + " \"producer_send_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 2.0000000000000003E-6,\n" - + " \"msMaxLatency\" : 2.0000000000000003E-6\n" - + " },\n" - + " \"total\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.4000000000000001E-5,\n" - + " \"msMaxLatency\" : 1.4000000000000001E-5\n" - + " },\n" - + " \"handlers_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 6.000000000000001E-6,\n" - + " \"msMaxLatency\" : 6.000000000000001E-6\n" - + " },\n" - + " \"handlers_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"queue\" : {\n" - + " \"tps\" : 0,\n" - + " \"msTotalTime\" : 0.0,\n" - + " \"msMaxLatency\" : 0.0\n" - + " },\n" - + " \"server_filters_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " }\n" - + " }\n" - + " } ],\n" - + " \"summary\" : {\n" - + " \"operation\" : \"\",\n" - + " \"stages\" : {\n" - + " \"server_filters_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 0.0,\n" - + " \"msMaxLatency\" : 0.0\n" - + " },\n" - + " \"prepare\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 5.0E-6,\n" - + " \"msMaxLatency\" : 5.0E-6\n" - + " },\n" - + " \"execution\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 3.0000000000000005E-6,\n" - + " \"msMaxLatency\" : 3.0000000000000005E-6\n" - + " },\n" - + " \"total\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.4000000000000001E-5,\n" - + " \"msMaxLatency\" : 1.4000000000000001E-5\n" - + " },\n" - + " \"producer_send_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 2.0000000000000003E-6,\n" - + " \"msMaxLatency\" : 2.0000000000000003E-6\n" - + " },\n" - + " \"handlers_request\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 6.000000000000001E-6,\n" - + " \"msMaxLatency\" : 6.000000000000001E-6\n" - + " },\n" - + " \"handlers_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " },\n" - + " \"queue\" : {\n" - + " \"tps\" : 0,\n" - + " \"msTotalTime\" : 0.0,\n" - + " \"msMaxLatency\" : 0.0\n" - + " },\n" - + " \"server_filters_response\" : {\n" - + " \"tps\" : 1,\n" - + " \"msTotalTime\" : 1.0000000000000002E-6,\n" - + " \"msMaxLatency\" : 1.0000000000000002E-6\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + " }\n" - + "}"; - Assert.assertEquals(Json.encodePrettily(Json.decodeValue(expect, Object.class)), - Json.encodePrettily(model.getProducer())); + expect = """ + { + "operationPerfGroups" : { + "groups" : { + "rest" : { + "200" : { + "transport" : "rest", + "status" : "200", + "operationPerfs" : [ { + "operation" : "m.s.o", + "stages" : { + "consumer-encode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "prepare" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "wait" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "total" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.4E-5, + "msMaxLatency" : 1.4E-5 + }, + "consumer-send" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "connection" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-decode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + } + }, + "latencyDistribution" : [ 1, 1, 1 ] + } ], + "summary" : { + "operation" : "", + "stages" : { + "consumer-encode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "prepare" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "total" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.4E-5, + "msMaxLatency" : 1.4E-5 + }, + "wait" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-send" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "connection" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + }, + "consumer-decode" : { + "totalRequests" : 1.0, + "msTotalTime" : 1.0000000000000002E-6, + "msMaxLatency" : 1.0000000000000002E-6 + } + }, + "latencyDistribution" : [ 1, 1, 1 ] + } + } + } + } + } + } + """; + JSONAssert.assertEquals(Json.encodePrettily(Json.decodeValue(expect, Object.class)), + Json.encodePrettily(model.getProducer()), false); } protected void prepareInvocation() { - - Deencapsulation.setField(invocationStageTrace, "start", 1L); - Deencapsulation.setField(invocationStageTrace, "startHandlersRequest", 2L); - Deencapsulation.setField(invocationStageTrace, "startClientFiltersRequest", 3L); - Deencapsulation.setField(invocationStageTrace, "startSend", 4L); - Deencapsulation.setField(invocationStageTrace, "finishGetConnection", 5L); - Deencapsulation.setField(invocationStageTrace, "finishWriteToBuffer", 6L); - Deencapsulation.setField(invocationStageTrace, "finishReceiveResponse", 7L); - Deencapsulation.setField(invocationStageTrace, "startClientFiltersResponse", 8L); - Deencapsulation.setField(invocationStageTrace, "finishClientFiltersResponse", 9L); - Deencapsulation.setField(invocationStageTrace, "finishHandlersResponse", 14L); - Deencapsulation.setField(invocationStageTrace, "finish", 15L); - Deencapsulation.setField(invocationStageTrace, "startExecution", 5L); - Deencapsulation.setField(invocationStageTrace, "startSchedule", 6L); - Deencapsulation.setField(invocationStageTrace, "startBusinessMethod", 8L); - Deencapsulation.setField(invocationStageTrace, "finishBusiness", 11L); - Deencapsulation.setField(invocationStageTrace, "finishHandlersResponse", 12L); - Deencapsulation.setField(invocationStageTrace, "finishServerFiltersResponse", 13L); - Deencapsulation.setField(invocationStageTrace, "invocation", invocation); + Mockito.when(invocationStageTrace.calcTotal()).thenReturn(14L); + Mockito.when(invocationStageTrace.calcPrepare()).thenReturn(1L); + Mockito.when(invocationStageTrace.calcConnection()).thenReturn(1L); + Mockito.when(invocationStageTrace.calcConsumerEncodeRequest()).thenReturn(1L); + Mockito.when(invocationStageTrace.calcConsumerSendRequest()).thenReturn(1L); + Mockito.when(invocationStageTrace.calcWait()).thenReturn(1L); + Mockito.when(invocationStageTrace.calcConsumerDecodeResponse()).thenReturn(1L); invocationType = InvocationType.CONSUMER; - new MockUp() { - @Mock - InvocationType getInvocationType() { - return invocationType; - } - - @Mock - boolean isConsumer() { - return InvocationType.CONSUMER.equals(invocationType); - } - - @Mock - String getRealTransportName() { - return Const.RESTFUL; - } - - @Mock - String getMicroserviceQualifiedName() { - return "m.s.o"; - } - @Mock - InvocationStageTrace getInvocationStageTrace() { - return invocationStageTrace; - } - }; + Mockito.when(invocation.getInvocationType()).thenReturn(invocationType); + Mockito.when(invocation.isConsumer()).thenReturn(InvocationType.CONSUMER.equals(invocationType)); + Mockito.when(invocation.getRealTransportName()).thenReturn(CoreConst.RESTFUL); + Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("m.s.o"); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); + Mockito.when(response.getStatusCode()).thenReturn(200); - new Expectations() { - { - response.getStatusCode(); - result = 200; - } - }; InvocationFinishEvent finishEvent = new InvocationFinishEvent(invocation, response); eventBus.post(finishEvent); - invocationType = InvocationType.PRODUCER; + invocationType = InvocationType.PROVIDER; + Mockito.when(invocation.getInvocationType()).thenReturn(invocationType); eventBus.post(finishEvent); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestMetricsRestPublisher.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestMetricsRestPublisher.java deleted file mode 100644 index 40b72f390d5..00000000000 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestMetricsRestPublisher.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.metrics.core.publish; - -import java.util.Map; - -import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.Clock; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; - -public class TestMetricsRestPublisher { - MetricsRestPublisher publisher = new MetricsRestPublisher(); - - @Test - public void measure_globalRegistryNull() { - Map result = publisher.measure(); - - Assert.assertEquals(0, result.size()); - } - - @Test - public void measure_normal() { - Clock clock = new ManualClock(); - GlobalRegistry globalRegistry = new GlobalRegistry(); - Registry registry = new DefaultRegistry(clock); - registry.timer(registry.createId("name", "t1", "v1", "t2", "v2")); - globalRegistry.add(registry); - - EventBus eventBus = new EventBus(); - - publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig()); - Map result = publisher.measure(); - - Assert.assertEquals(2, result.size()); - Assert.assertEquals(0, result.get("name(statistic=count,t1=v1,t2=v2)"), 0); - Assert.assertEquals(0, result.get("name(statistic=totalTime,t1=v1,t2=v2)"), 0); - } -} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestPublishUtils.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestPublishUtils.java index 68bd8f15979..dc8b1ec72d7 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestPublishUtils.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestPublishUtils.java @@ -16,73 +16,78 @@ */ package org.apache.servicecomb.metrics.core.publish; -import java.util.HashMap; import java.util.Map; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; -import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementTree; +import org.apache.servicecomb.metrics.core.meter.ThreadPoolMonitorPublishModelFactory; import org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroup; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo; import org.apache.servicecomb.metrics.core.publish.model.invocation.Utils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; -import com.netflix.spectator.api.patterns.ThreadPoolMonitorPublishModelFactory; +import jakarta.ws.rs.core.Response.Status; +import org.junit.jupiter.api.Test; public class TestPublishUtils { String op = "op"; @Test public void createPerfInfo() { - MeasurementNode stageNode = Utils.createStageNode(MeterInvocationConst.STAGE_TOTAL, 10, 10, 100); + MeasurementNode stageNode = Utils.createStageNode(InvocationStageTrace.STAGE_TOTAL, 10, 10, 100); PerfInfo perf = PublishUtils.createPerfInfo(stageNode); - Assert.assertEquals(10, perf.getTps()); - Assert.assertEquals(1000, perf.calcMsLatency(), 0); - Assert.assertEquals(100000, perf.getMsMaxLatency(), 0); + Assertions.assertEquals(10, perf.getTotalRequests(), 0); + Assertions.assertEquals(1000, perf.calcMsLatency(), 0); + Assertions.assertEquals(100000, perf.getMsMaxLatency(), 0); } @Test public void createOperationPerf() { OperationPerf opPerf = Utils.createOperationPerf(op); - PerfInfo perfInfo = opPerf.findStage(MeterInvocationConst.STAGE_TOTAL); - Assert.assertEquals(10, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + PerfInfo perfInfo = opPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + Integer[] latencyDistribution = opPerf.getLatencyDistribution(); + Assertions.assertEquals(10, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + Assertions.assertEquals(2, latencyDistribution.length); + Assertions.assertEquals(1, latencyDistribution[0].intValue()); + Assertions.assertEquals(2, latencyDistribution[1].intValue()); } @Test public void addOperationPerfGroups() { OperationPerfGroups groups = new OperationPerfGroups(); PublishUtils.addOperationPerfGroups(groups, - Const.RESTFUL, + CoreConst.RESTFUL, op, Utils.createStatusNode(Status.OK.name(), Utils.totalStageNode)); - Map statusMap = groups.getGroups().get(Const.RESTFUL); + Map statusMap = groups.getGroups().get(CoreConst.RESTFUL); OperationPerfGroup group = statusMap.get(Status.OK.name()); - PerfInfo perfInfo = group.getSummary().findStage(MeterInvocationConst.STAGE_TOTAL); - Assert.assertEquals(10, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + PerfInfo perfInfo = group.getSummary().findStage(InvocationStageTrace.STAGE_TOTAL); + Integer[] latencyDistribution = group.getSummary().getLatencyDistribution(); + Assertions.assertEquals(10, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + Assertions.assertEquals(2, latencyDistribution.length); + Assertions.assertEquals(1, latencyDistribution[0].intValue()); + Assertions.assertEquals(2, latencyDistribution[1].intValue()); } @Test public void createThreadPoolPublishModels_empty() { - Map threadPools = new HashMap<>(); - - ThreadPoolMonitorPublishModelFactory.create(new MeasurementTree(), threadPools); + Map threadPools = + ThreadPoolMonitorPublishModelFactory.create(new MeasurementTree()); - Assert.assertTrue(threadPools.isEmpty()); + Assertions.assertTrue(threadPools.isEmpty()); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestSlowInvocationLogger.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestSlowInvocationLogger.java new file mode 100644 index 00000000000..e09252c4e61 --- /dev/null +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestSlowInvocationLogger.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.core.publish; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.OperationConfig; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.event.InvocationFinishEvent; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.google.common.eventbus.EventBus; + +@ExtendWith(MockitoExtension.class) +public class TestSlowInvocationLogger { + @Mock + SCBEngine scbEngine; + + @Mock + Invocation invocation; + + @Mock + OperationMeta operationMeta; + + @Mock + RestOperationMeta restOperationMeta; + + @Mock + OperationConfig operationConfig; + + @Mock + Response response; + + @Mock + InvocationStageTrace stageTrace; + + InvocationFinishEvent event; + + SlowInvocationLogger logger; + + LogCollector logCollector; + + @BeforeEach + public void setup() { + EventBus eventBus = Mockito.spy(EventBus.class); + Mockito.doNothing().when(eventBus).register(Mockito.any()); + Mockito.when(scbEngine.getEventBus()).thenReturn(eventBus); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.getConfig()).thenReturn(operationConfig); + + logger = new SlowInvocationLogger(scbEngine); + event = new InvocationFinishEvent(invocation, response); + logCollector = new LogCollector(); + } + + @AfterEach + public void tearDown() { + logCollector.tearDown(); + } + + @Test + public void disable() { + logger.onInvocationFinish(event); + + Assertions.assertTrue(logCollector.getEvents().isEmpty()); + } + + @Test + public void enableButNotSlow() { + + Mockito.when(operationConfig.isSlowInvocationEnabled()).thenReturn(true); + Mockito.when(operationConfig.getNanoSlowInvocation()).thenReturn(2L); + Mockito.when(stageTrace.calcTotal()).thenReturn(1L); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); + logger.onInvocationFinish(event); + + Assertions.assertTrue(logCollector.getEvents().isEmpty()); + } + + @Test + public void consumerSlow() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Mockito.when(invocation.getEndpoint()).thenReturn(endpoint); + Mockito.when(endpoint.getEndpoint()).thenReturn("rest://1.1.1.1:1234"); + Mockito.when(invocation.isProducer()).thenReturn(false); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta); + Mockito.when(operationConfig.isSlowInvocationEnabled()).thenReturn(true); + Mockito.when(operationConfig.getNanoSlowInvocation()).thenReturn(1L); + Mockito.when(stageTrace.calcTotal()).thenReturn(1L); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); + logger.onInvocationFinish(event); + + Assertions.assertEquals(""" + Slow Consumer invocation [null](0 ms)[null] + http method : null + url : null + endpoint : rest://1.1.1.1:1234 + status code : 0 + total : 0.0ms + prepare : 0.0ms + connection : 0.0ms + consumer-encode : 0.0ms + consumer-send : 0.0ms + wait : 0.0ms + consumer-decode : 0.0ms + """, + logCollector.getEvent(0).getMessage().getFormattedMessage()); + } + + @Test + public void edgeSlow() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Mockito.when(invocation.getEndpoint()).thenReturn(endpoint); + Mockito.when(endpoint.getEndpoint()).thenReturn("rest://1.1.1.1:1234"); + Mockito.when(invocation.isEdge()).thenReturn(true); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta); + Mockito.when(operationConfig.isSlowInvocationEnabled()).thenReturn(true); + Mockito.when(operationConfig.getNanoSlowInvocation()).thenReturn(1L); + Mockito.when(stageTrace.calcTotal()).thenReturn(1L); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); + logger.onInvocationFinish(event); + + Assertions.assertEquals(""" + Slow Edge invocation [null](0 ms)[null] + http method : null + url : null + endpoint : rest://1.1.1.1:1234 + status code : 0 + total : 0.0ms + prepare : 0.0ms + provider-decode : 0.0ms + connection : 0.0ms + consumer-encode : 0.0ms + consumer-send : 0.0ms + wait : 0.0ms + consumer-decode : 0.0ms + provider-encode : 0.0ms + provider-send : 0.0ms + """, + logCollector.getEvent(0).getMessage().getFormattedMessage()); + } + + @Test + public void producerSlow() { + + HttpServletRequestEx requestEx = Mockito.mock(HttpServletRequestEx.class); + + Mockito.when(invocation.getRequestEx()).thenReturn(requestEx); + Mockito.when(requestEx.getRemoteAddr()).thenReturn("1.1.1.1"); + Mockito.when(requestEx.getRemotePort()).thenReturn(1234); + Mockito.when(invocation.isProducer()).thenReturn(true); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta); + Mockito.when(operationConfig.isSlowInvocationEnabled()).thenReturn(true); + Mockito.when(operationConfig.getNanoSlowInvocation()).thenReturn(1L); + Mockito.when(stageTrace.calcTotal()).thenReturn(1L); + Mockito.when(invocation.getInvocationStageTrace()).thenReturn(stageTrace); + + logger.onInvocationFinish(event); + + Assertions.assertEquals(""" + Slow Provider invocation [null](0 ms)[null] + http method : null + url : null + endpoint : 1.1.1.1:1234 + status code : 0 + total : 0.0ms + prepare : 0.0ms + provider-decode : 0.0ms + queue : 0.0ms + execute : 0.0ms + provider-encode : 0.0ms + provider-send : 0.0ms + """, + logCollector.getEvent(0).getMessage().getFormattedMessage()); + } +} diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestThreadPoolPublishModelFactory.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestThreadPoolPublishModelFactory.java index ab8c8986163..f00e49180ae 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestThreadPoolPublishModelFactory.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestThreadPoolPublishModelFactory.java @@ -17,64 +17,54 @@ package org.apache.servicecomb.metrics.core.publish; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.RunnableScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; +import org.apache.servicecomb.core.executor.ThreadPoolExecutorEx; +import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.apache.servicecomb.metrics.core.ThreadPoolMetersInitializer; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.collect.Lists; -import com.google.common.eventbus.EventBus; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.patterns.PolledMeter; -import com.netflix.spectator.api.patterns.ThreadPoolMonitor; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.mockito.junit.jupiter.MockitoExtension; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import org.skyscreamer.jsonassert.JSONAssert; +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) public class TestThreadPoolPublishModelFactory { - protected EventBus eventBus = new EventBus(); + MeterRegistry registry = new SimpleMeterRegistry(); - protected Registry registry = new DefaultRegistry(new ManualClock()); - - @Mocked - ThreadPoolExecutor threadPoolExecutor; - - @Mocked + @Mock BlockingQueue queue; @Test - public void createDefaultPublishModel() throws JsonProcessingException { - new Expectations() { - { - threadPoolExecutor.getQueue(); - result = queue; - queue.size(); - result = 10d; - } - }; - new MockUp() { - @Mock - void delayedExecute(RunnableScheduledFuture task) { + public void createDefaultPublishModel() throws Exception { + ThreadPoolExecutorEx threadPoolExecutor = Mockito.mock(ThreadPoolExecutorEx.class); + Mockito.when(threadPoolExecutor.getQueue()).thenReturn(queue); + Mockito.doReturn(10).when(queue).size(); + MetricsBootstrapConfig metricsBootstrapConfig = Mockito.mock(MetricsBootstrapConfig.class); + ThreadPoolMetersInitializer threadPoolMetersInitializer = new ThreadPoolMetersInitializer() { + @Override + public void createThreadPoolMeters() { + createThreadPoolMeters("test", threadPoolExecutor); } }; - ThreadPoolMonitor.attach(registry, threadPoolExecutor, "test"); - - PolledMeter.update(registry); - PublishModelFactory factory = new PublishModelFactory(Lists.newArrayList(registry.iterator())); + threadPoolMetersInitializer.init(registry, EventManager.getEventBus(), metricsBootstrapConfig); + PublishModelFactory factory = new PublishModelFactory(registry.getMeters()); DefaultPublishModel model = factory.createDefaultPublishModel(); - Assert.assertEquals( - "{\"test\":{\"avgTaskCount\":0.0,\"avgCompletedTaskCount\":0.0,\"currentThreadsBusy\":0,\"maxThreads\":0,\"poolSize\":0,\"corePoolSize\":0,\"queueSize\":10}}", - JsonUtils.writeValueAsString(model.getThreadPools())); + JSONAssert.assertEquals( + """ + {"test":{"avgTaskCount":0.0,"avgCompletedTaskCount":0.0,"currentThreadsBusy":0,"maxThreads":0,"poolSize":0,"corePoolSize":0,"queueSize":10,"rejected":0.0}}""", + JsonUtils.writeValueAsString(model.getThreadPools()), false); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerf.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerf.java index ef7af2377b7..97079bfe168 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerf.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerf.java @@ -16,9 +16,9 @@ */ package org.apache.servicecomb.metrics.core.publish.model.invocation; -import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestOperationPerf { String op = "op"; @@ -27,21 +27,21 @@ public class TestOperationPerf { @Test public void add() { - Assert.assertTrue(opPerf.getStages().isEmpty()); + Assertions.assertTrue(opPerf.getStages().isEmpty()); OperationPerf otherOpPerf = Utils.createOperationPerf(op); opPerf.add(otherOpPerf); - Assert.assertEquals(op, otherOpPerf.getOperation()); + Assertions.assertEquals(op, otherOpPerf.getOperation()); - PerfInfo perfInfo = opPerf.findStage(MeterInvocationConst.STAGE_TOTAL); - Assert.assertEquals(10, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + PerfInfo perfInfo = opPerf.findStage(InvocationStageTrace.STAGE_TOTAL); + Assertions.assertEquals(10, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); - perfInfo = opPerf.findStage(MeterInvocationConst.STAGE_EXECUTION); - Assert.assertEquals(10, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + perfInfo = opPerf.findStage(InvocationStageTrace.STAGE_PROVIDER_BUSINESS); + Assertions.assertEquals(10, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerfGroup.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerfGroup.java index f3655fa30d3..ff0191b14b5 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerfGroup.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestOperationPerfGroup.java @@ -16,25 +16,24 @@ */ package org.apache.servicecomb.metrics.core.publish.model.invocation; -import javax.ws.rs.core.Response.Status; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.junit.jupiter.api.Assertions; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import jakarta.ws.rs.core.Response.Status; +import org.junit.jupiter.api.Test; public class TestOperationPerfGroup { String op = "op"; - OperationPerfGroup group = new OperationPerfGroup(Const.RESTFUL, Status.OK.name()); + OperationPerfGroup group = new OperationPerfGroup(CoreConst.RESTFUL, Status.OK.name()); @Test public void construct() { - Assert.assertEquals(Const.RESTFUL, group.getTransport()); - Assert.assertEquals(Status.OK.name(), group.getStatus()); - Assert.assertTrue(group.getOperationPerfs().isEmpty()); - Assert.assertNull(group.getSummary()); + Assertions.assertEquals(CoreConst.RESTFUL, group.getTransport()); + Assertions.assertEquals(Status.OK.name(), group.getStatus()); + Assertions.assertTrue(group.getOperationPerfs().isEmpty()); + Assertions.assertNull(group.getSummary()); } @Test @@ -43,18 +42,18 @@ public void addOperationPerf() { group.addOperationPerf(opPerf); group.addOperationPerf(opPerf); - Assert.assertThat(group.getOperationPerfs(), Matchers.contains(opPerf, opPerf)); + Assertions.assertTrue(group.getOperationPerfs().contains(opPerf)); OperationPerf summary = group.getSummary(); - PerfInfo perfInfo = summary.findStage(MeterInvocationConst.STAGE_TOTAL); - Assert.assertEquals(20, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + PerfInfo perfInfo = summary.findStage(InvocationStageTrace.STAGE_TOTAL); + Assertions.assertEquals(20, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); - perfInfo = summary.findStage(MeterInvocationConst.STAGE_EXECUTION); - Assert.assertEquals(20, perfInfo.getTps()); - Assert.assertEquals(1000, perfInfo.calcMsLatency(), 0); - Assert.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); + perfInfo = summary.findStage(InvocationStageTrace.STAGE_PROVIDER_BUSINESS); + Assertions.assertEquals(20, perfInfo.getTotalRequests(), 0); + Assertions.assertEquals(1000, perfInfo.calcMsLatency(), 0); + Assertions.assertEquals(100000, perfInfo.getMsMaxLatency(), 0); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestPerfInfo.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestPerfInfo.java index ce147e652a7..35c6d83e72c 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestPerfInfo.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/TestPerfInfo.java @@ -16,18 +16,18 @@ */ package org.apache.servicecomb.metrics.core.publish.model.invocation; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestPerfInfo { @Test public void construct() { PerfInfo perf = new PerfInfo(); - Assert.assertEquals(0, perf.getTps()); - Assert.assertEquals(0, perf.getMsTotalTime(), 0); - Assert.assertEquals(0, perf.getMsMaxLatency(), 0); - Assert.assertEquals(0, perf.calcMsLatency(), 0); + Assertions.assertEquals(0, perf.getTotalRequests(), 0); + Assertions.assertEquals(0, perf.getMsTotalTime(), 0); + Assertions.assertEquals(0, perf.getMsMaxLatency(), 0); + Assertions.assertEquals(0, perf.calcMsLatency(), 0); } @Test @@ -35,21 +35,21 @@ public void add_changeMax() { PerfInfo sum = new PerfInfo(); PerfInfo other = new PerfInfo(); - other.setTps(10); + other.setTotalRequests(10); other.setMsTotalTime(10); other.setMsMaxLatency(100); sum.add(other); other = new PerfInfo(); - other.setTps(20); + other.setTotalRequests(20); other.setMsTotalTime(20); other.setMsMaxLatency(200); sum.add(other); - Assert.assertEquals(30, sum.getTps()); - Assert.assertEquals(30, sum.getMsTotalTime(), 0); - Assert.assertEquals(200, sum.getMsMaxLatency(), 0); - Assert.assertEquals(1.0, sum.calcMsLatency(), 0); + Assertions.assertEquals(30, sum.getTotalRequests(), 0); + Assertions.assertEquals(30, sum.getMsTotalTime(), 0); + Assertions.assertEquals(200, sum.getMsMaxLatency(), 0); + Assertions.assertEquals(1.0, sum.calcMsLatency(), 0); } @Test @@ -57,29 +57,29 @@ public void add_notChangeMax() { PerfInfo sum = new PerfInfo(); PerfInfo other = new PerfInfo(); - other.setTps(10); + other.setTotalRequests(10); other.setMsTotalTime(10); other.setMsMaxLatency(100); sum.add(other); other = new PerfInfo(); - other.setTps(20); + other.setTotalRequests(20); other.setMsTotalTime(20); other.setMsMaxLatency(50); sum.add(other); - Assert.assertEquals(30, sum.getTps()); - Assert.assertEquals(1.0, sum.calcMsLatency(), 0); - Assert.assertEquals(100, sum.getMsMaxLatency(), 0); + Assertions.assertEquals(30, sum.getTotalRequests(), 0); + Assertions.assertEquals(1.0, sum.calcMsLatency(), 0); + Assertions.assertEquals(100, sum.getMsMaxLatency(), 0); } @Test public void testToString() { PerfInfo perf = new PerfInfo(); - perf.setTps(10); + perf.setTotalRequests(10); perf.setMsTotalTime(10); perf.setMsMaxLatency(100); - Assert.assertEquals("PerfInfo [tps=10, msTotalTime=10.0, msLatency=1.0, msMaxLatency=100.0]", perf.toString()); + Assertions.assertEquals("PerfInfo [tps=10.0, msTotalTime=10.0, msLatency=1.0, msMaxLatency=100.0]", perf.toString()); } } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/Utils.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/Utils.java index ec2f7704f2b..17a62c57569 100644 --- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/Utils.java +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/model/invocation/Utils.java @@ -17,50 +17,59 @@ package org.apache.servicecomb.metrics.core.publish.model.invocation; import java.util.HashMap; +import java.util.List; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; +import org.apache.servicecomb.core.invocation.InvocationStageTrace; +import org.apache.servicecomb.foundation.metrics.publish.MeasurementNode; import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.publish.PublishUtils; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.Id; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.Statistic; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Meter.Type; +import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.Tags; +import jakarta.ws.rs.core.Response.Status; public class Utils { - static Registry registry = new DefaultRegistry(); - - public static MeasurementNode totalStageNode = Utils.createStageNode(MeterInvocationConst.STAGE_TOTAL, 10, 10, 100); + public static MeasurementNode totalStageNode = Utils.createStageNode(InvocationStageTrace.STAGE_TOTAL, 10, 10, 100); public static MeasurementNode executeStageNode = - Utils.createStageNode(MeterInvocationConst.STAGE_EXECUTION, 10, 10, 100); + Utils.createStageNode(InvocationStageTrace.STAGE_PROVIDER_BUSINESS, 10, 10, 100); + + public static Id initId = new Id("id", Tags.empty(), null, null, Type.OTHER); public static MeasurementNode createStageNode(String stage, double count, double totalTime, double max) { - Id id = registry.createId("id").withTag(Statistic.count); - Measurement countMeasurement = new Measurement(id.withTag(Statistic.count), 0, count); - Measurement totalTimeMeasurement = new Measurement(id.withTag(Statistic.totalTime), 0, totalTime); - Measurement maxMeasurement = new Measurement(id.withTag(Statistic.max), 0, max); + Id id = initId; + Measurement countMeasurement = new Measurement(() -> count, Statistic.COUNT); + Measurement totalTimeMeasurement = new Measurement(() -> totalTime, Statistic.TOTAL_TIME); + Measurement maxMeasurement = new Measurement(() -> max, Statistic.MAX); - MeasurementNode stageNode = new MeasurementNode(stage, null); - stageNode.addChild(Statistic.count.name(), countMeasurement); - stageNode.addChild(Statistic.totalTime.name(), totalTimeMeasurement); - stageNode.addChild(Statistic.max.name(), maxMeasurement); + MeasurementNode stageNode = new MeasurementNode(stage, id, null); + stageNode.addChild(Statistic.COUNT.name(), id, countMeasurement); + stageNode.addChild(Statistic.TOTAL_TIME.name(), id, totalTimeMeasurement); + stageNode.addChild(Statistic.MAX.name(), id, maxMeasurement); return stageNode; } public static MeasurementNode createStatusNode(String status, MeasurementNode... stageNodes) { - MeasurementNode statusNode = new MeasurementNode(status, new HashMap<>()); - + Id id = initId; + MeasurementNode statusNode = new MeasurementNode(status, id, new HashMap<>()); + MeasurementNode typeNode = new MeasurementNode(MeterInvocationConst.TAG_STAGE, id, new HashMap<>()); + MeasurementNode latencyNode = new MeasurementNode(MeterInvocationConst.TAG_DISTRIBUTION, id, + new HashMap<>()); + List measurements = latencyNode.getMeasurements(); + measurements.add(new Measurement(() -> 1, Statistic.VALUE)); + measurements.add(new Measurement(() -> 2, Statistic.VALUE)); for (MeasurementNode stageNode : stageNodes) { - statusNode.getChildren().put(stageNode.getName(), stageNode); + typeNode.getChildren().put(stageNode.getName(), stageNode); } + statusNode.getChildren().put(latencyNode.getName(), latencyNode); + statusNode.getChildren().put(typeNode.getName(), typeNode); return statusNode; } diff --git a/metrics/metrics-core/src/test/resources/log4j2.xml b/metrics/metrics-core/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/metrics/metrics-core/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/metrics/metrics-integration/metrics-prometheus/pom.xml b/metrics/metrics-integration/metrics-prometheus/pom.xml index 52843dd4c9c..20d23c9d567 100644 --- a/metrics/metrics-integration/metrics-prometheus/pom.xml +++ b/metrics/metrics-integration/metrics-prometheus/pom.xml @@ -21,7 +21,7 @@ metrics-integration org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -48,4 +48,4 @@ - \ No newline at end of file + diff --git a/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusConfiguration.java b/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusConfiguration.java new file mode 100644 index 00000000000..cc986aad016 --- /dev/null +++ b/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.metrics.prometheus; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PrometheusConfiguration { + @Bean + public PrometheusPublisher prometheusPublisher() { + return new PrometheusPublisher(); + } +} diff --git a/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusPublisher.java b/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusPublisher.java index af62c09fa10..19cd28d510b 100644 --- a/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusPublisher.java +++ b/metrics/metrics-integration/metrics-prometheus/src/main/java/org/apache/servicecomb/metrics/prometheus/PrometheusPublisher.java @@ -21,20 +21,21 @@ import java.util.ArrayList; import java.util.List; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import com.google.common.eventbus.EventBus; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Registry; -import com.netflix.spectator.api.Tag; +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; import io.prometheus.client.Collector; import io.prometheus.client.Collector.MetricFamilySamples.Sample; import io.prometheus.client.CollectorRegistry; @@ -43,19 +44,25 @@ public class PrometheusPublisher extends Collector implements Collector.Describable, MetricsInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(PrometheusPublisher.class); - static final String METRICS_PROMETHEUS_ADDRESS = "servicecomb.metrics.prometheus.address"; + public static final String METRICS_PROMETHEUS_ADDRESS = "servicecomb.metrics.prometheus.address"; private HTTPServer httpServer; - private GlobalRegistry globalRegistry; + private MeterRegistry meterRegistry; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - this.globalRegistry = globalRegistry; + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + this.meterRegistry = meterRegistry; //prometheus default port allocation is here : https://github.com/prometheus/prometheus/wiki/Default-port-allocations - String address = - DynamicPropertyFactory.getInstance().getStringProperty(METRICS_PROMETHEUS_ADDRESS, "0.0.0.0:9696").get(); + String address = environment.getProperty(METRICS_PROMETHEUS_ADDRESS, String.class, "0.0.0.0:9696"); try { InetSocketAddress socketAddress = getSocketAddress(address); @@ -79,36 +86,35 @@ private InetSocketAddress getSocketAddress(String address) { @Override public List describe() { List familySamples = new ArrayList<>(); - if (globalRegistry == null) { - return familySamples; - } List samples = new ArrayList<>(); - for (Registry registry : globalRegistry.getRegistries()) { - for (Meter meter : registry) { - meter.measure().forEach(measurement -> { - Sample sample = convertMeasurementToSample(measurement); - samples.add(sample); - }); - } + + for (Meter meter : this.meterRegistry.getMeters()) { + meter.measure().forEach(measurement -> { + Sample sample = convertMeasurementToSample(meter, measurement); + samples.add(sample); + }); } - familySamples.add(new MetricFamilySamples("ServiceComb Metrics", Type.UNTYPED, "ServiceComb Metrics", samples)); + familySamples.add(new MetricFamilySamples("ServiceComb_Metrics", Type.UNKNOWN, "ServiceComb Metrics", samples)); return familySamples; } - protected Sample convertMeasurementToSample(Measurement measurement) { - String prometheusName = measurement.id().name().replace(".", "_"); + protected Sample convertMeasurementToSample(Meter meter, Measurement measurement) { + String prometheusName = meter.getId().getName().replace(".", "_"); List labelNames = new ArrayList<>(); List labelValues = new ArrayList<>(); - for (Tag tag : measurement.id().tags()) { - labelNames.add(tag.key()); - labelValues.add(tag.value()); + labelNames.add("appId"); + labelValues.add(BootStrapProperties.readApplication(environment)); + + for (Tag tag : meter.getId().getTags()) { + labelNames.add(tag.getKey()); + labelValues.add(tag.getValue()); } - return new Sample(prometheusName, labelNames, labelValues, measurement.value()); + return new Sample(prometheusName, labelNames, labelValues, measurement.getValue()); } @Override @@ -122,7 +128,7 @@ public void destroy() { return; } - httpServer.stop(); + httpServer.close(); httpServer = null; LOGGER.info("Prometheus httpServer stopped."); } diff --git a/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer b/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer deleted file mode 100644 index b4c9faac2c6..00000000000 --- a/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.metrics.prometheus.PrometheusPublisher \ No newline at end of file diff --git a/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..e64b469a4a9 --- /dev/null +++ b/metrics/metrics-integration/metrics-prometheus/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.metrics.prometheus.PrometheusConfiguration diff --git a/metrics/metrics-integration/metrics-prometheus/src/test/java/org/apache/servicecomb/metrics/prometheus/TestPrometheusPublisher.java b/metrics/metrics-integration/metrics-prometheus/src/test/java/org/apache/servicecomb/metrics/prometheus/TestPrometheusPublisher.java index cc10b4e6b7d..bd9fdd0bfd7 100644 --- a/metrics/metrics-integration/metrics-prometheus/src/test/java/org/apache/servicecomb/metrics/prometheus/TestPrometheusPublisher.java +++ b/metrics/metrics-integration/metrics-prometheus/src/test/java/org/apache/servicecomb/metrics/prometheus/TestPrometheusPublisher.java @@ -17,77 +17,93 @@ package org.apache.servicecomb.metrics.prometheus; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; +import static org.apache.servicecomb.metrics.prometheus.PrometheusPublisher.METRICS_PROMETHEUS_ADDRESS; + import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.netflix.spectator.api.Counter; -import com.netflix.spectator.api.DefaultRegistry; -import com.netflix.spectator.api.ManualClock; -import com.netflix.spectator.api.Registry; +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + import com.sun.net.httpserver.HttpServer; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.prometheus.client.exporter.HTTPServer; -@SuppressWarnings("restriction") public class TestPrometheusPublisher { - GlobalRegistry globalRegistry = new GlobalRegistry(new ManualClock()); + MeterRegistry meterRegistry = new SimpleMeterRegistry(); PrometheusPublisher publisher = new PrometheusPublisher(); - @Rule - public ExpectedException thrown = ExpectedException.none(); + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + publisher.setEnvironment(environment); + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + } - @AfterClass + @AfterAll public static void teardown() { - ArchaiusUtils.resetConfig(); } @Test public void testBadPublishAddress() { - thrown.expect(ServiceCombException.class); - - ArchaiusUtils.setProperty(PrometheusPublisher.METRICS_PROMETHEUS_ADDRESS, "a:b:c"); - publisher.init(globalRegistry, null, null); + Mockito.when(environment.getProperty(METRICS_PROMETHEUS_ADDRESS, String.class, "0.0.0.0:9696")) + .thenReturn("a:b:c"); + Assertions.assertThrows(ServiceCombException.class, () -> { + publisher.init(meterRegistry, null, null); + }); } @Test public void testBadPublishAddress_BadPort() { - thrown.expect(ServiceCombException.class); - - ArchaiusUtils.setProperty(PrometheusPublisher.METRICS_PROMETHEUS_ADDRESS, "localhost:xxxx"); - publisher.init(globalRegistry, null, null); + Mockito.when(environment.getProperty(METRICS_PROMETHEUS_ADDRESS, String.class, "0.0.0.0:9696")) + .thenReturn("localhost:xxxx"); + Assertions.assertThrows(ServiceCombException.class, () -> { + publisher.init(meterRegistry, null, null); + }); } @Test public void testBadPublishAddress_TooLargePort() { - thrown.expect(ServiceCombException.class); - - ArchaiusUtils.setProperty(PrometheusPublisher.METRICS_PROMETHEUS_ADDRESS, "localhost:9999999"); - publisher.init(globalRegistry, null, null); + Mockito.when(environment.getProperty(METRICS_PROMETHEUS_ADDRESS, String.class, "0.0.0.0:9696")) + .thenReturn("localhost:9999999"); + Assertions.assertThrows(ServiceCombException.class, () -> { + publisher.init(meterRegistry, null, null); + }); } @Test public void collect() throws IllegalAccessException, IOException { - ArchaiusUtils.setProperty(PrometheusPublisher.METRICS_PROMETHEUS_ADDRESS, "localhost:0"); - publisher.init(globalRegistry, null, null); - - Registry registry = new DefaultRegistry(new ManualClock()); - globalRegistry.add(registry); + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_APPLICATION)).thenReturn("testAppId"); + Mockito.when(environment.getProperty(METRICS_PROMETHEUS_ADDRESS, String.class, "0.0.0.0:9696")) + .thenReturn("localhost:0"); + publisher.setEnvironment(environment); + publisher.init(meterRegistry, null, new MetricsBootstrapConfig(environment)); - Counter counter = registry.counter("count.name", "tag1", "tag1v", "tag2", "tag2v"); + Counter counter = meterRegistry.counter("count.name", "tag1", "tag1v", "tag2", "tag2v"); counter.increment(); HTTPServer httpServer = (HTTPServer) FieldUtils.readField(publisher, "httpServer", true); @@ -96,9 +112,12 @@ public void collect() throws IllegalAccessException, IOException { URL url = new URL("http://localhost:" + server.getAddress().getPort() + "/metrics"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); try (InputStream is = conn.getInputStream()) { - Assert.assertEquals("# HELP ServiceComb Metrics ServiceComb Metrics\n" + - "# TYPE ServiceComb Metrics untyped\n" + - "count_name{tag1=\"tag1v\",tag2=\"tag2v\",} 1.0\n", IOUtils.toString(is)); + Assertions.assertEquals(""" + # HELP ServiceComb_Metrics ServiceComb Metrics + # TYPE ServiceComb_Metrics untyped + count_name{appId="testAppId",tag1="tag1v",tag2="tag2v",} 1.0 + """, + IOUtils.toString(is, StandardCharsets.UTF_8)); } publisher.destroy(); diff --git a/metrics/metrics-integration/pom.xml b/metrics/metrics-integration/pom.xml index 05e6fc25e1c..d989f8bc2a4 100644 --- a/metrics/metrics-integration/pom.xml +++ b/metrics/metrics-integration/pom.xml @@ -22,7 +22,7 @@ metrics org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/metrics/pom.xml b/metrics/pom.xml index 10bcd71d738..95eb85051fc 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -24,8 +24,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default metrics diff --git a/parent/pom.xml b/parent/pom.xml deleted file mode 100644 index ef3a8dd0c46..00000000000 --- a/parent/pom.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - - 4.0.0 - - - org.apache.servicecomb - java-chassis-dependencies - 1.2.0-SNAPSHOT - ../java-chassis-dependencies - - - java-chassis-parent - pom - - Java Chassis::Parent - Java Chassis Parent - https://github.com/apache/servicecomb-java-chassis - - - UTF-8 - 1.8 - - -Dfile.encoding=UTF-8 - UTF-8 - - - - - - com.github.tomakehurst - wiremock-standalone - 2.6.0 - test - - - - - - - org.awaitility - awaitility - 3.0.0 - test - - - org.hamcrest - hamcrest-all - test - - - org.jmockit - jmockit - test - - - org.mockito - mockito-core - test - - - org.hamcrest - hamcrest-core - test - - - org.powermock - powermock-api-mockito - test - - - org.powermock - powermock-module-junit4 - test - - - com.github.seanyinx - unit-scaffolding - 1.0.0 - test - - - junit - junit - test - - - - javax.inject - javax.inject - - - org.springframework - spring-aspects - - - diff --git a/parents/default/pom.xml b/parents/default/pom.xml new file mode 100644 index 00000000000..b8954d029b8 --- /dev/null +++ b/parents/default/pom.xml @@ -0,0 +1,120 @@ + + + + + 4.0.0 + + + org.apache.servicecomb + java-chassis-dependencies + 3.4.0-SNAPSHOT + ../../dependencies/default + + + java-chassis-parent + pom + + Java Chassis::Parent::Default + Java Chassis Parent + https://github.com/apache/servicecomb-java-chassis + + + + org.awaitility + awaitility + test + + + org.hamcrest + hamcrest-all + test + + + org.hamcrest + hamcrest-core + test + + + org.mockito + mockito-core + test + + + net.bytebuddy + byte-buddy + test + + + com.github.seanyinx + unit-scaffolding + test + + + junit + junit + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.assertj + assertj-core + test + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.boot + spring-boot-starter-logging + + + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-api + test + + + org.apache.logging.log4j + log4j-core + test + + + diff --git a/parents/pom.xml b/parents/pom.xml new file mode 100644 index 00000000000..8fce5793c5c --- /dev/null +++ b/parents/pom.xml @@ -0,0 +1,38 @@ + + + + + 4.0.0 + + + + org.apache.servicecomb + java-chassis + 3.4.0-SNAPSHOT + + + java-chassis-parents + Java Chassis::Parents + pom + + + default + + + diff --git a/pom.xml b/pom.xml index 6743791138d..25882c4ca33 100644 --- a/pom.xml +++ b/pom.xml @@ -23,13 +23,13 @@ org.apache apache - 18 + 35 org.apache.servicecomb java-chassis - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT pom ServiceComb Java Chassis @@ -37,8 +37,39 @@ https://github.com/apache/servicecomb-java-chassis + 17 + 17 UTF-8 + 17 true + + + 3.6.0 + 4.3.0 + 12.2.0 + 0.48.0 + 3.6.3 + 3.2.8 + 0.8.14 + 3.12.0 + 2.5 + 3.15.0 + 3.5.4 + 3.4.2 + 3.9.0 + 3.2.0 + 1.7.1 + 0.6.1 + 3.19.2 + 1.47.0 + 12.3.1 + 3.1.1 + 3.21.0 + 3.3.0 + 4.9.8.2 + 3.5.4 + 3.5.4 + @@ -104,11 +135,10 @@ - parent - java-chassis-dependencies + dependencies + parents common foundations - deployment handlers providers transports @@ -119,29 +149,29 @@ edge metrics dynamic-config - archetypes - java-chassis-dependencies-springboot2 - java-chassis-spring-boot + spring-boot + solutions + clients + governance + huawei-cloud - - - - org.apache.maven.plugins - maven-jxr-plugin - 2.5 - - - - + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + org.apache.maven.plugins maven-checkstyle-plugin - ../etc/checkstyle.xml - **/demo/** + ci/checkstyle/checkstyle.xml + ci/checkstyle/suppressions.xml + true @@ -169,7 +199,34 @@ org.codehaus.mojo license-maven-plugin - 1.16 + 2.7.1 + + + default-cli + + + true + + /org/codehaus/mojo/license/third-party-file-groupByMultiLicense.ftl + + The Apache Software License, Version 2.0|The Apache License, Version 2.0 + The Apache Software License, Version 2.0|Apache License, Version 2.0 + The Apache Software License, Version 2.0|Apache Public License 2.0 + The Apache Software License, Version 2.0|Apache 2 + The Apache Software License, Version 2.0|Apache 2.0 + The Apache Software License, Version 2.0|Apache-2.0 + The Apache Software License, Version 2.0|Apache License 2.0 + The Apache Software License, Version 2.0|Apache License, version 2.0 + 3-Clause BSD License|BSD 3-clause + 3-Clause BSD License|BSD 3-Clause + Eclipse Public License v1.0|Eclipse Public License 1.0 + Eclipse Public License v1.0|Eclipse Public License - v 1.0 + The MIT License|MIT License + + org.apache.servicecomb* + + + org.apache.rat @@ -180,12 +237,13 @@ .travis.yml **/*.md **/*.MD - **/target/* + **/*.iml + .github/** **/etc/eclipse-java-google-style.xml **/etc/intellij-java-google-style.xml - **/resources/ssl/** + **/resources/ssl/** **/src/release/licenses/** @@ -193,19 +251,23 @@ **/**.log **/target/** + + **/resources/webroot/images/*.png + **/resources/webroot/images/*.jpg - **/io/vertx/ext/web/impl/MimeTypesUtils.java + **/org/apache/servicecomb/foundation/common/utils/MimeTypesUtils.java **/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java - **/java/org/apache/servicecomb/foundation/vertx/stream/PumpImplEx.java **/java/org/apache/servicecomb/foundation/protobuf/internal/model/ProtobufRoot.java + + **/resources/google/protobuf/**.proto org.codehaus.mojo exec-maven-plugin - 1.2.1 + ${exec-maven-plugin.version} @@ -217,31 +279,45 @@ org.apache.maven.plugins maven-surefire-plugin + ${surefire-maven-plugin.version} + + -Djdk.attach.allowAttachSelf + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/java.nio=ALL-UNNAMED + --add-opens java.base/java.nio.channels.spi=ALL-UNNAMED + --add-opens java.base/java.nio.file=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.util.concurrent=ALL-UNNAMED + --add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED + --add-opens java.base/java.util.jar=ALL-UNNAMED + --add-opens java.base/java.util.stream=ALL-UNNAMED + --add-opens java.base/java.time=ALL-UNNAMED + --add-opens java.base/jdk.internal.loader=ALL-UNNAMED + --add-opens java.base/sun.net.dns=ALL-UNNAMED + --add-opens java.base/sun.nio.ch=ALL-UNNAMED + --add-opens java.base/sun.security.jca=ALL-UNNAMED + --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED + --add-reads java.base=java.desktop + ${maven.test.skip} ${maven.test.failure.ignore} ${excludesFile} - 1 + 5 + 2 true alphabetical - - org.codehaus.mojo - findbugs-maven-plugin - 3.0.1 - - true - true - true - findbugs-exclude.xml - - org.apache.maven.plugins maven-jar-plugin + ${maven-jar-plugin.version} @@ -251,13 +327,30 @@ + + com.github.spotbugs + spotbugs-maven-plugin + + true + true + Medium + ${session.executionRootDirectory}/ci/spotbugs/exclude.xml + + + + + check + + + + org.eluder.coveralls coveralls-maven-plugin - 4.3.0 + ${coveralls-maven-plugin.version} ${project.basedir}/coverage-reports/target/site/jacoco-aggregate/jacoco.xml @@ -266,22 +359,17 @@ maven-remote-resources-plugin - 1.5 + ${maven-remote-resources-plugin.version} io.fabric8 docker-maven-plugin - 0.20.0 - - - org.codehaus.gmaven - gmaven-plugin - 1.5 + ${docker-maven-plugin.version} org.jacoco jacoco-maven-plugin - 0.7.8 + ${jacoco-maven-plugin.version} *$Impl_* @@ -325,67 +413,60 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + ${maven-compiler-plugin.version} - 1.8 - 1.8 + -parameters true true + - -Werror -Xlint:all - - -Xlint:-classfile - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.jacoco - jacoco-maven-plugin - [0.0.1,) - - prepare-agent - - - - - - - - - - org.apache.maven.plugins maven-project-info-reports-plugin - 2.4 + ${maven-project-info-reports-plugin.version} org.apache.maven.plugins maven-site-plugin - 3.4 + ${site-maven-plugin.version} org.apache.maven.plugins maven-checkstyle-plugin - 2.17 + ${checkstyle-maven-plugin.version} true com.puppycrawl.tools checkstyle - 7.6 + ${puppycrawl-checkstyle.version} + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + ${main.class} + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbug-maven-plugin.version} + @@ -393,6 +474,9 @@ release + + distribution + false @@ -405,7 +489,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${gpg-maven-plugin.version} sign-artifacts @@ -419,7 +503,7 @@ org.apache.maven.plugins maven-source-plugin - 2.2.1 + ${source-maven-plugin.version} attach-sources @@ -432,7 +516,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${javadoc-maven-plugin.version} attach-javadocs @@ -441,11 +525,22 @@ + + 17 + + + + created + t + Date created: + + + org.apache.maven.plugins maven-release-plugin - 2.5.3 + ${release-maven-plugin.version} true false @@ -460,16 +555,6 @@ it demo - integration-tests - - - - distribution - - false - - - java-chassis-distribution @@ -478,12 +563,6 @@ coverage-reports - - samples - - samples - - docker-machine @@ -514,6 +593,59 @@ + + owasp-dependency-check + + + + org.owasp + dependency-check-maven + ${dependency-check-maven-plugin.version} + + + src/owasp-dependency-check-suppressions.xml + + 7 + false + false + false + false + false + false + false + false + false + false + false + false + + + + + aggregate + + + + + + + + + + org.owasp + dependency-check-maven + ${dependency-check-maven-plugin.version} + + + + aggregate + + + + + + + diff --git a/providers/pom.xml b/providers/pom.xml index 250b9268eeb..9bd8a52f271 100644 --- a/providers/pom.xml +++ b/providers/pom.xml @@ -21,8 +21,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default providers Java Chassis::Providers diff --git a/providers/provider-jaxrs/pom.xml b/providers/provider-jaxrs/pom.xml index e0e7ccd82b3..1bd923857c6 100644 --- a/providers/provider-jaxrs/pom.xml +++ b/providers/provider-jaxrs/pom.xml @@ -23,7 +23,7 @@ org.apache.servicecomb providers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT provider-jaxrs Java Chassis::Providers::JAXRS @@ -36,9 +36,5 @@ org.apache.servicecomb swagger-invocation-jaxrs - - org.apache.servicecomb - swagger-generator-jaxrs - diff --git a/providers/provider-pojo/pom.xml b/providers/provider-pojo/pom.xml index 3cf90fa7c43..922f544b9f5 100644 --- a/providers/provider-pojo/pom.xml +++ b/providers/provider-pojo/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb providers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT provider-pojo Java Chassis::Providers::POJO @@ -31,18 +31,29 @@ java-chassis-core - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + foundation-test-scaffolding test - log4j - log4j + org.apache.servicecomb + registry-local test - org.apache.servicecomb - foundation-test-scaffolding + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.mockito + mockito-inline + test diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java new file mode 100644 index 00000000000..87e6efbc1d3 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/DefaultMethodMeta.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.springframework.util.ReflectionUtils; + +public class DefaultMethodMeta { + private final Map defaultMethodHandles = new ConcurrentHashMapEx<>(); + + // java11 + private final Method privateLookupIn = ReflectionUtils.findMethod(MethodHandles.class, + "privateLookupIn", Class.class, Lookup.class); + + // only for java8 + private Constructor lookupConstructor; + + public MethodHandle getOrCreateMethodHandle(Object proxy, Method method) { + return defaultMethodHandles.computeIfAbsent(method, key -> createMethodHandle(proxy, method)); + } + + protected MethodHandle createMethodHandle(Object proxy, Method method) { + try { + if (privateLookupIn != null) { + return createForJava11(proxy, method); + } + + return createForJava8(proxy, method); + } catch (Exception e) { + throw AsyncUtils.rethrow(e); + } + } + + protected MethodHandle createForJava11(Object proxy, Method method) throws Exception { + Lookup lookup = MethodHandles.lookup(); + Lookup privateLookup = (Lookup) privateLookupIn.invoke(null, method.getDeclaringClass(), lookup); + return privateLookup + .unreflectSpecial(method, method.getDeclaringClass()) + .bindTo(proxy); + } + + protected MethodHandle createForJava8(Object proxy, Method method) throws Exception { + if (lookupConstructor == null) { + lookupConstructor = ReflectionUtils.accessibleConstructor(Lookup.class, Class.class); + } + return lookupConstructor.newInstance(method.getDeclaringClass()) + .unreflectSpecial(method, method.getDeclaringClass()) + .bindTo(proxy); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/FilterInvocationCaller.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/FilterInvocationCaller.java new file mode 100644 index 00000000000..ef8829bee30 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/FilterInvocationCaller.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import static org.apache.servicecomb.core.provider.consumer.InvokerUtils.isAsyncMethod; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; + +public class FilterInvocationCaller implements InvocationCaller { + // if not a sync method, should never throw exception directly + @Override + public Object call(Method method, PojoConsumerMetaRefresher metaRefresher, PojoInvocationCreator invocationCreator, + Object[] args) { + if (isAsyncMethod(method)) { + CompletableFuture invocationFuture = invocationCreator.createAsync(method, metaRefresher, args); + return invocationFuture.thenCompose(this::doCall); + } + PojoInvocation invocation = invocationCreator.create(method, metaRefresher, args); + CompletableFuture future = CompletableFuture.completedFuture(invocation) + .thenCompose(this::doCall); + return InvokerUtils.toSync(future, invocation.getWaitTime()); + } + + protected CompletableFuture doCall(PojoInvocation invocation) { + return InvokerUtils.invoke(invocation) + .thenApply(response -> { + if (response.isSucceed()) { + return invocation.convertResponse(response); + } + throw ExceptionFactory.convertConsumerException(response.getResult()); + }); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/InvocationCaller.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/InvocationCaller.java new file mode 100644 index 00000000000..79b1e9f80b5 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/InvocationCaller.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import java.lang.reflect.Method; + +public interface InvocationCaller { + Object call(Method method, PojoConsumerMetaRefresher metaRefresher, PojoInvocationCreator invocationCreator, + Object[] args); +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java index 21dfa8d17b7..ac0be460210 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/Invoker.java @@ -20,58 +20,33 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.provider.consumer.InvokerUtils; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.swagger.engine.SwaggerConsumer; -import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.InvocationContextCompletableFuture; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.springframework.util.StringUtils; public class Invoker implements InvocationHandler { - static class InvokerMeta { - final ReferenceConfig referenceConfig; + public static final Method METHOD_HASH_CODE; - final MicroserviceMeta microserviceMeta; + public static final Method METHOD_EQUALS; - final SchemaMeta schemaMeta; + public static final Method METHOD_TO_STRING; - final SwaggerConsumer swaggerConsumer; - - public InvokerMeta(ReferenceConfig referenceConfig, - MicroserviceMeta microserviceMeta, SchemaMeta schemaMeta, - SwaggerConsumer swaggerConsumer) { - this.referenceConfig = referenceConfig; - this.microserviceMeta = microserviceMeta; - this.schemaMeta = schemaMeta; - this.swaggerConsumer = swaggerConsumer; - } - - // initialized and meta not changed - public boolean isValid() { - SCBEngine.getInstance().ensureStatusUp(); - return swaggerConsumer != null && microserviceMeta == referenceConfig.getMicroserviceMeta(); + static { + try { + METHOD_HASH_CODE = Object.class.getDeclaredMethod("hashCode"); + METHOD_EQUALS = Object.class.getDeclaredMethod("equals", Object.class); + METHOD_TO_STRING = Object.class.getDeclaredMethod("toString"); + } catch (NoSuchMethodException e) { + throw new Error(e); } } - // 原始数据 - protected String microserviceName; + protected final PojoConsumerMetaRefresher metaRefresher; - protected String schemaId; + protected final PojoInvocationCreator invocationCreator; - protected Class consumerIntf; + protected final DefaultMethodMeta defaultMethodMeta = new DefaultMethodMeta(); - // 生成的数据 - protected InvokerMeta invokerMeta = new InvokerMeta(null, null, null, null); + protected InvocationCaller invocationCaller; @SuppressWarnings("unchecked") public static T createProxy(String microserviceName, String schemaId, Class consumerIntf) { @@ -80,105 +55,65 @@ public static T createProxy(String microserviceName, String schemaId, Class< } public Invoker(String microserviceName, String schemaId, Class consumerIntf) { - this.microserviceName = microserviceName; - this.schemaId = schemaId; - this.consumerIntf = consumerIntf; + this.metaRefresher = createInvokerMeta(microserviceName, schemaId, consumerIntf); + this.invocationCreator = createInvocationCreator(); } - protected InvokerMeta createInvokerMeta() { - ReferenceConfig referenceConfig = findReferenceConfig(); - MicroserviceMeta microserviceMeta = referenceConfig.getMicroserviceMeta(); - - SchemaMeta schemaMeta; - if (StringUtils.isEmpty(schemaId)) { - // 未指定schemaId,看看consumer接口是否等于契约接口 - schemaMeta = microserviceMeta.findSchemaMeta(consumerIntf); - if (schemaMeta == null) { - // 尝试用consumer接口名作为schemaId - schemaMeta = microserviceMeta.findSchemaMeta(consumerIntf.getName()); - } - } else { - schemaMeta = microserviceMeta.findSchemaMeta(schemaId); - } - - if (schemaMeta == null) { - throw new IllegalStateException( - String.format( - "Schema not exist, microserviceName=%s, schemaId=%s, consumer interface=%s; " - + "new producer not running or not deployed.", - microserviceName, - StringUtils.isEmpty(schemaId) ? "" : schemaId, - consumerIntf.getName())); - } + protected PojoConsumerMetaRefresher createInvokerMeta(String microserviceName, String schemaId, + Class consumerIntf) { + return new PojoConsumerMetaRefresher(microserviceName, schemaId, consumerIntf); + } - SwaggerConsumer swaggerConsumer = CseContext.getInstance().getSwaggerEnvironment().createConsumer(consumerIntf, - schemaMeta.getSwaggerIntf()); - return new InvokerMeta(referenceConfig, microserviceMeta, schemaMeta, swaggerConsumer); + public PojoInvocationCreator createInvocationCreator() { + return new PojoInvocationCreator(); } - protected ReferenceConfig findReferenceConfig() { - return SCBEngine.getInstance().getReferenceConfigForInvoke(microserviceName); + protected InvocationCaller createInvocationCaller() { + return new FilterInvocationCaller(); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { - InvokerMeta currentInvokerMeta = invokerMeta; - if (!currentInvokerMeta.isValid()) { - synchronized (this) { - currentInvokerMeta = invokerMeta; - if (!currentInvokerMeta.isValid()) { - invokerMeta = createInvokerMeta(); - currentInvokerMeta = invokerMeta; - } - } + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.isDefault()) { + return defaultMethodMeta.getOrCreateMethodHandle(proxy, method) + .invokeWithArguments(args); } - - SwaggerConsumerOperation consumerOperation = currentInvokerMeta.swaggerConsumer.findOperation(method.getName()); - if (consumerOperation == null) { - throw new IllegalStateException( - String.format( - "Consumer method %s:%s not exist in contract, microserviceName=%s, schemaId=%s; " - + "new producer not running or not deployed.", - consumerIntf.getName(), - method.getName(), - microserviceName, - schemaId)); + if (METHOD_HASH_CODE.equals(method)) { + return objectHashCode(proxy); + } + if (METHOD_EQUALS.equals(method)) { + return objectEquals(proxy, args[0]); + } + if (METHOD_TO_STRING.equals(method)) { + return objectToString(proxy); } - Invocation invocation = InvocationFactory - .forConsumer(currentInvokerMeta.referenceConfig, currentInvokerMeta.schemaMeta, - consumerOperation.getSwaggerMethod().getName(), null); - - consumerOperation.getArgumentsMapper().toInvocation(args, invocation); + SCBEngine.getInstance().ensureStatusUp(); + prepareInvocationCaller(); + return invocationCaller.call(method, metaRefresher, invocationCreator, args); + } - if (CompletableFuture.class.equals(method.getReturnType())) { - return completableFutureInvoke(invocation, consumerOperation); + protected void prepareInvocationCaller() { + if (invocationCaller != null) { + return; } - return syncInvoke(invocation, consumerOperation); + this.invocationCaller = createInvocationCaller(); } - protected Object syncInvoke(Invocation invocation, SwaggerConsumerOperation consumerOperation) { - Response response = InvokerUtils.innerSyncInvoke(invocation); - if (response.isSuccessed()) { - return consumerOperation.getResponseMapper().mapResponse(response); - } + private String objectClassName(Object obj) { + return obj.getClass().getName(); + } + + private int objectHashCode(Object obj) { + return System.identityHashCode(obj); + } - throw ExceptionFactory.convertConsumerException(response.getResult()); + private boolean objectEquals(Object obj, Object other) { + return obj == other; } - protected CompletableFuture completableFutureInvoke(Invocation invocation, - SwaggerConsumerOperation consumerOperation) { - CompletableFuture future = new InvocationContextCompletableFuture<>(invocation); - InvokerUtils.reactiveInvoke(invocation, response -> { - if (response.isSuccessed()) { - Object result = consumerOperation.getResponseMapper().mapResponse(response); - future.complete(result); - return; - } - - future.completeExceptionally(response.getResult()); - }); - return future; + private String objectToString(Object obj) { + return objectClassName(obj) + '@' + Integer.toHexString(objectHashCode(obj)); } } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConfig.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConfig.java deleted file mode 100644 index af6358b0894..00000000000 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConfig.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import com.netflix.config.DynamicPropertyFactory; - -@Configuration -class PojoConfig { - - private static final String LOADING_MODE_BLOCKING = "blocking"; - - @Bean - Executor executor() { - if (LOADING_MODE_BLOCKING.equals(loadingMode())) { - return Runnable::run; - } - - return Executors.newSingleThreadExecutor(); - } - - private String loadingMode() { - return DynamicPropertyFactory.getInstance() - .getStringProperty( - "servicecomb.rpcReference.loadingMode", - LOADING_MODE_BLOCKING) - .get(); - } -} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConst.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConst.java index 74b50e1a046..90030f91152 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConst.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConst.java @@ -25,6 +25,10 @@ private PojoConst() { public static final String SCHEMA_ID = "schema-id"; + public static final String FIELD_SCHEMA_INTERFACE = "schemaInterfaceName"; + + public static final String SCHEMA_INTERFACE = "schema-interface"; + public static final String IMPL = "implementation"; public static final String FIELD_MICROSERVICE_NAME = "microserviceName"; diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerMetaRefresher.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerMetaRefresher.java new file mode 100644 index 00000000000..46350d40c5e --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerMetaRefresher.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; +import org.apache.servicecomb.provider.pojo.definition.PojoConsumerMeta; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.Response.Status; + +public class PojoConsumerMetaRefresher { + private static final Logger LOGGER = LoggerFactory.getLogger(PojoConsumerMetaRefresher.class); + + protected final String microserviceName; + + // can be null, should find SchemaMeta by consumerIntf in this time + protected final String schemaId; + + protected final Class consumerIntf; + + protected SCBEngine scbEngine; + + // not always equals codec meta + // for highway, codec meta is relate to target instance + // to avoid limit producer to only allow append parameter + protected PojoConsumerMeta consumerMeta; + + public PojoConsumerMetaRefresher(String microserviceName, String schemaId, Class consumerIntf) { + this.microserviceName = microserviceName; + this.schemaId = schemaId; + this.consumerIntf = consumerIntf; + } + + public PojoConsumerMeta getLatestMeta() { + ensureStatusUp(); + ensureMetaAvailable(); + return consumerMeta; + } + + public CompletableFuture getLatestMetaAsync() { + ensureStatusUp(); + return ensureMetaAvailableAsync().thenCompose(v -> CompletableFuture.completedFuture(consumerMeta)); + } + + private void ensureStatusUp() { + if (scbEngine == null) { + if (SCBEngine.getInstance() == null) { + String message = + "The request is rejected. Cannot process the request due to SCBEngine not ready."; + LOGGER.warn(message); + throw new InvocationException(Status.SERVICE_UNAVAILABLE, new CommonExceptionData(message)); + } + + this.scbEngine = SCBEngine.getInstance(); + } + + scbEngine.ensureStatusUp(); + } + + private void ensureMetaAvailable() { + if (isNeedRefresh()) { + synchronized (this) { + if (isNeedRefresh()) { + this.consumerMeta = refreshMeta(); + } + } + } + } + + private CompletableFuture ensureMetaAvailableAsync() { + if (isNeedRefresh()) { + return refreshMetaAsync(); + } + return CompletableFuture.completedFuture(null); + } + + private boolean isNeedRefresh() { + return consumerMeta == null; + } + + protected PojoConsumerMeta refreshMeta() { + MicroserviceReferenceConfig microserviceReferenceConfig = scbEngine + .getOrCreateReferenceConfig(microserviceName); + if (microserviceReferenceConfig == null) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData(String.format("Failed to invoke service %s. Maybe service" + + " not registered or no active instance.", microserviceName))); + } + MicroserviceMeta microserviceMeta = microserviceReferenceConfig.getMicroserviceMeta(); + + SchemaMeta schemaMeta = findSchemaMeta(microserviceMeta); + if (schemaMeta == null) { + throw new IllegalStateException( + String.format( + "Schema not exist, microserviceName=%s, schemaId=%s, consumer interface=%s; " + + "new producer not running or not deployed.", + microserviceName, + schemaId, + consumerIntf.getName())); + } + + SwaggerConsumer swaggerConsumer = scbEngine.getSwaggerEnvironment() + .createConsumer(consumerIntf, schemaMeta.getSwagger()); + return new PojoConsumerMeta(microserviceReferenceConfig, swaggerConsumer, schemaMeta); + } + + protected CompletableFuture refreshMetaAsync() { + CompletableFuture microserviceReferenceConfigFuture = scbEngine + .getOrCreateReferenceConfigAsync(microserviceName); + return microserviceReferenceConfigFuture.thenCompose((microserviceReferenceConfig) -> { + if (microserviceReferenceConfig == null) { + return CompletableFuture.failedFuture(new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData(String.format("Failed to invoke service %s. Maybe service" + + " not registered or no active instance.", microserviceName)))); + } + synchronized (this) { + if (isNeedRefresh()) { + MicroserviceMeta microserviceMeta = microserviceReferenceConfig.getMicroserviceMeta(); + + SchemaMeta schemaMeta = findSchemaMeta(microserviceMeta); + if (schemaMeta == null) { + return CompletableFuture.failedFuture(new IllegalStateException( + String.format( + "Schema not exist, microserviceName=%s, schemaId=%s, consumer interface=%s; " + + "new producer not running or not deployed.", + microserviceName, + schemaId, + consumerIntf.getName()))); + } + + SwaggerConsumer swaggerConsumer = scbEngine.getSwaggerEnvironment() + .createConsumer(consumerIntf, schemaMeta.getSwagger()); + consumerMeta = new PojoConsumerMeta(microserviceReferenceConfig, swaggerConsumer, schemaMeta); + } + return CompletableFuture.completedFuture(null); + } + }); + } + + private SchemaMeta findSchemaMeta(MicroserviceMeta microserviceMeta) { + // if present schemaId, just use it + if (StringUtils.isNotEmpty(schemaId)) { + return microserviceMeta.findSchemaMeta(schemaId); + } + + // try interface name second + return microserviceMeta.findSchemaMeta(consumerIntf.getName()); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerProvider.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerProvider.java deleted file mode 100644 index 86c23304bd9..00000000000 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoConsumerProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo; - -import static org.apache.servicecomb.provider.pojo.PojoConst.POJO; - -import org.apache.servicecomb.core.provider.consumer.AbstractConsumerProvider; -import org.springframework.stereotype.Component; - -@Component -public class PojoConsumerProvider extends AbstractConsumerProvider { - @Override - public String getName() { - return POJO; - } -} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocation.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocation.java new file mode 100644 index 00000000000..c0d7b9b8af3 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocation.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.provider.pojo.definition.PojoConsumerOperationMeta; +import org.apache.servicecomb.swagger.invocation.Response; + +public class PojoInvocation extends Invocation { + protected final PojoConsumerOperationMeta consumerOperationMeta; + + public PojoInvocation(PojoConsumerOperationMeta consumerOperationMeta) { + super(consumerOperationMeta.createReferenceConfig(), + consumerOperationMeta.getOperationMeta(), + consumerOperationMeta.getInvocationRuntimeType(), + null); + this.consumerOperationMeta = consumerOperationMeta; + InvocationFactory.setSrcMicroservice(this); + } + + public ReferenceConfig getReferenceConfig() { + return referenceConfig; + } + + public Object convertResponse(Response response) { + return consumerOperationMeta.getSwaggerConsumerOperation().getResponseMapper().mapResponse(response); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocationCreator.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocationCreator.java new file mode 100644 index 00000000000..54dd320fe68 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoInvocationCreator.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.provider.pojo.definition.PojoConsumerMeta; +import org.apache.servicecomb.provider.pojo.definition.PojoConsumerOperationMeta; + +public class PojoInvocationCreator { + public PojoInvocation create(Method method, PojoConsumerMetaRefresher metaRefresher, Object[] args) { + long startCreateInvocation = System.nanoTime(); + PojoConsumerMeta pojoConsumerMeta = metaRefresher.getLatestMeta(); + PojoConsumerOperationMeta consumerOperationMeta = pojoConsumerMeta.ensureFindOperationMeta(method); + + PojoInvocation invocation = new PojoInvocation(consumerOperationMeta); + invocation.setSuccessResponseType(consumerOperationMeta.getResponsesType()); + invocation.setInvocationArguments(consumerOperationMeta.getSwaggerConsumerOperation().toInvocationArguments(args)); + invocation.setSync(consumerOperationMeta.isSync()); + invocation.getInvocationStageTrace().startCreateInvocation(startCreateInvocation); + invocation.getInvocationStageTrace().finishCreateInvocation(); + return invocation; + } + + public CompletableFuture createAsync(Method method, PojoConsumerMetaRefresher metaRefresher, + Object[] args) { + CompletableFuture pojoConsumerMetaFuture = metaRefresher.getLatestMetaAsync(); + return pojoConsumerMetaFuture.thenCompose(pojoConsumerMeta -> { + PojoConsumerOperationMeta consumerOperationMeta = pojoConsumerMeta.ensureFindOperationMeta(method); + + PojoInvocation invocation = new PojoInvocation(consumerOperationMeta); + invocation.setSuccessResponseType(consumerOperationMeta.getResponsesType()); + invocation.setInvocationArguments( + consumerOperationMeta.getSwaggerConsumerOperation().toInvocationArguments(args)); + invocation.setSync(consumerOperationMeta.isSync()); + + return CompletableFuture.completedFuture(invocation); + }); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoProducerProvider.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoProducerProvider.java index 119831640c6..b63c065618a 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoProducerProvider.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/PojoProducerProvider.java @@ -17,31 +17,25 @@ package org.apache.servicecomb.provider.pojo; -import javax.inject.Inject; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.core.provider.producer.AbstractProducerProvider; -import org.apache.servicecomb.foundation.common.RegisterManager; +import org.apache.servicecomb.core.provider.producer.ProducerMeta; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.provider.pojo.instance.PojoInstanceFactory; import org.apache.servicecomb.provider.pojo.instance.SpringInstanceFactory; import org.apache.servicecomb.provider.pojo.schema.PojoProducerMeta; import org.apache.servicecomb.provider.pojo.schema.PojoProducers; -import org.springframework.stereotype.Component; -@Component public class PojoProducerProvider extends AbstractProducerProvider { - private RegisterManager instanceFactoryMgr = - new RegisterManager<>("pojo instance factory manager"); + private final Map instanceFactoryMgr = new HashMap<>(); - @Inject - private ProducerSchemaFactory producerSchemaFactory; - - @Inject - private PojoProducers pojoProducers; - - public void registerInstanceFactory(InstanceFactory instanceFactory) { - instanceFactoryMgr.register(instanceFactory.getImplName(), instanceFactory); + private void registerInstanceFactory(InstanceFactory instanceFactory) { + instanceFactoryMgr.put(instanceFactory.getImplName(), instanceFactory); } public PojoProducerProvider() { @@ -50,20 +44,19 @@ public PojoProducerProvider() { } @Override - public void init() throws Exception { - for (PojoProducerMeta pojoProducerMeta : pojoProducers.getProducers()) { - initPojoProducerMeta(pojoProducerMeta); + public List init() { + // for some test cases, there is no spring context + if (BeanUtils.getContext() == null) { + return Collections.emptyList(); + } - try { - producerSchemaFactory.getOrCreateProducerSchema( - pojoProducerMeta.getSchemaId(), - pojoProducerMeta.getInstanceClass(), - pojoProducerMeta.getInstance()); - } catch (Throwable e) { - throw new IllegalArgumentException( - "create producer schema failed, class=" + pojoProducerMeta.getInstanceClass().getName(), e); - } + PojoProducers pojoProducers = BeanUtils.getContext().getBean(PojoProducers.class); + for (ProducerMeta producerMeta : pojoProducers.getProducerMetas()) { + PojoProducerMeta pojoProducerMeta = (PojoProducerMeta) producerMeta; + initPojoProducerMeta(pojoProducerMeta); } + + return pojoProducers.getProducerMetas(); } @Override @@ -72,29 +65,44 @@ public String getName() { } private void initPojoProducerMeta(PojoProducerMeta pojoProducerMeta) { + parseSchemaInterface(pojoProducerMeta); + parseImplementation(pojoProducerMeta); + } + + private void parseImplementation(PojoProducerMeta pojoProducerMeta) { if (pojoProducerMeta.getInstance() != null) { return; } - String[] nameAndValue = parseImplementation(pojoProducerMeta.getImplementation()); - - InstanceFactory factory = instanceFactoryMgr.ensureFindValue(nameAndValue[0]); - Object instance = factory.create(nameAndValue[1]); - Class instanceClass = BeanUtils.getImplClassFromBean(instance); - - pojoProducerMeta.setInstance(instance); - pojoProducerMeta.setInstanceClass(instanceClass); - } - - private String[] parseImplementation(String implementation) { + String implementation = pojoProducerMeta.getImplementation(); String implName = PojoConst.POJO; - String implValue = implementation; + String implValue = pojoProducerMeta.getImplementation(); int idx = implementation.indexOf(':'); if (idx != -1) { implName = implementation.substring(0, idx); implValue = implementation.substring(idx + 1); } - return new String[] {implName, implValue}; + InstanceFactory factory = instanceFactoryMgr.get(implName); + if (factory == null) { + throw new IllegalStateException("failed to find instance factory, name=" + implName); + } + + Object instance = factory.create(implValue); + pojoProducerMeta.setInstance(instance); + } + + private void parseSchemaInterface(PojoProducerMeta pojoProducerMeta) { + if (pojoProducerMeta.getSchemaInterface() != null || StringUtils + .isEmpty(pojoProducerMeta.getSchemaInterfaceName())) { + return; + } + + try { + Class si = Class.forName(pojoProducerMeta.getSchemaInterfaceName()); + pojoProducerMeta.setSchemaInterface(si); + } catch (Exception e) { + throw new Error("can not find schema interface " + pojoProducerMeta.getSchemaInterfaceName(), e); + } } } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/ProviderPojoConfiguration.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/ProviderPojoConfiguration.java new file mode 100644 index 00000000000..81bf83a756d --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/ProviderPojoConfiguration.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo; + +import org.apache.servicecomb.provider.pojo.schema.PojoProducers; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ProviderPojoConfiguration { + @Bean + public static RpcReferenceBeanDefinitionRegistry rpcReferenceBeanDefinitionRegistry() { + return new RpcReferenceBeanDefinitionRegistry(); + } + + @Bean + public static PojoProducers pojoProducers() { + return new PojoProducers(); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReference.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReference.java index ae9354f49c1..a800b3f24ed 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReference.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReference.java @@ -17,7 +17,9 @@ package org.apache.servicecomb.provider.pojo; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; @@ -26,7 +28,7 @@ @Documented @Retention(RUNTIME) -@Target(FIELD) +@Target({FIELD, METHOD, ANNOTATION_TYPE}) public @interface RpcReference { String microserviceName(); diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java new file mode 100644 index 00000000000..32e10077131 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcReferenceBeanDefinitionRegistry.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.pojo; + +import org.apache.servicecomb.provider.pojo.reference.RpcReferenceProcessor; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; + +/** + * In order to support FactoryBean eager inject @RpcReference, add RpcReferenceProcessor + * before FactoryBean is initialized. + */ +public class RpcReferenceBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor { + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + beanFactory.addBeanPostProcessor(new RpcReferenceProcessor(beanFactory)); + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcSchema.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcSchema.java index 80e1c82da10..f9d9fbc1109 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcSchema.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/RpcSchema.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.provider.pojo; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -30,8 +31,10 @@ @Inherited @Documented @Retention(RUNTIME) -@Target(TYPE) +@Target({TYPE, ANNOTATION_TYPE}) @Component public @interface RpcSchema { String schemaId() default ""; + + Class schemaInterface() default Object.class; } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerMeta.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerMeta.java new file mode 100644 index 00000000000..1de414759d8 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerMeta.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo.definition; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import jakarta.ws.rs.core.Response.Status; + +public class PojoConsumerMeta { + private final MicroserviceReferenceConfig microserviceReferenceConfig; + + private final SchemaMeta schemaMeta; + + private final Map operationMetas = new HashMap<>(); + + public PojoConsumerMeta(MicroserviceReferenceConfig microserviceReferenceConfig, SwaggerConsumer swaggerConsumer, + SchemaMeta schemaMeta) { + this.microserviceReferenceConfig = microserviceReferenceConfig; + this.schemaMeta = schemaMeta; + + for (SwaggerConsumerOperation swaggerConsumerOperation : swaggerConsumer.getOperations().values()) { + String operationId = swaggerConsumerOperation.getSwaggerOperation().getOperationId(); + // SwaggerConsumer has make sure can find operationMeta + OperationMeta operationMeta = schemaMeta.ensureFindOperation(operationId); + PojoConsumerOperationMeta pojoConsumerOperationMeta = new PojoConsumerOperationMeta(this, operationMeta, + swaggerConsumerOperation); + + operationMetas.put(swaggerConsumerOperation.getConsumerMethod(), pojoConsumerOperationMeta); + } + } + + public MicroserviceReferenceConfig getMicroserviceReferenceConfig() { + return microserviceReferenceConfig; + } + + public MicroserviceMeta getMicroserviceMeta() { + return schemaMeta.getMicroserviceMeta(); + } + + public SchemaMeta getSchemaMeta() { + return schemaMeta; + } + + public PojoConsumerOperationMeta ensureFindOperationMeta(Method method) { + PojoConsumerOperationMeta pojoConsumerOperationMeta = operationMetas.get(method); + if (pojoConsumerOperationMeta == null) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, + String.format( + "Consumer method %s:%s not exist in contract, microserviceName=%s, schemaId=%s.", + method.getDeclaringClass().getName(), + method.getName(), + schemaMeta.getMicroserviceName(), + schemaMeta.getSchemaId())); + } + return pojoConsumerOperationMeta; + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerOperationMeta.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerOperationMeta.java new file mode 100644 index 00000000000..1d5bf5fed93 --- /dev/null +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/definition/PojoConsumerOperationMeta.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.pojo.definition; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.findResponseTypeProcessor; + +import java.lang.reflect.Type; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.core.definition.InvocationRuntimeType; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.reflect.TypeToken; + +public class PojoConsumerOperationMeta { + private final PojoConsumerMeta pojoConsumerMeta; + + private final OperationMeta operationMeta; + + private final SwaggerConsumerOperation swaggerConsumerOperation; + + private JavaType responseType; + + private InvocationRuntimeType invocationRuntimeType; + + private final boolean sync; + + public PojoConsumerOperationMeta(PojoConsumerMeta pojoConsumerMeta, OperationMeta operationMeta, + SwaggerConsumerOperation swaggerConsumerOperation) { + this.pojoConsumerMeta = pojoConsumerMeta; + this.operationMeta = operationMeta; + this.swaggerConsumerOperation = swaggerConsumerOperation; + this.sync = InvokerUtils.isSyncMethod(swaggerConsumerOperation.getConsumerMethod()); + initResponseType(); + initRuntimeType(); + } + + private void initRuntimeType() { + invocationRuntimeType = operationMeta.buildBaseConsumerRuntimeType(); + invocationRuntimeType.setArgumentsMapper(swaggerConsumerOperation.getArgumentsMapper()); + invocationRuntimeType.setAssociatedClass(swaggerConsumerOperation.getConsumerClass()); + invocationRuntimeType.setAssociatedMethod(swaggerConsumerOperation.getConsumerMethod()); + } + + public PojoConsumerMeta getPojoConsumerMeta() { + return pojoConsumerMeta; + } + + public OperationMeta getOperationMeta() { + return operationMeta; + } + + public SwaggerConsumerOperation getSwaggerConsumerOperation() { + return swaggerConsumerOperation; + } + + public JavaType getResponsesType() { + return responseType; + } + + public InvocationRuntimeType getInvocationRuntimeType() { + return invocationRuntimeType; + } + + public ReferenceConfig createReferenceConfig() { + return pojoConsumerMeta.getMicroserviceReferenceConfig() + .createReferenceConfig(operationMeta); + } + + private void initResponseType() { + Type intfResponseType = + TypeToken.of(swaggerConsumerOperation.getConsumerClass()) + .resolveType(swaggerConsumerOperation.getConsumerMethod().getGenericReturnType()) + .getType(); + if (intfResponseType instanceof Class && Part.class.isAssignableFrom((Class) intfResponseType)) { + responseType = TypeFactory.defaultInstance().constructType(Part.class); + return; + } + + intfResponseType = findResponseTypeProcessor(intfResponseType).extractResponseType(intfResponseType); + if (intfResponseType != null) { + responseType = TypeFactory.defaultInstance().constructType(intfResponseType); + } + } + + public boolean isSync() { + return sync; + } +} diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/instance/PojoInstanceFactory.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/instance/PojoInstanceFactory.java index d5ee0f61943..291d0cdc90a 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/instance/PojoInstanceFactory.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/instance/PojoInstanceFactory.java @@ -30,7 +30,7 @@ public String getImplName() { public Object create(String className) { try { Class clazz = Class.forName(className); - return clazz.newInstance(); + return clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new Error("Fail to create instance of class:" + className, e); } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/ReferenceDefParser.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/ReferenceDefParser.java index a57b4877b7f..3884b49145b 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/ReferenceDefParser.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/ReferenceDefParser.java @@ -17,12 +17,12 @@ package org.apache.servicecomb.provider.pojo.reference; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; import org.apache.servicecomb.provider.pojo.PojoConst; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; import org.w3c.dom.Element; public class ReferenceDefParser extends AbstractSingleBeanDefinitionParser { @@ -39,9 +39,9 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit String schemaId = element.getAttribute(PojoConst.SCHEMA_ID); String intf = element.getAttribute(PojoConst.INTERFACE); - if (StringUtils.isEmpty(intf) && !StringUtils.isEmpty(schemaId)) { + if (StringUtils.isEmpty(intf) && StringUtils.isNotEmpty(schemaId)) { // 尝试将schemaId当作接口名使用 - Class consumerIntf = ClassUtils.getClassByName(null, schemaId); + Class consumerIntf = ReflectUtils.getClassByName(schemaId); if (consumerIntf != null) { intf = schemaId; } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java index 71be2c9ca00..ba5ded3f12c 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/reference/RpcReferenceProcessor.java @@ -17,28 +17,27 @@ package org.apache.servicecomb.provider.pojo.reference; import java.lang.reflect.Field; +import java.lang.reflect.Method; import org.apache.servicecomb.provider.pojo.RpcReference; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.stereotype.Component; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringValueResolver; -@Component -public class RpcReferenceProcessor implements BeanPostProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; +public class RpcReferenceProcessor implements BeanPostProcessor { + private final ConfigurableBeanFactory beanFactory; + + public RpcReferenceProcessor(ConfigurableBeanFactory beanFactory) { + this.beanFactory = beanFactory; + } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 扫描所有field,处理扩展的field标注 - ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() { - public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { - processConsumerField(bean, field); - } - }); - + ReflectionUtils.doWithFields(bean.getClass(), field -> processConsumerField(bean, field)); + ReflectionUtils.doWithMethods(bean.getClass(), method -> processConsumerMethod(bean, beanName, method)); return bean; } @@ -47,6 +46,14 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw return bean; } + protected void processConsumerMethod(Object bean, String beanName, Method method) throws BeansException { + RpcReference reference = method.getAnnotation(RpcReference.class); + if (reference == null) { + return; + } + handleReferenceMethod(bean, beanName, method, reference); + } + protected void processConsumerField(Object bean, Field field) { RpcReference reference = field.getAnnotation(RpcReference.class); if (reference == null) { @@ -56,24 +63,32 @@ protected void processConsumerField(Object bean, Field field) { handleReferenceField(bean, field, reference); } - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; + private void handleReferenceMethod(Object bean, String beanName, Method method, RpcReference reference) + throws BeansException { + try { + PojoReferenceMeta pojoReference = createPojoReferenceMeta(reference, method.getParameterTypes()[0]); + method.invoke(bean, pojoReference.getProxy()); + } catch (Exception e) { + throw new BeanCreationException(beanName, "", e); + } } private void handleReferenceField(Object obj, Field field, RpcReference reference) { + PojoReferenceMeta pojoReference = createPojoReferenceMeta(reference, field.getType()); + ReflectionUtils.makeAccessible(field); + ReflectionUtils.setField(field, obj, pojoReference.getProxy()); + } + + private PojoReferenceMeta createPojoReferenceMeta(RpcReference reference, Class consumerInterface) { String microserviceName = reference.microserviceName(); - microserviceName = resolver.resolveStringValue(microserviceName); + microserviceName = beanFactory.resolveEmbeddedValue(microserviceName); PojoReferenceMeta pojoReference = new PojoReferenceMeta(); pojoReference.setMicroserviceName(microserviceName); pojoReference.setSchemaId(reference.schemaId()); - pojoReference.setConsumerIntf(field.getType()); - + pojoReference.setConsumerIntf(consumerInterface); pojoReference.afterPropertiesSet(); - - ReflectionUtils.makeAccessible(field); - ReflectionUtils.setField(field, obj, pojoReference.getProxy()); + return pojoReference; } } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducerMeta.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducerMeta.java index e486249a4b5..d63541cdfe3 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducerMeta.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducerMeta.java @@ -17,17 +17,25 @@ package org.apache.servicecomb.provider.pojo.schema; -import javax.inject.Inject; - import org.apache.servicecomb.core.provider.producer.ProducerMeta; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.annotations.VisibleForTesting; public class PojoProducerMeta extends ProducerMeta implements InitializingBean { - @Inject + @Autowired protected PojoProducers pojoProducers; private String implementation; + private String schemaInterfaceName; + + @VisibleForTesting + void setPojoProducers(PojoProducers pojoProducers) { + this.pojoProducers = pojoProducers; + } + public String getImplementation() { return implementation; } @@ -36,8 +44,17 @@ public void setImplementation(String implementation) { this.implementation = implementation; } + public String getSchemaInterfaceName() { + return schemaInterfaceName; + } + + public PojoProducerMeta setSchemaInterfaceName(String schemaInterfaceName) { + this.schemaInterfaceName = schemaInterfaceName; + return this; + } + @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() { pojoProducers.registerPojoProducer(this); } } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducers.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducers.java index b173ead6529..a6a5a818f0f 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducers.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/PojoProducers.java @@ -16,35 +16,25 @@ */ package org.apache.servicecomb.provider.pojo.schema; -import java.util.Collection; +import java.util.ArrayList; +import java.util.List; -import org.apache.servicecomb.foundation.common.RegisterManager; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.provider.producer.ProducerMeta; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.provider.pojo.RpcSchema; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -@Component public class PojoProducers implements BeanPostProcessor { - // key为schemaId - private RegisterManager pojoMgr = new RegisterManager<>("pojo service manager"); + private final List producerMetas = new ArrayList<>(); - public void registerPojoProducer(PojoProducerMeta pojoProducer) { - pojoMgr.register(pojoProducer.getSchemaId(), pojoProducer); + public synchronized void registerPojoProducer(PojoProducerMeta pojoProducer) { + producerMetas.add(pojoProducer); } - public Collection getProducers() { - return pojoMgr.values(); - } - - /** - * @deprecated Replaced by {@link #getProducers()} - */ - @Deprecated - public Collection getProcucers() { - return getProducers(); + public List getProducerMetas() { + return producerMetas; } @Override @@ -63,8 +53,8 @@ protected void processProvider(String beanName, Object bean) { // aop后,新的实例的父类可能是原class,也可能只是个proxy,父类不是原class // 所以,需要先取出原class,再取标注 Class beanCls = BeanUtils.getImplClassFromBean(bean); - if(beanCls == null) { - return; + if (beanCls == null) { + return; } RpcSchema rpcSchema = beanCls.getAnnotation(RpcSchema.class); if (rpcSchema == null) { @@ -83,8 +73,8 @@ protected void processProvider(String beanName, Object bean) { PojoProducerMeta pojoProducerMeta = new PojoProducerMeta(); pojoProducerMeta.setSchemaId(schemaId); + pojoProducerMeta.setSchemaInterface(rpcSchema.schemaInterface()); pojoProducerMeta.setInstance(bean); - pojoProducerMeta.setInstanceClass(beanCls); registerPojoProducer(pojoProducerMeta); } diff --git a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/SchemaDefParser.java b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/SchemaDefParser.java index e8d017bb1ac..a8ffdf137c3 100644 --- a/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/SchemaDefParser.java +++ b/providers/provider-pojo/src/main/java/org/apache/servicecomb/provider/pojo/schema/SchemaDefParser.java @@ -44,5 +44,6 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { builder.addPropertyValue(PojoConst.FIELD_SCHEMA_ID, element.getAttribute(PojoConst.SCHEMA_ID)); builder.addPropertyValue(PojoConst.IMPL, element.getAttribute(PojoConst.IMPL)); + builder.addPropertyValue(PojoConst.FIELD_SCHEMA_INTERFACE, element.getAttribute(PojoConst.SCHEMA_INTERFACE)); } } diff --git a/providers/provider-pojo/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider b/providers/provider-pojo/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider new file mode 100644 index 00000000000..b5a9f25c66a --- /dev/null +++ b/providers/provider-pojo/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.provider.pojo.PojoProducerProvider diff --git a/providers/provider-pojo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/providers/provider-pojo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..4edb96c93f0 --- /dev/null +++ b/providers/provider-pojo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.provider.pojo.ProviderPojoConfiguration diff --git a/providers/provider-pojo/src/main/resources/META-INF/spring/spring-paas-cse-rpc-1.0.xsd b/providers/provider-pojo/src/main/resources/META-INF/spring/spring-paas-cse-rpc-1.0.xsd index 8548560bf99..095bdc44ed0 100644 --- a/providers/provider-pojo/src/main/resources/META-INF/spring/spring-paas-cse-rpc-1.0.xsd +++ b/providers/provider-pojo/src/main/resources/META-INF/spring/spring-paas-cse-rpc-1.0.xsd @@ -18,24 +18,23 @@ --> + xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.huawei.com/schema/paas/cse/rpc" + elementFormDefault="qualified" attributeFormDefault="unqualified"> - - - - - - + + + + + + + - - - - - - - - + + + + + + + + diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java deleted file mode 100644 index d3e46c065c1..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.common; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.mockito.Mockito; -import org.springframework.context.ApplicationContext; - -import mockit.Mock; -import mockit.MockUp; - -public class MockUtil { - - private static MockUtil instance = new MockUtil(); - - private MockUtil() { - - } - - public static MockUtil getInstance() { - return instance; - } - - public void mockBeanUtils() { - - new MockUp() { - @Mock - ApplicationContext getContext() { - return Mockito.mock(ApplicationContext.class); - } - - @Mock - T getBean(String name) { - return null; - } - }; - } - - public void mockBeanUtilsObject() { - - new MockUp() { - @Mock - ApplicationContext getContext() { - return Mockito.mock(ApplicationContext.class); - } - - @SuppressWarnings("unchecked") - @Mock - T getBean(String name) { - return (T) new Object(); - } - }; - } -} diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestInvoker.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestInvoker.java deleted file mode 100644 index f391cda2cd4..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestInvoker.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo; - -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager; -import org.apache.servicecomb.core.provider.consumer.InvokerUtils; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.provider.pojo.Invoker.InvokerMeta; -import org.apache.servicecomb.swagger.engine.SwaggerConsumer; -import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; -import org.apache.servicecomb.swagger.engine.bootstrap.BootstrapNormal; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.InvocationContextCompletableFuture; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestInvoker { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - SCBEngine scbEngine = new SCBEngine(); - - @Before - public void setup() { - new MockUp() { - @Mock - SCBEngine getInstance() { - return scbEngine; - } - }; - scbEngine.setStatus(SCBStatus.UP); - } - - @Test - public void testNormalSchemaId(@Injectable ConsumerProviderManager manager, - @Injectable ReferenceConfig config, - @Injectable MicroserviceMeta microserviceMeta) { - new Expectations() { - { - manager.getReferenceConfig("test"); - result = config; - config.getMicroserviceMeta(); - result = microserviceMeta; - } - }; - scbEngine.setConsumerProviderManager(manager); - CseContext.getInstance().setSwaggerEnvironment(new BootstrapNormal().boot()); - - Invoker invoker = new Invoker("test", "schemaId", IPerson.class); - InvokerMeta invokerMeta = invoker.createInvokerMeta(); - - Assert.assertEquals(IPerson.class, invokerMeta.swaggerConsumer.getConsumerIntf()); - } - - @Test - public void testFindSchemaByConsumerInterface(@Injectable ConsumerProviderManager manager, - @Injectable ReferenceConfig config, - @Injectable MicroserviceMeta microserviceMeta) { - new Expectations() { - { - manager.getReferenceConfig("test"); - result = config; - config.getMicroserviceMeta(); - result = microserviceMeta; - microserviceMeta.findSchemaMeta(IPerson.class); - } - }; - scbEngine.setConsumerProviderManager(manager); - CseContext.getInstance().setSwaggerEnvironment(new BootstrapNormal().boot()); - - Invoker invoker = new Invoker("test", null, IPerson.class); - InvokerMeta invokerMeta = invoker.createInvokerMeta(); - - Assert.assertEquals(IPerson.class, invokerMeta.swaggerConsumer.getConsumerIntf()); - } - - @Test - public void testConsumerInterfaceAsSchemaId(@Injectable ConsumerProviderManager manager, - @Injectable ReferenceConfig config, - @Injectable MicroserviceMeta microserviceMeta) { - new Expectations() { - { - manager.getReferenceConfig("test"); - result = config; - config.getMicroserviceMeta(); - result = microserviceMeta; - microserviceMeta.findSchemaMeta(IPerson.class); - result = null; - } - }; - scbEngine.setConsumerProviderManager(manager); - CseContext.getInstance().setSwaggerEnvironment(new BootstrapNormal().boot()); - - Invoker invoker = new Invoker("test", null, IPerson.class); - InvokerMeta invokerMeta = invoker.createInvokerMeta(); - Assert.assertEquals(IPerson.class, invokerMeta.swaggerConsumer.getConsumerIntf()); - } - - @Test - public void syncInvoke_normal(@Mocked Invocation invocation, - @Mocked SwaggerConsumerOperation consumerOperation, - @Mocked ConsumerResponseMapper mapper) { - Response response = Response.ok("1"); - new MockUp() { - @Mock - Response innerSyncInvoke(Invocation invocation) { - return response; - } - }; - new Expectations() { - { - consumerOperation.getResponseMapper(); - result = mapper; - mapper.mapResponse(response); - result = 1; - } - }; - - Invoker invoker = new Invoker("test", null, IPerson.class); - Object result = invoker.syncInvoke(invocation, consumerOperation); - Assert.assertEquals(1, result); - } - - @Test - public void syncInvoke_failed(@Mocked Invocation invocation, - @Mocked SwaggerConsumerOperation consumerOperation, - @Mocked ConsumerResponseMapper mapper) { - Throwable error = new Error("failed"); - Response response = Response.createConsumerFail(error); - new MockUp() { - @Mock - Response innerSyncInvoke(Invocation invocation) { - return response; - } - }; - - expectedException.expect(InvocationException.class); - expectedException.expectCause(Matchers.sameInstance(error)); - - Invoker invoker = new Invoker("test", null, IPerson.class); - invoker.syncInvoke(invocation, consumerOperation); - } - - @Test - public void completableFutureInvoke_normal(@Mocked Invocation invocation, - @Mocked SwaggerConsumerOperation consumerOperation, - @Mocked ConsumerResponseMapper mapper) { - Response response = Response.ok("1"); - new MockUp() { - @Mock - void reactiveInvoke(Invocation invocation, AsyncResponse asyncResp) { - asyncResp.handle(response); - } - }; - new Expectations() { - { - consumerOperation.getResponseMapper(); - result = mapper; - mapper.mapResponse(response); - result = 1; - } - }; - - Invoker invoker = new Invoker("test", null, IPerson.class); - CompletableFuture future = invoker.completableFutureInvoke(invocation, consumerOperation); - future.whenComplete((result, ex) -> { - Assert.assertEquals(1, result); - Assert.assertEquals(null, ex); - }); - - Assert.assertThat(future, Matchers.instanceOf(InvocationContextCompletableFuture.class)); - } - - @Test - public void completableFutureInvoke_failed(@Mocked Invocation invocation, - @Mocked SwaggerConsumerOperation consumerOperation, - @Mocked ConsumerResponseMapper mapper) { - Throwable error = new Error("failed"); - Response response = Response.createConsumerFail(error); - new MockUp() { - @Mock - void reactiveInvoke(Invocation invocation, AsyncResponse asyncResp) { - asyncResp.handle(response); - } - }; - - Invoker invoker = new Invoker("test", null, IPerson.class); - CompletableFuture future = invoker.completableFutureInvoke(invocation, consumerOperation); - future.whenComplete((result, ex) -> { - Assert.assertEquals(null, result); - Assert.assertSame(error, ex); - }); - } - - @Test - public void createInvokerMeta_schemaNotInContract(@Injectable ConsumerProviderManager manager, - @Injectable ReferenceConfig config, - @Injectable MicroserviceMeta microserviceMeta) { - new Expectations() { - { - manager.getReferenceConfig("test"); - result = config; - config.getMicroserviceMeta(); - result = microserviceMeta; - microserviceMeta.findSchemaMeta("schemaId"); - result = null; - } - }; - scbEngine.setConsumerProviderManager(manager); - CseContext.getInstance().setSwaggerEnvironment(new BootstrapNormal().boot()); - - Invoker invoker = new Invoker("test", "schemaId", IPerson.class); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("Schema not exist, microserviceName=test, schemaId=schemaId, consumer interface=org.apache.servicecomb.provider.pojo.IPerson; " - + "new producer not running or not deployed.")); - invoker.createInvokerMeta(); - } - - @Test - public void invoke_methodNotInContract(@Mocked SwaggerConsumer swaggerConsumer, - @Mocked ReferenceConfig referenceConfig, @Mocked MicroserviceMeta microserviceMeta) { - Invoker invoker = new Invoker("test", null, IPerson.class); - InvokerMeta invokerMeta = new InvokerMeta(referenceConfig, microserviceMeta, null, swaggerConsumer); - Deencapsulation.setField(invoker, "invokerMeta", invokerMeta); - new Expectations() { - { - swaggerConsumer.findOperation(anyString); - result = null; - referenceConfig.getMicroserviceMeta(); - result = microserviceMeta; - } - }; - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers - .is("Consumer method org.apache.servicecomb.provider.pojo.IPerson:trim not exist in contract, " - + "microserviceName=test, schemaId=null; new producer not running or not deployed.")); - invoker.invoke(null, ReflectUtils.findMethod(String.class, "trim"), null); - } -} diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoConsumerProvider.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoConsumerProvider.java deleted file mode 100644 index 1a119ce955b..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoConsumerProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo; - -import static org.apache.servicecomb.provider.pojo.PojoConst.POJO; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import org.junit.Test; - -public class TestPojoConsumerProvider { - @Test - public void providerNameIsPojo() throws Exception { - PojoConsumerProvider pojoConsumerProvider = new PojoConsumerProvider(); - assertThat(pojoConsumerProvider.getName(), is(POJO)); - } -} diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoProducerProvider.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoProducerProvider.java deleted file mode 100644 index 48329971779..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/TestPojoProducerProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; -import org.apache.servicecomb.provider.pojo.schema.PojoProducerMeta; -import org.apache.servicecomb.provider.pojo.schema.PojoProducers; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mocked; - -public class TestPojoProducerProvider { - @Test - public void testPojoProducerProviderAlreadyInited(@Injectable ProducerSchemaFactory factory, - @Injectable PojoProducers producers, @Injectable PojoProducerMeta meta, @Mocked RegistryUtils utils, - @Injectable Microservice service) throws Exception { - List producersMeta = new ArrayList<>(); - producersMeta.add(meta); - Person bean = new Person(); - new Expectations() { - { - producers.getProducers(); - result = producersMeta; - meta.getInstance(); - result = bean; - } - }; - PojoProducerProvider provider = new PojoProducerProvider(); - Deencapsulation.setField(provider, "producerSchemaFactory", factory); - Deencapsulation.setField(provider, "pojoProducers", producers); - provider.init(); - // expectations done in Expectations - } - - @Test - public void testPojoProducerProvider(@Injectable ProducerSchemaFactory factory, - @Injectable PojoProducers producers, @Injectable PojoProducerMeta meta, @Mocked RegistryUtils utils, - @Injectable Microservice service) throws Exception { - List producersMeta = new ArrayList<>(); - producersMeta.add(meta); - new Expectations() { - { - producers.getProducers(); - result = producersMeta; - meta.getInstance(); - result = null; - meta.getImplementation(); - result = "pojo:org.apache.servicecomb.provider.pojo.Person"; - } - }; - PojoProducerProvider provider = new PojoProducerProvider(); - Deencapsulation.setField(provider, "producerSchemaFactory", factory); - Deencapsulation.setField(provider, "pojoProducers", producers); - provider.init(); - Assert.assertEquals(provider.getName(), "pojo"); - // expectations done in Expectations - } -} diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestPojoInstanceFactory.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestPojoInstanceFactory.java index 57143094d16..489451ef5f7 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestPojoInstanceFactory.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestPojoInstanceFactory.java @@ -18,29 +18,25 @@ package org.apache.servicecomb.provider.pojo.instance; import org.apache.servicecomb.provider.pojo.PojoConst; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestPojoInstanceFactory { @Test - public void testInitException() - throws Exception { - + public void testInitException() { PojoInstanceFactory lPojoInstanceFactory = new PojoInstanceFactory(); try { lPojoInstanceFactory.create("TestPojoInstanceFactory"); } catch (Error e) { - Assert.assertEquals("Fail to create instance of class:TestPojoInstanceFactory", e.getMessage()); + Assertions.assertEquals("Fail to create instance of class:TestPojoInstanceFactory", e.getMessage()); } } @Test - public void testInit() - throws Exception { - + public void testInit() { PojoInstanceFactory lPojoInstanceFactory = new PojoInstanceFactory(); lPojoInstanceFactory.create("org.apache.servicecomb.provider.pojo.instance.TestPojoInstanceFactory"); - Assert.assertEquals(PojoConst.POJO, lPojoInstanceFactory.getImplName()); + Assertions.assertEquals(PojoConst.POJO, lPojoInstanceFactory.getImplName()); } } diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestSpringInstanceFactory.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestSpringInstanceFactory.java index 2b178170b63..610ee5176fd 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestSpringInstanceFactory.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/instance/TestSpringInstanceFactory.java @@ -17,34 +17,41 @@ package org.apache.servicecomb.provider.pojo.instance; -import org.apache.servicecomb.provider.common.MockUtil; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.provider.pojo.PojoConst; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.context.ApplicationContext; public class TestSpringInstanceFactory { @Test - public void testInitException() - throws Exception { + public void testInitException() { SpringInstanceFactory lSpringInstanceFactory = new SpringInstanceFactory(); - MockUtil.getInstance().mockBeanUtils(); - try { - lSpringInstanceFactory.create("TestSpringInstanceFactory"); - } catch (Error e) { - Assert.assertEquals("Fail to find bean:TestSpringInstanceFactory", e.getMessage()); + try (MockedStatic beanUtilsMockedStatic = Mockito.mockStatic(BeanUtils.class)) { + beanUtilsMockedStatic.when(BeanUtils::getContext).thenReturn(Mockito.mock(ApplicationContext.class)); + beanUtilsMockedStatic.when(() -> BeanUtils.getBean(Mockito.anyString())).thenReturn(null); + try { + lSpringInstanceFactory.create("TestSpringInstanceFactory"); + } catch (Error e) { + Assertions.assertEquals("Fail to find bean:TestSpringInstanceFactory", e.getMessage()); + } } } @Test - public void testInit() - throws Exception { + public void testInit() { SpringInstanceFactory lSpringInstanceFactory = new SpringInstanceFactory(); - MockUtil.getInstance().mockBeanUtils(); - MockUtil.getInstance().mockBeanUtilsObject(); - lSpringInstanceFactory.create("org.apache.servicecomb.provider.pojo.instance.TestPojoInstanceFactory"); - Assert.assertEquals(PojoConst.SPRING, lSpringInstanceFactory.getImplName()); + try (MockedStatic beanUtilsMockedStatic = Mockito.mockStatic(BeanUtils.class)) { + beanUtilsMockedStatic.when(BeanUtils::getContext).thenReturn(Mockito.mock(ApplicationContext.class)); + beanUtilsMockedStatic.when(() -> BeanUtils.getBean(Mockito.anyString())).thenReturn(new Object()); + + lSpringInstanceFactory.create("org.apache.servicecomb.provider.pojo.instance.TestPojoInstanceFactory"); + Assertions.assertEquals(PojoConst.SPRING, lSpringInstanceFactory.getImplName()); + } } } diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/PojoReferenceMetaTest.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/PojoReferenceMetaTest.java index 343b19fc9fb..1ecf031569c 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/PojoReferenceMetaTest.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/PojoReferenceMetaTest.java @@ -18,25 +18,45 @@ package org.apache.servicecomb.provider.pojo.reference; import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.provider.pojo.IPerson; -import org.junit.Assert; -import org.junit.Test; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class PojoReferenceMetaTest { + static Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void teardown() { + } + @Test public void testHasConsumerInterface() { + SCBEngine scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + PojoReferenceMeta pojoReferenceMeta = new PojoReferenceMeta(); pojoReferenceMeta.setMicroserviceName("test"); pojoReferenceMeta.setSchemaId("schemaId"); pojoReferenceMeta.setConsumerIntf(IPerson.class); pojoReferenceMeta.afterPropertiesSet(); - Assert.assertEquals(IPerson.class, pojoReferenceMeta.getObjectType()); - assertThat(pojoReferenceMeta.getProxy(), instanceOf(IPerson.class)); - Assert.assertEquals(true, pojoReferenceMeta.isSingleton()); + Assertions.assertEquals(IPerson.class, pojoReferenceMeta.getObjectType()); + MatcherAssert.assertThat(pojoReferenceMeta.getProxy(), instanceOf(IPerson.class)); + Assertions.assertTrue(pojoReferenceMeta.isSingleton()); + + scbEngine.destroy(); } @Test @@ -47,9 +67,9 @@ public void testNoConsumerInterface() { try { pojoReferenceMeta.afterPropertiesSet(); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals( + Assertions.assertEquals( "microserviceName=test, schemaid=schemaId, \n" + "do not support implicit interface anymore, \n" + "because that caused problems:\n" diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestReferenceDefParser.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestReferenceDefParser.java deleted file mode 100644 index 62a9d9f1ef6..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestReferenceDefParser.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo.reference; - -import org.apache.servicecomb.provider.pojo.PojoConst; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.w3c.dom.Element; - -public class TestReferenceDefParser { - - @Test - public void testDoParse() - throws Exception { - - ReferenceDefParser lReferenceDefParser = new ReferenceDefParser(); - - Element element = Mockito.mock(Element.class); - Mockito.when(element.getAttribute(PojoConst.SCHEMA_ID)).thenReturn("abc"); - lReferenceDefParser.doParse(element, null, Mockito.mock(BeanDefinitionBuilder.class)); - Assert.assertEquals(PojoReferenceMeta.class, lReferenceDefParser.getBeanClass(null)); - } -} diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java index c29aa160588..7162a8a154d 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/reference/TestRpcReferenceProcessor.java @@ -17,45 +17,65 @@ package org.apache.servicecomb.provider.pojo.reference; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.foundation.test.scaffolding.spring.SpringUtils; import org.apache.servicecomb.provider.pojo.Person; import org.apache.servicecomb.provider.pojo.PersonReference; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.context.ApplicationContext; - -import mockit.Injectable; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.core.env.Environment; public class TestRpcReferenceProcessor { - RpcReferenceProcessor consumers = new RpcReferenceProcessor(); + static Environment environment = Mockito.mock(Environment.class); + + static ConfigurableBeanFactory beanFactory = Mockito.mock(ConfigurableBeanFactory.class); + + RpcReferenceProcessor consumers = new RpcReferenceProcessor(beanFactory); + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void teardown() { + } @Test public void postProcessAfterInitialization() { Object bean = new Object(); - Assert.assertSame(bean, consumers.postProcessAfterInitialization(bean, "test")); + Assertions.assertSame(bean, consumers.postProcessAfterInitialization(bean, "test")); } @Test - public void testReference(@Injectable ApplicationContext applicationContext) throws Exception { + public void testReference() { + SCBEngine scbEngine = SCBBootstrap.createSCBEngineForTest(environment); + PersonReference bean = new PersonReference(); - Assert.assertNull(bean.person); + Assertions.assertNull(bean.person); + + Mockito.when(beanFactory.resolveEmbeddedValue("test")).thenReturn("test"); + Assertions.assertSame(bean, consumers.postProcessBeforeInitialization(bean, "id")); - consumers.setEmbeddedValueResolver((strVal) -> strVal); - Assert.assertSame(bean, consumers.postProcessBeforeInitialization(bean, "id")); + Assertions.assertNotNull(bean.person); - Assert.assertNotNull(bean.person); + scbEngine.destroy(); } @Test - public void testNoReference(@Injectable ApplicationContext applicationContext) throws Exception { + public void testNoReference() { Person bean = new Person(); - Assert.assertNull(bean.name); + Assertions.assertNull(bean.name); - Assert.assertSame(bean, consumers.postProcessBeforeInitialization(bean, "id")); + Assertions.assertSame(bean, consumers.postProcessBeforeInitialization(bean, "id")); - Assert.assertNull(bean.name); + Assertions.assertNull(bean.name); } @Test diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoProducers.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoProducers.java index 7394b6a5e9e..4a44fdefd47 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoProducers.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoProducers.java @@ -21,11 +21,8 @@ import org.apache.servicecomb.provider.pojo.IPerson; import org.apache.servicecomb.provider.pojo.Person; import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestPojoProducers { PojoProducers producer = new PojoProducers(); @@ -33,22 +30,22 @@ public class TestPojoProducers { @Test public void postProcessBeforeInitialization() { Object bean = new Object(); - Assert.assertSame(bean, producer.postProcessBeforeInitialization(bean, "test")); + Assertions.assertSame(bean, producer.postProcessBeforeInitialization(bean, "test")); } @Test public void testPojoProducers() { Person bean = new Person(); - Assert.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); - Assert.assertEquals(producer.getProducers().size(), 1); + Assertions.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); + Assertions.assertEquals(producer.getProducerMetas().size(), 1); } @Test - public void testPojoProducersSchemaNull(@Injectable RpcSchema schema) { + public void testPojoProducersSchemaNull() { IPerson bean = new IPerson() { }; - Assert.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); - Assert.assertEquals(producer.getProducers().size(), 0); + Assertions.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); + Assertions.assertEquals(producer.getProducerMetas().size(), 0); } @RpcSchema @@ -57,14 +54,10 @@ static class PersonEmptySchema implements IPerson { } @Test - public void testPojoProducersSchemaIdNull(@Injectable RpcSchema schema) { + public void testPojoProducersSchemaIdNull() { IPerson bean = new PersonEmptySchema(); - new Expectations() { - { - } - }; - Assert.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); - Assert.assertEquals(producer.getProducers().size(), 1); + Assertions.assertSame(bean, producer.postProcessAfterInitialization(bean, "test")); + Assertions.assertEquals(producer.getProducerMetas().size(), 1); } @Test diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoSchemaMeta.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoSchemaMeta.java index cb0a63bd5a3..303a5af3e87 100644 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoSchemaMeta.java +++ b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestPojoSchemaMeta.java @@ -17,37 +17,35 @@ package org.apache.servicecomb.provider.pojo.schema; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Mocked; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestPojoSchemaMeta { PojoProducerMeta lPojoSchemaMeta = null; - @Before + @BeforeEach public void setUp() throws Exception { lPojoSchemaMeta = new PojoProducerMeta(); } - @After + @AfterEach public void tearDown() throws Exception { lPojoSchemaMeta = null; } @Test - public void testGetImplementation(@Mocked PojoProducers producers) - throws Exception { + public void testGetImplementation() { + PojoProducers producers = Mockito.mock(PojoProducers.class); lPojoSchemaMeta.setImplementation("implementation"); - Deencapsulation.setField(lPojoSchemaMeta, "pojoProducers", producers); + lPojoSchemaMeta.setPojoProducers(producers); lPojoSchemaMeta.afterPropertiesSet(); - Assert.assertEquals("implementation", lPojoSchemaMeta.getImplementation()); + Assertions.assertEquals("implementation", lPojoSchemaMeta.getImplementation()); } @Test @@ -55,13 +53,13 @@ public void testGetInstance() throws Exception { Object lObject = new Object(); lPojoSchemaMeta.setInstance(lObject); - Assert.assertEquals(lObject, lPojoSchemaMeta.getInstance()); + Assertions.assertEquals(lObject, lPojoSchemaMeta.getInstance()); } @Test public void testGetSchemaId() throws Exception { lPojoSchemaMeta.setSchemaId("schemaId"); - Assert.assertEquals("schemaId", lPojoSchemaMeta.getSchemaId()); + Assertions.assertEquals("schemaId", lPojoSchemaMeta.getSchemaId()); } } diff --git a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestSchemaDefParser.java b/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestSchemaDefParser.java deleted file mode 100644 index bffcb931409..00000000000 --- a/providers/provider-pojo/src/test/java/org/apache/servicecomb/provider/pojo/schema/TestSchemaDefParser.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.pojo.schema; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.w3c.dom.Element; - -public class TestSchemaDefParser { - - @Test - public void testDoParse() - throws Exception { - - SchemaDefParser lSchemaDefParser = new SchemaDefParser(); - lSchemaDefParser.shouldGenerateId(); - lSchemaDefParser.shouldParseNameAsAliases(); - lSchemaDefParser.getBeanClass(null); - lSchemaDefParser.doParse(Mockito.mock(Element.class), null, Mockito.mock(BeanDefinitionBuilder.class)); - Assert.assertEquals(true, lSchemaDefParser.shouldGenerateId()); - } -} diff --git a/providers/provider-pojo/src/test/resources/log4j.properties b/providers/provider-pojo/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/providers/provider-pojo/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/providers/provider-pojo/src/test/resources/microservice.yaml b/providers/provider-pojo/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..5ff7ed9ae41 --- /dev/null +++ b/providers/provider-pojo/src/test/resources/microservice.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + filter-chains: + consumer: + default: empty + producer: + default: empty diff --git a/providers/provider-rest-common/pom.xml b/providers/provider-rest-common/pom.xml index 0784862bc91..075a9f9146b 100644 --- a/providers/provider-rest-common/pom.xml +++ b/providers/provider-rest-common/pom.xml @@ -23,7 +23,7 @@ org.apache.servicecomb providers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT provider-rest-common Java Chassis::Providers::Rest Common @@ -33,19 +33,26 @@ org.apache.servicecomb common-rest + + - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test org.apache.servicecomb foundation-test-scaffolding + + org.mockito + mockito-inline + test + diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/InvocationToHttpServletRequest.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/InvocationToHttpServletRequest.java index eb126d4c81f..bf4fe454b95 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/InvocationToHttpServletRequest.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/InvocationToHttpServletRequest.java @@ -23,7 +23,7 @@ import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.common.rest.definition.RestParam; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; @@ -31,19 +31,20 @@ import io.vertx.core.net.SocketAddress; /** - * when transport is not over http, mock a HttpServletRequest from Invocation + * when transport is not over http, mock an HttpServletRequest from Invocation */ public class InvocationToHttpServletRequest extends AbstractHttpServletRequest { - private RestOperationMeta swaggerOperation; + private final RestOperationMeta swaggerOperation; - private Object[] args; - - private SocketAddress sockerAddress; + private final Invocation invocation; public InvocationToHttpServletRequest(Invocation invocation) { this.swaggerOperation = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); - this.args = invocation.getArgs(); - this.sockerAddress = (SocketAddress) invocation.getHandlerContext().get(Const.REMOTE_ADDRESS); + this.invocation = invocation; + } + + private SocketAddress getSockerAddress() { + return (SocketAddress) invocation.getHandlerContext().get(CoreConst.REMOTE_ADDRESS); } @Override @@ -53,7 +54,7 @@ public String getParameter(String name) { return null; } - Object value = param.getValue(args); + Object value = param.getValue(invocation.getSwaggerArguments()); if (value == null) { return null; } @@ -68,14 +69,14 @@ public String[] getParameterValues(String name) { return null; } - return param.getValueAsStrings(args); + return param.getValueAsStrings(invocation.getSwaggerArguments()); } @Override public Map getParameterMap() { Map paramMap = new HashMap<>(); for (RestParam param : swaggerOperation.getParamList()) { - String[] value = param.getValueAsStrings(args); + String[] value = param.getValueAsStrings(invocation.getSwaggerArguments()); paramMap.put(param.getParamName(), value); } return paramMap; @@ -104,7 +105,7 @@ public String getMethod() { @Override public String getPathInfo() { try { - return this.swaggerOperation.getPathBuilder().createPathString(args); + return this.swaggerOperation.getPathBuilder().createPathString(invocation.getSwaggerArguments()); } catch (Exception e) { throw new ServiceCombException("Failed to get path info.", e); } @@ -112,17 +113,17 @@ public String getPathInfo() { @Override public String getRemoteAddr() { - return this.sockerAddress == null ? "" : this.sockerAddress.host(); + return this.getSockerAddress() == null ? "" : this.getSockerAddress().host(); } @Override public String getRemoteHost() { - return this.sockerAddress == null ? "" : this.sockerAddress.host(); + return this.getSockerAddress() == null ? "" : this.getSockerAddress().host(); } @Override public int getRemotePort() { - return this.sockerAddress == null ? 0 : this.sockerAddress.port(); + return this.getSockerAddress() == null ? 0 : this.getSockerAddress().port(); } @Override diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapper.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapper.java index 3c4680a2699..2e9ac697393 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapper.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapper.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.provider.rest.common; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.core.Invocation; @@ -25,8 +25,8 @@ import org.apache.servicecomb.swagger.invocation.arguments.producer.AbstractProducerContextArgMapper; public class ProducerHttpRequestArgMapper extends AbstractProducerContextArgMapper { - public ProducerHttpRequestArgMapper(int producerArgIdx) { - super(producerArgIdx); + public ProducerHttpRequestArgMapper(String invocationArgumentName, String swaggerArgumentName) { + super(invocationArgumentName, swaggerArgumentName); } @Override diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapperFactory.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapperFactory.java index db55ff4cece..b830af1bd10 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapperFactory.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerHttpRequestArgMapperFactory.java @@ -17,16 +17,12 @@ package org.apache.servicecomb.provider.rest.common; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory; -@Component -@Qualifier("producer") -public class ProducerHttpRequestArgMapperFactory implements ContextArgumentMapperFactory { +public class ProducerHttpRequestArgMapperFactory implements ProducerContextArgumentMapperFactory { @Override public Class getContextClass() { @@ -34,7 +30,7 @@ public Class getContextClass() { } @Override - public ArgumentMapper create(int providerArgIdx) { - return new ProducerHttpRequestArgMapper(providerArgIdx); + public ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName) { + return new ProducerHttpRequestArgMapper(invocationArgumentName, swaggerArgumentName); } } diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketArgMapperFactory.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketArgMapperFactory.java new file mode 100644 index 00000000000..b0f554a8466 --- /dev/null +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketArgMapperFactory.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.rest.common; + +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory; + +import io.vertx.core.http.ServerWebSocket; + +public class ProducerServerWebSocketArgMapperFactory implements ProducerContextArgumentMapperFactory { + + @Override + public Class getContextClass() { + return ServerWebSocket.class; + } + + @Override + public ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName) { + return new ProducerServerWebSocketMapper(invocationArgumentName, swaggerArgumentName); + } +} diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketMapper.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketMapper.java new file mode 100644 index 00000000000..21d040b5c87 --- /dev/null +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProducerServerWebSocketMapper.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.rest.common; + +import org.apache.servicecomb.common.rest.WebSocketTransportContext; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.producer.AbstractProducerContextArgMapper; + + +public class ProducerServerWebSocketMapper extends AbstractProducerContextArgMapper { + public ProducerServerWebSocketMapper(String invocationArgumentName, String swaggerArgumentName) { + super(invocationArgumentName, swaggerArgumentName); + } + + @Override + public Object createContextArg(SwaggerInvocation invocation) { + WebSocketTransportContext context = invocation.getTransportContext(); + return context.getServerWebSocket(); + } +} diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProviderRestCommonConfiguration.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProviderRestCommonConfiguration.java new file mode 100644 index 00000000000..662c2ffba42 --- /dev/null +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/ProviderRestCommonConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.provider.rest.common; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ProviderRestCommonConfiguration { + @Bean + public static RestProducers restProducers() { + return new RestProducers(); + } +} diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestConsumerProvider.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestConsumerProvider.java deleted file mode 100644 index f87b6816fa1..00000000000 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestConsumerProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.rest.common; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.provider.consumer.AbstractConsumerProvider; -import org.springframework.stereotype.Component; - -@Component -public class RestConsumerProvider extends AbstractConsumerProvider { - @Override - public String getName() { - return RestConst.REST; - } -} diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducerProvider.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducerProvider.java index 56daa2dae38..5bca923ce1a 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducerProvider.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducerProvider.java @@ -17,35 +17,27 @@ package org.apache.servicecomb.provider.rest.common; -import javax.inject.Inject; +import java.util.List; import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; import org.apache.servicecomb.core.provider.producer.AbstractProducerProvider; import org.apache.servicecomb.core.provider.producer.ProducerMeta; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; -@Component public class RestProducerProvider extends AbstractProducerProvider { - - @Inject - protected ProducerSchemaFactory producerSchemaFactory; - - @Inject - protected RestProducers restProducers; - @Override public String getName() { return RestConst.REST; } @Override - public void init() throws Exception { - for (ProducerMeta producerMeta : restProducers.getProducerMetaList()) { - producerSchemaFactory.getOrCreateProducerSchema( - producerMeta.getSchemaId(), - producerMeta.getInstanceClass(), - producerMeta.getInstance()); + public List init() { + // for some UT case, there is no spring context + if (BeanUtils.getContext() == null) { + return null; } + + RestProducers restProducers = BeanUtils.getContext().getBean(RestProducers.class); + return restProducers.getProducerMetaList(); } } diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducers.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducers.java index 4b3cedd0b7e..8aed65f3ba7 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducers.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestProducers.java @@ -16,30 +16,32 @@ */ package org.apache.servicecomb.provider.rest.common; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.core.provider.producer.ProducerMeta; import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.common.utils.ReflectUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; -import com.netflix.config.DynamicPropertyFactory; +public class RestProducers implements BeanPostProcessor, EnvironmentAware { + private final List producerMetaList = new ArrayList<>(); -@Component -public class RestProducers implements BeanPostProcessor { - private List producerMetaList = new ArrayList<>(); - - private boolean scanRestController = DynamicPropertyFactory.getInstance() - .getBooleanProperty(RestConst.PROVIDER_SCAN_REST_CONTROLLER, true).get(); + @SuppressWarnings("unchecked") + private final Class restControllerCls = (Class) ReflectUtils + .getClassByName("org.springframework.web.bind.annotation.RestController"); public List getProducerMetaList() { return producerMetaList; } + private Environment environment; + @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; @@ -60,20 +62,23 @@ protected void processProvider(String beanName, Object bean) { return; } RestSchema restSchema = beanCls.getAnnotation(RestSchema.class); - ProducerMeta producerMeta; - if (restSchema == null) { - if (!scanRestController) { - return; - } - RestController controller = beanCls.getAnnotation(RestController.class); - if (controller == null) { - return; - } - producerMeta = new ProducerMeta(beanCls.getName(), bean, beanCls); - } else { - producerMeta = new ProducerMeta(restSchema.schemaId(), bean, beanCls); + if (restSchema != null) { + ProducerMeta producerMeta = new ProducerMeta(restSchema.schemaId(), bean); + producerMeta.setSchemaInterface(restSchema.schemaInterface()); + producerMetaList.add(producerMeta); + return; } - producerMetaList.add(producerMeta); + if (restControllerCls != null && + environment.getProperty(RestConst.PROVIDER_SCAN_REST_CONTROLLER, boolean.class, true) + && beanCls.getAnnotation(restControllerCls) != null) { + ProducerMeta producerMeta = new ProducerMeta(beanCls.getName(), bean); + producerMetaList.add(producerMeta); + } + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; } } diff --git a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestSchema.java b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestSchema.java index 97f44607893..5edadcc6e86 100644 --- a/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestSchema.java +++ b/providers/provider-rest-common/src/main/java/org/apache/servicecomb/provider/rest/common/RestSchema.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.provider.rest.common; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -30,8 +31,10 @@ @Inherited @Documented @Retention(RUNTIME) -@Target(TYPE) +@Target({TYPE, ANNOTATION_TYPE}) @Component public @interface RestSchema { String schemaId(); + + Class schemaInterface() default Object.class; } diff --git a/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider b/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider new file mode 100644 index 00000000000..ee817607b15 --- /dev/null +++ b/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.core.ProducerProvider @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.provider.rest.common.RestProducerProvider diff --git a/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory b/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory new file mode 100644 index 00000000000..1561d349cf1 --- /dev/null +++ b/providers/provider-rest-common/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.provider.rest.common.ProducerHttpRequestArgMapperFactory +org.apache.servicecomb.provider.rest.common.ProducerServerWebSocketArgMapperFactory diff --git a/providers/provider-rest-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/providers/provider-rest-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..dfbc633bfe5 --- /dev/null +++ b/providers/provider-rest-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.provider.rest.common.ProviderRestCommonConfiguration diff --git a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestInvocationToHttpServletRequest.java b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestInvocationToHttpServletRequest.java index 79c1c903061..4453fc897c2 100644 --- a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestInvocationToHttpServletRequest.java +++ b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestInvocationToHttpServletRequest.java @@ -21,315 +21,230 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.common.rest.definition.RestParam; import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; import io.vertx.core.net.SocketAddress; -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestInvocationToHttpServletRequest { - @Mocked - Invocation invocation; + Invocation invocation = Mockito.mock(Invocation.class); - @Mocked - OperationMeta operationMeta; + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - @Mocked - RestOperationMeta swaggerOperation; + RestOperationMeta swaggerOperation = Mockito.mock(RestOperationMeta.class); - @Mocked - Object[] args; + Map args; - @Mocked - SocketAddress socketAddress; + SocketAddress socketAddress = Mockito.mock(SocketAddress.class); Map handlerContext = new HashMap<>(); HttpServletRequest request; - @Before + @BeforeEach public void setup() { - handlerContext.put(Const.REMOTE_ADDRESS, socketAddress); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerOperation; - invocation.getArgs(); - result = args; - invocation.getHandlerContext(); - result = handlerContext; - } - }; + handlerContext.put(CoreConst.REMOTE_ADDRESS, socketAddress); + args = new HashMap<>(); + + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(swaggerOperation); request = new InvocationToHttpServletRequest(invocation); } + @AfterEach + public void tearDown() { + + } + @Test public void testGetParameterNotFound() { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = null; - } - }; - - Assert.assertNull(request.getParameter("name")); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(null); + + Assertions.assertNull(request.getParameter("name")); } @Test - public void testGetParameterNull(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = null; - } - }; - - Assert.assertNull(request.getParameter("name")); + public void testGetParameterNull() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn(null); + + Assertions.assertNull(request.getParameter("name")); } @Test - public void testGetParameterNormal(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = "value"; - } - }; - - Assert.assertEquals("value", request.getParameter("name")); + public void testGetParameterNormal() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn("value"); + + Assertions.assertEquals("value", request.getParameter("name")); } @Test public void testGetParameterValuesNotFound() { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = null; - } - }; - - Assert.assertNull(request.getParameterValues("name")); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(null); + + Assertions.assertNull(request.getParameterValues("name")); } @Test - public void testGetParameterValuesNormal(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValueAsStrings(args); - result = new String[] {"value"}; - } - }; - - Assert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); + public void testGetParameterValuesNormal() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValueAsStrings(args)).thenReturn(new String[] {"value"}); + + MatcherAssert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); } @Test - public void testGetParameterMap(@Mocked RestParam p1, @Mocked RestParam p2) { - new Expectations() { - { - swaggerOperation.getParamList(); - result = Arrays.asList(p1, p2); - p1.getValueAsStrings(args); - result = new String[] {"v1"}; - p1.getParamName(); - result = "p1"; - p2.getValueAsStrings(args); - result = new String[] {"v2"}; - p2.getParamName(); - result = "p2"; - } - }; + public void testGetParameterMap() { + RestParam p1 = Mockito.mock(RestParam.class); + RestParam p2 = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamList()).thenReturn(Arrays.asList(p1, p2)); + Mockito.when(p1.getValueAsStrings(args)).thenReturn(new String[] {"v1"}); + Mockito.when(p1.getParamName()).thenReturn("p1"); + Mockito.when(p2.getValueAsStrings(args)).thenReturn(new String[] {"v2"}); + Mockito.when(p2.getParamName()).thenReturn("p2"); Map params = request.getParameterMap(); - Assert.assertThat(params.size(), Matchers.is(2)); - Assert.assertThat(params, Matchers.hasEntry("p1", new String[] {"v1"})); - Assert.assertThat(params, Matchers.hasEntry("p2", new String[] {"v2"})); + MatcherAssert.assertThat(params.size(), Matchers.is(2)); + MatcherAssert.assertThat(params, Matchers.hasEntry("p1", new String[] {"v1"})); + MatcherAssert.assertThat(params, Matchers.hasEntry("p2", new String[] {"v2"})); } @Test - public void testGetHeader(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = "value"; - } - }; - - Assert.assertEquals("value", request.getHeader("name")); + public void testGetHeader() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn("value"); + + Assertions.assertEquals("value", request.getHeader("name")); } @Test - public void testGetIntHeaderNotFound(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = null; - } - }; - - Assert.assertEquals(-1, request.getIntHeader("name")); + public void testGetIntHeaderNotFound() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn(null); + + Assertions.assertEquals(-1, request.getIntHeader("name")); } @Test - public void testGetIntHeaderNotNumber(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = "value"; - } - }; + public void testGetIntHeaderNotNumber() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn("value"); try { request.getIntHeader("name"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (NumberFormatException e) { - Assert.assertEquals("For input string: \"value\"", e.getMessage()); + Assertions.assertEquals("For input string: \"value\"", e.getMessage()); } } @Test - public void testGetIntHeaderNormal(@Mocked RestParam restParam) { - new Expectations() { - { - swaggerOperation.getParamByName("name"); - result = restParam; - restParam.getValue(args); - result = "1"; - } - }; - - Assert.assertEquals(1, request.getIntHeader("name")); + public void testGetIntHeaderNormal() { + RestParam restParam = Mockito.mock(RestParam.class); + Mockito.when(swaggerOperation.getParamByName("name")).thenReturn(restParam); + Mockito.when(restParam.getValue(args)).thenReturn("1"); + + Assertions.assertEquals(1, request.getIntHeader("name")); } @Test public void testGetMethod() { - new Expectations() { - { - swaggerOperation.getHttpMethod(); - result = "GET"; - } - }; - - Assert.assertEquals("GET", request.getMethod()); + Mockito.when(swaggerOperation.getHttpMethod()).thenReturn("GET"); + + Assertions.assertEquals("GET", request.getMethod()); } @Test - public void testGetPathInfoNormal(@Mocked URLPathBuilder builder) throws Exception { - new Expectations() { - { - swaggerOperation.getPathBuilder(); - result = builder; - builder.createPathString(args); - result = "/path"; - } - }; - - Assert.assertEquals("/path", request.getPathInfo()); + public void testGetPathInfoNormal() throws Exception { + URLPathBuilder builder = Mockito.mock(URLPathBuilder.class); + Mockito.when(swaggerOperation.getPathBuilder()).thenReturn(builder); + Mockito.when(builder.createPathString(args)).thenReturn("/path"); + + Assertions.assertEquals("/path", request.getPathInfo()); } @Test - public void testGetPathInfoException(@Mocked URLPathBuilder builder) throws Exception { - new Expectations() { - { - swaggerOperation.getPathBuilder(); - result = builder; - builder.createPathString(args); - result = new Exception("error"); - } - }; + public void testGetPathInfoException() throws Exception { + URLPathBuilder builder = Mockito.mock(URLPathBuilder.class); + Mockito.when(swaggerOperation.getPathBuilder()).thenReturn(builder); + Mockito.when(builder.createPathString(args)).thenThrow(new Exception("error")); try { request.getPathInfo(); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("Failed to get path info.", e.getMessage()); - Assert.assertEquals("error", e.getCause().getMessage()); + Assertions.assertEquals("Failed to get path info.", e.getMessage()); + Assertions.assertEquals("error", e.getCause().getMessage()); } } @Test public void testGetRemoteAddress() throws Exception { - new Expectations() { - { - socketAddress.host(); - result = "127.0.0.2"; - socketAddress.port(); - result = 8088; - } - }; + Mockito.when(socketAddress.host()).thenReturn("127.0.0.2"); + Mockito.when(socketAddress.port()).thenReturn(8088); + Mockito.when(invocation.getHandlerContext()).thenReturn(handlerContext); String addr = request.getRemoteAddr(); String host = request.getRemoteHost(); int port = request.getRemotePort(); - Assert.assertEquals(addr, "127.0.0.2"); - Assert.assertEquals(host, "127.0.0.2"); - Assert.assertEquals(port, 8088); + Assertions.assertEquals(addr, "127.0.0.2"); + Assertions.assertEquals(host, "127.0.0.2"); + Assertions.assertEquals(port, 8088); } @Test - public void testGetRemoteAddressEmpty(@Mocked Invocation invocation) throws Exception { - handlerContext.remove(Const.REMOTE_ADDRESS); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerOperation; - invocation.getArgs(); - result = args; - invocation.getHandlerContext(); - result = handlerContext; - } - }; + public void testGetRemoteAddressEmpty() throws Exception { + Invocation invocation = Mockito.mock(Invocation.class); + + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(swaggerOperation); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + handlerContext.remove(CoreConst.REMOTE_ADDRESS); + Mockito.when(invocation.getHandlerContext()).thenReturn(handlerContext); InvocationToHttpServletRequest request = new InvocationToHttpServletRequest(invocation); String addr = request.getRemoteAddr(); String host = request.getRemoteHost(); int port = request.getRemotePort(); - Assert.assertEquals(addr, ""); - Assert.assertEquals(host, ""); - Assert.assertEquals(port, 0); + Assertions.assertEquals(addr, ""); + Assertions.assertEquals(host, ""); + Assertions.assertEquals(port, 0); } @Test - public void testGetContextPath(@Mocked Invocation invocation) throws Exception { + public void testGetContextPath() { InvocationToHttpServletRequest request = new InvocationToHttpServletRequest(invocation); - Assert.assertEquals("", request.getContextPath()); + Assertions.assertEquals("", request.getContextPath()); } @Test public void getContentType() { - Assert.assertNull(request.getContentType()); + Assertions.assertNull(request.getContentType()); } @Test public void getCharacterEncoding() { - Assert.assertNull(request.getCharacterEncoding()); + Assertions.assertNull(request.getCharacterEncoding()); } } diff --git a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestProducerHttpRequestArgMapper.java b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestProducerHttpRequestArgMapper.java index 2883139cd93..ba11c447897 100644 --- a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestProducerHttpRequestArgMapper.java +++ b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestProducerHttpRequestArgMapper.java @@ -20,55 +20,44 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; -import org.junit.Assert; -import org.junit.Test; -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestProducerHttpRequestArgMapper { - @Mocked - Invocation invocation; + Invocation invocation = Mockito.mock(Invocation.class); - ProducerHttpRequestArgMapper mapper = new ProducerHttpRequestArgMapper(0); + ProducerHttpRequestArgMapper mapper = new ProducerHttpRequestArgMapper("test", "test"); @Test - public void testGetFromContext(@Mocked HttpServletRequest request) { + public void testGetFromContext() { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); Map context = new HashMap<>(); context.put(RestConst.REST_REQUEST, request); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - } - }; + Mockito.when(invocation.getHandlerContext()).thenReturn(context); - Assert.assertSame(request, mapper.createContextArg(invocation)); + Assertions.assertSame(request, mapper.createContextArg(invocation)); } @Test - public void testCreateFromInvocation(@Mocked HttpServletRequest request, @Mocked OperationMeta operationMeta, - @Mocked RestOperationMeta swaggerOperation) { + public void testCreateFromInvocation() { + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + RestOperationMeta swaggerOperation = Mockito.mock(RestOperationMeta.class); Map context = new HashMap<>(); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerOperation; - } - }; + Mockito.when(invocation.getHandlerContext()).thenReturn(context); + Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); + Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(swaggerOperation); - Assert.assertEquals(InvocationToHttpServletRequest.class, mapper.createContextArg(invocation).getClass()); + Assertions.assertEquals(InvocationToHttpServletRequest.class, mapper.createContextArg(invocation).getClass()); } } diff --git a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestConsumerProvider.java b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestConsumerProvider.java deleted file mode 100644 index d630645d2c2..00000000000 --- a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestConsumerProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.rest.common; - -import org.apache.servicecomb.common.rest.RestConst; -import org.junit.Assert; -import org.junit.Test; - -public class TestRestConsumerProvider { - - @Test - public void testInit() throws Exception { - RestConsumerProvider instance = new RestConsumerProvider(); - instance.init(); - Assert.assertEquals(RestConst.REST, instance.getName()); - } -} diff --git a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestProducers.java b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestProducers.java index 2416e67fe04..9e70423e22f 100644 --- a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestProducers.java +++ b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestProducers.java @@ -17,13 +17,27 @@ package org.apache.servicecomb.provider.rest.common; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.test.scaffolding.spring.SpringUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestRestProducers { @RestSchema(schemaId = "test") - public class RestSchemaForTest { + public static class RestSchemaForTest { + } + + static Environment environment = Mockito.mock(Environment.class); + + @BeforeAll + public static void setUpClass() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty(RestConst.PROVIDER_SCAN_REST_CONTROLLER, boolean.class, true)) + .thenReturn(true); } RestProducers producer = new RestProducers(); @@ -31,21 +45,21 @@ public class RestSchemaForTest { @Test public void postProcessBeforeInitialization() { Object bean = new Object(); - Assert.assertSame(bean, producer.postProcessBeforeInitialization(bean, "test")); + Assertions.assertSame(bean, producer.postProcessBeforeInitialization(bean, "test")); } @Test public void postProcessAfterInitializationNormal() { RestSchemaForTest bean = new RestSchemaForTest(); - Assert.assertSame(bean, producer.postProcessAfterInitialization(bean, "")); - Assert.assertEquals(1, producer.getProducerMetaList().size()); + Assertions.assertSame(bean, producer.postProcessAfterInitialization(bean, "")); + Assertions.assertEquals(1, producer.getProducerMetaList().size()); } @Test public void postProcessAfterInitializationNoAnnotation() { Object bean = new Object(); - Assert.assertSame(bean, producer.postProcessAfterInitialization(bean, "")); - Assert.assertEquals(0, producer.getProducerMetaList().size()); + Assertions.assertSame(bean, producer.postProcessAfterInitialization(bean, "")); + Assertions.assertEquals(0, producer.getProducerMetaList().size()); } @Test diff --git a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestServiceProvider.java b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestServiceProvider.java index 6e9598e491f..e7713afdde9 100644 --- a/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestServiceProvider.java +++ b/providers/provider-rest-common/src/test/java/org/apache/servicecomb/provider/rest/common/TestRestServiceProvider.java @@ -17,57 +17,24 @@ package org.apache.servicecomb.provider.rest.common; -import java.util.HashMap; - import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.definition.schema.ProducerSchemaFactory; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; -import mockit.Mock; -import mockit.MockUp; - public class TestRestServiceProvider { - @Test - public void testInit() throws Exception { + public void testInit() { ApplicationContext context = Mockito.mock(ApplicationContext.class); - Mockito.when(context.getBeansWithAnnotation(RestSchema.class)).thenReturn(new HashMap<>()); - - new MockUp() { - @Mock - ApplicationContext getContext() { - return context; - } - }; - - RestProducerProvider restProducerProvider = new RestProducerProvider(); - ReflectUtils.setField(restProducerProvider, "producerSchemaFactory", new ProducerSchemaFactory()); - ReflectUtils.setField(restProducerProvider, "restProducers", new RestProducers()); - - restProducerProvider.init(); - Assert.assertEquals(RestConst.REST, restProducerProvider.getName()); - } - - @Test - public void testInvoke() throws Exception { - // Invocation invocation = Mockito.mock(Invocation.class); - // AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - // OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - // Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - // RestProviderOperation restProviderOperationMeta = Mockito.mock(RestProviderOperation.class); - // Mockito.when(operationMeta.getExtData("rest.operation")).thenReturn(restProviderOperationMeta); - // ArgsMapper argsMapper = Mockito.mock(ArgsMapper.class); - // Mockito.when(restProviderOperationMeta.getArgsMapper()).thenReturn(argsMapper); - // try { - // RestProducerProvider.getInstance().invoke(invocation, asyncResp); - // } catch (Exception e) { - // Assert.assertEquals(null, e.getMessage()); - // } - // Assert.assertEquals(invocation.getContext(), ContextUtils.getInvocationContext().getContext()); + Mockito.when(context.getBean(RestProducers.class)).thenReturn(new RestProducers()); + try (MockedStatic beanUtilsMockedStatic = Mockito.mockStatic(BeanUtils.class)) { + beanUtilsMockedStatic.when(BeanUtils::getContext).thenReturn(context); + RestProducerProvider restProducerProvider = new RestProducerProvider(); + restProducerProvider.init(); + Assertions.assertEquals(RestConst.REST, restProducerProvider.getName()); + } } } diff --git a/providers/provider-rest-common/src/test/resources/log4j.properties b/providers/provider-rest-common/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/providers/provider-rest-common/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/providers/provider-springmvc/pom.xml b/providers/provider-springmvc/pom.xml index 7091a955cf5..4792027cc64 100644 --- a/providers/provider-springmvc/pom.xml +++ b/providers/provider-springmvc/pom.xml @@ -17,13 +17,13 @@ --> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 org.apache.servicecomb providers - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT provider-springmvc Java Chassis::Providers::Spring MVC @@ -33,6 +33,11 @@ org.apache.servicecomb provider-rest-common + + org.apache.servicecomb + registry-local + test + org.apache.servicecomb swagger-invocation-springmvc @@ -41,14 +46,24 @@ org.apache.servicecomb swagger-generator-springmvc + + + com.google.code.findbugs + jsr305 + + + org.apache.servicecomb + foundation-test-scaffolding + test + - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.mockito + mockito-inline test diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CommonToHttpServletRequest.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CommonToHttpServletRequest.java index 2d5d75ed8eb..e1cd368eb7c 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CommonToHttpServletRequest.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CommonToHttpServletRequest.java @@ -17,9 +17,9 @@ package org.apache.servicecomb.provider.springmvc.reference; -import java.io.File; +import static org.apache.servicecomb.foundation.common.utils.PartUtils.getSinglePart; + import java.io.IOException; -import java.io.InputStream; import java.net.HttpCookie; import java.util.ArrayList; import java.util.Arrays; @@ -29,43 +29,45 @@ import java.util.List; import java.util.Map; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.Part; -import javax.ws.rs.core.HttpHeaders; - import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.foundation.common.part.FilePart; -import org.apache.servicecomb.foundation.common.part.InputStreamPart; -import org.apache.servicecomb.foundation.common.part.ResourcePart; import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; -import org.springframework.core.io.Resource; + +import com.google.common.annotations.VisibleForTesting; + +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; // restTemplate convert parameters to invocation args. public class CommonToHttpServletRequest extends AbstractHttpServletRequest { - private Map> queryParams; + private final Map> queryParams; - private Map> httpHeaders; + private final Map> httpHeaders; + + //contains all the file key in the parts + private List fileKeys = new ArrayList<>(); // gen by httpHeaders private Cookie[] cookies; @SuppressWarnings("unchecked") public CommonToHttpServletRequest(Map pathParams, Map> queryParams, - Map> httpHeaders, Object bodyObject, boolean isFormData) { + Map> httpHeaders, Object bodyObject, List fileKeys) { setAttribute(RestConst.PATH_PARAMETERS, pathParams); - - if (isFormData) { - setAttribute(RestConst.FORM_PARAMETERS, (Map) bodyObject); - } else { - setAttribute(RestConst.BODY_PARAMETER, bodyObject); - } + this.fileKeys = fileKeys; + setAttribute(RestConst.BODY_PARAMETER, bodyObject); this.queryParams = queryParams; this.httpHeaders = httpHeaders; } + @SuppressWarnings("unchecked") + public CommonToHttpServletRequest(Map pathParams, Map> queryParams, + Map> httpHeaders, Object bodyObject) { + this(pathParams, queryParams, httpHeaders, bodyObject, null); + } + @Override public String getContentType() { return getHeader(HttpHeaders.CONTENT_TYPE); @@ -87,10 +89,10 @@ public String getParameter(String name) { public String[] getParameterValues(String name) { List queryValues = queryParams.get(name); if (queryValues == null || queryValues.isEmpty()) { - return null; + return new String[0]; } - return queryValues.toArray(new String[queryValues.size()]); + return queryValues.toArray(new String[0]); } @Override @@ -142,7 +144,7 @@ private Cookie[] createCookies() { } } - return result.toArray(new Cookie[result.size()]); + return result.toArray(new Cookie[0]); } @Override @@ -157,48 +159,52 @@ public void setHeader(String name, String value) { @Override public void addHeader(String name, String value) { - List list = httpHeaders.computeIfAbsent(name, key -> { - return new ArrayList<>(); - }); + List list = httpHeaders.computeIfAbsent(name, key -> new ArrayList<>()); list.add(value); } @Override - public Part getPart(String name) throws IOException, ServletException { + public Part getPart(String name) { Object value = findPartInputValue(name); - if (value == null) { - return null; - } - - if (Part.class.isInstance(value)) { - return (Part) value; - } - - if (InputStream.class.isInstance(value)) { - return new InputStreamPart(name, (InputStream) value); - } + return getSinglePart(name, value); + } - if (Resource.class.isInstance(value)) { - return new ResourcePart(name, (Resource) value); - } + @Override + public Collection getParts() { + @SuppressWarnings("unchecked") + Map form = (Map) getAttribute(RestConst.BODY_PARAMETER); + List partList = new ArrayList<>(); + filePartListWithForm(partList, form); + return partList; + } - if (File.class.isInstance(value)) { - return new FilePart(name, (File) value); + private void filePartListWithForm(List partList, Map form) { + for (String key : fileKeys) { + Object value = form.get(key); + if (value == null) { + continue; + } + if (Collection.class.isInstance(value)) { + Collection collection = (Collection) value; + for (Object part : collection) { + partList.add(getSinglePart(key, part)); + } + continue; + } + if (value.getClass().isArray()) { + Object[] params = (Object[]) value; + for (Object param : params) { + partList.add(getSinglePart(key, param)); + } + continue; + } + partList.add(getSinglePart(key, value)); } - - throw new IllegalStateException( - String.format("File input parameter of %s could be %s / %s / %s or %s, but got %s.", - name, - Part.class.getName(), - InputStream.class.getName(), - Resource.class.getName(), - File.class.getName(), - value.getClass().getName())); } protected Object findPartInputValue(String name) { @SuppressWarnings("unchecked") - Map form = (Map) getAttribute(RestConst.FORM_PARAMETERS); + Map form = (Map) getAttribute(RestConst.BODY_PARAMETER); Object value = form.get(name); if (value == null) { return null; @@ -214,4 +220,9 @@ protected Object findPartInputValue(String name) { } return value; } + + @VisibleForTesting + public List getFileKeys() { + return fileKeys; + } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java index 6f3388396a6..ba056e180fb 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java @@ -18,12 +18,12 @@ package org.apache.servicecomb.provider.springmvc.reference; import java.io.OutputStream; +import java.lang.reflect.Type; import java.net.URI; +import java.util.Collections; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; - import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.common.rest.codec.RestCodec; import org.apache.servicecomb.common.rest.definition.RestOperationMeta; @@ -32,20 +32,32 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.invocation.InvocationFactory; import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; +import org.apache.servicecomb.registry.definition.DefinitionConst; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.annotations.VisibleForTesting; + import io.netty.handler.codec.http.QueryStringDecoder; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.Response.Status; public class CseClientHttpRequest implements ClientHttpRequest { + // URL format:cse://microserviceName/business url private URI uri; @@ -64,6 +76,8 @@ public class CseClientHttpRequest implements ClientHttpRequest { private RequestMeta requestMeta; + private Type responseType; + public CseClientHttpRequest() { } @@ -84,7 +98,8 @@ protected RequestMeta getRequestMeta() { return requestMeta; } - protected void setRequestMeta(RequestMeta requestMeta) { + @VisibleForTesting + public void setRequestMeta(RequestMeta requestMeta) { this.requestMeta = requestMeta; } @@ -108,10 +123,24 @@ public void setContext(InvocationContext context) { this.context = context; } + public Type getResponseType() { + return responseType; + } + + public void setResponseType(Type responseType) { + this.responseType = responseType; + } + public void setRequestBody(Object requestBody) { this.requestBody = requestBody; } + public void setHttpHeaders(HttpHeaders headers) { + if (headers != null) { + this.httpHeaders = headers; + } + } + @Override public HttpMethod getMethod() { return method; @@ -122,6 +151,11 @@ public URI getURI() { return uri; } + @Override + public Map getAttributes() { + return Collections.emptyMap(); + } + @Override public HttpHeaders getHeaders() { return httpHeaders; @@ -140,60 +174,81 @@ public ClientHttpResponse execute() { QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri.getRawSchemeSpecificPart()); queryParams = queryStringDecoder.parameters(); - Object[] args = this.collectArguments(); + Map swaggerArguments = this.collectArguments(); // 异常流程,直接抛异常出去 - return this.invoke(args); + return this.invoke(swaggerArguments); } protected RequestMeta createRequestMeta(String httpMethod, URI uri) { - String microserviceName = uri.getAuthority(); - - ReferenceConfig referenceConfig = findReferenceConfig(microserviceName); + String microserviceName = parseMicroserviceName(uri); + + MicroserviceReferenceConfig microserviceReferenceConfig = SCBEngine.getInstance() + .getOrCreateReferenceConfig(microserviceName); + if (microserviceReferenceConfig == null) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, + new CommonExceptionData(String.format("Failed to invoke service %s. Maybe service" + + " not registered or no active instance.", microserviceName))); + } + MicroserviceMeta microserviceMeta = microserviceReferenceConfig.getMicroserviceMeta(); - MicroserviceMeta microserviceMeta = referenceConfig.getMicroserviceMeta(); ServicePathManager servicePathManager = ServicePathManager.getServicePathManager(microserviceMeta); if (servicePathManager == null) { throw new Error(String.format("no schema defined for %s:%s", microserviceMeta.getAppId(), - microserviceMeta.getName())); + microserviceMeta.getMicroserviceName())); } OperationLocator locator = servicePathManager.consumerLocateOperation(path, httpMethod); RestOperationMeta swaggerRestOperation = locator.getOperation(); + OperationMeta operationMeta = locator.getOperation().getOperationMeta(); + ReferenceConfig referenceConfig = microserviceReferenceConfig.createReferenceConfig(operationMeta); + Map pathParams = locator.getPathVarMap(); return new RequestMeta(referenceConfig, swaggerRestOperation, pathParams); } - protected ReferenceConfig findReferenceConfig(String microserviceName) { - return SCBEngine.getInstance().getReferenceConfigForInvoke(microserviceName); + private String parseMicroserviceName(URI uri) { + String microserviceName = uri.getAuthority(); + return microserviceName.replace(CseUriTemplateHandler.APP_SERVICE_SEPARATOR_INTERNAL, + DefinitionConst.APP_SERVICE_SEPARATOR); } protected String findUriPath(URI uri) { return uri.getRawPath(); } - protected Invocation prepareInvocation(Object[] args) { + protected Invocation prepareInvocation(Map swaggerArguments) { Invocation invocation = InvocationFactory.forConsumer(requestMeta.getReferenceConfig(), requestMeta.getOperationMeta(), - args); + requestMeta.getOperationMeta().buildBaseConsumerRuntimeType(), + swaggerArguments); + invocation.getHandlerContext().put(RestConst.REST_CLIENT_REQUEST_PATH, - path + "?" + this.uri.getRawQuery()); + path + (this.uri.getRawQuery() == null ? "" : "?" + this.uri.getRawQuery())); if (context != null) { - invocation.addContext(context); + invocation.addContext(context.getContext()); + invocation.addLocalContext(context.getLocalContext()); } - invocation.getHandlerContext().put(RestConst.CONSUMER_HEADER, httpHeaders); + + if (responseType != null && + !(responseType instanceof Class && Part.class.isAssignableFrom((Class) responseType))) { + invocation.setSuccessResponseType(TypeFactory.defaultInstance().constructType(responseType)); + } + + invocation.getHandlerContext().put(RestConst.CONSUMER_HEADER, httpHeaders.toSingleValueMap()); return invocation; } - private CseClientHttpResponse invoke(Object[] args) { - Invocation invocation = prepareInvocation(args); + @VisibleForTesting + CseClientHttpResponse invoke(Map swaggerArguments) { + Invocation invocation = prepareInvocation(swaggerArguments); Response response = doInvoke(invocation); - if (response.isSuccessed()) { + if (response.isSucceed()) { return new CseClientHttpResponse(response); } @@ -204,9 +259,11 @@ protected Response doInvoke(Invocation invocation) { return InvokerUtils.innerSyncInvoke(invocation); } - protected Object[] collectArguments() { + protected Map collectArguments() { HttpServletRequest mockRequest = new CommonToHttpServletRequest(requestMeta.getPathParams(), queryParams, - httpHeaders, requestBody, requestMeta.getSwaggerRestOperation().isFormData()); + httpHeaders, requestBody, + requestMeta.getSwaggerRestOperation().getFileKeys()); + // no types info, so will not convert any parameters return RestCodec.restToArgs(mockRequest, requestMeta.getSwaggerRestOperation()); } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java index 52092c90d7b..e3caf103b09 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpResponse.java @@ -19,15 +19,15 @@ import java.io.IOException; import java.io.InputStream; -import java.util.List; import java.util.Map.Entry; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.response.Headers; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; +import io.vertx.core.MultiMap; + /** * cse应答在transport层已经完成了码流到对象的转换 * 这里是适配springmvc的机制,让调用者能拿到已经转换好的对象 @@ -36,6 +36,7 @@ public class CseClientHttpResponse implements ClientHttpResponse { // 让springmvc client以为应答有body // mark、reset都是有锁的,这里通过重写取消了锁 private static final InputStream BODY_INPUT_STREAM = new InputStream() { + @Override public boolean markSupported() { return true; } @@ -49,11 +50,12 @@ public int read() throws IOException { return 0; } + @Override public void reset() throws IOException { } }; - private Response response; + private final Response response; private HttpHeaders httpHeaders; @@ -74,12 +76,10 @@ public InputStream getBody() throws IOException { public HttpHeaders getHeaders() { if (httpHeaders == null) { HttpHeaders tmpHeaders = new HttpHeaders(); - Headers headers = response.getHeaders(); - if (headers.getHeaderMap() != null) { - for (Entry> entry : headers.getHeaderMap().entrySet()) { - for (Object value : entry.getValue()) { - tmpHeaders.add(entry.getKey(), String.valueOf(value)); - } + MultiMap headers = response.getHeaders(); + if (headers != null) { + for (Entry entry : headers.entries()) { + tmpHeaders.add(entry.getKey(), entry.getValue()); } } @@ -90,11 +90,12 @@ public HttpHeaders getHeaders() { @Override public HttpStatus getStatusCode() throws IOException { - // TODO:springmvc不允许自定义http错误码 return HttpStatus.valueOf(response.getStatusCode()); } @Override + @Deprecated(since = "6.0") + @SuppressWarnings("deprecations") public int getRawStatusCode() throws IOException { return response.getStatusCode(); } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java new file mode 100644 index 00000000000..018abc9c3d5 --- /dev/null +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverter.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.springmvc.reference; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.GenericHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.lang.Nullable; + +public class CseHttpMessageConverter implements GenericHttpMessageConverter { + + private static final List ALL_MEDIA_TYPE = Arrays.asList(MediaType.ALL); + + @Override + public boolean canRead(Class clazz, MediaType mediaType) { + return true; + } + + @Override + public boolean canWrite(Class clazz, MediaType mediaType) { + return true; + } + + @Override + public List getSupportedMediaTypes() { + return ALL_MEDIA_TYPE; + } + + @Override + public Object read(Class clazz, HttpInputMessage inputMessage) throws HttpMessageNotReadableException { + throw new IllegalStateException("not supported"); + } + + private Object read(HttpInputMessage inputMessage) { + throw new IllegalStateException("not supported"); + } + + @Override + public void write(Object o, MediaType contentType, + HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + write(o, outputMessage); + } + + private void write(Object o, HttpOutputMessage outputMessage) { + CseClientHttpRequest request = (CseClientHttpRequest) outputMessage; + request.setRequestBody(o); + } + + @Override + public boolean canRead(Type type, @Nullable Class contextClass, @Nullable MediaType mediaType) { + return true; + } + + @Override + public Object read(Type type, @Nullable Class contextClass, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { + throw new IllegalStateException("not supported"); + } + + @Override + public boolean canWrite(@Nullable Type type, Class clazz, @Nullable MediaType mediaType) { + return true; + } + + @Override + public void write(Object o, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { + write(o, outputMessage); + } +} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java new file mode 100644 index 00000000000..402c714a932 --- /dev/null +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseHttpMessageConverterExtractor.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.springmvc.reference; + +import java.io.IOException; + +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.ResponseExtractor; + +public class CseHttpMessageConverterExtractor implements ResponseExtractor { + @Override + @SuppressWarnings("unchecked") + public T extractData(ClientHttpResponse response) throws IOException { + return (T) ((CseClientHttpResponse) response).getResult(); + } +} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRequestCallback.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRequestCallback.java index 3f824644dd7..fd1e33cb967 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRequestCallback.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRequestCallback.java @@ -17,18 +17,23 @@ package org.apache.servicecomb.provider.springmvc.reference; import java.io.IOException; +import java.lang.reflect.Type; +import org.apache.servicecomb.foundation.common.utils.GenericsUtils; import org.springframework.http.client.ClientHttpRequest; import org.springframework.web.client.RequestCallback; public class CseRequestCallback implements RequestCallback { - private Object requestBody; + private final Object requestBody; - private RequestCallback orgCallback; + private final RequestCallback targetCallback; - public CseRequestCallback(Object requestBody, RequestCallback orgCallback) { + private final Type responseType; + + public CseRequestCallback(Object requestBody, RequestCallback targetCallback, Type responseType) { this.requestBody = requestBody; - this.orgCallback = orgCallback; + this.targetCallback = targetCallback; + this.responseType = responseType; } /** @@ -36,14 +41,26 @@ public CseRequestCallback(Object requestBody, RequestCallback orgCallback) { */ @Override public void doWithRequest(ClientHttpRequest request) throws IOException { - orgCallback.doWithRequest(request); + targetCallback.doWithRequest(request); + CseClientHttpRequest req = (CseClientHttpRequest) request; + req.setResponseType(overrideResponseType()); if (!CseHttpEntity.class.isInstance(requestBody)) { return; } - CseClientHttpRequest req = (CseClientHttpRequest) request; CseHttpEntity entity = (CseHttpEntity) requestBody; req.setContext(entity.getContext()); } + + private Type overrideResponseType() { + if (GenericsUtils.isGenericResponseType(responseType)) { + // code: List response = restTemplate + // .postForObject("/testListObjectParam", request, List.class); + // will using server schema type to deserialize + return null; + } + // code: MyObject response = .postForObject("/testListObjectParam", request, MyObject.class); + return responseType; + } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java new file mode 100644 index 00000000000..c6626353aa2 --- /dev/null +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseResponseEntityResponseExtractor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.provider.springmvc.reference; + +import java.io.IOException; +import java.lang.reflect.Type; + +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.Nullable; +import org.springframework.web.client.ResponseExtractor; + +public class CseResponseEntityResponseExtractor implements ResponseExtractor> { + @Nullable + private final CseHttpMessageConverterExtractor delegate; + + public CseResponseEntityResponseExtractor(@Nullable Type responseType) { + if (responseType != null && Void.class != responseType) { + this.delegate = new CseHttpMessageConverterExtractor<>(); + } else { + this.delegate = null; + } + } + + @Override + public ResponseEntity extractData(ClientHttpResponse response) throws IOException { + if (this.delegate != null) { + T body = this.delegate.extractData(response); + return ResponseEntity.status(response.getStatusCode().value()).headers(response.getHeaders()).body(body); + } else { + return ResponseEntity.status(response.getStatusCode().value()).headers(response.getHeaders()).build(); + } + } +} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java index 9a63c8ab3e1..b4f3923b004 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseRestTemplate.java @@ -20,10 +20,15 @@ import java.lang.reflect.Type; import java.net.URI; import java.util.Arrays; +import java.util.Map; import org.apache.servicecomb.common.rest.RestConst; -import org.springframework.web.client.CseHttpMessageConverter; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; import org.springframework.web.client.RequestCallback; +import org.springframework.web.client.ResponseExtractor; +import org.springframework.web.client.RestClientException; public class CseRestTemplate extends AcceptableRestTemplate { public CseRestTemplate() { @@ -32,27 +37,153 @@ public CseRestTemplate() { setUriTemplateHandler(new CseUriTemplateHandler()); } + // GET + + @Override + @Nullable + public T getForObject(String url, Class responseType, Object... uriVariables) throws RestClientException { + RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T getForObject(String url, Class responseType, Map uriVariables) throws RestClientException { + RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T getForObject(URI url, Class responseType) throws RestClientException { + RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.GET, requestCallback, responseExtractor); + } + + // HEAD + // no override + + // POST + + @Override + @Nullable + public T postForObject(String url, @Nullable Object request, Class responseType, + Object... uriVariables) throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T postForObject(String url, @Nullable Object request, Class responseType, + Map uriVariables) throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T postForObject(URI url, @Nullable Object request, Class responseType) + throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.POST, requestCallback, responseExtractor); + } + + // PUT + // no override + + // PATCH + + @Override + @Nullable + public T patchForObject(String url, @Nullable Object request, Class responseType, + Object... uriVariables) throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T patchForObject(String url, @Nullable Object request, Class responseType, + Map uriVariables) throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor, uriVariables); + } + + @Override + @Nullable + public T patchForObject(URI url, @Nullable Object request, Class responseType) + throws RestClientException { + + RequestCallback requestCallback = httpEntityCallback(request, responseType); + CseHttpMessageConverterExtractor responseExtractor = + new CseHttpMessageConverterExtractor<>(); + return execute(url, HttpMethod.PATCH, requestCallback, responseExtractor); + } + + // DELETE + // no override + + // OPTIONS + // no override + + // exchange + // no override + + @Override + public ResponseExtractor> responseEntityExtractor(Type responseType) { + return new CseResponseEntityResponseExtractor<>(responseType); + } + @Override - protected RequestCallback httpEntityCallback(Object requestBody) { + public RequestCallback httpEntityCallback(Object requestBody) { RequestCallback callback = super.httpEntityCallback(requestBody); - CseRequestCallback cseCallback = new CseRequestCallback(requestBody, callback); + CseRequestCallback cseCallback = new CseRequestCallback(requestBody, callback, null); return cseCallback; } @Override - protected RequestCallback httpEntityCallback(Object requestBody, Type responseType) { + public RequestCallback httpEntityCallback(Object requestBody, Type responseType) { RequestCallback callback = super.httpEntityCallback(requestBody, responseType); - CseRequestCallback cseCallback = new CseRequestCallback(requestBody, callback); + CseRequestCallback cseCallback = new CseRequestCallback(requestBody, callback, responseType); + return cseCallback; + } + + @Override + public RequestCallback acceptHeaderRequestCallback(Class responseType) { + RequestCallback callback = super.acceptHeaderRequestCallback(responseType); + CseRequestCallback cseCallback = new CseRequestCallback(null, callback, responseType); return cseCallback; } @Override public boolean isAcceptable(String uri) { - return uri.startsWith(RestConst.URI_PREFIX); + return uri.startsWith(RestConst.URI_PREFIX) || uri.startsWith(RestConst.URI_PREFIX_NEW); } @Override public boolean isAcceptable(URI uri) { - return RestConst.SCHEME.equals(uri.getScheme()); + return RestConst.SCHEME.equals(uri.getScheme()) || RestConst.SCHEME_NEW.equals(uri.getScheme()); } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseUriTemplateHandler.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseUriTemplateHandler.java index 0890759b0e2..08f2b9da880 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseUriTemplateHandler.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseUriTemplateHandler.java @@ -16,62 +16,44 @@ */ package org.apache.servicecomb.provider.springmvc.reference; -import java.lang.reflect.Field; import java.net.URI; -import java.net.URISyntaxException; import java.util.Map; import org.apache.servicecomb.common.rest.RestConst; -import org.springframework.util.ReflectionUtils; -import org.springframework.web.util.DefaultUriTemplateHandler; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.springframework.web.util.DefaultUriBuilderFactory; -/** - * 默认不支持下面第1个场景,需要做出修正 - * cse://app:ms/path to cse://app/ms/path - * cse://ms/path to cse://ms/path - */ -public class CseUriTemplateHandler extends DefaultUriTemplateHandler { - private Field hostField = ReflectionUtils.findField(UriComponentsBuilder.class, "host"); +public class CseUriTemplateHandler extends DefaultUriBuilderFactory { + // Must be one of URI unreserved `ALPHA / DIGIT / "-" / "." / "_" / "~"` + public static final String APP_SERVICE_SEPARATOR_INTERNAL = "~"; public CseUriTemplateHandler() { - ReflectionUtils.makeAccessible(hostField); } @Override - protected URI expandInternal(String uriTemplate, Map uriVariables) { - UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate); - UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables); - return createUri(uriTemplate, uriComponentsBuilder, uriComponents); + public URI expand(String uriTemplate, Map uriVars) { + return super.expand(parseUrl(uriTemplate), uriVars); } @Override - protected URI expandInternal(String uriTemplate, Object... uriVariables) { - UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate); - UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables); - return createUri(uriTemplate, uriComponentsBuilder, uriComponents); + public URI expand(String uriTemplate, Object... uriVars) { + return super.expand(parseUrl(uriTemplate), uriVars); } - private URI createUri(String uriTemplate, UriComponentsBuilder builder, UriComponents uriComponents) { - String strUri = uriComponents.toUriString(); - - if (isCrossApp(uriTemplate, builder)) { - int idx = strUri.indexOf('/', RestConst.URI_PREFIX.length()); - strUri = strUri.substring(0, idx) + ":" + strUri.substring(idx + 1); + private static String parseUrl(String uriTemplate) { + int indexSchema = -1; + if (uriTemplate.startsWith(RestConst.URI_PREFIX)) { + indexSchema = RestConst.URI_PREFIX.length(); } - - try { - // Avoid further encoding (in the case of strictEncoding=true) - return new URI(strUri); - } catch (URISyntaxException ex) { - throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex); + if (uriTemplate.startsWith(RestConst.URI_PREFIX_NEW)) { + indexSchema = RestConst.URI_PREFIX_NEW.length(); } - } - - protected boolean isCrossApp(String uriTemplate, UriComponentsBuilder builder) { - String host = (String) ReflectionUtils.getField(hostField, builder); - int pos = RestConst.URI_PREFIX.length() + host.length(); - return uriTemplate.charAt(pos) == ':'; + if (indexSchema != -1) { + int indexPath = uriTemplate.indexOf("/", indexSchema); + String host = uriTemplate.substring(indexSchema, indexPath); + host = host.replace(DefinitionConst.APP_SERVICE_SEPARATOR, APP_SERVICE_SEPARATOR_INTERNAL); + return uriTemplate.substring(0, indexSchema) + host + uriTemplate.substring(indexPath); + } + return uriTemplate; } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RequestMeta.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RequestMeta.java index 18cb5c58d6c..be4aac4cfa2 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RequestMeta.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RequestMeta.java @@ -27,13 +27,13 @@ * 封装每一次调用的元数据 */ public class RequestMeta { - private ReferenceConfig referenceConfig; + private final ReferenceConfig referenceConfig; - private OperationMeta operationMeta; + private final OperationMeta operationMeta; - private RestOperationMeta swaggerRestOperation; + private final RestOperationMeta swaggerRestOperation; - private Map pathParams; + private final Map pathParams; public RequestMeta(ReferenceConfig referenceConfig, RestOperationMeta swaggerRestOperation, Map pathParams) { diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateBuilder.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateBuilder.java index b77f28cfd28..f8a5ceab17f 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateBuilder.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateBuilder.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.provider.springmvc.reference; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; public final class RestTemplateBuilder { private static final RestTemplateWrapper wrapper = new RestTemplateWrapper(); @@ -25,7 +25,7 @@ public final class RestTemplateBuilder { private RestTemplateBuilder() { } - public static RestTemplate create() { + public static RestOperations create() { return wrapper; } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java deleted file mode 100644 index bbead58292d..00000000000 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateCopyHeaderFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; - -public class RestTemplateCopyHeaderFilter implements HttpClientFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateCopyHeaderFilter.class); - - @Override - public int getOrder() { - return Integer.MIN_VALUE; - } - - @Override - public void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx) { - HttpHeaders httpHeaders = (HttpHeaders) invocation.getHandlerContext().get(RestConst.CONSUMER_HEADER); - if (httpHeaders == null) { - return; - } - - httpHeaders.forEach((key, values) -> { - if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(key)) { - LOGGER.debug("skip copy content-length into request"); - return; - } - - for (String value : values) { - // null args should not be set to requestEx to avoid NullPointerException in Netty. - if (null == value) { - LOGGER.debug("header value is null, key = [{}]. Will not set this header into request", key); - continue; - } - requestEx.addHeader(key, value); - } - }); - } - - @Override - public Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx) { - return null; - } -} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateWrapper.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateWrapper.java index 6d50d9ffd17..e91cfb68afd 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateWrapper.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/RestTemplateWrapper.java @@ -40,9 +40,8 @@ import org.springframework.web.util.UriTemplateHandler; /** - * 用于同时支持cse调用和非cse调用 + * Wrapper class to support java chassis invocation and non java chassis invocation. */ -// TODO: 2017/7/1 what we want to expose is RestOperations instead, since some RestTemplate methods are not to be called by users class RestTemplateWrapper extends RestTemplate { private final List acceptableRestTemplates = new ArrayList<>(); diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfig.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfig.java index 506eb1b6d57..f250b9f209c 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfig.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfig.java @@ -19,12 +19,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestOperations; @Configuration class ServiceCombRestTemplateConfig { @Bean - RestTemplate restTemplate() { + RestOperations restTemplate() { return RestTemplateBuilder.create(); } } diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/UrlWithProviderPrefixClientHttpRequestFactory.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/UrlWithProviderPrefixClientHttpRequestFactory.java index 6c7ba67d39e..8f0ec70ed00 100644 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/UrlWithProviderPrefixClientHttpRequestFactory.java +++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/UrlWithProviderPrefixClientHttpRequestFactory.java @@ -30,7 +30,7 @@ */ public class UrlWithProviderPrefixClientHttpRequestFactory implements ClientHttpRequestFactory { static class UrlWithProviderPrefixClientHttpRequest extends CseClientHttpRequest { - private String prefix; + private final String prefix; public UrlWithProviderPrefixClientHttpRequest(URI uri, HttpMethod httpMethod, String prefix) { super(uri, httpMethod); @@ -43,7 +43,7 @@ protected String findUriPath(URI uri) { } } - private String prefix; + private final String prefix; public UrlWithProviderPrefixClientHttpRequestFactory(String prefix) { this.prefix = prefix; diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java deleted file mode 100644 index d66a0c63924..00000000000 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import java.io.OutputStream; -import java.net.URI; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.provider.consumer.InvokerUtils; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.AsyncClientHttpRequest; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.concurrent.CompletableToListenableFutureAdapter; -import org.springframework.util.concurrent.ListenableFuture; - -import io.netty.handler.codec.http.QueryStringDecoder; - -public class CseAsyncClientHttpRequest extends CseClientHttpRequest implements AsyncClientHttpRequest { - - CseAsyncClientHttpRequest() { - } - - CseAsyncClientHttpRequest(URI uri, HttpMethod method) { - this.setUri(uri); - this.setMethod(method); - } - - @Override - public OutputStream getBody() { - return null; - } - - private ListenableFuture invoke(Object[] args) { - Invocation invocation = prepareInvocation(args); - invocation.getHandlerContext().put(RestConst.CONSUMER_HEADER, this.getHeaders()); - CompletableFuture clientHttpResponseCompletableFuture = doAsyncInvoke(invocation); - return new CompletableToListenableFutureAdapter(clientHttpResponseCompletableFuture); - } - - protected CompletableFuture doAsyncInvoke(Invocation invocation) { - CompletableFuture completableFuture = new CompletableFuture<>(); - InvokerUtils.reactiveInvoke(invocation, (Response response) -> { - if (response.isSuccessed()) { - completableFuture.complete(new CseClientHttpResponse(response)); - } else { - completableFuture.completeExceptionally(response.getResult()); - } - }); - return completableFuture; - } - - - @Override - public ListenableFuture executeAsync() { - this.setPath(findUriPath(this.getURI())); - this.setRequestMeta(createRequestMeta(this.getMethod().name(), this.getURI())); - QueryStringDecoder queryStringDecoder = new QueryStringDecoder(this.getURI().getRawSchemeSpecificPart()); - this.setQueryParams(queryStringDecoder.parameters()); - Object[] args = this.collectArguments(); - return this.invoke(args); - } -} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java deleted file mode 100644 index d27cf78bb26..00000000000 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import java.net.URI; - -import org.springframework.http.HttpMethod; -import org.springframework.http.client.AsyncClientHttpRequest; -import org.springframework.http.client.AsyncClientHttpRequestFactory; - -public class CseAsyncClientHttpRequestFactory implements AsyncClientHttpRequestFactory { - @Override - public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) { - return new CseAsyncClientHttpRequest(uri, httpMethod); - } -} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java deleted file mode 100644 index 1ca4b4c2a53..00000000000 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; -import org.springframework.http.HttpEntity; -import org.springframework.http.client.AsyncClientHttpRequest; -import org.springframework.web.client.AsyncRequestCallback; - -public class CseAsyncRequestCallback implements AsyncRequestCallback { - private HttpEntity requestBody; - - CseAsyncRequestCallback(HttpEntity requestBody) { - this.requestBody = requestBody; - } - - @Override - public void doWithRequest(AsyncClientHttpRequest request) { - CseAsyncClientHttpRequest cseAsyncClientHttpRequest = (CseAsyncClientHttpRequest) request; - if (requestBody != null) { - cseAsyncClientHttpRequest.setRequestBody(requestBody.getBody()); - } - - if (!CseHttpEntity.class.isInstance(requestBody)) { - return; - } - - CseAsyncClientHttpRequest req = (CseAsyncClientHttpRequest) request; - CseHttpEntity entity = (CseHttpEntity) requestBody; - req.setContext(entity.getContext()); - } -} diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java deleted file mode 100644 index 4bf1ba50dd9..00000000000 --- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import java.lang.reflect.Type; -import java.util.Arrays; - -import org.apache.servicecomb.provider.springmvc.reference.CseUriTemplateHandler; -import org.springframework.http.HttpEntity; -import org.springframework.web.client.AsyncRequestCallback; -import org.springframework.web.client.AsyncRestTemplate; -import org.springframework.web.client.CseHttpMessageConverter; - -public class CseAsyncRestTemplate extends AsyncRestTemplate { - public CseAsyncRestTemplate() { - setMessageConverters(Arrays.asList(new CseHttpMessageConverter())); - setAsyncRequestFactory(new CseAsyncClientHttpRequestFactory()); - setUriTemplateHandler(new CseUriTemplateHandler()); - } - - @Override - protected AsyncRequestCallback httpEntityCallback(HttpEntity requestBody) { - return new CseAsyncRequestCallback(requestBody); - } - - @Override - protected AsyncRequestCallback httpEntityCallback(HttpEntity requestBody, Type responseType) { - return new CseAsyncRequestCallback(requestBody); - } -} \ No newline at end of file diff --git a/providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java b/providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java deleted file mode 100644 index 648cf8a730b..00000000000 --- a/providers/provider-springmvc/src/main/java/org/springframework/web/client/CseHttpMessageConverter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.client; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.http.converter.HttpMessageNotWritableException; -import org.springframework.util.ReflectionUtils; - -/** - * 需要访问MessageBodyClientHttpResponseWrapper - * 这是一个package级别的类,只好放在特殊的包内了 - */ -public class CseHttpMessageConverter implements HttpMessageConverter { - - private static final List ALL_MEDIA_TYPE = Arrays.asList(MediaType.ALL); - - private static final Field RESPONSE_FIELD = - ReflectionUtils.findField(MessageBodyClientHttpResponseWrapper.class, "response"); - - static { - RESPONSE_FIELD.setAccessible(true); - } - - @Override - public boolean canRead(Class clazz, MediaType mediaType) { - return true; - } - - @Override - public boolean canWrite(Class clazz, MediaType mediaType) { - return true; - } - - @Override - public List getSupportedMediaTypes() { - return ALL_MEDIA_TYPE; - } - - @Override - public Object read(Class clazz, - HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - MessageBodyClientHttpResponseWrapper respWrapper = (MessageBodyClientHttpResponseWrapper) inputMessage; - CseClientHttpResponse resp = - (CseClientHttpResponse) ReflectionUtils.getField(RESPONSE_FIELD, respWrapper); - return resp.getResult(); - } - - @Override - public void write(Object t, MediaType contentType, - HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { - CseClientHttpRequest request = (CseClientHttpRequest) outputMessage; - request.setRequestBody(t); - } -} diff --git a/providers/provider-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter b/providers/provider-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter deleted file mode 100644 index 96608236881..00000000000 --- a/providers/provider-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.provider.springmvc.reference.RestTemplateCopyHeaderFilter diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java deleted file mode 100644 index 3219774d574..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/common/MockUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.common; - -import java.lang.reflect.Field; - -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.springframework.util.ReflectionUtils; - -import mockit.Mock; -import mockit.MockUp; - -public class MockUtil { - private static MockUtil instance = new MockUtil(); - - private MockUtil() { - - } - - public static MockUtil getInstance() { - return instance; - } - - public void mockReflectionUtils() { - - new MockUp() { - @Mock - Object getField(Field field, Object target) { - Response response = Response.ok(200); - return new CseClientHttpResponse(response); - } - }; - } - - public void mockCseClientHttpRequest() { - - new MockUp() { - @Mock - public void setRequestBody(Object requestBody) { - - } - }; - } -} diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfigTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfigTest.java index ae35f4b7b9b..c250b58415e 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfigTest.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/ServiceCombRestTemplateConfigTest.java @@ -18,10 +18,10 @@ package org.apache.servicecomb.provider.springmvc.reference; import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; -import org.junit.Test; -import org.springframework.web.client.RestTemplate; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.Test; +import org.springframework.web.client.RestOperations; public class ServiceCombRestTemplateConfigTest { @@ -29,8 +29,8 @@ public class ServiceCombRestTemplateConfigTest { @Test public void exposesServiceCombRestTemplate() { - RestTemplate restTemplate = config.restTemplate(); + RestOperations restTemplate = config.restTemplate(); - assertThat(restTemplate, instanceOf(RestTemplateWrapper.class)); + MatcherAssert.assertThat(restTemplate, instanceOf(RestTemplateWrapper.class)); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCommonToHttpServletRequest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCommonToHttpServletRequest.java index d0522cd775d..3b06470412a 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCommonToHttpServletRequest.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCommonToHttpServletRequest.java @@ -17,48 +17,62 @@ package org.apache.servicecomb.provider.springmvc.reference; +import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.core.HttpHeaders; - import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; public class TestCommonToHttpServletRequest { @Test public void testConstructFormTrue() { Map forms = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, forms, true); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, forms); - Assert.assertEquals(null, request.getAttribute(RestConst.BODY_PARAMETER)); - Assert.assertEquals(forms, request.getAttribute(RestConst.FORM_PARAMETERS)); + Assertions.assertEquals(forms, request.getAttribute(RestConst.BODY_PARAMETER)); } @Test public void testConstructFormFalse() { Object body = new Object(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, body, false); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, body); - Assert.assertEquals(null, request.getAttribute(RestConst.FORM_PARAMETERS)); - Assert.assertEquals(body, request.getAttribute(RestConst.BODY_PARAMETER)); + Assertions.assertEquals(body, request.getAttribute(RestConst.BODY_PARAMETER)); + } + + @Test + public void testConstructNormal() { + List fileKeys = new ArrayList<>(); + fileKeys.add("test1"); + fileKeys.add("test2"); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, null, fileKeys); + Assertions.assertEquals(2, ((CommonToHttpServletRequest) request).getFileKeys().size()); + Assertions.assertEquals("test1", ((CommonToHttpServletRequest) request).getFileKeys().get(0)); + Assertions.assertEquals("test2", ((CommonToHttpServletRequest) request).getFileKeys().get(1)); } @Test public void testConstructPath() { Map pathParams = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(pathParams, null, null, null, false); + HttpServletRequest request = new CommonToHttpServletRequest(pathParams, null, null, null); - Assert.assertEquals(pathParams, request.getAttribute(RestConst.PATH_PARAMETERS)); + Assertions.assertEquals(pathParams, request.getAttribute(RestConst.PATH_PARAMETERS)); } @Test @@ -66,8 +80,8 @@ public void testGetContentType() { Map> httpHeaders = new HashMap<>(); httpHeaders.put(HttpHeaders.CONTENT_TYPE, Arrays.asList("json")); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertEquals("json", request.getContentType()); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertEquals("json", request.getContentType()); } @Test @@ -75,8 +89,8 @@ public void testGetParameterNormal() { Map> queryParams = new HashMap<>(); queryParams.put("name", Arrays.asList("value")); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertEquals("value", request.getParameter("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + Assertions.assertEquals("value", request.getParameter("name")); } @Test @@ -84,16 +98,16 @@ public void testGetParameterEmpty() { Map> queryParams = new HashMap<>(); queryParams.put("name", Arrays.asList()); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertEquals(null, request.getParameter("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + Assertions.assertNull(request.getParameter("name")); } @Test public void testGetParameterNull() { Map> queryParams = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertEquals(null, request.getParameter("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + Assertions.assertNull(request.getParameter("name")); } @Test @@ -101,8 +115,8 @@ public void testGetParameterValuesNormal() { Map> queryParams = new HashMap<>(); queryParams.put("name", Arrays.asList("value")); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + MatcherAssert.assertThat(request.getParameterValues("name"), Matchers.arrayContaining("value")); } @Test @@ -110,16 +124,16 @@ public void testGetParameterValuesEmpty() { Map> queryParams = new HashMap<>(); queryParams.put("name", Arrays.asList()); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertArrayEquals(null, request.getParameterValues("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + Assertions.assertArrayEquals(new String[0], request.getParameterValues("name")); } @Test public void testGetParameterValuesNull() { Map> queryParams = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null, false); - Assert.assertArrayEquals(null, request.getParameterValues("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, queryParams, null, null); + Assertions.assertArrayEquals(new String[0], request.getParameterValues("name")); } @Test @@ -127,8 +141,8 @@ public void testGetHeaderNormal() { Map> httpHeaders = new HashMap<>(); httpHeaders.put("name", Arrays.asList("value")); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertEquals("value", request.getHeader("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertEquals("value", request.getHeader("name")); } @Test @@ -136,8 +150,8 @@ public void testGetHeaderEmpty() { Map> httpHeaders = new HashMap<>(); httpHeaders.put("name", Arrays.asList()); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertEquals(null, request.getHeader("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertNull(request.getHeader("name")); } @Test @@ -145,24 +159,24 @@ public void testGetHeaderNamesNormal() { Map> httpHeaders = new HashMap<>(); httpHeaders.put("name", Arrays.asList("value")); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + MatcherAssert.assertThat(Collections.list(request.getHeaderNames()), Matchers.contains("name")); } @Test public void testGetHeaderNamesEmpty() { Map> httpHeaders = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertFalse(request.getHeaderNames().hasMoreElements()); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertFalse(request.getHeaderNames().hasMoreElements()); } @Test public void testGetHeaderNull() { Map> httpHeaders = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertEquals(null, request.getHeader("name")); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertNull(request.getHeader("name")); } @Test @@ -170,8 +184,8 @@ public void testGetHeadersNormal() { Map> httpHeaders = new HashMap<>(); httpHeaders.put("name", Arrays.asList("value")); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + MatcherAssert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("value")); } @Test @@ -179,24 +193,24 @@ public void testGetHeadersEmpty() { Map> httpHeaders = new HashMap<>(); httpHeaders.put("name", Arrays.asList()); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertFalse(request.getHeaders("name").hasMoreElements()); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertFalse(request.getHeaders("name").hasMoreElements()); } @Test public void testGetHeadersNull() { Map> httpHeaders = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertFalse(request.getHeaders("name").hasMoreElements()); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertFalse(request.getHeaders("name").hasMoreElements()); } @Test public void testGetCookiesNull() { Map> httpHeaders = new HashMap<>(); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); - Assert.assertEquals(0, request.getCookies().length); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); + Assertions.assertEquals(0, request.getCookies().length); } @Test @@ -204,35 +218,65 @@ public void testGetCookiesNormal() { Map> httpHeaders = new HashMap<>(); httpHeaders.put(HttpHeaders.COOKIE, Arrays.asList("k1=v1;k2=v2;")); - HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, httpHeaders, null); Cookie[] cookies = request.getCookies(); - Assert.assertSame(cookies, request.getCookies()); - Assert.assertEquals(1, cookies.length); - Assert.assertEquals("k1", cookies[0].getName()); - Assert.assertEquals("v1", cookies[0].getValue()); + Assertions.assertSame(cookies, request.getCookies()); + Assertions.assertEquals(1, cookies.length); + Assertions.assertEquals("k1", cookies[0].getName()); + Assertions.assertEquals("v1", cookies[0].getValue()); } @Test public void testGetInputStream() throws IOException { - HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, null, false); - Assert.assertNull(request.getInputStream()); + HttpServletRequest request = new CommonToHttpServletRequest(null, null, null, null); + Assertions.assertNull(request.getInputStream()); } @Test public void testSetHeader() { Map> httpHeaders = new HashMap<>(); - HttpServletRequestEx request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); + HttpServletRequestEx request = new CommonToHttpServletRequest(null, null, httpHeaders, null); request.setHeader("name", "v1"); request.setHeader("name", "v2"); - Assert.assertEquals("v2", request.getHeader("name")); + Assertions.assertEquals("v2", request.getHeader("name")); } @Test public void testAddHeader() { Map> httpHeaders = new HashMap<>(); - HttpServletRequestEx request = new CommonToHttpServletRequest(null, null, httpHeaders, null, false); + HttpServletRequestEx request = new CommonToHttpServletRequest(null, null, httpHeaders, null); request.addHeader("name", "v1"); request.addHeader("name", "v2"); - Assert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("v1", "v2")); + MatcherAssert.assertThat(Collections.list(request.getHeaders("name")), Matchers.contains("v1", "v2")); + } + + @Test + public void testGetParts() { + List restParams = new ArrayList<>(); + restParams.add("test1"); + restParams.add("test2"); + File file1 = new File("file1.txt"); + File file2 = new File("file2.txt"); + File[] files = {file1, file2}; + List list = Arrays.asList(files); + Map objectMap = new HashMap<>(); + objectMap.put("test1", list); + objectMap.put("test2", files); + objectMap.put("test3", list); + objectMap.put("test4", "haha"); + + Map pathParams = new HashMap<>(); + HttpServletRequest request = new CommonToHttpServletRequest(pathParams, null, null, objectMap, restParams); + try { + Collection tmpParts = request.getParts(); + ArrayList parts = new ArrayList<>(tmpParts); + Assertions.assertEquals(4, parts.size()); + Assertions.assertEquals("test1", parts.get(0).getName()); + Assertions.assertEquals("test1", parts.get(1).getName()); + Assertions.assertEquals("test2", parts.get(2).getName()); + Assertions.assertEquals("test2", parts.get(3).getName()); + } catch (Throwable e) { + Assertions.fail("should not throw exception"); + } } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequest.java deleted file mode 100644 index aadf55f60f9..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.provider.springmvc.reference; - -import java.net.URI; -import java.util.Collections; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.common.rest.RestEngineSchemaListener; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.http.HttpMethod; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -public class TestCseClientHttpRequest { - static UnitTestMeta meta = new UnitTestMeta(); - - @Before - public void setup() { - SCBEngine.getInstance().setStatus(SCBStatus.UP); - CseContext.getInstance() - .getSchemaListenerManager() - .setSchemaListenerList(Collections.singletonList(new RestEngineSchemaListener())); - meta.registerSchema(new SpringmvcSwaggerGeneratorContext(), SpringmvcImpl.class); - SCBEngine.getInstance().setConsumerProviderManager(meta.getConsumerProviderManager()); - } - - @RequestMapping(path = "SpringmvcImpl") - static class SpringmvcImpl { - @RequestMapping(path = "/bytes", method = RequestMethod.POST) - public byte[] bytes(@RequestBody byte[] input) { - input[0] = (byte) (input[0] + 1); - return input; - } - } - - @Test - public void testNormal() { - UnitTestMeta meta = new UnitTestMeta(); - - CseContext.getInstance() - .getSchemaListenerManager() - .setSchemaListenerList(Collections.singletonList(new RestEngineSchemaListener())); - - meta.registerSchema(new SpringmvcSwaggerGeneratorContext(), SpringmvcImpl.class); - - Holder holder = new Holder<>(); - CseClientHttpRequest client = - new CseClientHttpRequest(URI.create("cse://app:test/" + SpringmvcImpl.class.getSimpleName() + "/bytes"), - HttpMethod.POST) { - - /** - * {@inheritDoc} - */ - @Override - protected Response doInvoke(Invocation invocation) { - holder.value = invocation; - return Response.ok("result"); - } - }; - byte[] body = "abc".getBytes(); - client.setRequestBody(body); - - client.execute(); - - Assert.assertArrayEquals(body, holder.value.getSwaggerArgument(0)); - } -} diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequestFactory.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequestFactory.java index 8b92976a318..35b8950de63 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequestFactory.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpRequestFactory.java @@ -20,8 +20,8 @@ import java.io.IOException; import java.net.URI; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.springframework.http.HttpMethod; public class TestCseClientHttpRequestFactory { @@ -31,10 +31,10 @@ public void testCseClientHttpRequestFactory() { CseClientHttpRequestFactory lCseClientHttpRequestFactory = new CseClientHttpRequestFactory(); try { - Assert.assertEquals(HttpMethod.GET, + Assertions.assertEquals(HttpMethod.GET, lCseClientHttpRequestFactory.createRequest(URI.create("/test"), HttpMethod.GET).getMethod()); } catch (IOException e) { - Assert.assertNotNull(e); + Assertions.assertNotNull(e); } } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpResponse.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpResponse.java index b2fd6d30d0c..46d65e28357 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpResponse.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseClientHttpResponse.java @@ -20,8 +20,8 @@ import java.io.IOException; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; public class TestCseClientHttpResponse { @@ -33,32 +33,32 @@ public class TestCseClientHttpResponse { @Test public void testGetResult() { - Assert.assertNull(cseclientrequest.getResult()); + Assertions.assertNull(cseclientrequest.getResult()); } @Test public void testGetBody() throws IOException { - Assert.assertNotNull(cseclientrequest.getBody()); + Assertions.assertNotNull(cseclientrequest.getBody()); } @Test public void testGetHeaders() { - Assert.assertNotNull(cseclientrequest.getHeaders()); + Assertions.assertNotNull(cseclientrequest.getHeaders()); } @Test public void testGetStatusCode() throws IOException { - Assert.assertEquals(HttpStatus.OK, cseclientrequest.getStatusCode()); + Assertions.assertEquals(HttpStatus.OK, cseclientrequest.getStatusCode()); } @Test public void testGetRawStatusCode() throws IOException { - Assert.assertEquals(200, cseclientrequest.getRawStatusCode()); + Assertions.assertEquals(200, cseclientrequest.getRawStatusCode()); } @Test public void testGetStatusText() throws IOException { cseclientrequest.close(); - Assert.assertEquals(HttpStatus.OK.getReasonPhrase(), cseclientrequest.getStatusText()); + Assertions.assertEquals(HttpStatus.OK.getReasonPhrase(), cseclientrequest.getStatusText()); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseHttpEntity.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseHttpEntity.java index ecec41b1dbd..e057c70ec4b 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseHttpEntity.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseHttpEntity.java @@ -17,8 +17,8 @@ package org.apache.servicecomb.provider.springmvc.reference; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestCseHttpEntity { @Test @@ -26,14 +26,14 @@ public void test() { CseHttpEntity entity = new CseHttpEntity<>(null, null); entity.addContext("c1", "c1v"); - Assert.assertEquals(1, entity.getContext().getContext().size()); - Assert.assertEquals("c1v", entity.getContext().getContext("c1")); + Assertions.assertEquals(1, entity.getContext().getContext().size()); + Assertions.assertEquals("c1v", entity.getContext().getContext("c1")); InvocationContext context = new InvocationContext(); context.addContext("c2", "c2v"); entity.setContext(context); - Assert.assertEquals(1, entity.getContext().getContext().size()); - Assert.assertEquals("c2v", entity.getContext().getContext("c2")); + Assertions.assertEquals(1, entity.getContext().getContext().size()); + Assertions.assertEquals("c2v", entity.getContext().getContext("c2")); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRequestCallback.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRequestCallback.java index 943632c2f3f..ce2d11257c1 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRequestCallback.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRequestCallback.java @@ -18,32 +18,32 @@ import java.io.IOException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.web.client.RequestCallback; -import mockit.Injectable; -import mockit.Mocked; - public class TestCseRequestCallback { @Test - public void testNormal(@Mocked RequestCallback callback) throws IOException { + public void testNormal() throws IOException { + RequestCallback callback = Mockito.mock(RequestCallback.class); CseClientHttpRequest request = new CseClientHttpRequest(); - CseRequestCallback cb = new CseRequestCallback(null, callback); + CseRequestCallback cb = new CseRequestCallback(null, callback, null); cb.doWithRequest(request); - Assert.assertEquals(null, request.getContext()); + Assertions.assertNull(request.getContext()); } @Test - public void testCseEntity(@Injectable CseHttpEntity entity, - @Mocked RequestCallback callback) throws IOException { + public void testCseEntity() throws IOException { + CseHttpEntity entity = Mockito.mock(CseHttpEntity.class); + RequestCallback callback = Mockito.mock(RequestCallback.class); CseClientHttpRequest request = new CseClientHttpRequest(); entity.addContext("c1", "c2"); - CseRequestCallback cb = new CseRequestCallback(entity, callback); + CseRequestCallback cb = new CseRequestCallback(entity, callback, null); cb.doWithRequest(request); - Assert.assertEquals(entity.getContext(), request.getContext()); + Assertions.assertEquals(entity.getContext(), request.getContext()); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRestTemplate.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRestTemplate.java index d863eeee748..85957c30602 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRestTemplate.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseRestTemplate.java @@ -17,13 +17,13 @@ package org.apache.servicecomb.provider.springmvc.reference; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestCseRestTemplate { - @Test - public void testCseRestTemplate() { - Assert.assertEquals(CseRestTemplate.class, new CseRestTemplate().getClass()); - } + @Test + public void testCseRestTemplate() { + Assertions.assertEquals(CseRestTemplate.class, new CseRestTemplate().getClass()); + } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseUriTemplateHandler.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseUriTemplateHandler.java index 9d095f2a25c..9407ded239c 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseUriTemplateHandler.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestCseUriTemplateHandler.java @@ -20,24 +20,41 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestCseUriTemplateHandler { @Test public void testCrossApp() { CseUriTemplateHandler handler = new CseUriTemplateHandler(); URI uri = handler.expand("cse://{ap}{p}:ms/{path}?q={query}", "ap", "p", "path", "query"); - Assert.assertEquals("cse://app:ms/path?q=query", uri.toString()); + Assertions.assertEquals("cse://app~ms/path?q=query", uri.toString()); Map vars = new HashMap<>(); vars.put("app", "app"); vars.put("path", "path"); vars.put("q", "query"); uri = handler.expand("cse://{app}:ms/{path}?q={q}", vars); - Assert.assertEquals("cse://app:ms/path?q=query", uri.toString()); + Assertions.assertEquals("cse://app~ms/path?q=query", uri.toString()); uri = handler.expand("cse://ms/{path}?q={query}", "path", "query"); - Assert.assertEquals("cse://ms/path?q=query", uri.toString()); + Assertions.assertEquals("cse://ms/path?q=query", uri.toString()); + } + + @Test + public void testCrossAppServiceComb() { + CseUriTemplateHandler handler = new CseUriTemplateHandler(); + URI uri = handler.expand("servicecomb://{ap}{p}:ms/{path}?q={query}", "ap", "p", "path", "query"); + Assertions.assertEquals("servicecomb://app~ms/path?q=query", uri.toString()); + + Map vars = new HashMap<>(); + vars.put("app", "app"); + vars.put("path", "path"); + vars.put("q", "query"); + uri = handler.expand("servicecomb://{app}:ms/{path}?q={q}", vars); + Assertions.assertEquals("servicecomb://app~ms/path?q=query", uri.toString()); + + uri = handler.expand("servicecomb://ms/{path}?q={query}", "path", "query"); + Assertions.assertEquals("servicecomb://ms/path?q=query", uri.toString()); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRequestMeta.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRequestMeta.java index 0f548586807..cabcbde4678 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRequestMeta.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRequestMeta.java @@ -23,8 +23,8 @@ import org.apache.servicecomb.common.rest.definition.RestOperationMeta; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; public class TestRequestMeta { @@ -41,30 +41,30 @@ public class TestRequestMeta { @Test public void testGetReferenceConfig() { ReferenceConfig value = requestmeta.getReferenceConfig(); - Assert.assertNotNull(value); + Assertions.assertNotNull(value); } @Test public void testGetPathParams() { Map value = requestmeta.getPathParams(); - Assert.assertNotNull(value); + Assertions.assertNotNull(value); } @Test public void testGetSwaggerRestOperation() { RestOperationMeta value = requestmeta.getSwaggerRestOperation(); - Assert.assertNotNull(value); + Assertions.assertNotNull(value); } @Test public void testGetOperationMeta() { - Assert.assertNull(requestmeta.getOperationMeta()); + Assertions.assertNull(requestmeta.getOperationMeta()); } @Test public void testGetOperationQualifiedName() { Mockito.when(operationMeta.getSchemaQualifiedName()).thenReturn("value"); String qualifiedName = operationMeta.getSchemaQualifiedName(); - Assert.assertEquals("value", qualifiedName); + Assertions.assertEquals("value", qualifiedName); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateBuilder.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateBuilder.java index b87885ecb2a..0bd76111ba9 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateBuilder.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateBuilder.java @@ -19,12 +19,12 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertThat; import java.net.URI; -import org.junit.Test; -import org.springframework.web.client.RestTemplate; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.Test; +import org.springframework.web.client.RestOperations; import com.seanyinx.github.unit.scaffolding.Randomness; @@ -51,13 +51,13 @@ public boolean isAcceptable(URI uri) { public void addsRestTemplateToWrapper() { RestTemplateBuilder.addAcceptableRestTemplate(1, underlying); - RestTemplate restTemplate = RestTemplateBuilder.create(); + RestOperations restTemplate = RestTemplateBuilder.create(); - assertThat(restTemplate, instanceOf(RestTemplateWrapper.class)); + MatcherAssert.assertThat(restTemplate, instanceOf(RestTemplateWrapper.class)); RestTemplateWrapper wrapper = (RestTemplateWrapper) restTemplate; - assertThat(wrapper.getRestTemplate(url), is(underlying)); - assertThat(wrapper.getRestTemplate(URI.create(url)), is(underlying)); + MatcherAssert.assertThat(wrapper.getRestTemplate(url), is(underlying)); + MatcherAssert.assertThat(wrapper.getRestTemplate(URI.create(url)), is(underlying)); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java deleted file mode 100644 index 5e25daec3b6..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateCopyHeaderFilter.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpHeaders; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestRestTemplateCopyHeaderFilter { - RestTemplateCopyHeaderFilter filter = new RestTemplateCopyHeaderFilter(); - - @Test - public void getOrder() { - Assert.assertEquals(Integer.MIN_VALUE, filter.getOrder()); - } - - @Test - public void beforeSendRequestNoHeader(@Mocked Invocation invocation) { - Map context = new HashMap<>(); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - } - }; - - HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, null, new HttpHeaders(), null, false); - filter.beforeSendRequest(invocation, requestEx); - Assert.assertFalse(requestEx.getHeaderNames().hasMoreElements()); - } - - @Test - public void beforeSendRequestWithNullHeader(@Mocked Invocation invocation) { - Map context = new HashMap<>(1); - HttpHeaders httpHeaders = new HttpHeaders(); - context.put(RestConst.CONSUMER_HEADER, httpHeaders); - httpHeaders.add("headerName0", "headerValue0"); - httpHeaders.add("headerName1", null); - httpHeaders.add("headerName2", "headerValue2"); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - } - }; - - HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, null, new HttpHeaders(), null, false); - filter.beforeSendRequest(invocation, requestEx); - Assert.assertEquals("headerValue0", requestEx.getHeader("headerName0")); - Assert.assertEquals("headerValue2", requestEx.getHeader("headerName2")); - Assert.assertNull(requestEx.getHeader("headerName1")); - } - - @Test - public void beforeSendRequestHaveHeader(@Mocked Invocation invocation) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add("name", "value"); - - Map context = new HashMap<>(); - context.put(RestConst.CONSUMER_HEADER, httpHeaders); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - } - }; - - HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, null, new HttpHeaders(), null, false); - filter.beforeSendRequest(invocation, requestEx); - Assert.assertThat(Collections.list(requestEx.getHeaders("name")), Matchers.contains("value")); - } - - @Test - public void beforeSendRequestSkipContentLength(@Mocked Invocation invocation) { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_LENGTH, "0"); - - Map context = new HashMap<>(); - context.put(RestConst.CONSUMER_HEADER, httpHeaders); - new Expectations() { - { - invocation.getHandlerContext(); - result = context; - } - }; - - HttpServletRequestEx requestEx = new CommonToHttpServletRequest(null, null, new HttpHeaders(), null, false); - filter.beforeSendRequest(invocation, requestEx); - Assert.assertNull((requestEx.getHeader(HttpHeaders.CONTENT_LENGTH))); - } - - @Test - public void afterReceiveResponse() { - Assert.assertNull(filter.afterReceiveResponse(null, null)); - } -} diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateWrapper.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateWrapper.java index 27a31f7e153..736c0d0dfbf 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateWrapper.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestRestTemplateWrapper.java @@ -22,7 +22,6 @@ import static java.util.Collections.singletonList; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -45,8 +44,9 @@ import java.util.Map; import java.util.Set; -import org.junit.Before; -import org.junit.Test; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -60,7 +60,7 @@ import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.ResponseExtractor; import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.UriTemplateHandler; public class TestRestTemplateWrapper { @@ -77,8 +77,7 @@ public class TestRestTemplateWrapper { private final String param2 = uniquify("param2"); - @SuppressWarnings("serial") - private final Map paramsMap = new HashMap() { + private final Map paramsMap = new HashMap<>() { { put(uniquify("key1"), param1); put(uniquify("key2"), param2); @@ -95,7 +94,7 @@ public class TestRestTemplateWrapper { private final List httpMethods = asList(GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE); - @Before + @BeforeEach public void setUp() throws Exception { when(underlying.isAcceptable(url)).thenReturn(true); when(underlying.isAcceptable(uri)).thenReturn(true); @@ -109,17 +108,17 @@ public void headForHeadersWithUnderlyingRestTemplate() { when(underlying.headForHeaders(url, param1, param2)).thenReturn(expected); actual = wrapper.headForHeaders(url, param1, param2); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).headForHeaders(url, param1, param2); when(underlying.headForHeaders(url, paramsMap)).thenReturn(expected); actual = wrapper.headForHeaders(url, paramsMap); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).headForHeaders(url, paramsMap); when(underlying.headForHeaders(uri)).thenReturn(expected); actual = wrapper.headForHeaders(uri); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).headForHeaders(uri); } @@ -130,17 +129,17 @@ public void optionsForAllowWithUnderlyingRestTemplate() { when(underlying.optionsForAllow(url, param1, param2)).thenReturn(expected); actual = wrapper.optionsForAllow(url, param1, param2); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).optionsForAllow(url, param1, param2); when(underlying.optionsForAllow(url, paramsMap)).thenReturn(expected); actual = wrapper.optionsForAllow(url, paramsMap); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).optionsForAllow(url, paramsMap); when(underlying.optionsForAllow(uri)).thenReturn(expected); actual = wrapper.optionsForAllow(uri); - assertThat(actual, is(expected)); + MatcherAssert.assertThat(actual, is(expected)); verify(underlying).optionsForAllow(uri); } @@ -150,17 +149,17 @@ public void getForObjectWithUnderlyingRestTemplate() { when(underlying.getForObject(url, String.class, param1, param2)).thenReturn(response); actual = wrapper.getForObject(url, String.class, param1, param2); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).getForObject(url, String.class, param1, param2); when(underlying.getForObject(url, String.class, paramsMap)).thenReturn(response); actual = wrapper.getForObject(url, String.class, paramsMap); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).getForObject(url, String.class, paramsMap); when(underlying.getForObject(uri, String.class)).thenReturn(response); actual = wrapper.getForObject(uri, String.class); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).getForObject(uri, String.class); } @@ -170,17 +169,17 @@ public void getForEntityWithUnderlyingRestTemplate() { when(underlying.getForEntity(url, String.class, param1, param2)).thenReturn(responseEntity); actual = wrapper.getForEntity(url, String.class, param1, param2); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).getForEntity(url, String.class, param1, param2); when(underlying.getForEntity(url, String.class, paramsMap)).thenReturn(responseEntity); actual = wrapper.getForEntity(url, String.class, paramsMap); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).getForEntity(url, String.class, paramsMap); when(underlying.getForEntity(uri, String.class)).thenReturn(responseEntity); actual = wrapper.getForEntity(uri, String.class); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).getForEntity(uri, String.class); } @@ -190,17 +189,17 @@ public void postForObjectWithUnderlyingRestTemplate() { when(underlying.postForObject(url, requestEntity, String.class, param1, param2)).thenReturn(response); actual = wrapper.postForObject(url, requestEntity, String.class, param1, param2); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).postForObject(url, requestEntity, String.class, param1, param2); when(underlying.postForObject(url, requestEntity, String.class, paramsMap)).thenReturn(response); actual = wrapper.postForObject(url, requestEntity, String.class, paramsMap); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).postForObject(url, requestEntity, String.class, paramsMap); when(underlying.postForObject(uri, requestEntity, String.class)).thenReturn(response); actual = wrapper.postForObject(uri, requestEntity, String.class); - assertThat(actual, is(response)); + MatcherAssert.assertThat(actual, is(response)); verify(underlying).postForObject(uri, requestEntity, String.class); } @@ -210,17 +209,17 @@ public void postForEntityWithUnderlyingRestTemplate() { when(underlying.postForEntity(url, requestEntity, String.class, param1, param2)).thenReturn(responseEntity); actual = wrapper.postForEntity(url, requestEntity, String.class, param1, param2); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).postForEntity(url, requestEntity, String.class, param1, param2); when(underlying.postForEntity(url, requestEntity, String.class, paramsMap)).thenReturn(responseEntity); actual = wrapper.postForEntity(url, requestEntity, String.class, paramsMap); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).postForEntity(url, requestEntity, String.class, paramsMap); when(underlying.postForEntity(uri, requestEntity, String.class)).thenReturn(responseEntity); actual = wrapper.postForEntity(uri, requestEntity, String.class); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).postForEntity(uri, requestEntity, String.class); } @@ -230,17 +229,17 @@ public void postForLocationWithUnderlyingRestTemplate() { when(underlying.postForLocation(url, requestEntity, param1, param2)).thenReturn(uri); actual = wrapper.postForLocation(url, requestEntity, param1, param2); - assertThat(actual, is(uri)); + MatcherAssert.assertThat(actual, is(uri)); verify(underlying).postForLocation(url, requestEntity, param1, param2); when(underlying.postForLocation(url, requestEntity, paramsMap)).thenReturn(uri); actual = wrapper.postForLocation(url, requestEntity, paramsMap); - assertThat(actual, is(uri)); + MatcherAssert.assertThat(actual, is(uri)); verify(underlying).postForLocation(url, requestEntity, paramsMap); when(underlying.postForLocation(uri, requestEntity)).thenReturn(uri); actual = wrapper.postForLocation(uri, requestEntity); - assertThat(actual, is(uri)); + MatcherAssert.assertThat(actual, is(uri)); verify(underlying).postForLocation(uri, requestEntity); } @@ -256,17 +255,17 @@ public void executeWithUnderlyingRestTemplate() { when(underlying.execute(url, method, requestCallback, responseExtractor, param1, param2)) .thenReturn(responseEntity); actual = wrapper.execute(url, method, requestCallback, responseExtractor, param1, param2); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).execute(url, method, requestCallback, responseExtractor, param1, param2); when(underlying.execute(url, method, requestCallback, responseExtractor, paramsMap)).thenReturn(responseEntity); actual = wrapper.execute(url, method, requestCallback, responseExtractor, paramsMap); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).execute(url, method, requestCallback, responseExtractor, paramsMap); when(underlying.execute(uri, method, requestCallback, responseExtractor)).thenReturn(responseEntity); actual = wrapper.execute(uri, method, requestCallback, responseExtractor); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).execute(uri, method, requestCallback, responseExtractor); } } @@ -278,53 +277,53 @@ public void exchangeWithUnderlyingRestTemplate() { for (HttpMethod method : httpMethods) { when(underlying.exchange(url, method, requestEntity, String.class, param1, param2)).thenReturn(responseEntity); actual = wrapper.exchange(url, method, requestEntity, String.class, param1, param2); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).exchange(url, method, requestEntity, String.class, param1, param2); when(underlying.exchange(url, method, requestEntity, String.class, paramsMap)).thenReturn(responseEntity); actual = wrapper.exchange(url, method, requestEntity, String.class, paramsMap); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).exchange(url, method, requestEntity, String.class, paramsMap); when(underlying.exchange(uri, method, requestEntity, String.class)).thenReturn(responseEntity); actual = wrapper.exchange(uri, method, requestEntity, String.class); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).exchange(uri, method, requestEntity, String.class); RequestEntity request = new RequestEntity<>(method, uri); when(underlying.exchange(request, String.class)).thenReturn(responseEntity); actual = wrapper.exchange(request, String.class); - assertThat(actual, is(responseEntity)); + MatcherAssert.assertThat(actual, is(responseEntity)); verify(underlying).exchange(request, String.class); } } @Test public void exchangeUsingParameterizedTypeWithUnderlyingRestTemplate() { - ParameterizedTypeReference> typeReference = new ParameterizedTypeReference>() { + ParameterizedTypeReference> typeReference = new ParameterizedTypeReference<>() { }; ResponseEntity> actual; for (HttpMethod method : httpMethods) { when(underlying.exchange(url, method, requestEntity, typeReference, param1, param2)).thenReturn(typedResponse); actual = wrapper.exchange(url, method, requestEntity, typeReference, param1, param2); - assertThat(actual, is(typedResponse)); + MatcherAssert.assertThat(actual, is(typedResponse)); verify(underlying).exchange(url, method, requestEntity, typeReference, param1, param2); when(underlying.exchange(url, method, requestEntity, typeReference, paramsMap)).thenReturn(typedResponse); actual = wrapper.exchange(url, method, requestEntity, typeReference, paramsMap); - assertThat(actual, is(typedResponse)); + MatcherAssert.assertThat(actual, is(typedResponse)); verify(underlying).exchange(url, method, requestEntity, typeReference, paramsMap); when(underlying.exchange(uri, method, requestEntity, typeReference)).thenReturn(typedResponse); actual = wrapper.exchange(uri, method, requestEntity, typeReference); - assertThat(actual, is(typedResponse)); + MatcherAssert.assertThat(actual, is(typedResponse)); verify(underlying).exchange(uri, method, requestEntity, typeReference); RequestEntity request = new RequestEntity<>(method, uri); when(underlying.exchange(request, typeReference)).thenReturn(typedResponse); actual = wrapper.exchange(request, typeReference); - assertThat(actual, is(typedResponse)); + MatcherAssert.assertThat(actual, is(typedResponse)); verify(underlying).exchange(request, typeReference); } } @@ -361,8 +360,8 @@ public void setInterceptorsWithUnderlying() { wrapper.setInterceptors(interceptors); - assertThat(wrapper.getInterceptors(), contains(interceptor1, interceptor2)); - assertThat(wrapper.defaultRestTemplate.getInterceptors(), contains(interceptor1, interceptor2)); + MatcherAssert.assertThat(wrapper.getInterceptors(), contains(interceptor1, interceptor2)); + MatcherAssert.assertThat(wrapper.defaultRestTemplate.getInterceptors(), contains(interceptor1, interceptor2)); verify(underlying, never()).setInterceptors(interceptors); } @@ -372,8 +371,8 @@ public void doNotSetRequestFactoryWithUnderlying() { wrapper.setRequestFactory(requestFactory); - assertThat(wrapper.getRequestFactory(), is(requestFactory)); - assertThat(wrapper.defaultRestTemplate.getRequestFactory(), is(requestFactory)); + MatcherAssert.assertThat(wrapper.getRequestFactory(), is(requestFactory)); + MatcherAssert.assertThat(wrapper.defaultRestTemplate.getRequestFactory(), is(requestFactory)); verify(underlying, never()).setRequestFactory(requestFactory); } @@ -384,8 +383,8 @@ public void setErrorHandlerWithUnderlying() { wrapper.setErrorHandler(errorHandler); - assertThat(wrapper.getErrorHandler(), is(errorHandler)); - assertThat(wrapper.defaultRestTemplate.getErrorHandler(), is(errorHandler)); + MatcherAssert.assertThat(wrapper.getErrorHandler(), is(errorHandler)); + MatcherAssert.assertThat(wrapper.defaultRestTemplate.getErrorHandler(), is(errorHandler)); verify(underlying).setErrorHandler(errorHandler); } @@ -396,8 +395,8 @@ public void setDefaultUriVariablesWithUnderlying() { wrapper.setDefaultUriVariables(uriVariables); - assertThat(defaultUriVariablesOf(wrapper), is(uriVariables)); - assertThat(defaultUriVariablesOf(wrapper.defaultRestTemplate), is(uriVariables)); + MatcherAssert.assertThat(defaultUriVariablesOf(wrapper), is(uriVariables)); + MatcherAssert.assertThat(defaultUriVariablesOf(wrapper.defaultRestTemplate), is(uriVariables)); verify(underlying).setDefaultUriVariables(uriVariables); } @@ -408,39 +407,38 @@ public void dotNotSetUriTemplateHandlerWithUnderlying() { wrapper.setUriTemplateHandler(uriTemplateHandler); - assertThat(wrapper.getUriTemplateHandler(), is(uriTemplateHandler)); - assertThat(wrapper.defaultRestTemplate.getUriTemplateHandler(), is(uriTemplateHandler)); + MatcherAssert.assertThat(wrapper.getUriTemplateHandler(), is(uriTemplateHandler)); + MatcherAssert.assertThat(wrapper.defaultRestTemplate.getUriTemplateHandler(), is(uriTemplateHandler)); verify(underlying, never()).setUriTemplateHandler(uriTemplateHandler); } - @SuppressWarnings("unchecked") @Test public void setMessageConvertersWithUnderlying() { ByteArrayHttpMessageConverter messageConverter = mock(ByteArrayHttpMessageConverter.class); wrapper.setMessageConverters(singletonList(messageConverter)); - assertThat(wrapper.getMessageConverters(), contains(messageConverter)); - assertThat(wrapper.defaultRestTemplate.getMessageConverters(), contains(messageConverter)); + MatcherAssert.assertThat(wrapper.getMessageConverters(), contains(messageConverter)); + MatcherAssert.assertThat(wrapper.defaultRestTemplate.getMessageConverters(), contains(messageConverter)); verify(underlying, never()).setMessageConverters(singletonList(messageConverter)); } @Test public void getsAcceptableRestTemplate() { - assertThat(wrapper.getRestTemplate(uri), is(underlying)); - assertThat(wrapper.getRestTemplate(url), is(underlying)); + MatcherAssert.assertThat(wrapper.getRestTemplate(uri), is(underlying)); + MatcherAssert.assertThat(wrapper.getRestTemplate(url), is(underlying)); } @Test public void getsDefaultRestTemplate() { reset(underlying); - assertThat(wrapper.getRestTemplate(uri), is(wrapper.defaultRestTemplate)); - assertThat(wrapper.getRestTemplate(url), is(wrapper.defaultRestTemplate)); + MatcherAssert.assertThat(wrapper.getRestTemplate(uri), is(wrapper.defaultRestTemplate)); + MatcherAssert.assertThat(wrapper.getRestTemplate(url), is(wrapper.defaultRestTemplate)); } private Map defaultUriVariablesOf(RestTemplate wrapper1) { - return ((DefaultUriTemplateHandler) wrapper1.getUriTemplateHandler()).getDefaultUriVariables(); + return ((DefaultUriBuilderFactory) wrapper1.getUriTemplateHandler()).getDefaultUriVariables(); } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithProviderPrefixClientHttpRequestFactory.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithProviderPrefixClientHttpRequestFactory.java index c66684188ab..4c3ca6b6cb1 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithProviderPrefixClientHttpRequestFactory.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithProviderPrefixClientHttpRequestFactory.java @@ -26,17 +26,14 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; import org.apache.servicecomb.provider.springmvc.reference.UrlWithProviderPrefixClientHttpRequestFactory.UrlWithProviderPrefixClientHttpRequest; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.springframework.http.HttpMethod; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - public class TestUrlWithProviderPrefixClientHttpRequestFactory { UrlWithProviderPrefixClientHttpRequestFactory factory = new UrlWithProviderPrefixClientHttpRequestFactory("/a/b/c"); @@ -47,12 +44,17 @@ public void findUriPath() throws IOException { UrlWithProviderPrefixClientHttpRequest request = (UrlWithProviderPrefixClientHttpRequest) factory.createRequest(uri, HttpMethod.GET); - Assert.assertEquals("/v1/path", request.findUriPath(uri)); + Assertions.assertEquals("/v1/path", request.findUriPath(uri)); } @Test - public void invoke_checkPath(@Mocked Invocation invocation, @Mocked RequestMeta requestMeta) { - Map handlerContext = new HashMap<>(); + @SuppressWarnings("unchecked") + public void invoke_checkPath() { + Invocation invocation = Mockito.mock(Invocation.class); + RequestMeta requestMeta = Mockito.mock(RequestMeta.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(requestMeta.getOperationMeta()).thenReturn(operationMeta); + Map handlerContext = new HashMap<>(); UrlWithProviderPrefixClientHttpRequest request = new UrlWithProviderPrefixClientHttpRequest(uri, HttpMethod.GET, "/a/b/c") { @Override @@ -61,20 +63,16 @@ protected Response doInvoke(Invocation invocation) { } }; - new Expectations(InvocationFactory.class) { - { - invocation.getHandlerContext(); - result = handlerContext; - InvocationFactory.forConsumer((ReferenceConfig) any, (OperationMeta) any, (Object[]) any); - result = invocation; - } - }; - - Deencapsulation.setField(request, "requestMeta", requestMeta); - Deencapsulation.setField(request, "path", request.findUriPath(uri)); + Mockito.when(invocation.getHandlerContext()).thenReturn(handlerContext); + try (MockedStatic invocationFactoryMockedStatic = Mockito.mockStatic(InvocationFactory.class)) { + invocationFactoryMockedStatic.when(() -> InvocationFactory.forConsumer(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(invocation); + request.setRequestMeta(requestMeta); + request.setPath(request.findUriPath(uri)); - Deencapsulation.invoke(request, "invoke", new Object[] {new Object[] {}}); + request.invoke(new HashMap<>()); - Assert.assertEquals("/v1/path?null", handlerContext.get(RestConst.REST_CLIENT_REQUEST_PATH)); + Assertions.assertEquals("/v1/path", handlerContext.get(RestConst.REST_CLIENT_REQUEST_PATH)); + } } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithServiceNameClientHttpRequestFactory.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithServiceNameClientHttpRequestFactory.java index 0ba928e27b3..883bb3a393d 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithServiceNameClientHttpRequestFactory.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/TestUrlWithServiceNameClientHttpRequestFactory.java @@ -26,17 +26,14 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.core.provider.consumer.ReferenceConfig; import org.apache.servicecomb.provider.springmvc.reference.UrlWithServiceNameClientHttpRequestFactory.UrlWithServiceNameClientHttpRequest; import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.springframework.http.HttpMethod; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - public class TestUrlWithServiceNameClientHttpRequestFactory { UrlWithServiceNameClientHttpRequestFactory factory = new UrlWithServiceNameClientHttpRequestFactory(); @@ -47,12 +44,17 @@ public void findUriPath() throws IOException { UrlWithServiceNameClientHttpRequest request = (UrlWithServiceNameClientHttpRequest) factory.createRequest(uri, HttpMethod.GET); - Assert.assertEquals("/ms/v1/path", request.findUriPath(uri)); + Assertions.assertEquals("/ms/v1/path", request.findUriPath(uri)); } @Test - public void invoke_checkPath(@Mocked Invocation invocation, @Mocked RequestMeta requestMeta) { - Map handlerContext = new HashMap<>(); + @SuppressWarnings("unchecked") + public void invoke_checkPath() { + Invocation invocation = Mockito.mock(Invocation.class); + RequestMeta requestMeta = Mockito.mock(RequestMeta.class); + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + Mockito.when(requestMeta.getOperationMeta()).thenReturn(operationMeta); + Map handlerContext = new HashMap<>(); UrlWithServiceNameClientHttpRequest request = new UrlWithServiceNameClientHttpRequest(uri, HttpMethod.GET) { @Override protected Response doInvoke(Invocation invocation) { @@ -60,20 +62,15 @@ protected Response doInvoke(Invocation invocation) { } }; - new Expectations(InvocationFactory.class) { - { - invocation.getHandlerContext(); - result = handlerContext; - InvocationFactory.forConsumer((ReferenceConfig) any, (OperationMeta) any, (Object[]) any); - result = invocation; - } - }; - - Deencapsulation.setField(request, "requestMeta", requestMeta); - Deencapsulation.setField(request, "path", request.findUriPath(uri)); - - Deencapsulation.invoke(request, "invoke", new Object[] {new Object[] {}}); + Mockito.when(invocation.getHandlerContext()).thenReturn(handlerContext); + try (MockedStatic invocationFactoryMockedStatic = Mockito.mockStatic(InvocationFactory.class)) { + invocationFactoryMockedStatic.when(() -> InvocationFactory.forConsumer(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(invocation); + request.setRequestMeta(requestMeta); + request.setPath(request.findUriPath(uri)); + request.invoke(new HashMap<>()); - Assert.assertEquals("/ms/v1/path?null", handlerContext.get(RestConst.REST_CLIENT_REQUEST_PATH)); + Assertions.assertEquals("/ms/v1/path", handlerContext.get(RestConst.REST_CLIENT_REQUEST_PATH)); + } } } diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java deleted file mode 100644 index ce10009a042..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import java.net.URI; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpMethod; - -public class CseAsyncClientHttpRequestFactoryTest { - @Test - public void testCseAsyncClientHttpRequestFactory() { - CseAsyncClientHttpRequestFactory cseAsyncClientHttpRequestFactory = new CseAsyncClientHttpRequestFactory(); - Assert.assertEquals(HttpMethod.GET, - cseAsyncClientHttpRequestFactory.createAsyncRequest(URI.create("/test"), HttpMethod.GET).getMethod()); - } -} \ No newline at end of file diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java deleted file mode 100644 index d45dc37bfb3..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import java.net.URI; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.common.rest.RestEngineSchemaListener; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse; -import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -public class CseAsyncClientHttpRequestTest { - static UnitTestMeta meta = new UnitTestMeta(); - - @BeforeClass - public static void classSetup() { - CseContext.getInstance() - .getSchemaListenerManager() - .setSchemaListenerList(Collections.singletonList(new RestEngineSchemaListener())); - meta.registerSchema(new SpringmvcSwaggerGeneratorContext(), CseAsyncClientHttpRequestTestSchema.class); - SCBEngine.getInstance().setConsumerProviderManager(meta.getConsumerProviderManager()); - SCBEngine.getInstance().setStatus(SCBStatus.UP); - } - - @RequestMapping(path = "CseAsyncClientHttpRequestTestSchema") - static class CseAsyncClientHttpRequestTestSchema { - @RequestMapping(path = "/testbytes", method = RequestMethod.POST) - public byte[] testbytes(@RequestBody byte[] input) { - input[0] = (byte) (input[0] + 1); - return input; - } - } - - @Test - public void testNormal() { - Holder holder = new Holder<>(); - CseAsyncClientHttpRequest client = - new CseAsyncClientHttpRequest(URI.create( - "cse://app:test/" + CseAsyncClientHttpRequestTest.CseAsyncClientHttpRequestTestSchema.class.getSimpleName() - + "/testbytes"), - HttpMethod.POST) { - @Override - protected CompletableFuture doAsyncInvoke(Invocation invocation) { - CompletableFuture completableFuture = new CompletableFuture<>(); - holder.value = invocation; - completableFuture.complete(new CseClientHttpResponse(Response.ok("result"))); - return completableFuture; - } - }; - byte[] body = "abc".getBytes(); - client.setRequestBody(body); - client.executeAsync(); - Assert.assertArrayEquals(body, holder.value.getSwaggerArgument(0)); - } - - @Test - public void testFail() { - Throwable error = new Error("failed"); - Response response = Response.createConsumerFail(error); - - CseAsyncClientHttpRequest client = - new CseAsyncClientHttpRequest(URI.create( - "cse://app:test/" + CseAsyncClientHttpRequestTest.CseAsyncClientHttpRequestTestSchema.class.getSimpleName() - + "/testbytes"), - HttpMethod.POST) { - @Override - protected CompletableFuture doAsyncInvoke(Invocation invocation) { - CompletableFuture completableFuture = new CompletableFuture<>(); - completableFuture.complete(new CseClientHttpResponse(response)); - return completableFuture; - } - }; - ListenableFuture future = client.executeAsync(); - future.addCallback( - new ListenableFutureCallback() { - @Override - public void onFailure(Throwable ex) { - Assert.assertSame(error, ex); - } - - @Override - public void onSuccess(ClientHttpResponse result) { - } - } - ); - } -} \ No newline at end of file diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java deleted file mode 100644 index daefd3ac85d..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.HttpEntity; - -import mockit.Injectable; - -public class CseAsyncRequestCallbackTest { - @Test - public void testNormal() { - CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest(); - CseAsyncRequestCallback> cb = new CseAsyncRequestCallback<>(null); - cb.doWithRequest(request); - Assert.assertEquals(null, request.getContext()); - } - - @Test - public void testHttpEntity(@Injectable HttpEntity entity) { - CseAsyncRequestCallback cb = new CseAsyncRequestCallback<>(entity); - CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest(); - cb.doWithRequest(request); - Assert.assertEquals(entity.getBody(), request.getBody()); - } - - @Test - public void testCseEntity(@Injectable CseHttpEntity entity) { - CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest(); - entity.addContext("c1", "c2"); - CseAsyncRequestCallback cb = new CseAsyncRequestCallback<>(entity); - cb.doWithRequest(request); - Assert.assertEquals(entity.getContext(), request.getContext()); - } -} \ No newline at end of file diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java deleted file mode 100644 index 3e5ce64cb16..00000000000 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.provider.springmvc.reference.async; - -import org.junit.Assert; -import org.junit.Test; - -public class CseAsyncRestTemplateTest { - - @Test - public void testCseAsyncRestTemplate() { - Assert.assertEquals(CseAsyncRestTemplate.class, new CseAsyncRestTemplate().getClass()); - } -} \ No newline at end of file diff --git a/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java b/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java deleted file mode 100644 index 23ee30dce6d..00000000000 --- a/providers/provider-springmvc/src/test/java/org/springframework/web/client/TestCseHttpMessageConverter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.client; - -import java.io.IOException; - -import org.apache.servicecomb.provider.common.MockUtil; -import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.http.HttpOutputMessage; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.http.converter.HttpMessageNotWritableException; - -public class TestCseHttpMessageConverter { - - @Test - public void testAll() { - MockUtil.getInstance().mockReflectionUtils(); - MockUtil.getInstance().mockCseClientHttpRequest(); - CseHttpMessageConverter lCseHttpMessageConverter = new CseHttpMessageConverter(); - lCseHttpMessageConverter.canWrite(null, null); - lCseHttpMessageConverter.getSupportedMediaTypes(); - try { - lCseHttpMessageConverter.read(this.getClass(), null); - } catch (HttpMessageNotReadableException | IOException ignored) { - } - try { - HttpOutputMessage httpOutputMessage = Mockito.mock(CseClientHttpRequest.class); - lCseHttpMessageConverter.write(null, null, httpOutputMessage); - } catch (HttpMessageNotWritableException | IOException ignored) { - } - - Assert.assertEquals(true, lCseHttpMessageConverter.canRead(null, null)); - } -} diff --git a/providers/provider-springmvc/src/test/resources/log4j2.xml b/providers/provider-springmvc/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/providers/provider-springmvc/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/providers/provider-springmvc/src/test/resources/microservice.yaml b/providers/provider-springmvc/src/test/resources/microservice.yaml new file mode 100644 index 00000000000..5ff7ed9ae41 --- /dev/null +++ b/providers/provider-springmvc/src/test/resources/microservice.yaml @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb: + filter-chains: + consumer: + default: empty + producer: + default: empty diff --git a/samples/README.md b/samples/README.md index 08d84503d1d..751a1d0aa93 100644 --- a/samples/README.md +++ b/samples/README.md @@ -1,10 +1 @@ -# samples - -It's the samples of Java chassis -1. pojo sample -2. jaxrs sample -3. spring mvc sample -4. code first sample -5. customer handler sample -6. extend metrics health checker sample -7. write metrics data into separate text files sample \ No newline at end of file +java-chassis samples are moved to [servicecomb-samples](https://github.com/apache/servicecomb-samples/tree/master/java-chassis-samples) diff --git a/samples/apm-agent/pom.xml b/samples/apm-agent/pom.xml deleted file mode 100644 index 698981d1ad2..00000000000 --- a/samples/apm-agent/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - - 4.0.0 - - org.apache.servicecomb.samples - apm-agent - 1.2.0-SNAPSHOT - Java Chassis::Samples::apm-agent - - - UTF-8 - 1.8 - - -Dfile.encoding=UTF-8 - UTF-8 - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${project.version} - pom - import - - - - - - - org.apache.servicecomb - provider-rest-common - provided - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - default-jar - package - - - - - - org.apache.servicecomb.samples.apm.AgentMain - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - -Werror - -Xlint:all - - - - - - \ No newline at end of file diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java deleted file mode 100644 index 213c7900414..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm; - -import java.lang.instrument.Instrumentation; - -public class AgentMain { - public static void premain(String args, Instrumentation inst) { - // to support web container, we can not just only inject spiJar to system classloader - // in this sample, javaAgent jar equals ServiceComb plugin jar - inst.addTransformer( - new SCBClassFileTransformer(AgentMain.class.getProtectionDomain().getCodeSource().getLocation())); - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java deleted file mode 100644 index ae6d8cfb677..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.ProtectionDomain; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class SCBClassFileTransformer implements ClassFileTransformer { - private static final Logger LOGGER = Logger.getLogger(SCBClassFileTransformer.class.getName()); - - private volatile boolean loaded; - - private URL scbSpiJar; - - public SCBClassFileTransformer(URL scbSpiJar) { - this.scbSpiJar = scbSpiJar; - } - - @Override - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, - ProtectionDomain protectionDomain, byte[] classfileBuffer) { - if (!loaded && className.startsWith("org/apache/servicecomb")) { - injectSPI(loader); - } - return classfileBuffer; - } - - private synchronized void injectSPI(ClassLoader loader) { - if (loaded) { - return; - } - - try { - Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - addURLMethod.setAccessible(true); - addURLMethod.invoke(loader, scbSpiJar); - loaded = true; - } catch (Throwable e) { - LOGGER.log(Level.SEVERE, - String.format("Failed to inject %s to classLoader %s.", scbSpiJar, loader.getClass().getName()), e); - } - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmBootListener.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmBootListener.java deleted file mode 100644 index 7ad4284db0c..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmBootListener.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl; - -import org.apache.servicecomb.core.BootListener; -import org.apache.servicecomb.core.event.InvocationBusinessMethodFinishEvent; -import org.apache.servicecomb.core.event.InvocationBusinessMethodStartEvent; -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.event.InvocationStartEvent; -import org.apache.servicecomb.samples.apm.impl.output.AbstractOutputGenerator; -import org.apache.servicecomb.samples.apm.impl.output.ConsumerOutputGenerator; -import org.apache.servicecomb.samples.apm.impl.output.EdgeOutputGenerator; -import org.apache.servicecomb.samples.apm.impl.output.HeaderOutputGenerator; -import org.apache.servicecomb.samples.apm.impl.output.ProducerOutputGenerator; - -import com.google.common.eventbus.AllowConcurrentEvents; -import com.google.common.eventbus.Subscribe; - -public class ApmBootListener implements BootListener { - private AbstractOutputGenerator headerOutputGenerator = new HeaderOutputGenerator(); - - private AbstractOutputGenerator consumerOutputGenerator = new ConsumerOutputGenerator(); - - private AbstractOutputGenerator producerOutputGenerator = new ProducerOutputGenerator(); - - private AbstractOutputGenerator edgeOutputGenerator = new EdgeOutputGenerator(); - - @AllowConcurrentEvents - @Subscribe - public void onInvocationStart(InvocationStartEvent event) { - ApmContext apmContext = new ApmContext(); - apmContext.setTraceId(event.getInvocation().getTraceId()); - event.getInvocation().addLocalContext("apm", apmContext); - } - - @AllowConcurrentEvents - @Subscribe - public void onInvocationBusinessStart(InvocationBusinessMethodStartEvent event) { - ApmContext apmContext = event.getInvocation().getLocalContext("apm"); - ApmContextUtils.setApmContext(apmContext); - } - - @AllowConcurrentEvents - @Subscribe - public void onInvocationBusinessFinish(InvocationBusinessMethodFinishEvent event) { - ApmContextUtils.removeApmContext(); - } - - /** - * in real APM implementation: create span and so on for stages - * @param event - */ - @AllowConcurrentEvents - @Subscribe - public void onInvocationFinish(InvocationFinishEvent event) { - StringBuilder sb = new StringBuilder(); - headerOutputGenerator.generate(sb, event); - if (event.getInvocation().isConsumer()) { - if (event.getInvocation().isEdge()) { - edgeOutputGenerator.generate(sb, event); - } else { - consumerOutputGenerator.generate(sb, event); - } - } else { - producerOutputGenerator.generate(sb, event); - } - System.out.println(sb.toString()); - } - - @Override - public void onBootEvent(BootEvent event) { - if (EventType.BEFORE_HANDLER.equals(event.getEventType())) { - event.getScbEngine().getEventBus().register(this); - } - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContext.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContext.java deleted file mode 100644 index 9ab46ae3158..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContext.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl; - -public class ApmContext { - private String traceId; - - public String getTraceId() { - return traceId; - } - - public void setTraceId(String traceId) { - this.traceId = traceId; - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContextUtils.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContextUtils.java deleted file mode 100644 index 3fd8cb077ee..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/ApmContextUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl; - -public class ApmContextUtils { - private static ThreadLocal threadApmContext = new ThreadLocal<>(); - - public static ApmContext getApmContext() { - return threadApmContext.get(); - } - - public static ApmContext getAndRemoveApmContext() { - ApmContext context = threadApmContext.get(); - if (context != null) { - threadApmContext.remove(); - } - return context; - } - - public static void setApmContext(ApmContext apmContext) { - threadApmContext.set(apmContext); - } - - public static void removeApmContext() { - threadApmContext.remove(); - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/AbstractOutputGenerator.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/AbstractOutputGenerator.java deleted file mode 100644 index 9c731a20e27..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/AbstractOutputGenerator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl.output; - -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.core.event.InvocationFinishEvent; - -import com.google.common.base.Strings; - -public abstract class AbstractOutputGenerator { - static final String PAD2_KEY11_FMT = generateFmt(2, 11); - - static final String PAD2_TIME_FMT = generateTimeFmt(2); - - static final String PAD4_TIME_FMT = generateTimeFmt(4); - - static final String PAD6_TIME_FMT = generateTimeFmt(6); - - protected static String generateFmt(int leftPad, int keyLen) { - return Strings.repeat(" ", leftPad) + "%-" + keyLen + "s: %s\n"; - } - - protected static String generateTimeFmt(int leftPad) { - return Strings.repeat(" ", leftPad) + "%-" + (27 - leftPad) + "s: %.3fms\n"; - } - - protected void appendLine(StringBuilder sb, String fmt, String headerKey, Object value) { - sb.append(String.format(fmt, headerKey, value)); - } - - protected void appendTimeLine(StringBuilder sb, String fmt, String headerKey, double nano) { - sb.append(String.format(fmt, headerKey, nano / TimeUnit.MILLISECONDS.toNanos(1))); - } - - abstract public void generate(StringBuilder sb, InvocationFinishEvent event); -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java deleted file mode 100644 index 12e35ffee4d..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl.output; - -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; - -public class ConsumerOutputGenerator extends AbstractOutputGenerator { - @Override - public void generate(StringBuilder sb, InvocationFinishEvent event) { - InvocationStageTrace stageTrace = event.getInvocation().getInvocationStageTrace(); - - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.HANDLERS_REQUEST, stageTrace.calcHandlersRequestTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.CLIENT_FILTERS_REQUEST, - stageTrace.calcClientFiltersRequestTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.CONSUMER_SEND_REQUEST, stageTrace.calcSendRequestTime()); - appendTimeLine(sb, PAD6_TIME_FMT, InvocationStageTrace.CONSUMER_GET_CONNECTION, stageTrace.calcGetConnectionTime()); - appendTimeLine(sb, PAD6_TIME_FMT, InvocationStageTrace.CONSUMER_WRITE_TO_BUF, stageTrace.calcWriteToBufferTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.CONSUMER_WAIT_RESPONSE, - stageTrace.calcReceiveResponseTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.CONSUMER_WAKE_CONSUMER, stageTrace.calcWakeConsumer()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.CLIENT_FILTERS_RESPONSE, - stageTrace.calcClientFiltersResponseTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.HANDLERS_RESPONSE, stageTrace.calcHandlersResponseTime()); - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java deleted file mode 100644 index 5beb10dfd18..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl.output; - -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; - -public class EdgeOutputGenerator extends ConsumerOutputGenerator { - @Override - public void generate(StringBuilder sb, InvocationFinishEvent event) { - InvocationStageTrace stageTrace = event.getInvocation().getInvocationStageTrace(); - - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.THREAD_POOL_QUEUE, stageTrace.calcThreadPoolQueueTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.SERVER_FILTERS_REQUEST, - stageTrace.calcServerFiltersRequestTime()); - - super.generate(sb, event); - - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.SERVER_FILTERS_RESPONSE, - stageTrace.calcServerFiltersResponseTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.PRODUCER_SEND_RESPONSE, stageTrace.calcSendResponseTime()); - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java deleted file mode 100644 index 4ee3570a322..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl.output; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; - -public class HeaderOutputGenerator extends AbstractOutputGenerator { - @Override - public void generate(StringBuilder sb, InvocationFinishEvent event) { - Invocation invocation = event.getInvocation(); - RestOperationMeta restOperationMeta = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION); - InvocationStageTrace stageTrace = event.getInvocation().getInvocationStageTrace(); - - sb.append(invocation.getInvocationQualifiedName()).append(":\n"); - appendLine(sb, PAD2_KEY11_FMT, "http method", restOperationMeta.getHttpMethod()); - appendLine(sb, PAD2_KEY11_FMT, "url", restOperationMeta.getAbsolutePath()); - appendLine(sb, PAD2_KEY11_FMT, "status code", event.getResponse().getStatusCode()); - appendLine(sb, PAD2_KEY11_FMT, "traceId", invocation.getTraceId()); - - appendTimeLine(sb, PAD2_TIME_FMT, "total", stageTrace.calcTotalTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.PREPARE, stageTrace.calcInvocationPrepareTime()); - } -} diff --git a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java b/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java deleted file mode 100644 index 1b6250f002c..00000000000 --- a/samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.apm.impl.output; - -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; - -public class ProducerOutputGenerator extends AbstractOutputGenerator { - @Override - public void generate(StringBuilder sb, InvocationFinishEvent event) { - Invocation invocation = event.getInvocation(); - InvocationStageTrace stageTrace = invocation.getInvocationStageTrace(); - - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.THREAD_POOL_QUEUE, stageTrace.calcThreadPoolQueueTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.SERVER_FILTERS_REQUEST, - stageTrace.calcServerFiltersRequestTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.HANDLERS_REQUEST, stageTrace.calcHandlersRequestTime()); - appendTimeLine(sb, PAD4_TIME_FMT, invocation.getOperationMeta().getSchemaQualifiedName(), - stageTrace.calcBusinessTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.HANDLERS_RESPONSE, stageTrace.calcHandlersResponseTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.SERVER_FILTERS_RESPONSE, - stageTrace.calcServerFiltersResponseTime()); - appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.PRODUCER_SEND_RESPONSE, stageTrace.calcSendResponseTime()); - } -} diff --git a/samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener b/samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener deleted file mode 100644 index e0efc733bbf..00000000000 --- a/samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.samples.apm.impl.ApmBootListener \ No newline at end of file diff --git a/samples/auth-sample/README.md b/samples/auth-sample/README.md deleted file mode 100644 index e199f059d22..00000000000 --- a/samples/auth-sample/README.md +++ /dev/null @@ -1,100 +0,0 @@ -## Auth-Sample - -To make sure the security between the interfaces of services, users can enable `RSA Authorizaiton` by simple configuration as below. - -## Consumer Service - -* Add dependence in pom.xml file: - - ```xml - - org.apache.servicecomb - handler-publickey-auth - - ``` - -* Add handler chain in microservice.yaml: - - ```yaml - cse: - # other configurations omitted - handler: - chain: - Consumer: - default: auth-consumer - ``` - -## Provider Service - -* Add dependence in pom.xml file: - - ```xml - - org.apache.servicecomb - handler-publickey-auth - - ``` - -* Add handler chain in microservice.yaml: - - ```yaml - cse: - # other configurations omitted - handler: - chain: - Consumer: - default: auth-provider - ``` - -## Sample Quick Start - -Auth sample use `RestTemplate` to present RSA communication between provider and consumer. - -1. Start the ServiceComb/Service Center - - - [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - - make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the auth-provider service - - - Start provider service by maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `AuthProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/auth-sample/auth-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.auth.provider.AuthProviderMain" - ``` - - - Start provider service by IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function `AuthProviderMain` of provider service and `RUN` it like any other Java program. - -3. Start the auth-consumer service - - Just like how to start auth-provider service. But the main class of auth-consumer service is `AuthConsumerMain`. - - ```bash - cd samples/auth-sample/auth-consumer/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.auth.consumer.AuthConsumerMain" - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs if the consumer can invoke the producer: - 1. *'Hello Authenticate'* means the consumer calls sayhi with name=Authenticate successfully - 2. *'Hello person ServiceComb/Authenticate'* means the consumer calls sayhello successfully \ No newline at end of file diff --git a/samples/auth-sample/auth-consumer/pom.xml b/samples/auth-sample/auth-consumer/pom.xml deleted file mode 100644 index 13ea21f1733..00000000000 --- a/samples/auth-sample/auth-consumer/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - auth-sample - 1.2.0-SNAPSHOT - - auth-consumer - Java Chassis::Samples::Auth::Consumer - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - handler-publickey-auth - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/auth-sample/auth-consumer/src/main/java/org/apache/servicecomb/samples/auth/consumer/AuthConsumerMain.java b/samples/auth-sample/auth-consumer/src/main/java/org/apache/servicecomb/samples/auth/consumer/AuthConsumerMain.java deleted file mode 100644 index eeb21cfc581..00000000000 --- a/samples/auth-sample/auth-consumer/src/main/java/org/apache/servicecomb/samples/auth/consumer/AuthConsumerMain.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.auth.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -@Component -public class AuthConsumerMain { - - private static RestTemplate restTemplate = RestTemplateBuilder.create(); - - public static void main(String[] args) throws Exception { - init(); - Person person = new Person(); - person.setName("ServiceComb/Authenticate"); - System.out - .println("RestTemplate Consumer or POJO Consumer. You can choose whatever you like."); - String sayHiResult = restTemplate - .postForObject( - "cse://auth-provider/springmvchello/sayhi?name=Authenticate", - null, - String.class); - String sayHelloResult = restTemplate.postForObject( - "cse://auth-provider/springmvchello/sayhello", - person, - String.class); - System.out.println(sayHiResult); - System.out.println(sayHelloResult); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties b/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml b/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index 7b3542fbe91..00000000000 --- a/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,32 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: auth-sample -service_description: - name: authConsumer - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: auth-consumer, loadbalance - references: - auth-provider: - version-rule: 0.0.1 diff --git a/samples/auth-sample/auth-provider/pom.xml b/samples/auth-sample/auth-provider/pom.xml deleted file mode 100644 index 9e956a087d8..00000000000 --- a/samples/auth-sample/auth-provider/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - auth-sample - 1.2.0-SNAPSHOT - - auth-provider - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-publickey-auth - - - org.apache.servicecomb - provider-springmvc - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/AuthProviderMain.java b/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/AuthProviderMain.java deleted file mode 100644 index f52388eb520..00000000000 --- a/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/AuthProviderMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.auth.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class AuthProviderMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/SpringmvcHelloImpl.java b/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/SpringmvcHelloImpl.java deleted file mode 100644 index 42ef65d88fa..00000000000 --- a/samples/auth-sample/auth-provider/src/main/java/org/apache/servicecomb/samples/auth/provider/SpringmvcHelloImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.auth.provider; - - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -@RestSchema(schemaId = "springmvcHello") -@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON) -public class SpringmvcHelloImpl implements Hello { - - @Override - @RequestMapping(path = "/sayhi", method = RequestMethod.POST) - public String sayHi(@RequestParam(name = "name") String name) { - return "Hello " + name; - } - - @Override - @RequestMapping(path = "/sayhello", method = RequestMethod.POST) - public String sayHello(@RequestBody Person person) { - return "Hello person " + person.getName(); - } -} diff --git a/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties b/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml b/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml deleted file mode 100644 index 550a798a901..00000000000 --- a/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,33 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: auth-sample -service_description: - name: auth-provider - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Provider: - default: auth-provider - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 diff --git a/samples/auth-sample/pom.xml b/samples/auth-sample/pom.xml deleted file mode 100644 index bdf1bf01c11..00000000000 --- a/samples/auth-sample/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - auth-sample - Java Chassis::Samples::Auth - pom - - auth-provider - auth-consumer - - diff --git a/samples/bmi/README.md b/samples/bmi/README.md deleted file mode 100644 index 10c5a52abe2..00000000000 --- a/samples/bmi/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Body Mass Index(BMI) Calculator Microservice Demo -## Architecture of BMI Calculator -There are two microservices in this demo. -* Webapp (API Gateway) -* BMI Calculator (computing service) - -## Prerequisite -1. [Oracle JDK 1.8+](https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html) -2. [Maven 3.x](https://maven.apache.org/install.html) -3. [Gradle 4.x](https://gradle.org/install/)(Optional) - -## Quick Start(Linux) -1. Run the service center - - [how to start service center](http://servicecomb.apache.org/users/setup-environment/#) - -2. Get the bmi demo's code -```bash -git clone https://github.com/apache/servicecomb-java-chassis.git -cd servicecomb-java-chassis/samples -``` -3. Run microservices -* via maven - * Run the **BMI calculator service** - ```bash - (cd bmi/calculator; mvn spring-boot:run) - ``` - * Run the **webapp service** - ```bash - (cd bmi/webapp; mvn spring-boot:run) - ``` -* via gradle - * Install ServiceComb Java Chassis - ```bash - mvn clean install -DskipTests - ``` - * Run the **BMI calculator service** - ```bash - (cd bmi/calculator; gradle bootRun) - ``` - * Run the **webapp service** - ```bash - (cd bmi/webapp; gradle bootRun) - ``` -4. Visit the services via **http://127.0.0.1:8889**. diff --git a/samples/bmi/build.gradle b/samples/bmi/build.gradle deleted file mode 100644 index 3b73658926b..00000000000 --- a/samples/bmi/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -allprojects { - apply plugin: 'maven' - - group = 'org.apache.servicecomb.samples' - version = '1.0.0-SNAPSHOT' -} - -buildscript { - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.12.RELEASE") - } - repositories { - mavenLocal() - mavenCentral() - } -} - -subprojects { - apply plugin: 'java' - apply plugin: 'org.springframework.boot' - - sourceCompatibility = 1.8 - targetCompatibility = 1.8 - - tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - } - - repositories { - mavenLocal() - mavenCentral() - } - - dependencies { - compile group: 'org.hibernate', name: 'hibernate-validator', version:'5.2.4.Final' - } -} diff --git a/samples/bmi/calculator/build.gradle b/samples/bmi/calculator/build.gradle deleted file mode 100644 index 71c00197b78..00000000000 --- a/samples/bmi/calculator/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -description = 'Java Chassis::Samples::BMI::Calculator' - -dependencies { - compile(group: 'org.springframework.boot', name: 'spring-boot-starter') { - exclude(module: 'commons-logging') - } - compile group: 'org.apache.servicecomb', name: 'spring-boot-starter-provider' - compile group: 'org.apache.servicecomb', name: 'handler-flowcontrol-qps' - compile group: 'org.apache.servicecomb', name: 'handler-bizkeeper' - compile group: 'org.apache.servicecomb', name: 'handler-tracing-zipkin' -} - -// dependency-management-plugin is a replacement of dependencyManagement in maven -// we need to enable the plugin and specify the dependencyManagement in the following form in each submodule -// according to the official document: https://github.com/spring-gradle-plugins/dependency-management-plugin. -buildscript { - dependencies { - classpath('io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE') - } - repositories { - mavenLocal() - mavenCentral() - } -} - -apply plugin: 'io.spring.dependency-management' - -dependencyManagement { - imports { - mavenBom 'org.apache.servicecomb:java-chassis-dependencies:1.0.0-SNAPSHOT' - } -} diff --git a/samples/bmi/calculator/pom.xml b/samples/bmi/calculator/pom.xml deleted file mode 100644 index baab624ba45..00000000000 --- a/samples/bmi/calculator/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - bmi - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - bmi-calculator - Java Chassis::Samples::BMI::Calculator - - - - org.springframework.boot - spring-boot-starter - - - - org.apache.servicecomb - spring-boot-starter-provider - - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-tracing-zipkin - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/BMIViewObject.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/BMIViewObject.java deleted file mode 100644 index 54f00ec718d..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/BMIViewObject.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import java.text.SimpleDateFormat; -import java.util.Date; - -public class BMIViewObject { - - private double result; - - private String instanceId; - - private String callTime; - - public BMIViewObject(double result, String instanceId, Date now) { - this.result = result; - this.instanceId = instanceId; - this.callTime = new SimpleDateFormat("HH:mm:ss").format(now); - } - - public double getResult() { - return result; - } - - public void setResult(double result) { - this.result = result; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public String getCallTime() { - return callTime; - } - - public void setCallTime(String callTime) { - this.callTime = callTime; - } -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorApplication.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorApplication.java deleted file mode 100644 index 0d4b3aef5d9..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorApplication.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class CalculatorApplication { - - public static void main(String[] args) { - SpringApplication.run(CalculatorApplication.class, args); - } -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorEndpoint.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorEndpoint.java deleted file mode 100644 index 8be9b4004c2..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorEndpoint.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -/** - * {@link CalculatorEndpoint} provides the common interface for different endpoint implementations. - * It needs to be declared as public. - */ -public interface CalculatorEndpoint { - /** - * Calculate the BMI(Body Mass Index). - */ - BMIViewObject calculate(double height, double weight); -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorRestEndpoint.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorRestEndpoint.java deleted file mode 100644 index a3db932caab..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorRestEndpoint.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import java.util.Date; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * {@link CalculatorRestEndpoint} provides the rest implementation of {@link CalculatorEndpoint}. - * The rest endpoint is accessed by /bmi?height={value}&width={value} with HTTP GET. - */ -@RestSchema(schemaId = "calculatorRestEndpoint") -@RequestMapping(path = "/") -public class CalculatorRestEndpoint implements CalculatorEndpoint { - - private final CalculatorService calculatorService; - - private final InstanceInfoService instanceInfoService; - - @Autowired - public CalculatorRestEndpoint(CalculatorService calculatorService, InstanceInfoService instanceInfoService) { - this.calculatorService = calculatorService; - this.instanceInfoService = instanceInfoService; - } - - @GetMapping(path = "/bmi") - @Override - public BMIViewObject calculate(double height, double weight) { - - String instanceId = instanceInfoService.getInstanceId(); - double bmiResult = calculatorService.calculate(height, weight); - return new BMIViewObject(bmiResult, instanceId, new Date()); - } -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorService.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorService.java deleted file mode 100644 index 4d0fc8d6e60..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorService.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -/** - * {@link CalculatorService} provides interface of actual BMI calculation. - */ -public interface CalculatorService { - - /** - * @see CalculatorEndpoint#calculate(double, double) - */ - double calculate(double height, double weight); -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorServiceImpl.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorServiceImpl.java deleted file mode 100644 index 505eebe71ac..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/CalculatorServiceImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -import org.springframework.stereotype.Service; - -@Service -public class CalculatorServiceImpl implements CalculatorService { - - /** - * {@inheritDoc} - */ - @Override - public double calculate(double height, double weight) { - if (height <= 0 || weight <= 0) { - throw new IllegalArgumentException("Arguments must be above 0"); - } - double heightInMeter = height / 100; - double bmi = weight / (heightInMeter * heightInMeter); - return roundToOnePrecision(bmi); - } - - private double roundToOnePrecision(double value) { - return new BigDecimal(value).setScale(1, RoundingMode.HALF_UP).doubleValue(); - } -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoService.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoService.java deleted file mode 100644 index d6fad3291ff..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoService.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -/** - * {@link InstanceInfoService} provides interface of instance information. - */ -public interface InstanceInfoService { - - String getInstanceId(); -} diff --git a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoServiceImpl.java b/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoServiceImpl.java deleted file mode 100644 index f3ae184b322..00000000000 --- a/samples/bmi/calculator/src/main/java/org/apache/servicecomb/samples/bmi/InstanceInfoServiceImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.springframework.stereotype.Service; - -@Service -public class InstanceInfoServiceImpl implements InstanceInfoService { - - /** - * {@inheritDoc} - */ - @Override - public String getInstanceId() { - - MicroserviceInstance instance = RegistryUtils.getMicroserviceInstance(); - if (instance == null) { - throw new IllegalStateException( - "unable to find any service instances, maybe there is problem registering in service center?"); - } - return instance.getInstanceId(); - } -} diff --git a/samples/bmi/calculator/src/main/resources/microservice.yaml b/samples/bmi/calculator/src/main/resources/microservice.yaml deleted file mode 100644 index 43da6026740..00000000000 --- a/samples/bmi/calculator/src/main/resources/microservice.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# all interconnected microservices must belong to an application wth the same ID -APPLICATION_ID: bmi -service_description: -# name of the declaring microservice - name: calculator - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:7777 - handler: - chain: - Provider: - default: bizkeeper-provider \ No newline at end of file diff --git a/samples/bmi/pom.xml b/samples/bmi/pom.xml deleted file mode 100644 index 3e27c95ceb3..00000000000 --- a/samples/bmi/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - 4.0.0 - - - org.springframework.boot - spring-boot-starter-parent - 1.5.12.RELEASE - - - - org.apache.servicecomb.samples - bmi - Java Chassis::Samples::BMI - 1.2.0-SNAPSHOT - pom - - - calculator - webapp - - - Quick Start Demo for Using ServiceComb Java Chassis - - - UTF-8 - UTF-8 - 1.8 - ${project.version} - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - org.hibernate - hibernate-validator - - - - - - org.apache.rat - apache-rat-plugin - - - .travis.yml - **/*.md - **/target/* - - **/resources/ssl/** - - **/*.proto - - **/*.idl - - - - - - - diff --git a/samples/bmi/settings.gradle b/samples/bmi/settings.gradle deleted file mode 100644 index 308a503ba76..00000000000 --- a/samples/bmi/settings.gradle +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -rootProject.name = 'bmi' -include ':bmi-calculator' -include ':webapp' - -project(':bmi-calculator').projectDir = "$rootDir/calculator" as File -project(':webapp').projectDir = "$rootDir/webapp" as File \ No newline at end of file diff --git a/samples/bmi/webapp/build.gradle b/samples/bmi/webapp/build.gradle deleted file mode 100644 index 1624d9cf568..00000000000 --- a/samples/bmi/webapp/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -description = 'Java Chassis::Samples::BMI::Webapp' - -dependencies { - compile(group: 'org.springframework.boot', name: 'spring-boot-starter') { - exclude(module: 'commons-logging') - } - compile group: 'org.apache.servicecomb', name: 'spring-boot-starter-servicecomb' - compile group: 'org.apache.servicecomb', name: 'spring-boot-starter-discovery' - compile group: 'org.apache.servicecomb', name: 'spring-cloud-zuul' - compile group: 'org.apache.servicecomb', name: 'spring-cloud-zuul-zipkin' -} - -// dependency-management-plugin is a replacement of dependencyManagement in maven -// we need to enable the plugin and specify the dependencyManagement in the following form in each submodule -// according to the official document: https://github.com/spring-gradle-plugins/dependency-management-plugin. -buildscript { - dependencies { - classpath('io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE') - } - repositories { - mavenLocal() - mavenCentral() - } -} - -apply plugin: 'io.spring.dependency-management' - -dependencyManagement { - imports { - mavenBom 'org.apache.servicecomb:java-chassis-dependencies:1.0.0-SNAPSHOT' - } -} diff --git a/samples/bmi/webapp/pom.xml b/samples/bmi/webapp/pom.xml deleted file mode 100644 index a45bee5b959..00000000000 --- a/samples/bmi/webapp/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - bmi - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - webapp - Java Chassis::Samples::BMI::Webapp - - - - org.springframework.boot - spring-boot-starter - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - spring-boot-starter-servicecomb - - - org.apache.servicecomb - spring-boot-starter-discovery - - - org.apache.servicecomb - spring-cloud-zuul - - - org.apache.servicecomb - spring-cloud-zuul-zipkin - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - diff --git a/samples/bmi/webapp/src/main/java/org/apache/servicecomb/samples/bmi/GatewayApplication.java b/samples/bmi/webapp/src/main/java/org/apache/servicecomb/samples/bmi/GatewayApplication.java deleted file mode 100644 index 5f8be1efad0..00000000000 --- a/samples/bmi/webapp/src/main/java/org/apache/servicecomb/samples/bmi/GatewayApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.bmi; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; - -@SpringBootApplication -@EnableZuulProxy -@EnableServiceComb -public class GatewayApplication { - public static void main(String[] args) { - SpringApplication.run(GatewayApplication.class, args); - } -} diff --git a/samples/bmi/webapp/src/main/resources/application.yaml b/samples/bmi/webapp/src/main/resources/application.yaml deleted file mode 100644 index 0c901dca218..00000000000 --- a/samples/bmi/webapp/src/main/resources/application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -zuul: - routes: - calculator: /calculator/** - -# disable netflix eurkea since it's not used for service discovery -ribbon: - eureka: - enabled: false - -server: - port: 8889 - -servicecomb: - tracing: - enabled: false diff --git a/samples/bmi/webapp/src/main/resources/microservice.yaml b/samples/bmi/webapp/src/main/resources/microservice.yaml deleted file mode 100644 index 5f8d524c3c5..00000000000 --- a/samples/bmi/webapp/src/main/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# all interconnected microservices must belong to an application wth the same ID -APPLICATION_ID: bmi -service_description: -# name of the declaring microservice - name: gateway - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - diff --git a/samples/bmi/webapp/src/main/resources/static/index.html b/samples/bmi/webapp/src/main/resources/static/index.html deleted file mode 100644 index faabdf7c776..00000000000 --- a/samples/bmi/webapp/src/main/resources/static/index.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - -
- -
-
-

BMI Calculator

- -
- - -
-
- - -
- - -
- - - -
-
- - - - - diff --git a/samples/codefirst-sample/README.md b/samples/codefirst-sample/README.md deleted file mode 100644 index e3f8e03a97c..00000000000 --- a/samples/codefirst-sample/README.md +++ /dev/null @@ -1,86 +0,0 @@ -## Code First Sample - -ServiceComb Java Chassis supports generating provider-service API implicitly. When the service is started, an API is automatically generated and registered to the service center. - -When you develop a microservice in transparent RPC mode, the code does not show how you want to define an API, and all generated APIs are POST methods, The input parameters of all the methods will be packaged as a class and transferred as body parameters. Therefore, if you develop providers using implicit APIs, you are advised to choose Spring MVC or JAX-RS mode to obtain complete RESTful statements. - -For detail information please refer to [Doc](http://servicecomb.apache.org/users/service-contract/) - - - -## Sample Quick Start - -1. Start the ServiceComb/Service Center - - - [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - - make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the codefirst-provider service - - - Start provider service via maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `CodeFirstProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/codefirst-sample/codefirst-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.codefirst.provider.CodeFirstProviderMain" - ``` - - - Start provider service via gradle - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `CodeFirstProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/codefirst-sample/codefirst-provider/ - gradle clean run - ``` - - - Start provider service via IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function `CodeFirstProviderMain` of provider service and `RUN` it like any other Java program. - -3. Start the codefirst-consumer service - - ```bash - cd samples/codefirst-sample/codefirst-consumer/ - ``` - - - Start consumer service via maven - - Just like how to start codefirst-provider service. But the main class of codefirst-consumer service is `CodeFirstConsumerMain`. - - ```bash - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.codefirst.consumer.CodeFirstConsumerMain" - ``` - - - Start consumer service via gradle - - ```bash - gradle clean run - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs if the consumer can invoke the producer: - 1. *'Pojo Hello Java Chassis'* means the consumer calls sayhi successfully - 2. *'Jaxrs Hello Java Chassis'* means the consumer calls Jaxrs sayhi successfully - 3. *'Spring mvc Hello Java Chassis'* means the consumer calls SpringMvc sayhi successfully - 4. *'Pojo Hello person ServiceComb/Java Chassis'* means the consumer calls sayhello successfully - 5. *'Jaxrs Hello person ServiceComb/Java Chassis'* means the consumer calls Jaxrs sayhello successfully - 6. *'Spring mvc Hello person ServiceComb/Java Chassis'* means the consumer calls SpringMvc sayhello successfully \ No newline at end of file diff --git a/samples/codefirst-sample/build.gradle b/samples/codefirst-sample/build.gradle deleted file mode 100644 index 67a7af59574..00000000000 --- a/samples/codefirst-sample/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -allprojects { - apply plugin: 'maven' - - group = 'org.apache.servicecomb.samples' - version = '1.0.0-SNAPSHOT' -} - -subprojects { - apply plugin: 'java' - - sourceCompatibility = 1.8 - targetCompatibility = 1.8 - - tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - } - - repositories { - mavenLocal() - mavenCentral() - } -} \ No newline at end of file diff --git a/samples/codefirst-sample/codefirst-consumer/build.gradle b/samples/codefirst-sample/codefirst-consumer/build.gradle deleted file mode 100644 index 90d4ddc0f72..00000000000 --- a/samples/codefirst-sample/codefirst-consumer/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -description = 'Java Chassis::Samples::CodeFirst::Consumer' - -dependencies { - compile group: 'org.apache.servicecomb', name: 'provider-pojo' - compile group: 'org.apache.servicecomb', name: 'transport-highway' - compile group: 'org.apache.servicecomb', name: 'transport-rest-vertx' - compile group: 'org.apache.servicecomb.samples', name: 'common-schema', version: '1.0.0-SNAPSHOT' - compile group: 'org.slf4j', name: 'slf4j-log4j12' -} - -apply plugin: 'application' - -mainClassName = 'org.apache.servicecomb.samples.codefirst.consumer.CodeFirstConsumerMain' - -// dependency-management-plugin is a replacement of dependencyManagement in maven -// we need to enable the plugin and specify the dependencyManagement in the following form in each submodule -// according to the official document: https://github.com/spring-gradle-plugins/dependency-management-plugin. -buildscript { - repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath('io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE') - } -} - -apply plugin: 'io.spring.dependency-management' - -dependencyManagement { - imports { - mavenBom 'org.apache.servicecomb:java-chassis-dependencies:1.0.0-SNAPSHOT' - } -} diff --git a/samples/codefirst-sample/codefirst-consumer/pom.xml b/samples/codefirst-sample/codefirst-consumer/pom.xml deleted file mode 100644 index 769f4721e38..00000000000 --- a/samples/codefirst-sample/codefirst-consumer/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - codefirst-sample - 1.2.0-SNAPSHOT - - codefirst-consumer - Java Chassis::Samples::CodeFirst::Consumer - - UTF-8 - - - - org.apache.servicecomb.samples - common-schema - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.slf4j - slf4j-log4j12 - - - diff --git a/samples/codefirst-sample/codefirst-consumer/src/main/java/org/apache/servicecomb/samples/codefirst/consumer/CodeFirstConsumerMain.java b/samples/codefirst-sample/codefirst-consumer/src/main/java/org/apache/servicecomb/samples/codefirst/consumer/CodeFirstConsumerMain.java deleted file mode 100644 index 9eb14b81bec..00000000000 --- a/samples/codefirst-sample/codefirst-consumer/src/main/java/org/apache/servicecomb/samples/codefirst/consumer/CodeFirstConsumerMain.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.codefirst.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.stereotype.Component; - -@Component -public class CodeFirstConsumerMain { - - @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstJaxrsHello") - private static Hello jaxrsHello; - - @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstSpringmvcHello") - private static Hello springmvcHello; - - @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstHello") - private static Hello hello; - - public static void main(String[] args) throws Exception { - init(); - System.out.println(hello.sayHi("Java Chassis")); - System.out.println(jaxrsHello.sayHi("Java Chassis")); - System.out.println(springmvcHello.sayHi("Java Chassis")); - Person person = new Person(); - person.setName("ServiceComb/Java Chassis"); - System.out.println(hello.sayHello(person)); - System.out.println(jaxrsHello.sayHello(person)); - System.out.println(springmvcHello.sayHello(person)); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/codefirst-sample/codefirst-consumer/src/main/resources/config/log4j.demo.properties b/samples/codefirst-sample/codefirst-consumer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/codefirst-sample/codefirst-consumer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/codefirst-sample/codefirst-consumer/src/main/resources/microservice.yaml b/samples/codefirst-sample/codefirst-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index ae7231290d4..00000000000 --- a/samples/codefirst-sample/codefirst-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,31 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: codefirsttest -service_description: - name: codefirstClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - isolation: - Consumer: - enabled: false - references: - codefirst: - version-rule: 0.0.1 diff --git a/samples/codefirst-sample/codefirst-provider/build.gradle b/samples/codefirst-sample/codefirst-provider/build.gradle deleted file mode 100644 index 9c85d0717e0..00000000000 --- a/samples/codefirst-sample/codefirst-provider/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -description = 'Java Chassis::Samples::CodeFirst::Provider' - -dependencies { - compile group: 'org.apache.servicecomb', name: 'provider-pojo' - compile group: 'org.apache.servicecomb', name: 'provider-springmvc' - compile group: 'org.apache.servicecomb', name: 'transport-highway' - compile group: 'org.apache.servicecomb', name: 'transport-rest-vertx' - compile group: 'org.apache.servicecomb.samples', name: 'common-schema', version: '1.0.0-SNAPSHOT' - compile group: 'org.slf4j', name: 'slf4j-log4j12' -} - -apply plugin: 'application' - -mainClassName = 'org.apache.servicecomb.samples.codefirst.provider.CodeFirstProviderMain' - -// dependency-management-plugin is a replacement of dependencyManagement in maven -// we need to enable the plugin and specify the dependencyManagement in the following form in each submodule -// according to the official document: https://github.com/spring-gradle-plugins/dependency-management-plugin. -buildscript { - repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath('io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE') - } -} - -apply plugin: 'io.spring.dependency-management' - -dependencyManagement { - imports { - mavenBom 'org.apache.servicecomb:java-chassis-dependencies:1.0.0-SNAPSHOT' - } -} diff --git a/samples/codefirst-sample/codefirst-provider/pom.xml b/samples/codefirst-sample/codefirst-provider/pom.xml deleted file mode 100644 index 7ddb55ef3e3..00000000000 --- a/samples/codefirst-sample/codefirst-provider/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - codefirst-sample - 1.2.0-SNAPSHOT - - codefirst-provider - Java Chassis::Samples::CodeFirst::Provider - - UTF-8 - - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstJaxrsHelloImpl.java b/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstJaxrsHelloImpl.java deleted file mode 100644 index d79497f3585..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstJaxrsHelloImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.codefirst.provider; - - -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; - -@RpcSchema(schemaId = "codeFirstJaxrsHello") -@Path("/codefirstjaxrshello") -@Produces(MediaType.APPLICATION_JSON) -public class CodeFirstJaxrsHelloImpl implements Hello { - - @Path("/sayhi") - @POST - @Override - public String sayHi(String name) { - return "Jaxrs Hello " + name; - } - - @Path("/sayhello") - @POST - @Override - public String sayHello(Person person) { - return "Jaxrs Hello person " + person.getName(); - } -} diff --git a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstPojoHelloImpl.java b/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstPojoHelloImpl.java deleted file mode 100644 index 85f3582c16c..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstPojoHelloImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.codefirst.provider; - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; - -@RpcSchema(schemaId = "codeFirstHello") -public class CodeFirstPojoHelloImpl implements Hello { - - @Override - public String sayHi(String name) { - return "Pojo Hello " + name; - } - - @Override - public String sayHello(Person person) { - return "Pojo Hello person " + person.getName(); - } -} diff --git a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstProviderMain.java b/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstProviderMain.java deleted file mode 100644 index 2f8721b784f..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstProviderMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.codefirst.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class CodeFirstProviderMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstSpringmvcHelloImpl.java b/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstSpringmvcHelloImpl.java deleted file mode 100644 index 8d0370bc0a8..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/java/org/apache/servicecomb/samples/codefirst/provider/CodeFirstSpringmvcHelloImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.codefirst.provider; - - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -@RpcSchema(schemaId = "codeFirstSpringmvcHello") -@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON) -public class CodeFirstSpringmvcHelloImpl implements Hello { - - @Override - @RequestMapping(path = "/sayhi", method = RequestMethod.POST) - public String sayHi(@RequestParam(name = "name") String name) { - return "Spring mvc Hello " + name; - } - - @Override - @RequestMapping(path = "/sayhello", method = RequestMethod.POST) - public String sayHello(@RequestBody Person person) { - return "Spring mvc Hello person " + person.getName(); - } -} diff --git a/samples/codefirst-sample/codefirst-provider/src/main/resources/config/log4j.demo.properties b/samples/codefirst-sample/codefirst-provider/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/codefirst-sample/codefirst-provider/src/main/resources/microservice.yaml b/samples/codefirst-sample/codefirst-provider/src/main/resources/microservice.yaml deleted file mode 100644 index c7752332bdc..00000000000 --- a/samples/codefirst-sample/codefirst-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: codefirsttest -service_description: - name: codefirst - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 diff --git a/samples/codefirst-sample/pom.xml b/samples/codefirst-sample/pom.xml deleted file mode 100644 index d403d8b8fe0..00000000000 --- a/samples/codefirst-sample/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - codefirst-sample - Java Chassis::Samples::CodeFirst - pom - - - UTF-8 - - - - codefirst-provider - codefirst-consumer - - diff --git a/samples/codefirst-sample/settings.gradle b/samples/codefirst-sample/settings.gradle deleted file mode 100644 index c32b5bb43fa..00000000000 --- a/samples/codefirst-sample/settings.gradle +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -rootProject.name = 'codefirst-sample' -include ':codefirst-provider' -include ':codefirst-consumer' - -project(':codefirst-provider').projectDir = "$rootDir/codefirst-provider" as File -project(':codefirst-consumer').projectDir = "$rootDir/codefirst-consumer" as File \ No newline at end of file diff --git a/samples/common-schema/pom.xml b/samples/common-schema/pom.xml deleted file mode 100644 index dc3b9bba357..00000000000 --- a/samples/common-schema/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - common-schema - Java Chassis::Samples::Common Schema - diff --git a/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/Hello.java b/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/Hello.java deleted file mode 100644 index 6fcd139f7b8..00000000000 --- a/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/Hello.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.common.schema; - - -import org.apache.servicecomb.samples.common.schema.models.Person; - -public interface Hello { - - String sayHi(String name); - - String sayHello(Person person); -} diff --git a/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/models/Person.java b/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/models/Person.java deleted file mode 100644 index 96ba3229929..00000000000 --- a/samples/common-schema/src/main/java/org/apache/servicecomb/samples/common/schema/models/Person.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.common.schema.models; - -public class Person { - - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/samples/config-apollo-sample/README.md b/samples/config-apollo-sample/README.md deleted file mode 100644 index aea50648f3b..00000000000 --- a/samples/config-apollo-sample/README.md +++ /dev/null @@ -1,57 +0,0 @@ -## Use Apollo as Configuration Center - -To use Apollo as configuration source in ServiceComb Java Chassis services: - -* Start Apollo service and create a project to associate with Chassis service, then generate a token - - [How to use Apollo configuration center](http://servicecomb.apache.org/cn/users/dynamic-config/) - - -* Import `config-apollo` in pom: - - ```xml - - org.apache.servicecomb - config-apollo - - ``` - -* Configurations for Apollo itself in `microservice.yaml`, for example: - - ```yaml - apollo: - config: - serverUri: http://127.0.0.1:8070 #Apollo portal server address - serviceName: apollo-test #service name use AppId in apollo - env: DEV #default value DEV - clusters: default #default value default - namespace: application #default value application - token: #get token from Apollo web pages - ``` - -* Start Chassis service and update configurations in Apollo portal service. - - [Need to start service center first](http://servicecomb.apache.org/users/setup-environment/#) - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `MainServer`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/config-apollo-sample/ - mvn exec:java -Dexec.mainClass="MainServer" - ``` - -* Verify configurations can be configured dynamically. - - Before publishing a new configuration items from apollo portal, `MainServer` will just print `DynamicProperty: {name=timeout, current value=default}` - - After `timeout` configuration is published with value `100`, `MainServer` will print `DynamicProperty: {name=timeout, current value=100}` - - -## More - -[Apollo Doc](https://github.com/ctripcorp/apollo/wiki) - -[Use Apollo In ServiceComb](http://servicecomb.apache.org/cn/users/dynamic-config/) - diff --git a/samples/config-apollo-sample/pom.xml b/samples/config-apollo-sample/pom.xml deleted file mode 100644 index 757c1a8c561..00000000000 --- a/samples/config-apollo-sample/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - samples - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - config-apollo-sample - - - org.apache.servicecomb - foundation-common - - - com.netflix.archaius - archaius-core - - - org.apache.servicecomb - config-apollo - - - org.slf4j - slf4j-log4j12 - - - - - \ No newline at end of file diff --git a/samples/config-apollo-sample/src/main/java/MainServer.java b/samples/config-apollo-sample/src/main/java/MainServer.java deleted file mode 100644 index 830177b284b..00000000000 --- a/samples/config-apollo-sample/src/main/java/MainServer.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -import com.netflix.config.DynamicPropertyFactory; - -public class MainServer { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - while (true) { - System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("timeout", "default")); - Thread.sleep(3000); - } - } -} diff --git a/samples/config-apollo-sample/src/main/resources/log4j.properties b/samples/config-apollo-sample/src/main/resources/log4j.properties deleted file mode 100644 index ba21655518a..00000000000 --- a/samples/config-apollo-sample/src/main/resources/log4j.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -log4j.rootLogger=INFO \ No newline at end of file diff --git a/samples/config-apollo-sample/src/main/resources/microservice.yaml b/samples/config-apollo-sample/src/main/resources/microservice.yaml deleted file mode 100644 index d94cae8f7f2..00000000000 --- a/samples/config-apollo-sample/src/main/resources/microservice.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: apollotest -service_description: - name: apollo-test - version: 1.0.1 - -apollo: - config: - serverUri: http://127.0.0.1:8070 - serviceName: apollo-test #AppId in apollo - env: DEV - #default clusters name in apollo,if user create new clusters please replace this setting value - #more detail can be found at https://github.com/ctripcorp/apollo/wiki - clusters: default - #default namespace name in apollo,if user create new namespace please replace this setting value - #more detail can be found at https://github.com/ctripcorp/apollo/wiki/Apollo%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%E4%B9%8B%E2%80%9CNamespace%E2%80%9D - namespace: application - token: #get token from Apollo web pages -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider - #executors: - #default: test - #Provider: - #server: test - #server.wrapParam: test \ No newline at end of file diff --git a/samples/custom-handler-sample/README.md b/samples/custom-handler-sample/README.md deleted file mode 100644 index a8599ebfc8d..00000000000 --- a/samples/custom-handler-sample/README.md +++ /dev/null @@ -1,91 +0,0 @@ -## Customized Handler Sample - -ServiceComb support users to define a customized handler and and invoke the handler in handler chain. - -* Customize a handler by implement Handler interface, for example: - - ```java - public class MyHandler implements Handler { - private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class); - @Override - public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception { - //code before - LOGGER.info("It's my handler! \r\n"); - invocation.next(response -> { - // code after - asyncResponse.handle(response); - }); - } - } - ``` - -* Define handler `id` and `class` in `cse.handler.xml` `config` item under `resources/config` directory - - ```xml - - - - - ``` - -* Configure customized `MyHandler` in `microservice.yaml` file along with other handler together - - ```yaml - cse: - # other configurations omitted - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance, myhandler - ``` - -## Sample Quick Start - -1. Start the ServiceComb/Service Center - - - [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - - make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the custom-handler-provider service - - - Start provider service by maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `CustomHandlerProviderMain`. - - ```bash - cd servicecomb-java-chassis/ #need to complie code at root directory - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/custom-handler-sample/custom-handler-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.customerhandler.provider.CustomHandlerProviderMain" - ``` - - - Start provider service by IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function `CustomHandlerProviderMain` of provider service and `RUN` it like any other Java program. - -3. Start the custom-handler-consumer service - - Just like how to start custom-handler-provider service. But the main class of custom-handler-consumer service is `CustomHandlerCustomerMain`. - - ```bash - cd samples/custom-handler-sample/custom-handler-consumer - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.customerhandler.consumer.CustomHandlerCustomerMain" - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs: - 1. *'It's my handler!'* means custom handler had take effect - \ No newline at end of file diff --git a/samples/custom-handler-sample/custom-handler-consumer/pom.xml b/samples/custom-handler-sample/custom-handler-consumer/pom.xml deleted file mode 100644 index a901809f7d4..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - custom-handler-sample - 1.2.0-SNAPSHOT - - custom-handler-consumer - Java Chassis::Samples::Custom Handler::Consumer - - - - org.apache.servicecomb - provider-pojo - - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/consumer/CustomHandlerCustomerMain.java b/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/consumer/CustomHandlerCustomerMain.java deleted file mode 100644 index e7105071148..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/consumer/CustomHandlerCustomerMain.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.customerhandler.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.stereotype.Component; - -@Component -public class CustomHandlerCustomerMain { - - @RpcReference(microserviceName = "customerhandler", schemaId = "hello") - private static Hello hello; - - public static void main(String[] args) throws Exception { - init(); - System.out.println(hello.sayHi("Java Chassis")); - Person person = new Person(); - person.setName("ServiceComb/Java Chassis"); - System.out.println(hello.sayHello(person)); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/handlers/MyHandler.java b/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/handlers/MyHandler.java deleted file mode 100644 index da2f89abfe0..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/src/main/java/org/apache/servicecomb/samples/customerhandler/handlers/MyHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.customerhandler.handlers; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MyHandler implements Handler { - - private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class); - - @Override - public void handle(Invocation invocation, AsyncResponse asyncResponse) throws Exception { - //code before - - LOGGER.info("It's my handler! \r\n"); - - invocation.next(response -> { - // code after - asyncResponse.handle(response); - }); - } -} diff --git a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/cse.handler.xml b/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/cse.handler.xml deleted file mode 100644 index 0cac14f2495..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/cse.handler.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/log4j.demo.properties b/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml b/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index fd747ecb813..00000000000 --- a/samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,35 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: chstest -service_description: - name: chsClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance, myhandler - isolation: - Consumer: - enabled: false - references: - chs: - version-rule: 0.0.1 diff --git a/samples/custom-handler-sample/custom-handler-provider/pom.xml b/samples/custom-handler-sample/custom-handler-provider/pom.xml deleted file mode 100644 index 6a62549b0b6..00000000000 --- a/samples/custom-handler-sample/custom-handler-provider/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - custom-handler-sample - 1.2.0-SNAPSHOT - - custom-handler-provider - Java Chassis::Samples::Custom Handler::Provider - - - - org.apache.servicecomb - provider-pojo - - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - handler-flowcontrol-qps - - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/CustomHandlerProviderMain.java b/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/CustomHandlerProviderMain.java deleted file mode 100644 index 4ab2afe9a8a..00000000000 --- a/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/CustomHandlerProviderMain.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.customerhandler.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class CustomHandlerProviderMain { - - public static void main(String[] args) - throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/HelloImpl.java b/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/HelloImpl.java deleted file mode 100644 index 5b63369864e..00000000000 --- a/samples/custom-handler-sample/custom-handler-provider/src/main/java/org/apache/servicecomb/samples/customerhandler/provider/HelloImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.customerhandler.provider; - - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; - -@RpcSchema(schemaId = "hello") -public class HelloImpl implements Hello { - - @Override - public String sayHi(String name) { - return "Hello " + name; - } - - @Override - public String sayHello(Person person) { - return "Hello person " + person.getName(); - } -} diff --git a/samples/custom-handler-sample/custom-handler-provider/src/main/resources/config/log4j.demo.properties b/samples/custom-handler-sample/custom-handler-provider/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/custom-handler-sample/custom-handler-provider/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/custom-handler-sample/custom-handler-provider/src/main/resources/microservice.yaml b/samples/custom-handler-sample/custom-handler-provider/src/main/resources/microservice.yaml deleted file mode 100644 index 4b473cd8f2d..00000000000 --- a/samples/custom-handler-sample/custom-handler-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: chstest -service_description: - name: customerhandler - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 diff --git a/samples/custom-handler-sample/pom.xml b/samples/custom-handler-sample/pom.xml deleted file mode 100644 index de96cc53273..00000000000 --- a/samples/custom-handler-sample/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - custom-handler-sample - Java Chassis::Samples::Custom Handler - pom - - custom-handler-consumer - custom-handler-provider - - diff --git a/samples/jaxrs-sample/README.md b/samples/jaxrs-sample/README.md deleted file mode 100644 index 1f24c3d5597..00000000000 --- a/samples/jaxrs-sample/README.md +++ /dev/null @@ -1,68 +0,0 @@ -## JAX-RS Sample - -ServiceComb supports developers in developing services in JAX-RS mode by using JAX-RS. - -### Provider Service - -* Define a service API. Compile the Java API definition based on the API definition defined before development -* Implement the service. JAX-RS is used to describe the development of service code. -* Release the service. Add `@RestSchema` as the annotation of the service implementation class and specify schemaID, which indicates that the implementation is released as a schema of the current microservice. -* Create the jaxrsHello.bean.xml file in the resources/META-INF/spring directory and configure base-package that performs scanning - - [Detail information please refer to Doc](http://servicecomb.apache.org/users/develop-with-jax-rs/) - -### Consumer Service - -To consume a provider-service, only need to decalare a member of a service API type and add the `RpcReference` annotation for the member, the microservice that depends on the declaration and the `schemaID` just like pojo consumer sample. - -### Sample Quick Start - -1. Start the ServiceComb/Service Center - - - [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - - make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the jaxrs-provider service - - - Start provider service by maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `JaxrsProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/jaxrs-sample/jaxrs-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.jaxrs.provider.JaxrsProviderMain" - ``` - - - Start provider service by IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function `JaxrsProviderMain` of provider service and `RUN` it like any other Java Program. - -3. Start the jaxrs-consumer service - - Just like how to start jaxrs-provider service. But the main class of jaxrs-consumer service is `JaxrsConsumerMain`. - - ```bash - cd samples/jaxrs-sample/jaxrs-consumer/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.jaxrs.consumer.JaxrsConsumerMain" - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs if the consumer can invoke the producer: - 1. *'Hello Java Chassis'* means the consumer calls sayhi by RpcReference successfully - 2. *'Hello person ServiceComb/Java Chassis'* means the consumer calls sayhello by RpcReference successfully - 3. *'Bye !'* means the consumer calls saybye by RestTemplate successfully \ No newline at end of file diff --git a/samples/jaxrs-sample/jaxrs-consumer/pom.xml b/samples/jaxrs-sample/jaxrs-consumer/pom.xml deleted file mode 100644 index 5945409cde7..00000000000 --- a/samples/jaxrs-sample/jaxrs-consumer/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - jaxrs-sample - 1.2.0-SNAPSHOT - - jaxrs-consumer - Java Chassis::Samples::JAXRS::Consumer - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.apache.servicecomb - provider-springmvc - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/jaxrs-sample/jaxrs-consumer/src/main/java/org/apache/servicecomb/samples/jaxrs/consumer/JaxrsConsumerMain.java b/samples/jaxrs-sample/jaxrs-consumer/src/main/java/org/apache/servicecomb/samples/jaxrs/consumer/JaxrsConsumerMain.java deleted file mode 100644 index 67bcab523dc..00000000000 --- a/samples/jaxrs-sample/jaxrs-consumer/src/main/java/org/apache/servicecomb/samples/jaxrs/consumer/JaxrsConsumerMain.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.jaxrs.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -@Component -public class JaxrsConsumerMain { - - @RpcReference(microserviceName = "jaxrs", schemaId = "jaxrsHello") - private static Hello hello; - - public static void main(String[] args) throws Exception { - init(); - System.out.println(hello.sayHi("Java Chassis")); - Person person = new Person(); - person.setName("ServiceComb/Java Chassis"); - System.out.println(hello.sayHello(person)); - - RestTemplate restTemplate = RestTemplateBuilder.create(); - String result = restTemplate.getForObject("cse://jaxrs/jaxrshello/saybye", String.class); - System.out.println(result); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/config/log4j.demo.properties b/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservice.yaml b/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index 0f0958d0027..00000000000 --- a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,35 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: jaxrstest-sample -service_description: - name: helloClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance - isolation: - Consumer: - enabled: false - references: - jaxrs: - version-rule: 0.0.1 diff --git a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservices/hello/hello.yaml b/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index fb9328b2b32..00000000000 --- a/samples/jaxrs-sample/jaxrs-consumer/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,45 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.jaxrs.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string diff --git a/samples/jaxrs-sample/jaxrs-provider/pom.xml b/samples/jaxrs-sample/jaxrs-provider/pom.xml deleted file mode 100644 index c0ed35bced7..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - jaxrs-sample - 1.2.0-SNAPSHOT - - jaxrs-provider - Java Chassis::Samples::JAXRS::Provider - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - provider-jaxrs - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsHelloImpl.java b/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsHelloImpl.java deleted file mode 100644 index f26ad06290a..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsHelloImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.jaxrs.provider; - - -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; - -@RestSchema(schemaId = "jaxrsHello") -@Path("/jaxrshello") -@Produces(MediaType.APPLICATION_JSON) -public class JaxrsHelloImpl implements Hello { - - @Path("/sayhi") - @POST - @Override - public String sayHi(String name) { - return "Hello " + name; - } - - @Path("/sayhello") - @POST - @Override - public String sayHello(Person person) { - return "Hello person " + person.getName(); - } - - @Path("/saybye") - @GET - public String sayBye() { - return "Bye !"; - } -} diff --git a/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsProviderMain.java b/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsProviderMain.java deleted file mode 100644 index c9590d1a978..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/src/main/java/org/apache/servicecomb/samples/jaxrs/provider/JaxrsProviderMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.jaxrs.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class JaxrsProviderMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/config/log4j.demo.properties b/samples/jaxrs-sample/jaxrs-provider/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservice.yaml b/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservice.yaml deleted file mode 100644 index 1fe5accaddb..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: jaxrstest-sample -service_description: - name: jaxrs - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 diff --git a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservices/hello/hello.yaml b/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index fb9328b2b32..00000000000 --- a/samples/jaxrs-sample/jaxrs-provider/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,45 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.jaxrs.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string diff --git a/samples/jaxrs-sample/pom.xml b/samples/jaxrs-sample/pom.xml deleted file mode 100644 index 37b72138b24..00000000000 --- a/samples/jaxrs-sample/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - jaxrs-sample - Java Chassis::Samples::JAXRS - pom - - jaxrs-provider - jaxrs-consumer - - diff --git a/samples/local-service-registry/README.md b/samples/local-service-registry/README.md deleted file mode 100644 index 2b2d6946335..00000000000 --- a/samples/local-service-registry/README.md +++ /dev/null @@ -1,49 +0,0 @@ -## Local registry - -User can use local registry mechanisam and can connect server endpoints without using service center. -For local registry mechanism user should provide the local registry file at consumer side. -User can start provider service and get the provider schema file and put at the consumer side. -Consumer will use local registry function and it will connect the server end points. - -Please find the details as follows. - -## Provider Side - -* run the provider with/without service center and get the schema file. - -## Consumer Side changes - -* Add local registry file registry.yaml : - - ```yaml - localserv: - - id: "100" - version: "0.0.1" - appid: localservreg - schemaIds: - - localservregistry - instances: - - endpoints: - - rest://localhost:8080 - - highway://localhost:7070 - ``` - -* Add the following code at the beginning and end of the service consumer Main function - -```java - public class xxxClient { - public static void main(String[] args) { -   System.setProperty("local.registry.file", "/yourpath/registry.yaml"); - //your code -   System.clearProperty("local.registry.file"); - } - } -``` - If file present in this path "local.registry.file" then registry mode is Local registry mode. It will not connect to service center. - -* Add provider's schema file at below location of consumer side - - src/main/resources/microservices/{microserviceName}/{schemaId.yaml} - -here microserviceName is servers's microservice name. Like this multiple schemaId files we can put in same location. - -* Run the consumer and verify the API's output. diff --git a/samples/local-service-registry/local-registry-client/pom.xml b/samples/local-service-registry/local-registry-client/pom.xml deleted file mode 100644 index d185ca0454e..00000000000 --- a/samples/local-service-registry/local-registry-client/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.samples - local-service-registry - 1.2.0-SNAPSHOT - - local-registry-client - Java Chassis::Demo::LocalServiceRegistry::Client - - - - org.apache.servicecomb.samples - common-schema - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-bizkeeper - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb - handler-loadbalance - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - - diff --git a/samples/local-service-registry/local-registry-client/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryclient/LocalRegistryClient.java b/samples/local-service-registry/local-registry-client/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryclient/LocalRegistryClient.java deleted file mode 100644 index 3d261747c60..00000000000 --- a/samples/local-service-registry/local-registry-client/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryclient/LocalRegistryClient.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.localregistry.localregistryclient; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.web.client.RestTemplate; - -public class LocalRegistryClient { - private static RestTemplate templateNew = RestTemplateBuilder.create(); - - public static void main(String[] args) throws Exception { - System.setProperty("local.registry.file", "src/main/resources/registry.yaml"); - init(); - - run(); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } - - public static void run() throws Exception { - testLocalRegistry(templateNew); - } - - private static void testLocalRegistry(RestTemplate template) throws Exception { - String microserviceName = "localserv"; - String cseUrlPrefix = "cse://" + microserviceName + "/localservregistry/"; - - Map params = new HashMap<>(); - params.put("a", "5"); - params.put("b", "20"); - int result = template.postForObject(cseUrlPrefix + "add", params, Integer.class); - System.out.println(result); - - Person person = new Person(); - person.setName("local registry test"); - Person sayHiResult = template - .postForObject( - cseUrlPrefix + "sayhi", - person, - Person.class); - - System.out.println(sayHiResult.getName()); - } -} diff --git a/samples/local-service-registry/local-registry-client/src/main/resources/microservice.yaml b/samples/local-service-registry/local-registry-client/src/main/resources/microservice.yaml deleted file mode 100644 index 4a4da5a2d82..00000000000 --- a/samples/local-service-registry/local-registry-client/src/main/resources/microservice.yaml +++ /dev/null @@ -1,26 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: localservreg -service_description: - name: localclient - version: 0.0.1 -servicecomb: - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance diff --git a/samples/local-service-registry/local-registry-client/src/main/resources/microservices/localserv/hello.yaml b/samples/local-service-registry/local-registry-client/src/main/resources/microservices/localserv/hello.yaml deleted file mode 100644 index de3c2d2dbd2..00000000000 --- a/samples/local-service-registry/local-registry-client/src/main/resources/microservices/localserv/hello.yaml +++ /dev/null @@ -1,69 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: "2.0" -info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.samples.localregistry.localregistryserver.LocalServerApi" - x-java-interface: "cse.gen.localservreg.localserv.localservregistry.LocalServerApiIntf" -basePath: "/localservregistry" -consumes: -- "application/json" -produces: -- "application/json" -paths: - /add: - post: - operationId: "add" - parameters: - - name: "a" - in: "formData" - required: false - type: "integer" - format: "int32" - - name: "b" - in: "formData" - required: false - type: "integer" - format: "int32" - responses: - 200: - description: "response of 200" - schema: - type: "integer" - format: "int32" - /sayhi: - post: - operationId: "sayHi" - parameters: - - in: "body" - name: "student" - required: false - schema: - $ref: "#/definitions/Person" - responses: - 200: - description: "response of 200" - schema: - $ref: "#/definitions/Person" -definitions: - Person: - type: "object" - properties: - name: - type: "string" - x-java-class: "org.apache.servicecomb.samples.common.schema.models.Person" diff --git a/samples/local-service-registry/local-registry-client/src/main/resources/registry.yaml b/samples/local-service-registry/local-registry-client/src/main/resources/registry.yaml deleted file mode 100644 index 4a27438b508..00000000000 --- a/samples/local-service-registry/local-registry-client/src/main/resources/registry.yaml +++ /dev/null @@ -1,27 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -localserv: - - id: "100" - version: "0.0.1" - appid: localservreg - schemaIds: - - hello - instances: - - endpoints: - - rest://localhost:8080 - - highway://localhost:7070 \ No newline at end of file diff --git a/samples/local-service-registry/local-registry-server/pom.xml b/samples/local-service-registry/local-registry-server/pom.xml deleted file mode 100644 index 74894ece606..00000000000 --- a/samples/local-service-registry/local-registry-server/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.samples - local-service-registry - 1.2.0-SNAPSHOT - - local-registry-server - Java Chassis::Demo::LocalRegistry::Server - - - org.apache.servicecomb.samples - common-schema - - - org.apache.servicecomb - provider-jaxrs - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-bizkeeper - - - org.slf4j - slf4j-log4j12 - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - com.github.odavid.maven.plugins - mixin-maven-plugin - - - - org.apache.servicecomb.demo - docker-build-config - ${project.version} - - - - - - - diff --git a/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalRegistryServer.java b/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalRegistryServer.java deleted file mode 100644 index 82151d9b2f8..00000000000 --- a/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalRegistryServer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.localregistry.localregistryserver; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class LocalRegistryServer { - public static void main(String[] args) throws Exception { - System.setProperty("local.registry.file", "src/main/resources/registry.yaml"); - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalServerApi.java b/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalServerApi.java deleted file mode 100644 index e5fea871065..00000000000 --- a/samples/local-service-registry/local-registry-server/src/main/java/org/apache/servicecomb/samples/localregistry/localregistryserver/LocalServerApi.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.localregistry.localregistryserver; - -import javax.ws.rs.FormParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.apache.servicecomb.provider.rest.common.RestSchema; - -@RestSchema(schemaId = "hello") -@Path("/localservregistry") -@Produces(MediaType.APPLICATION_JSON) -public class LocalServerApi { - - @Path("/add") - @POST - public int add(@FormParam("a") int a, @FormParam("b") int b) { - return a + b; - } - - @Path("/sayhi") - @POST - public Person sayHi(Person student) { - student.setName("hello " + student.getName()); - return student; - } -} diff --git a/samples/local-service-registry/local-registry-server/src/main/resources/microservice.yaml b/samples/local-service-registry/local-registry-server/src/main/resources/microservice.yaml deleted file mode 100644 index ed2b8fc3860..00000000000 --- a/samples/local-service-registry/local-registry-server/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: localservreg -service_description: - name: localserv - version: 0.0.1 -servicecomb: - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/samples/local-service-registry/local-registry-server/src/main/resources/registry.yaml b/samples/local-service-registry/local-registry-server/src/main/resources/registry.yaml deleted file mode 100644 index 446814cf61d..00000000000 --- a/samples/local-service-registry/local-registry-server/src/main/resources/registry.yaml +++ /dev/null @@ -1,25 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -localserv: - - id: "100" - version: "0.0.2" - appid: localservreg - instances: - - endpoints: - - rest://localhost:8080 - - highway://localhost:7070 diff --git a/samples/local-service-registry/pom.xml b/samples/local-service-registry/pom.xml deleted file mode 100644 index 9d1e27095ce..00000000000 --- a/samples/local-service-registry/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - local-service-registry - Java Chassis::Demo::Local service registry - pom - - local-registry-server - local-registry-client - - - diff --git a/samples/metrics-extend-healthcheck/README.md b/samples/metrics-extend-healthcheck/README.md deleted file mode 100644 index 97bac1b6651..00000000000 --- a/samples/metrics-extend-healthcheck/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Extend Metrics Health Checker Sample -## What is Health Checker -Because micro-services is desgin by SRP(Single Responsibility Principle),one micro-service always depend on many components such as middle-ware like queue,database etc and other micro-services,so if one micro-service report failure,we want fast know what is the cause and more details to help us solve the problem. - -Health check mechanism can let user write some logic to check components of micro-service dependent and return check result. - -## How to use -### Add your checker implementation -Implement *org.apache.servicecomb.foundation.metrics.health.HealthChecker* interface: -```java -public interface HealthChecker { - String getName(); - - HealthCheckResult check(); -} -``` - -Then add the implementation class into **META-INF.service.org.apache.servicecomb.foundation.metrics.health.HealthChecker** by SPI(Service Provider Interface) way - -In this demo,we had make two checkers : -1. CustomHealthChecker - always return true checker -2. MySqlHealthChecker - sim check mysql can connect checker - -### Add Dependency in POM -```xml - - org.apache.servicecomb - metrics-core - {version} - -``` - -### Start service -```bash -mvn spring-boot:run -``` - -### Do check and get result -If you had config rest transport address in microservice.yaml like: -```yaml -cse: - rest: - address: 0.0.0.0:7777 -``` - -Then you can invoke http://{serverip}:7777/health get summary check result : true or false. - -**Only all registered health checker confirm isHealthy=true,the summary check result will be true,otherwise false** - -Also can invoke http://{serverip}:7777/health/details get details of each health checker reported. \ No newline at end of file diff --git a/samples/metrics-extend-healthcheck/pom.xml b/samples/metrics-extend-healthcheck/pom.xml deleted file mode 100644 index 8c75585534a..00000000000 --- a/samples/metrics-extend-healthcheck/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - samples - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - metrics-extend-healthcheck - Java Chassis::Samples::Metrics::Health Check - - - - org.springframework.boot - spring-boot-starter - - - - org.apache.servicecomb - spring-boot-starter-provider - - - - org.hibernate - hibernate-validator - - - - org.apache.servicecomb - metrics-core - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - diff --git a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/CustomHealthChecker.java b/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/CustomHealthChecker.java deleted file mode 100644 index bd53aa05492..00000000000 --- a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/CustomHealthChecker.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.metrics.extendhealthcheck; - -import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; -import org.apache.servicecomb.foundation.metrics.health.HealthChecker; - - -public class CustomHealthChecker implements HealthChecker { - @Override - public String getName() { - return "custom"; - } - - @Override - public HealthCheckResult check() { - return new HealthCheckResult(true, "custom", "no extra data"); - } -} diff --git a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/ExtendHealthCheckApplication.java b/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/ExtendHealthCheckApplication.java deleted file mode 100644 index 5467ba041d9..00000000000 --- a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/ExtendHealthCheckApplication.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.metrics.extendhealthcheck; - -import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableServiceComb -public class ExtendHealthCheckApplication { - public static void main(String[] args) { - SpringApplication.run(ExtendHealthCheckApplication.class, args); - } -} diff --git a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/MySqlHealthChecker.java b/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/MySqlHealthChecker.java deleted file mode 100644 index 6e11578792f..00000000000 --- a/samples/metrics-extend-healthcheck/src/main/java/org/apache/servicecomb/samples/metrics/extendhealthcheck/MySqlHealthChecker.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.metrics.extendhealthcheck; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; -import org.apache.servicecomb.foundation.metrics.health.HealthChecker; - - -//this is a demo health checker for mysql -public class MySqlHealthChecker implements HealthChecker { - @Override - public String getName() { - return "mysql"; - } - - @Override - public HealthCheckResult check() { - //add your health check code here - Connection connection = null; - try { - connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db?useSSL=false", "root", "pwd"); - return new HealthCheckResult(true, "local mysql health check", ""); - } catch (SQLException e) { - e.printStackTrace(); - return new HealthCheckResult(false, "local mysql health check", e.toString()); - } finally { - if (connection != null) { - try { - connection.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - } - } -} diff --git a/samples/metrics-extend-healthcheck/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.health.HealthChecker b/samples/metrics-extend-healthcheck/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.health.HealthChecker deleted file mode 100644 index f6b0794a409..00000000000 --- a/samples/metrics-extend-healthcheck/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.health.HealthChecker +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.samples.metrics.extendhealthcheck.CustomHealthChecker -org.apache.servicecomb.samples.metrics.extendhealthcheck.MySqlHealthChecker \ No newline at end of file diff --git a/samples/metrics-extend-healthcheck/src/main/resources/microservice.yaml b/samples/metrics-extend-healthcheck/src/main/resources/microservice.yaml deleted file mode 100644 index cb1bf609db0..00000000000 --- a/samples/metrics-extend-healthcheck/src/main/resources/microservice.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -# all interconnected microservices must belong to an application wth the same ID -APPLICATION_ID: metrics -service_description: -# name of the declaring microservice - name: metricsHealthCheckDemo - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:7777 \ No newline at end of file diff --git a/samples/metrics-write-file-sample/README.md b/samples/metrics-write-file-sample/README.md deleted file mode 100644 index 8f3a32c9202..00000000000 --- a/samples/metrics-write-file-sample/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Write Metrics Data into Separate Text Files Sample -## Purpose -This sample show how direct get metrics data and write them into separate text files,then other monitor system can load this file in order to get run state of micro-service. - -## What Contains -### metrics-write-file Module -This module contains the code how poll Monitors data from MonitorManager and convert data to a special format,then write into files. - -**We had designed that will use common Logging component for write file**,and there are many logging implements like log4j,log4j2,logback etc...,so we create *MetricsFileWriter* interface for later autowire. - -### metrics-write-file-log4j2-springboot Module -This module contain log4j2 MetricsFileWriter implement if your project use it as Logging component. - -### metrics-write-file-log4j-springboot Module -This module contain log4j MetricsFileWriter implement if your project use it as Logging component. - -## How to use -Startup ServiceApplication in metrics-write-file-log4j2-springboot or metrics-write-file-log4j-springboot - -1. If start service by maven -```bash -mvn spring-boot:run -``` -you can see metric files had generated in **samples/metrics-write-file-sample/metrics-write-file-log4j(log4j2)-springboot/target/metric** folder,open your browser and make a request to http://localhost:8080/f ,wait a moment then you can see invocation metric files also be generated. - -2. If start service by IDE - -you can see metric files had generated in **target/metric** folder,open your browser and make a request to http://localhost:8080/f ,wait a moment then you can see invocation metric files also be generated. diff --git a/samples/metrics-write-file-sample/metrics-write-file/pom.xml b/samples/metrics-write-file-sample/metrics-write-file/pom.xml deleted file mode 100644 index f8ebd03c6aa..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - metrics-write-file-sample - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - metrics-write-file - Java Chassis::Samples::Metrics::Write File - - - - org.apache.servicecomb - metrics-core - - - - - - - - - - - - - - - - - - diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java b/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java deleted file mode 100644 index 0e85fcf3650..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.mwf; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; -import org.apache.servicecomb.foundation.metrics.MetricsInitializer; -import org.apache.servicecomb.foundation.metrics.PolledEvent; -import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.spectator.api.Measurement; -import com.netflix.spectator.api.Meter; -import com.netflix.spectator.api.Tag; - -/** - * a sample for cloud eye - * - * related product only used logback or log4j2 - * both logback and log4j2 support write to different log file depend on different MDC value - * - * reference sample-logback.xml and sample-log4j2.xml - */ -public class CloudEyeFilePublisher implements MetricsInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(CloudEyeFilePublisher.class); - - private static final Logger CLOUD_EYE_LOGGER = LoggerFactory.getLogger("cloudEyeLogger"); - - private String filePrefix; - - private String hostName; - - @Override - public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) { - eventBus.register(this); - - Microservice microservice = RegistryUtils.getMicroservice(); - filePrefix = microservice.getAppId() + "." + microservice.getServiceName(); - - hostName = NetUtils.getHostName(); - if (StringUtils.isEmpty(hostName)) { - hostName = NetUtils.getHostAddress(); - } - - System.setProperty("cloudEye.logDir", - DynamicPropertyFactory - .getInstance() - .getStringProperty("cloudEye.logDir", "logs") - .get()); - } - - @Subscribe - public void onPolledEvent(PolledEvent event) { - long now = System.currentTimeMillis(); - for (Meter meter : event.getMeters()) { - for (Measurement measurement : meter.measure()) { - logMeasurement(measurement, now); - } - } - } - - protected void logMeasurement(Measurement measurement, long now) { - String metricKey = generateMetricKey(measurement); - - MDC.put("fileName", filePrefix + "." + metricKey + ".dat"); - - CloudEyeMetricModel metricModel = new CloudEyeMetricModel(); - metricModel.setNode(hostName); - metricModel.setTimestamp(now); - metricModel.getDynamicValue().put(metricKey, String.valueOf(measurement.value())); - - CloudEyeModel model = new CloudEyeModel(); - model.setPlugin_id(filePrefix); - model.setMetric(metricModel); - - try { - CLOUD_EYE_LOGGER.info(JsonUtils.writeValueAsString(model)); - } catch (JsonProcessingException e) { - LOGGER.error("Failed to write cloud eye log.", e); - } - } - - protected String generateMetricKey(Measurement measurement) { - StringBuilder sb = new StringBuilder(); - sb.append(measurement.id().name()); - for (Tag tag : measurement.id().tags()) { - sb.append('.').append(tag.value()); - } - return sb.toString(); - } -} diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeMetricModel.java b/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeMetricModel.java deleted file mode 100644 index 9bf1dab269b..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeMetricModel.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.mwf; - -import java.util.HashMap; -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; - -public class CloudEyeMetricModel { - private String node; - - private String scope_name; - - private long timestamp; - - private String inface_name; - - @JsonAnySetter - private Map dynamicValue = new HashMap<>(); - - public String getNode() { - return node; - } - - public void setNode(String node) { - this.node = node; - } - - public String getScope_name() { - return scope_name; - } - - public void setScope_name(String scope_name) { - this.scope_name = scope_name; - } - - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public String getInface_name() { - return inface_name; - } - - public void setInface_name(String inface_name) { - this.inface_name = inface_name; - } - - @JsonAnyGetter - public Map getDynamicValue() { - return dynamicValue; - } - - public void setDynamicValue(Map dynamicValue) { - this.dynamicValue = dynamicValue; - } -} diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeModel.java b/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeModel.java deleted file mode 100644 index f91acfcc940..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeModel.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.mwf; - -public class CloudEyeModel { - private String plugin_id; - - private CloudEyeMetricModel metric; - - public String getPlugin_id() { - return plugin_id; - } - - public void setPlugin_id(String plugin_id) { - this.plugin_id = plugin_id; - } - - public CloudEyeMetricModel getMetric() { - return metric; - } - - public void setMetric(CloudEyeMetricModel metric) { - this.metric = metric; - } -} diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer b/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer deleted file mode 100644 index 3a6ad61ea7c..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.samples.mwf.CloudEyeFilePublisher \ No newline at end of file diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-log4j2.xml b/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-log4j2.xml deleted file mode 100644 index 06fded29f06..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-log4j2.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - %msg%n - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-logback.xml b/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-logback.xml deleted file mode 100644 index 1803d81fa16..00000000000 --- a/samples/metrics-write-file-sample/metrics-write-file/src/main/resources/sample-logback.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - %d [%level] [%thread] - %msg (%F:%L\)%n - - - - - - - - - - - fileName - unknown - - - - - ${cloudEye.logDir}/${fileName} - true - - %msg%n - - - - - - - - - \ No newline at end of file diff --git a/samples/metrics-write-file-sample/pom.xml b/samples/metrics-write-file-sample/pom.xml deleted file mode 100644 index c78458486e1..00000000000 --- a/samples/metrics-write-file-sample/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - samples - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - metrics-write-file-sample - Java Chassis::Samples::Metrics - pom - - metrics-write-file - - - - - - org.apache.servicecomb - metrics-core - 1.2.0-SNAPSHOT - - - - - diff --git a/samples/pojo-sample/README.md b/samples/pojo-sample/README.md deleted file mode 100644 index be92196f467..00000000000 --- a/samples/pojo-sample/README.md +++ /dev/null @@ -1,91 +0,0 @@ -## POJO Sample - -POJO is also called as Transparent Remote Procedure Call (RPC), POJO development mode based on API and API implementation. The service developer does not need to use the description of Spring MVC and JAX-RS. - -### Provider Service - -The transparent RPC development mode supports two service release mode: Spring XML configuration and annotation configuration. - -The Spring XML Configuration Mode: - -* Define a service API. Compile the Java API definition based on the API definition defined before development. -* Implement the service. -* Release the service. Create the `pojoHello.bean.xml` file in the `resources/META-INF/spring` directory and declare the schema in the file. - -The Develop Method by Configure Remarks: - -* Define a service API, which is the same as the Spring XML mode -* Implement the service in the same way as using Spring XML. -* Release the service. `@RpcSchema` is used to define schema during the API Hello implementation. - -[Detail information please refer to Doc](http://servicecomb.apache.org/users/develop-with-transparent-rpc/) - -### Consumer Service - -To call a microservice, you only need to declare a member of a service API type and add the `@RpcReference` annotation for the member, the microservice that depends on the declaration, and the `schemaID`. The sample code is as follows. - -```java -@Component -public class CodeFirstConsumerMain { - @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstHello") - private static Hello hello; - public static void main(String[] args) throws Exception { - //init first - System.out.println(hello.sayHi("World!")); - } -} -``` - -[Detail information please refer to Doc](http://servicecomb.apache.org/users/develop-with-rpc/) - -### Sample Quick Start - -1. Start the ServiceComb/Service Center - - - [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - - make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the pojo-provider service - - - Start provider service by maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `PojoProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #only need to install at first time. - cd samples/pojo-sample/pojo-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.pojo.provider.PojoProviderMain" - ``` - - - Start provider service by IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function `PojoProviderMain` of provider service and `RUN` it like any other Java program. - -3. Start the pojo-consumer service - - Just like how to start pojo-provider service. But the main class of pojo-consumer service is `PojoConsumerMain`. - - ```bash - cd samples/pojo-sample/pojo-consumer/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.pojo.consumer.PojoConsumerMain" - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs if the consumer can invoke the producer: - 1. *'Hello person ServiceComb/Java Chassis'* means the consumer calls sayHello by RpcReference successfully - 2. *'a=1, b=2, result=3'* means the consumer calls compute.add by RpcReference successfully - ​ \ No newline at end of file diff --git a/samples/pojo-sample/pojo-consumer/pom.xml b/samples/pojo-sample/pojo-consumer/pom.xml deleted file mode 100644 index 17f4886e422..00000000000 --- a/samples/pojo-sample/pojo-consumer/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - pojo-sample - 1.2.0-SNAPSHOT - - pojo-consumer - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java b/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java deleted file mode 100644 index 418e31914ea..00000000000 --- a/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.pojo; - -public interface Compute { - - int add(int a, int b); - - int multi(int a, int b); - - int sub(int a, int b); - - int divide(int a, int b); -} diff --git a/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/consumer/PojoConsumerMain.java b/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/consumer/PojoConsumerMain.java deleted file mode 100644 index 4691573c73f..00000000000 --- a/samples/pojo-sample/pojo-consumer/src/main/java/org/apache/servicecomb/samples/pojo/consumer/PojoConsumerMain.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.pojo.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.apache.servicecomb.samples.pojo.Compute; -import org.springframework.stereotype.Component; - -@Component -public class PojoConsumerMain { - - @RpcReference(microserviceName = "hello", schemaId = "hello") - private static Hello hello; - - @RpcReference(microserviceName = "hello", schemaId = "codeFirstCompute") - public static Compute compute; - - public static void main(String[] args) - throws Exception { - init(); - System.out.println(hello.sayHi("Java Chassis")); - Person person = new Person(); - person.setName("ServiceComb/Java Chassis"); - System.out.println(hello.sayHello(person)); - System.out.println("a=1, b=2, result=" + compute.add(1, 2)); - } - - public static void init() - throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/pojo-sample/pojo-consumer/src/main/resources/config/log4j.demo.properties b/samples/pojo-sample/pojo-consumer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/pojo-sample/pojo-consumer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/pojo-sample/pojo-consumer/src/main/resources/microservice.yaml b/samples/pojo-sample/pojo-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index 0709396621f..00000000000 --- a/samples/pojo-sample/pojo-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,35 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: pojo-sample -service_description: - name: helloClient - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance - isolation: - Consumer: - enabled: false - references: - hello: - version-rule: 0.0.1 diff --git a/samples/pojo-sample/pojo-consumer/src/main/resources/microservices/hello/hello.yaml b/samples/pojo-sample/pojo-consumer/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index 32714e60063..00000000000 --- a/samples/pojo-sample/pojo-consumer/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,72 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.pojo.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string - /sayhello: - post: - operationId: sayHello - parameters: - - name: person - in: body - required: true - schema: - $ref: "#/definitions/Person" - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string -definitions: - Person: - type: "object" - properties: - name: - type: "string" - description: "person name" - xml: - name: "Person" diff --git a/samples/pojo-sample/pojo-provider/pom.xml b/samples/pojo-sample/pojo-provider/pom.xml deleted file mode 100644 index 27ae07e3b38..00000000000 --- a/samples/pojo-sample/pojo-provider/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - pojo-sample - 1.2.0-SNAPSHOT - - pojo-provider - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java b/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java deleted file mode 100644 index 418e31914ea..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/Compute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.pojo; - -public interface Compute { - - int add(int a, int b); - - int multi(int a, int b); - - int sub(int a, int b); - - int divide(int a, int b); -} diff --git a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/CodeFirstComputeImpl.java b/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/CodeFirstComputeImpl.java deleted file mode 100644 index 6430ee1fd30..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/CodeFirstComputeImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.pojo.provider; - - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.pojo.Compute; - -@RpcSchema(schemaId = "codeFirstCompute") -public class CodeFirstComputeImpl implements Compute { - @Override - public int add(int a, int b) { - return a + b; - } - - @Override - public int multi(int a, int b) { - return a * b; - } - - @Override - public int sub(int a, int b) { - return a - b; - } - - @Override - public int divide(int a, int b) { - if (b != 0) { - return a / b; - } - return 0; - } -} diff --git a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/HelloImpl.java b/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/HelloImpl.java deleted file mode 100644 index 811640d8253..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/HelloImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.pojo.provider; - - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; - -@RpcSchema(schemaId = "hello") -public class HelloImpl implements Hello { - - @Override - public String sayHi(String name) { - return "Hello " + name; - } - - @Override - public String sayHello(Person person) { - return "Hello person " + person.getName(); - } -} diff --git a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/PojoProviderMain.java b/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/PojoProviderMain.java deleted file mode 100644 index f0190d11e41..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/java/org/apache/servicecomb/samples/pojo/provider/PojoProviderMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.pojo.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class PojoProviderMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/pojo-sample/pojo-provider/src/main/resources/config/log4j.demo.properties b/samples/pojo-sample/pojo-provider/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/pojo-sample/pojo-provider/src/main/resources/microservice.yaml b/samples/pojo-sample/pojo-provider/src/main/resources/microservice.yaml deleted file mode 100644 index 1eda6501cf4..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,29 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: pojo-sample -service_description: - name: hello - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 diff --git a/samples/pojo-sample/pojo-provider/src/main/resources/microservices/hello/hello.yaml b/samples/pojo-sample/pojo-provider/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index 32714e60063..00000000000 --- a/samples/pojo-sample/pojo-provider/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,72 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.pojo.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string - /sayhello: - post: - operationId: sayHello - parameters: - - name: person - in: body - required: true - schema: - $ref: "#/definitions/Person" - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string -definitions: - Person: - type: "object" - properties: - name: - type: "string" - description: "person name" - xml: - name: "Person" diff --git a/samples/pojo-sample/pom.xml b/samples/pojo-sample/pom.xml deleted file mode 100644 index 401ad56c789..00000000000 --- a/samples/pojo-sample/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - pojo-sample - pom - - pojo-provider - pojo-consumer - - diff --git a/samples/pom.xml b/samples/pom.xml deleted file mode 100644 index 3dd3a8cc5cf..00000000000 --- a/samples/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - Java Chassis::Samples - pom - 1.2.0-SNAPSHOT - - codefirst-sample - custom-handler-sample - jaxrs-sample - pojo-sample - springmvc-sample - common-schema - auth-sample - bmi - metrics-write-file-sample - metrics-extend-healthcheck - config-apollo-sample - use-log4j2-sample - local-service-registry - trust-sample - apm-agent - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${project.version} - pom - import - - - org.apache.servicecomb.samples - common-schema - ${project.version} - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - -parameters - UTF-8 - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.rat - apache-rat-plugin - - - .travis.yml - **/*.md - **/target/* - - **/resources/ssl/** - - **/*.proto - - **/*.idl - - - - - - diff --git a/samples/springmvc-sample/README.md b/samples/springmvc-sample/README.md deleted file mode 100644 index 308f33b5564..00000000000 --- a/samples/springmvc-sample/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Spring MVC Sample - -`RestTemplate` is a RESTful API provide by the Spring framework. ServiceComb provides the API for service calling. Users can call microservices using customized URL and `RestTemplate` instance provided by ServiceComb regardless of the specific address of the service. - -* The URL must be in format of ServiceComb: `cse://microserviceName/path?querystring`. -* During use of this URL format, the ServiceComb framework will perform internal microservice descovery, fallbreak, and fault tolerance and send the requests to the microservice providers. - -## Sample Quick Start - -1. Start the ServiceComb/Service Center - - * [how to start the service center](http://servicecomb.apache.org/users/setup-environment/#) - * make sure service center address is configured correctly in `microservice.yaml` file - - ```yaml - cse: - service: - registry: - address: http://127.0.0.1:30100 #service center address - ``` - -2. Start the springmvc-provider service - - * Start provider service by maven - - Compile the source code at root directory of ServiceComb Java Chassis, which is `servicecomb-java-chassis/`, and use `mvn exec` to execute the main class `SpringmvcProviderMain`. - - ```bash - cd servicecomb-java-chassis/ - mvn clean install -Psamples -DskipTests #Only need to install at first time - cd samples/springmvc-sample/springmvc-provider/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.springmvc.provider.SpringmvcProviderMain" - ``` - - * Start provider service by IDE - - Import the project by InteliJ IDEA or Eclipse, add sample module to pom.xml file in root module `servicecomb-java-chassis/pom.xml`, and add `samples` to `` block, Then find `main` function of provider service and `RUN` it like any other Java Program. - -3. Start the springmvc-consumer service - - Just like how to start springmvc-provider service. But the main class of springmvc-consumer service is `SpringmvcConsumerMain`. - - ```bash - cd samples/springmvc-sample/springmvc-consumer/ - mvn exec:java -Dexec.mainClass="org.apache.servicecomb.samples.springmvc.consumer.SpringmvcConsumerMain" - ``` - -4. How to verify - On the producer side, the output should contain the following stuffs if the producer starts up successfully: - 1. *'swagger: 2.0 info: version: 1.0.0 ...'* means the producer generated swagger contracts - 2. *'rest listen success. address=0.0.0.0:8080'* means the rest endpoint is listening on port 8080 - 3. *'highway listen success. address=0.0.0.0:7070'* means the highway endpoint is listening on port 7070 - 4. *'Register microservice instance success'* means the producer has registered successfully to service center - - On the consumer side, you can see the following outputs if the consumer can invoke the producer: - 1. *'RestTemplate consumer sayhi services: Hello Java Chassis'* means the consumer calls sayhi by RestTemplate successfully - 2. *'RestTemplate consumer sayhello services: Hello person ServiceComb/Java Chassis'* means the consumer calls sayhello by RestTemplate successfully - 3. *'POJO consumer sayhi services: Hello Java Chassis'* means the consumer calls sayhi by RpcReference successfully - 4. *'POJO consumer sayhello services: Hello person ServiceComb/Java Chassis'* means the consumer calls sayhello by RpcReference successfully - ​ -## More - -[Develop with RestTemplate](http://servicecomb.apache.org/users/develop-with-rest-template/) \ No newline at end of file diff --git a/samples/springmvc-sample/pom.xml b/samples/springmvc-sample/pom.xml deleted file mode 100644 index c520c2cf897..00000000000 --- a/samples/springmvc-sample/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - springmvc-sample - pom - - springmvc-provider - springmvc-consumer - - diff --git a/samples/springmvc-sample/springmvc-consumer/pom.xml b/samples/springmvc-sample/springmvc-consumer/pom.xml deleted file mode 100644 index 7197129dc50..00000000000 --- a/samples/springmvc-sample/springmvc-consumer/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - springmvc-sample - 1.2.0-SNAPSHOT - - springmvc-consumer - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-springmvc - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java b/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java deleted file mode 100644 index a84d4d76244..00000000000 --- a/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.springmvc.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; -import org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.util.concurrent.ListenableFutureCallback; -import org.springframework.web.client.RestTemplate; - -@Component -public class SpringmvcConsumerMain { - private static final Logger LOG = LoggerFactory.getLogger(SpringmvcConsumerMain.class); - - private static RestTemplate restTemplate = RestTemplateBuilder.create(); - - @RpcReference(microserviceName = "springmvc", schemaId = "springmvcHello") - private static Hello hello; - - public static void main(String[] args) throws Exception { - init(); - Person person = new Person(); - person.setName("ServiceComb/Java Chassis"); - - // RestTemplate Consumer or POJO Consumer. You can choose whatever you like - // RestTemplate Consumer - String sayHiResult = - restTemplate.postForObject("cse://springmvc/springmvchello/sayhi?name=Java Chassis", null, String.class); - String sayHiDefaultResult = - restTemplate.postForObject("cse://springmvc/springmvchello/sayhi", null, String.class); - String sayHelloResult = restTemplate.postForObject("cse://springmvc/springmvchello/sayhello", person, String.class); - System.out.println("RestTemplate Consumer or POJO Consumer. You can choose whatever you like."); - System.out.println("RestTemplate consumer sayhi services: " + sayHiResult); - System.out.println("RestTemplate consumer sayHiDefault services: " + sayHiDefaultResult); - System.out.println("RestTemplate consumer sayhello services: " + sayHelloResult); - - // POJO Consumer - System.out.println("POJO consumer sayhi services: " + hello.sayHi("Java Chassis")); - System.out.println("POJO consumer sayhello services: " + hello.sayHello(person)); - - //AsyncRestTemplate Consumer - CseAsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate(); - ListenableFuture> responseEntityListenableFuture = cseAsyncRestTemplate - .postForEntity("cse://springmvc/springmvchello/sayhi?name=Java Chassis", null, String.class); - ResponseEntity responseEntity = responseEntityListenableFuture.get(); - System.out.println("AsyncRestTemplate Consumer sayHi services: " + responseEntity.getBody()); - - HttpEntity entity = new HttpEntity<>(person); - ListenableFuture> listenableFuture = cseAsyncRestTemplate - .exchange("cse://springmvc/springmvchello/sayhello", HttpMethod.POST, entity, String.class); - // ResponseEntity responseEntity1 = listenableFuture.get(); - // System.out.println("AsyncRestTemplate Consumer sayHello services: " + responseEntity1.getBody()); - - listenableFuture.addCallback( - new ListenableFutureCallback>() { - @Override - public void onFailure(Throwable ex) { - LOG.error("AsyncResTemplate Consumer catched exception when sayHello, ", ex); - } - - @Override - public void onSuccess(ResponseEntity result) { - System.out.println("AsyncRestTemplate Consumer sayHello services: " + result.getBody()); - } - }); - } - - public static void init() throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/springmvc-sample/springmvc-consumer/src/main/resources/config/log4j.demo.properties b/samples/springmvc-sample/springmvc-consumer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/springmvc-sample/springmvc-consumer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservice.yaml b/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservice.yaml deleted file mode 100644 index af852743409..00000000000 --- a/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,32 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvc-sample -service_description: - name: springmvcConsumer - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - handler: - chain: - Consumer: - default: bizkeeper-consumer,loadbalance - isolation: - Consumer: - enabled: false diff --git a/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservices/hello/hello.yaml b/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index 76007e94383..00000000000 --- a/samples/springmvc-sample/springmvc-consumer/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,72 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.springmvc.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string - /sayhello: - post: - operationId: sayHello - parameters: - - name: person - in: body - required: true - schema: - $ref: "#/definitions/Person" - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string -definitions: - Person: - type: "object" - properties: - name: - type: "string" - description: "person name" - xml: - name: "Person" diff --git a/samples/springmvc-sample/springmvc-provider/pom.xml b/samples/springmvc-sample/springmvc-provider/pom.xml deleted file mode 100644 index 6bcbee109f8..00000000000 --- a/samples/springmvc-sample/springmvc-provider/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - springmvc-sample - 1.2.0-SNAPSHOT - - springmvc-provider - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-springmvc - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java b/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java deleted file mode 100644 index c8d8087d804..00000000000 --- a/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.springmvc.provider; - - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.apache.servicecomb.samples.common.schema.Hello; -import org.apache.servicecomb.samples.common.schema.models.Person; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -@RestSchema(schemaId = "springmvcHello") -@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON) -public class SpringmvcHelloImpl implements Hello { - @Override - @RequestMapping(path = "/sayhi", method = RequestMethod.POST) - public String sayHi(@RequestParam(name = "name", defaultValue = "test") String name) { - return "Hello " + name; - } - - @Override - @RequestMapping(path = "/sayhello", method = RequestMethod.POST) - public String sayHello(@RequestBody Person person) { - return "Hello person " + person.getName(); - } -} diff --git a/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcProviderMain.java b/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcProviderMain.java deleted file mode 100644 index 3d516e779ec..00000000000 --- a/samples/springmvc-sample/springmvc-provider/src/main/java/org/apache/servicecomb/samples/springmvc/provider/SpringmvcProviderMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.springmvc.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class SpringmvcProviderMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/springmvc-sample/springmvc-provider/src/main/resources/config/log4j.demo.properties b/samples/springmvc-sample/springmvc-provider/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/springmvc-sample/springmvc-provider/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/springmvc-sample/springmvc-provider/src/main/resources/microservice.yaml b/samples/springmvc-sample/springmvc-provider/src/main/resources/microservice.yaml deleted file mode 100644 index af578139840..00000000000 --- a/samples/springmvc-sample/springmvc-provider/src/main/resources/microservice.yaml +++ /dev/null @@ -1,33 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: springmvc-sample -service_description: - name: springmvc - version: 0.0.2 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - handler: - chain: - Provider: - default: bizkeeper-provider diff --git a/samples/springmvc-sample/springmvc-provider/src/main/resources/microservices/hello/hello.yaml b/samples/springmvc-sample/springmvc-provider/src/main/resources/microservices/hello/hello.yaml deleted file mode 100644 index 76007e94383..00000000000 --- a/samples/springmvc-sample/springmvc-provider/src/main/resources/microservices/hello/hello.yaml +++ /dev/null @@ -1,72 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -swagger: '2.0' -info: - title: hello - version: 1.0.0 - x-java-interface: org.apache.servicecomb.samples.springmvc.Hello -basePath: /pojo/rest/hello -produces: - - application/json - -paths: - /sayhi: - post: - operationId: sayHi - parameters: - - name: name - in: body - required: true - schema: - type: string - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string - /sayhello: - post: - operationId: sayHello - parameters: - - name: person - in: body - required: true - schema: - $ref: "#/definitions/Person" - responses: - 200: - description: 正确返回 - schema: - type: string - default: - description: 默认返回 - schema: - type: string -definitions: - Person: - type: "object" - properties: - name: - type: "string" - description: "person name" - xml: - name: "Person" diff --git a/samples/trust-sample/README.md b/samples/trust-sample/README.md deleted file mode 100644 index e3a0694227c..00000000000 --- a/samples/trust-sample/README.md +++ /dev/null @@ -1,4 +0,0 @@ -## Trust Sample -This sample shows using public key mechanism to authenticate user and black/white user list. The public key mechanism security is based on Service Center, and users should first configure Service Center authentication. This sample does not show how to configure Service Center authentication. - -In this sample, both customer and hacker try to access store, while store configure it's black list to deny hacker's access. \ No newline at end of file diff --git a/samples/trust-sample/customer/pom.xml b/samples/trust-sample/customer/pom.xml deleted file mode 100644 index 73329554e9d..00000000000 --- a/samples/trust-sample/customer/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - trust-sample - 1.2.0-SNAPSHOT - - customer - - - org.apache.servicecomb - handler-publickey-auth - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/Compute.java b/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/Compute.java deleted file mode 100644 index b9557b2dc25..00000000000 --- a/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/Compute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.trust; - -public interface Compute { - - int add(int a, int b); - - int multi(int a, int b); - - int sub(int a, int b); - - int divide(int a, int b); -} diff --git a/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/consumer/CustomerMain.java b/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/consumer/CustomerMain.java deleted file mode 100644 index 5c277444efa..00000000000 --- a/samples/trust-sample/customer/src/main/java/org/apache/servicecomb/samples/trust/consumer/CustomerMain.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.trust.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.samples.trust.Compute; -import org.springframework.stereotype.Component; - -@Component -public class CustomerMain { - - @RpcReference(microserviceName = "store", schemaId = "codeFirstCompute") - public static Compute compute; - - public static void main(String[] args) - throws Exception { - init(); - System.out.println("a=1, b=2, result=" + compute.add(1, 2)); - } - - public static void init() - throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/trust-sample/customer/src/main/resources/config/log4j.demo.properties b/samples/trust-sample/customer/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/trust-sample/customer/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/trust-sample/customer/src/main/resources/microservice.yaml b/samples/trust-sample/customer/src/main/resources/microservice.yaml deleted file mode 100644 index c96ce3816ec..00000000000 --- a/samples/trust-sample/customer/src/main/resources/microservice.yaml +++ /dev/null @@ -1,37 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: trust-sample -service_description: - name: customer - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - isolation: - Consumer: - enabled: false - references: - hello: - version-rule: 0.0.1 - handler: - chain: - Consumer: - default: loadbalance,auth-consumer - Provider: - default: auth-provider diff --git a/samples/trust-sample/hacker/pom.xml b/samples/trust-sample/hacker/pom.xml deleted file mode 100644 index 26d3f6583dd..00000000000 --- a/samples/trust-sample/hacker/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - trust-sample - 1.2.0-SNAPSHOT - - hacker - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-publickey-auth - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/Compute.java b/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/Compute.java deleted file mode 100644 index b9557b2dc25..00000000000 --- a/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/Compute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.trust; - -public interface Compute { - - int add(int a, int b); - - int multi(int a, int b); - - int sub(int a, int b); - - int divide(int a, int b); -} diff --git a/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/consumer/HackerMain.java b/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/consumer/HackerMain.java deleted file mode 100644 index 64773193b9f..00000000000 --- a/samples/trust-sample/hacker/src/main/java/org/apache/servicecomb/samples/trust/consumer/HackerMain.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.trust.consumer; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.samples.trust.Compute; -import org.springframework.stereotype.Component; - -@Component -public class HackerMain { - @RpcReference(microserviceName = "store", schemaId = "codeFirstCompute") - public static Compute compute; - - public static void main(String[] args) - throws Exception { - init(); - System.out.println("a=1, b=2, result=" + compute.add(1, 2)); - } - - public static void init() - throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/trust-sample/hacker/src/main/resources/config/log4j.demo.properties b/samples/trust-sample/hacker/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/trust-sample/hacker/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/trust-sample/hacker/src/main/resources/microservice.yaml b/samples/trust-sample/hacker/src/main/resources/microservice.yaml deleted file mode 100644 index ec33b21baa6..00000000000 --- a/samples/trust-sample/hacker/src/main/resources/microservice.yaml +++ /dev/null @@ -1,37 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: trust-sample -service_description: - name: hacker - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - isolation: - Consumer: - enabled: false - references: - hello: - version-rule: 0.0.1 - handler: - chain: - Consumer: - default: loadbalance,auth-consumer - Provider: - default: auth-provider diff --git a/samples/trust-sample/pom.xml b/samples/trust-sample/pom.xml deleted file mode 100644 index ac546f7f4fb..00000000000 --- a/samples/trust-sample/pom.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - samples - 1.2.0-SNAPSHOT - - trust-sample - pom - - store - customer - hacker - - diff --git a/samples/trust-sample/store/pom.xml b/samples/trust-sample/store/pom.xml deleted file mode 100644 index 9f031509bac..00000000000 --- a/samples/trust-sample/store/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - 4.0.0 - - org.apache.servicecomb.samples - trust-sample - 1.2.0-SNAPSHOT - - store - - - org.apache.servicecomb - handler-bizkeeper - - - org.apache.servicecomb - handler-publickey-auth - - - org.apache.servicecomb - handler-loadbalance - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - handler-flowcontrol-qps - - - org.apache.servicecomb - provider-pojo - - - org.slf4j - slf4j-log4j12 - - - org.apache.servicecomb.samples - common-schema - - - diff --git a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/Compute.java b/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/Compute.java deleted file mode 100644 index b9557b2dc25..00000000000 --- a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/Compute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.samples.trust; - -public interface Compute { - - int add(int a, int b); - - int multi(int a, int b); - - int sub(int a, int b); - - int divide(int a, int b); -} diff --git a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/CodeFirstComputeImpl.java b/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/CodeFirstComputeImpl.java deleted file mode 100644 index 9c21237ee91..00000000000 --- a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/CodeFirstComputeImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.trust.provider; - - -import org.apache.servicecomb.provider.pojo.RpcSchema; -import org.apache.servicecomb.samples.trust.Compute; - -@RpcSchema(schemaId = "codeFirstCompute") -public class CodeFirstComputeImpl implements Compute { - @Override - public int add(int a, int b) { - return a + b; - } - - @Override - public int multi(int a, int b) { - return a * b; - } - - @Override - public int sub(int a, int b) { - return a - b; - } - - @Override - public int divide(int a, int b) { - if (b != 0) { - return a / b; - } - return 0; - } -} diff --git a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/TrustMain.java b/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/TrustMain.java deleted file mode 100644 index fcab51b38c8..00000000000 --- a/samples/trust-sample/store/src/main/java/org/apache/servicecomb/samples/trust/provider/TrustMain.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.trust.provider; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; - -public class TrustMain { - - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - } -} diff --git a/samples/trust-sample/store/src/main/resources/config/log4j.demo.properties b/samples/trust-sample/store/src/main/resources/config/log4j.demo.properties deleted file mode 100644 index e7a487da70e..00000000000 --- a/samples/trust-sample/store/src/main/resources/config/log4j.demo.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/logs/ -paas.logs.file=sample.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/samples/trust-sample/store/src/main/resources/microservice.yaml b/samples/trust-sample/store/src/main/resources/microservice.yaml deleted file mode 100644 index 4358d42b1cd..00000000000 --- a/samples/trust-sample/store/src/main/resources/microservice.yaml +++ /dev/null @@ -1,48 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: trust-sample -service_description: - name: store - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 - highway: - address: 0.0.0.0:7070 - handler: - chain: - Consumer: - default: loadbalance,auth-consumer - Provider: - default: auth-provider - publicKey: - accessControl: - black: - list01: - category: property ## property, fixed value - propertyName: serviceName ## property name, e.g. serviceName, appId, environment, alias, version and so on, also support key in properties. - rule: hacker ## property value match expression. -##if propertyName is serviceName, only supports prefix match and postfix match and exactly match. e.g. hacker*, *hacker, hacker - white: - list02: - category: property - propertyName: serviceName - rule: cust* \ No newline at end of file diff --git a/samples/use-log4j2-sample/pom.xml b/samples/use-log4j2-sample/pom.xml deleted file mode 100644 index 31f9cb4ebd5..00000000000 --- a/samples/use-log4j2-sample/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - samples - org.apache.servicecomb.samples - 1.2.0-SNAPSHOT - - 4.0.0 - - use-log4j2-sample - - - UTF-8 - UTF-8 - 1.8 - ${project.version} - - - - - - org.apache.servicecomb - java-chassis-dependencies - ${java-chassis.version} - pom - import - - - - - - - org.apache.servicecomb - transport-rest-vertx - - - org.apache.servicecomb - transport-highway - - - org.apache.servicecomb - provider-pojo - - - log4j - log4j - - - - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-core - - - \ No newline at end of file diff --git a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Application.java b/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Application.java deleted file mode 100644 index af2e674536e..00000000000 --- a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Application.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.uselog4j2; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; - -public class Application { - public static void main(String[] args) { - BeanUtils.init(); - } -} \ No newline at end of file diff --git a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Hello.java b/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Hello.java deleted file mode 100644 index 5b35784a0cb..00000000000 --- a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/Hello.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.uselog4j2; - -public interface Hello { - String hello(); -} \ No newline at end of file diff --git a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/HelloImpl.java b/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/HelloImpl.java deleted file mode 100644 index 1c9d9e4e4b6..00000000000 --- a/samples/use-log4j2-sample/src/main/java/org/apache/servicecomb/samples/uselog4j2/HelloImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.samples.uselog4j2; - -import org.apache.servicecomb.provider.pojo.RpcSchema; - -@RpcSchema(schemaId = "hello") -public class HelloImpl implements Hello { - - public String hello() { - return "Hello World!"; - } -} \ No newline at end of file diff --git a/samples/use-log4j2-sample/src/main/resources/log4j2.xml b/samples/use-log4j2-sample/src/main/resources/log4j2.xml deleted file mode 100644 index 0651a7b5db5..00000000000 --- a/samples/use-log4j2-sample/src/main/resources/log4j2.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - ./samples/use-log4j2-sample/target/log/ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/use-log4j2-sample/src/main/resources/microservice.yaml b/samples/use-log4j2-sample/src/main/resources/microservice.yaml deleted file mode 100644 index 3147b3e6862..00000000000 --- a/samples/use-log4j2-sample/src/main/resources/microservice.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: samples -service_description: - name: uselog4j2 - version: 0.0.1 -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - rest: - address: 0.0.0.0:8080 \ No newline at end of file diff --git a/scripts/change_pom.py b/scripts/change_pom.py deleted file mode 100644 index f2e274054cf..00000000000 --- a/scripts/change_pom.py +++ /dev/null @@ -1,59 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -import os - -try: - import xml.etree.cElementTree as ET -except: - import xml.etree.ElementTree as ET - -dir_path = os.path.dirname(os.path.realpath(__file__)) -project_dir = os.path.dirname(dir_path) -VERSION = os.getenv("VERSION") - - -def change_pom(pom_path): - print('changing' + pom_path) - tree = ET.parse(pom_path) - ET.register_namespace('', "http://maven.apache.org/POM/4.0.0") - root = tree.getroot() - POM_NS = "{http://maven.apache.org/POM/4.0.0}" - print 'replace first level vesion' - for child in tree.iterfind('%sversion' % (POM_NS)): - print 'change from ' + child.text + " to " + VERSION - child.text = VERSION - print 'replace second level vesion' - for child in tree.iterfind('%sparent' % (POM_NS)): - if child.find('%sgroupId' % POM_NS).text == "org.apache.servicecomb": - if child.find('%sversion' % POM_NS) is not None: - print 'change module version from ' + child.find('%sversion' % POM_NS).text + " to " + VERSION - child.find('%sversion' % POM_NS).text = VERSION - print 'replace cse dependency version' - for child in tree.iter('%sdependency' % (POM_NS)): - if child.find('%sgroupId' % POM_NS).text == "org.apache.servicecomb": - if child.find('%sversion' % POM_NS) is not None: - print 'change module version from ' + child.find('%sversion' % POM_NS).text + " to " + VERSION - child.find('%sversion' % POM_NS).text = VERSION - tree.write(pom_path) - - -if __name__ == "__main__": - for root, dirs, files in os.walk(project_dir): - for file in files: - if file.endswith("pom.xml"): - change_pom(os.path.join(root, file)) diff --git a/scripts/travis.sh b/scripts/travis.sh deleted file mode 100755 index dd55df63627..00000000000 --- a/scripts/travis.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- -#bin/sh - -##Check if the commit is tagged commit or not -TAGGEDCOMMIT=$(git tag -l --contains HEAD) -if [ "$TAGGEDCOMMIT" == "" ]; then - TAGGEDCOMMIT=false -else - TAGGEDCOMMIT=true -fi -echo $TAGGEDCOMMIT - - -if [ "$1" == "install" ]; then - if [ "$TAGGEDCOMMIT" == "true" ]; then - echo "Skipping the installation as it is tagged commit" - else - mvn apache-rat:check -Pit,samples,distribution - if [ $? != 0 ]; then - echo "${red}Rat check failed.${reset}" - exit 1 - fi - - mvn clean install -Ddocker.showLogs -Pdocker -Pjacoco -Pit -Pcoverage coveralls:report - if [ $? == 0 ]; then - echo "${green}Installation Success..${reset}" - else - echo "${red}Installation or Test Cases failed, please check the above logs for more details.${reset}" - exit 1 - fi - fi - echo "Installation Completed" -else - if [ "$TAGGEDCOMMIT" == "true" ]; then - echo "Decrypting the key" - openssl aes-256-cbc -K $encrypted_6d31958a1ad0_key -iv $encrypted_6d31958a1ad0_iv -in gpg-sec.tar.enc -out gpg-sec.tar -d - tar xvf gpg-sec.tar - echo "Deploying Staging Release" - mvn deploy -DskipTests -Prelease -Pdistribution -Ppassphrase --settings .travis.settings.xml - if [ $? == 0 ]; then - echo "${green}Staging Deployment is Success, please log on to Nexus Repo to see the staging release..${reset}" - else - echo "${red}Staging Release deployment failed.${reset}" - exit 1 - fi - else - echo "Deploy a Non-Signed Staging Release" - mvn deploy -DskipTests --settings .travis.settings.xml - if [ $? == 0 ]; then - echo "${green}Snapshot Deployment is Success, please log on to Nexus Repo to see the snapshot release..${reset}" - else - echo "${red}Snapshot deployment failed.${reset}" - # No need to exit 1 here as the snapshot depoyment will fail for private builds as decryption of password is allowed for ServiceComb repo and not forked repo's. - fi - - fi - echo "Deployment Completed" -fi diff --git a/service-registry/pom.xml b/service-registry/pom.xml index 5324bacf606..252d89eb433 100644 --- a/service-registry/pom.xml +++ b/service-registry/pom.xml @@ -21,55 +21,23 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default 4.0.0 - service-registry + service-registry-parent Java Chassis::Service Registry + pom - - - org.apache.servicecomb - deployment - - - org.apache.servicecomb - foundation-vertx - - - org.apache.servicecomb - foundation-config - - - org.apache.servicecomb - foundation-common - - - - io.vertx - vertx-codegen - provided - - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - org.apache.servicecomb - foundation-test-scaffolding - - - org.apache.commons - commons-lang3 - - + + registry-local + registry-service-center + registry-lightweight + registry-zero-config + registry-nacos + registry-zookeeper + registry-etcd + registry-consul + diff --git a/service-registry/registry-consul/pom.xml b/service-registry/registry-consul/pom.xml new file mode 100644 index 00000000000..380b9ea45fc --- /dev/null +++ b/service-registry/registry-consul/pom.xml @@ -0,0 +1,54 @@ + + + + + 4.0.0 + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + + registry-consul + Java Chassis::Service Registry::Consul + + + + org.kiwiproject + consul-client + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + java-chassis-core + + + com.google.code.gson + gson + + + diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConfiguration.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConfiguration.java new file mode 100644 index 00000000000..36422f0f110 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConfiguration.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +import com.google.common.net.HostAndPort; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.consul.config.ConsulDiscoveryProperties; +import org.apache.servicecomb.registry.consul.config.ConsulProperties; +import org.kiwiproject.consul.Consul; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@ConditionalOnProperty(prefix = "servicecomb.registry.consul", name = "enabled", matchIfMissing = true) +@Configuration +public class ConsulConfiguration { + + @Bean + @ConfigurationProperties(prefix = ConsulConst.CONSUL_REGISTRY_PREFIX) + @ConditionalOnMissingBean + public ConsulProperties consulProperties() { + return new ConsulProperties(); + } + + @Bean + @ConfigurationProperties(prefix = ConsulConst.CONSUL_DISCOVERY_REGISTRY_PREFIX) + @ConditionalOnMissingBean + public ConsulDiscoveryProperties consulDiscoveryProperties() { + return new ConsulDiscoveryProperties(); + } + + @Bean + @ConditionalOnBean(value = {ConsulProperties.class, ConsulDiscoveryProperties.class}) + @ConditionalOnMissingBean + public Consul consulClient(ConsulProperties consulProperties, ConsulDiscoveryProperties consulDiscoveryProperties) { + Consul.Builder builder = Consul.builder() + .withHostAndPort(HostAndPort.fromParts(consulProperties.getHost(), consulProperties.getPort())); + if (StringUtils.isNotBlank(consulDiscoveryProperties.getAclToken())) { + builder.withAclToken(consulDiscoveryProperties.getAclToken()); + } + return builder.build(); + } + + @Bean + @ConditionalOnBean(value = {Consul.class, Environment.class, RegistrationId.class, DataCenterProperties.class}) + @ConditionalOnMissingBean + public ConsulDiscovery consulDiscovery() { + return new ConsulDiscovery(); + } + + @Bean + @ConditionalOnBean(value = {Consul.class, Environment.class, RegistrationId.class, DataCenterProperties.class}) + @ConditionalOnMissingBean + public ConsulRegistration consulRegistration() { + return new ConsulRegistration(); + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConst.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConst.java new file mode 100644 index 00000000000..7074c34a3e0 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulConst.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +public class ConsulConst { + + public static final String CONSUL_REGISTRY_NAME = "consul-registry"; + + public static final String CONSUL_REGISTRY_PREFIX = "servicecomb.registry.consul"; + + public static final String CONSUL_DISCOVERY_REGISTRY_PREFIX = "servicecomb.registry.consul.discovery"; + + public static final String CONSUL_DEFAULT_ENVIRONMENT = "production"; +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscovery.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscovery.java new file mode 100644 index 00000000000..ce16ccc47b3 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscovery.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.registry.consul.config.ConsulDiscoveryProperties; +import org.apache.servicecomb.registry.consul.config.ConsulProperties; +import org.kiwiproject.consul.Consul; +import org.kiwiproject.consul.HealthClient; +import org.kiwiproject.consul.cache.ServiceHealthCache; +import org.kiwiproject.consul.cache.ServiceHealthKey; +import org.kiwiproject.consul.model.health.Service; +import org.kiwiproject.consul.model.health.ServiceHealth; +import org.kiwiproject.consul.option.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ConsulDiscovery implements Discovery { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDiscovery.class); + + @Resource + private ConsulProperties consulProperties; + + @Resource + private ConsulDiscoveryProperties consulDiscoveryProperties; + + @Resource + private Consul consulClient; + + @Resource + private Environment environment; + + private List consulDiscoveryInstanceList; + + private InstanceChangedListener instanceChangedListener; + + private ServiceHealthCache svHealth; + + @Override + public String name() { + return ConsulConst.CONSUL_REGISTRY_NAME; + } + + @Override + public boolean enabled(String application, String serviceName) { + return consulDiscoveryProperties.isEnabled(); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + LOGGER.info("findServiceInstances application:{}, serviceName:{}", application, serviceName); + consulDiscoveryInstanceList = getInstances(serviceName); + return consulDiscoveryInstanceList; + } + + @Override + public List findServices(String application) { + LOGGER.info("ConsulDiscovery findServices(application={})", application); + Map> response = consulClient.catalogClient().getServices().getResponse(); + if (!CollectionUtils.isEmpty(response)) { + return Lists.newArrayList(response.keySet()); + } + return Lists.newArrayList(); + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + this.instanceChangedListener = instanceChangedListener; + } + + @Override + public boolean enabled() { + return consulDiscoveryProperties.isEnabled(); + } + + @Override + public void init() { + LOGGER.info("ConsulDiscovery init"); + } + + @Override + public void run() { + LOGGER.info("ConsulDiscovery run"); + String serviceName = BootStrapProperties.readServiceName(environment); + HealthClient healthClient = consulClient.healthClient(); + svHealth = ServiceHealthCache.newCache(healthClient, serviceName, true, Options.BLANK_QUERY_OPTIONS, + consulDiscoveryProperties.getWatchSeconds()); + svHealth.addListener((Map newValues) -> instanceChangedListener.onInstanceChanged( + name(), BootStrapProperties.readApplication(environment), serviceName, getInstances(serviceName))); + svHealth.start(); + } + + @Override + public void destroy() { + if (svHealth != null) { + svHealth.stop(); + } + String serviceId = consulDiscoveryProperties.getServiceId(); + LOGGER.info("ConsulDiscovery destroy consul service id={}", serviceId); + if (consulClient != null) { + LOGGER.info("ConsulDiscovery consulClient destroy"); + consulClient.agentClient().deregister(serviceId); + consulClient.destroy(); + } + } + + public List getInstances(@NotNull final String serviceName) { + List instances = new ArrayList<>(); + addInstancesToList(instances, serviceName); + return instances; + } + + private void addInstancesToList(List instances, String serviceName) { + List healthServices = getHealthServices(serviceName); + if (!CollectionUtils.isEmpty(healthServices)) { + for (ServiceHealth serviceHealth : healthServices) { + Service service = serviceHealth.getService(); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + ConsulInstance consulInstance = gson.fromJson(service.getMeta().get("meta"), ConsulInstance.class); + instances.add(new ConsulDiscoveryInstance(consulInstance)); + } + } + } + + private List getHealthServices(String serviceName) { + HealthClient healthClient = consulClient.healthClient(); + return healthClient.getHealthyServiceInstances(serviceName).getResponse(); + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscoveryInstance.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscoveryInstance.java new file mode 100644 index 00000000000..f07e4a40543 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulDiscoveryInstance.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +import org.apache.servicecomb.registry.api.DiscoveryInstance; + +public class ConsulDiscoveryInstance extends ConsulInstance implements DiscoveryInstance { + + public ConsulDiscoveryInstance(ConsulInstance consulInstance) { + super(consulInstance); + } + + @Override + public String getRegistryName() { + return ConsulConst.CONSUL_REGISTRY_NAME; + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulInstance.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulInstance.java new file mode 100644 index 00000000000..722b3bbe28e --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulInstance.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstance; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ConsulInstance implements MicroserviceInstance { + private String serviceId; + + private String instanceId; + + private String environment; + + private String application; + + private String serviceName; + + private String alias; + + private String version; + + private String description; + + private DataCenterInfo dataCenterInfo; + + private List endpoints = new ArrayList<>(); + + private Map schemas = new HashMap<>(); + + private Map properties = new HashMap<>(); + + private MicroserviceInstanceStatus status; + + public ConsulInstance() { + + } + + public ConsulInstance(ConsulInstance other) { + this.serviceId = other.serviceId; + this.instanceId = other.instanceId; + this.environment = other.environment; + this.application = other.application; + this.serviceName = other.serviceName; + this.alias = other.alias; + this.version = other.version; + this.description = other.description; + this.dataCenterInfo = other.dataCenterInfo; + this.endpoints = other.endpoints; + this.schemas = other.schemas; + this.properties = other.properties; + this.status = other.status; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public void setApplication(String application) { + this.application = application; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { + this.dataCenterInfo = dataCenterInfo; + } + + public void setEndpoints(List endpoints) { + this.endpoints = endpoints; + } + + public void setSchemas(Map schemas) { + this.schemas = schemas; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setStatus(MicroserviceInstanceStatus status) { + this.status = status; + } + + @Override + public String getEnvironment() { + return this.environment; + } + + @Override + public String getApplication() { + return this.application; + } + + @Override + public String getServiceName() { + return this.serviceName; + } + + @Override + public String getAlias() { + return alias; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo == null ? new DataCenterInfo() : dataCenterInfo; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public Map getProperties() { + return properties; + } + + @Override + public Map getSchemas() { + return schemas; + } + + @Override + public List getEndpoints() { + return endpoints; + } + + public void addSchema(String schemaId, String content) { + this.schemas.put(schemaId, content); + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } + + public void addProperty(String key, String value) { + this.properties.put(key, value); + } + + @Override + public String getInstanceId() { + return instanceId; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return this.status; + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistration.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistration.java new file mode 100644 index 00000000000..6458d250fe7 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistration.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import jakarta.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.invocation.endpoint.EndpointUtils; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.servicecomb.registry.consul.config.ConsulDiscoveryProperties; +import org.kiwiproject.consul.AgentClient; +import org.kiwiproject.consul.Consul; +import org.kiwiproject.consul.model.agent.ImmutableRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class ConsulRegistration implements Registration { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulRegistration.class); + + private ConsulInstance consulInstance; + + @Resource + private ConsulDiscoveryProperties consulDiscoveryProperties; + + @Resource + private Consul consulClient; + + @Resource + private Environment environment; + + @Resource + private DataCenterProperties dataCenterProperties; + + @Resource + private RegistrationId registrationId; + + @Value("${servicecomb.rest.address:127.0.0.1:8080}") + private String restAddress; + + private ImmutableRegistration.Builder registrationBuilder; + + @Override + public String name() { + return ConsulConst.CONSUL_REGISTRY_NAME; + } + + @Override + public ConsulRegistrationInstance getMicroserviceInstance() { + return new ConsulRegistrationInstance(consulInstance); + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + consulInstance.setStatus(status); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + Map meta = new HashMap<>(); + meta.put("meta", gson.toJson(consulInstance)); + registrationBuilder.meta(meta); + ImmutableRegistration newService = registrationBuilder.build(); + AgentClient agentClient = consulClient.agentClient(); + agentClient.register(newService); + return true; + } + + @Override + public void addSchema(String schemaId, String content) { + if (consulDiscoveryProperties.isEnableSwaggerRegistration()) { + consulInstance.addSchema(schemaId, content); + } + } + + @Override + public void addEndpoint(String endpoint) { + consulInstance.addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + consulInstance.addProperty(key, value); + } + + @Override + public boolean enabled() { + return consulDiscoveryProperties.isEnabled(); + } + + @Override + public void init() { + LOGGER.info("ConsulRegistration init"); + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ConsulConst.CONSUL_DEFAULT_ENVIRONMENT; + } + String instanceId = registrationId.getInstanceId(); + consulInstance = new ConsulInstance(); + consulInstance.setInstanceId(instanceId); + consulInstance.setEnvironment(env); + consulInstance.setApplication(BootStrapProperties.readApplication(environment)); + consulInstance.setServiceName(BootStrapProperties.readServiceName(environment)); + consulInstance.setAlias(BootStrapProperties.readServiceAlias(environment)); + consulInstance.setDescription(BootStrapProperties.readServiceDescription(environment)); + if (StringUtils.isNotEmpty(dataCenterProperties.getName())) { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setName(dataCenterProperties.getName()); + dataCenterInfo.setRegion(dataCenterProperties.getRegion()); + dataCenterInfo.setAvailableZone(dataCenterProperties.getAvailableZone()); + consulInstance.setDataCenterInfo(dataCenterInfo); + } + consulInstance.setProperties(BootStrapProperties.readServiceProperties(environment)); + consulInstance.setVersion(BootStrapProperties.readServiceVersion(environment)); + consulInstance.setStatus( + MicroserviceInstanceStatus.valueOf(BootStrapProperties.readServiceInstanceInitialStatus(environment))); + } + + @Override + public void run() { + LOGGER.info("ConsulRegistration run"); + registrationBuilder = ImmutableRegistration.builder() + .name(consulInstance.getServiceName()); + List endpoints = consulInstance.getEndpoints(); + for (String endpoint : endpoints) { + Endpoint temp = EndpointUtils.parse(endpoint); + if (temp.getAddress() instanceof URIEndpointObject) { + String hostOrIp = ((URIEndpointObject) temp.getAddress()).getHostOrIp(); + int port = ((URIEndpointObject) temp.getAddress()).getPort(); + String serviceId = hostOrIp + ":" + port; + consulDiscoveryProperties.setServiceId(serviceId); + consulInstance.setServiceId(serviceId); + registrationBuilder.id(serviceId); + registrationBuilder.address(hostOrIp); + registrationBuilder.port(port); + break; + } + } + List tags = consulDiscoveryProperties.getTags(); + if (CollectionUtils.isEmpty(tags)) { + tags.add(consulInstance.getServiceName()); + } + registrationBuilder.tags(tags); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + Map meta = new HashMap<>(); + meta.put("meta", gson.toJson(consulInstance)); + registrationBuilder.meta(meta); + ImmutableRegistration newService = registrationBuilder.build(); + AgentClient agentClient = consulClient.agentClient(); + agentClient.register(newService); + LOGGER.info("ConsulRegistration newService"); + } + + @Override + public void destroy() { + LOGGER.info("ConsulRegistration destroy"); + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistrationInstance.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistrationInstance.java new file mode 100644 index 00000000000..dc0b83eaefc --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/ConsulRegistrationInstance.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul; + + +import org.apache.servicecomb.registry.api.RegistrationInstance; + +public class ConsulRegistrationInstance extends ConsulInstance implements RegistrationInstance { + + public ConsulRegistrationInstance(ConsulInstance instance) { + super(instance); + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulDiscoveryProperties.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulDiscoveryProperties.java new file mode 100644 index 00000000000..a6a23192eb4 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulDiscoveryProperties.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul.config; + +import org.springframework.core.style.ToStringCreator; + +import java.util.ArrayList; +import java.util.List; + + +public class ConsulDiscoveryProperties { + + private String aclToken; + + private List tags = new ArrayList<>(); + + private Boolean enabled = true; + + private Integer watchSeconds = 8; + + private Boolean enableSwaggerRegistration = false; + + private String serviceId; + + public String getAclToken() { + return this.aclToken; + } + + public void setAclToken(String aclToken) { + this.aclToken = aclToken; + } + + public List getTags() { + return this.tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public Boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean isEnableSwaggerRegistration() { + return enableSwaggerRegistration; + } + + public void setEnableSwaggerRegistration(Boolean enableSwaggerRegistration) { + this.enableSwaggerRegistration = enableSwaggerRegistration; + } + + public Integer getWatchSeconds() { + return watchSeconds; + } + + public void setWatchSeconds(Integer watchSeconds) { + this.watchSeconds = watchSeconds; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + @Override + public String toString() { + return new ToStringCreator(this).append("aclToken", this.aclToken) + .append("enabled", this.enabled) + .append("serviceId", this.serviceId) + .append("tags", this.tags) + .append("watchSeconds", this.watchSeconds) + .toString(); + } +} diff --git a/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulProperties.java b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulProperties.java new file mode 100644 index 00000000000..bb04a758330 --- /dev/null +++ b/service-registry/registry-consul/src/main/java/org/apache/servicecomb/registry/consul/config/ConsulProperties.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.consul.config; + +import jakarta.validation.constraints.NotNull; + +import org.springframework.validation.annotation.Validated; + + +@Validated +public class ConsulProperties { + + @NotNull + private String host = "localhost"; + + private String scheme = "http"; + + @NotNull + private Integer port = 8500; + + private Boolean enabled = true; + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return this.port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getScheme() { + return this.scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + @Override + public String toString() { + return "ConsulProperties{" + "host='" + this.host + '\'' + ", port=" + this.port + ", scheme=" + this.scheme + + ", enabled=" + this.enabled + "}"; + } +} diff --git a/service-registry/registry-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..9a0422d67c2 --- /dev/null +++ b/service-registry/registry-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.consul.ConsulConfiguration diff --git a/service-registry/registry-etcd/pom.xml b/service-registry/registry-etcd/pom.xml new file mode 100644 index 00000000000..10c037a03aa --- /dev/null +++ b/service-registry/registry-etcd/pom.xml @@ -0,0 +1,52 @@ + + + + + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-etcd + Java Chassis::Service Registry::Etcd + + + + + io.etcd + jetcd-core + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + java-chassis-core + + + + diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConfiguration.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConfiguration.java new file mode 100644 index 00000000000..a926c7bbc11 --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConfiguration.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EtcdConfiguration { + @Bean + @ConfigurationProperties(prefix = EtcdConst.ETCD_REGISTRY_PREFIX) + public EtcdRegistryProperties etcdRegistryProperties() { + return new EtcdRegistryProperties(); + } + + @Bean + public EtcdDiscovery etcdDiscovery() { + return new EtcdDiscovery(); + } + + @Bean + public EtcdRegistration etcdRegistration() { + return new EtcdRegistration(); + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConst.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConst.java new file mode 100644 index 00000000000..03b28f0d2ae --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdConst.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +public class EtcdConst { + + public static final String ETCD_REGISTRY_NAME = "etcd-registry"; + + public static final String ETCD_DISCOVERY_ROOT = "/servicecomb/registry/%s"; + + public static final String ETCD_REGISTRY_PREFIX = "servicecomb.registry.etcd"; + + public static final String ETCD_DISCOVERY_ENABLED = ETCD_REGISTRY_PREFIX + ".%s.%s.enabled"; + + public static final String ETCD_DEFAULT_ENVIRONMENT = "production"; +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscovery.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscovery.java new file mode 100644 index 00000000000..b43b9bdabd9 --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscovery.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.ConditionWaiter; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.foundation.common.utils.MuteExceptionUtil; +import org.apache.servicecomb.registry.api.Discovery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.collect.Lists; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.Watch; +import io.etcd.jetcd.kv.GetResponse; +import io.etcd.jetcd.options.GetOption; +import io.etcd.jetcd.options.WatchOption; + +public class EtcdDiscovery implements Discovery { + + private Environment environment; + + private String basePath; + + private EtcdRegistryProperties etcdRegistryProperties; + + private Client client; + + private InstanceChangedListener instanceChangedListener; + + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdDiscovery.class); + + private Map watchMap = new ConcurrentHashMapEx<>(); + + @Autowired + @SuppressWarnings("unused") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + @SuppressWarnings("unused") + public void setEtcdRegistryProperties(EtcdRegistryProperties etcdRegistryProperties) { + this.etcdRegistryProperties = etcdRegistryProperties; + } + + @Override + public String name() { + return EtcdConst.ETCD_REGISTRY_NAME; + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(EtcdConst.ETCD_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + + String prefixPath = basePath + "/" + application + "/" + serviceName; + watchMap.computeIfAbsent(prefixPath, listenServiceName -> { + Watch watchClient = client.getWatchClient(); + try { + ByteSequence prefixByteSeq = ByteSequence.from(prefixPath, Charset.defaultCharset()); + watchClient.watch(prefixByteSeq, WatchOption.builder().withPrefix(prefixByteSeq).build(), + resp -> watchNode(application, serviceName, prefixPath)); + } catch (Exception e) { + LOGGER.error("Failed to add watch", e); + } + return watchClient; + }); + +// async get all instances,because sync is bad way in etcd. + ConditionWaiter> waiter = new ConditionWaiter<>(new ArrayList<>(), 50, + TimeUnit.MILLISECONDS); + waiter.executeTaskAsync(() -> { + CompletableFuture getFuture = client.getKVClient() + .get(ByteSequence.from(prefixPath, StandardCharsets.UTF_8), + GetOption.builder().withPrefix(ByteSequence.from(prefixPath, StandardCharsets.UTF_8)).build()); + GetResponse getResponse = getFuture.get(); + return convertServiceInstanceList(getResponse.getKvs()); + }); + return waiter.waitForCompletion(); + } + + private void watchNode(String application, String serviceName, String prefixPath) { + + CompletableFuture getFuture = client.getKVClient() + .get(ByteSequence.from(prefixPath, StandardCharsets.UTF_8), + GetOption.builder().withPrefix(ByteSequence.from(prefixPath, StandardCharsets.UTF_8)).build()); + getFuture.thenAcceptAsync(response -> { + List discoveryInstanceList = convertServiceInstanceList(response.getKvs()); + instanceChangedListener.onInstanceChanged(name(), application, serviceName, discoveryInstanceList); + }).exceptionally(e -> { + LOGGER.error("watchNode error", e); + return null; + }); + } + + private List getValuesByPrefix(String prefix) { + + CompletableFuture getFuture = client.getKVClient() + .get(ByteSequence.from(prefix, StandardCharsets.UTF_8), + GetOption.builder().withPrefix(ByteSequence.from(prefix, StandardCharsets.UTF_8)).build()); + GetResponse response = MuteExceptionUtil.builder().withLog("get kv by prefix error") + .executeCompletableFuture(getFuture); + return response.getKvs(); + } + + private List convertServiceInstanceList(List keyValueList) { + + List list = Lists.newArrayListWithExpectedSize(keyValueList.size()); + for (KeyValue keyValue : keyValueList) { + EtcdDiscoveryInstance etcdDiscoveryInstance = getEtcdDiscoveryInstance(keyValue); + list.add(etcdDiscoveryInstance); + } + return list; + } + + private static EtcdDiscoveryInstance getEtcdDiscoveryInstance(KeyValue keyValue) { + String valueJson = new String(keyValue.getValue().getBytes(), Charset.defaultCharset()); + + EtcdInstance etcdInstance = MuteExceptionUtil.builder() + .withLog("convert json value to obj from etcd failure, {}", valueJson) + .executeFunctionWithDoubleParam(JsonUtils::readValue, valueJson.getBytes(StandardCharsets.UTF_8), + EtcdInstance.class); + return new EtcdDiscoveryInstance(etcdInstance); + } + + @Override + public List findServices(String application) { + + ConditionWaiter> waiter = new ConditionWaiter<>(new ArrayList<>(), 50, TimeUnit.MILLISECONDS); + waiter.executeTaskAsync(() -> { + String prefixPath = basePath + "/" + application; + List endpointKv = getValuesByPrefix(prefixPath); + return endpointKv.stream() + .map(kv -> kv.getKey().toString(StandardCharsets.UTF_8)) + .map(key -> { + String[] parts = StringUtils.split(key, "/"); + return parts.length > 5 ? parts[4] : null; + }) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + }); + return waiter.waitForCompletion(); + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + this.instanceChangedListener = instanceChangedListener; + } + + @Override + public boolean enabled() { + return etcdRegistryProperties.isEnabled(); + } + + @Override + public void init() { + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = EtcdConst.ETCD_DEFAULT_ENVIRONMENT; + } + basePath = String.format(EtcdConst.ETCD_DISCOVERY_ROOT, env); + } + + @Override + public void run() { + if (StringUtils.isEmpty(etcdRegistryProperties.getAuthenticationInfo())) { + this.client = Client.builder().endpoints(etcdRegistryProperties.getConnectString()).build(); + } else { + String[] authInfo = etcdRegistryProperties.getAuthenticationInfo().split(":"); + this.client = Client.builder().endpoints(etcdRegistryProperties.getConnectString()) + .user(ByteSequence.from(authInfo[0], Charset.defaultCharset())) + .password(ByteSequence.from(authInfo[1], Charset.defaultCharset())).build(); + } + } + + @Override + public void destroy() { + if (client != null) { + client.close(); + watchMap = null; + } + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscoveryInstance.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscoveryInstance.java new file mode 100644 index 00000000000..d75a3b04cf4 --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdDiscoveryInstance.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import org.apache.servicecomb.registry.api.DiscoveryInstance; +public class EtcdDiscoveryInstance extends EtcdInstance implements DiscoveryInstance { + + public EtcdDiscoveryInstance(EtcdInstance other) { + super(other); + } + + @Override + public String getRegistryName() { + return EtcdConst.ETCD_REGISTRY_NAME; + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdInstance.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdInstance.java new file mode 100644 index 00000000000..071e84bf3bc --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdInstance.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstance; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; + +public class EtcdInstance implements MicroserviceInstance { + private String serviceId; + + private String instanceId; + + private String environment; + + private String application; + + private String serviceName; + + private String alias; + + private String version; + + private String description; + + private DataCenterInfo dataCenterInfo; + + private List endpoints = new ArrayList<>(); + + private Map schemas = new HashMap<>(); + + private Map properties = new HashMap<>(); + + private MicroserviceInstanceStatus status; + + public EtcdInstance() { + + } + + public EtcdInstance(EtcdInstance other) { + this.serviceId = other.serviceId; + this.instanceId = other.instanceId; + this.environment = other.environment; + this.application = other.application; + this.serviceName = other.serviceName; + this.alias = other.alias; + this.version = other.version; + this.description = other.description; + this.dataCenterInfo = other.dataCenterInfo; + this.endpoints = other.endpoints; + this.schemas = other.schemas; + this.properties = other.properties; + this.status = other.status; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public void setApplication(String application) { + this.application = application; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { + this.dataCenterInfo = dataCenterInfo; + } + + public void setEndpoints(List endpoints) { + this.endpoints = endpoints; + } + + public void setSchemas(Map schemas) { + this.schemas = schemas; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setStatus(MicroserviceInstanceStatus status) { + this.status = status; + } + + @Override + public String getEnvironment() { + return this.environment; + } + + @Override + public String getApplication() { + return this.application; + } + + @Override + public String getServiceName() { + return this.serviceName; + } + + @Override + public String getAlias() { + return alias; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo == null ? new DataCenterInfo() : dataCenterInfo; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public Map getProperties() { + return properties; + } + + @Override + public Map getSchemas() { + return schemas; + } + + @Override + public List getEndpoints() { + return endpoints; + } + + public void addSchema(String schemaId, String content) { + this.schemas.put(schemaId, content); + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } + + public void addProperty(String key, String value) { + this.properties.put(key, value); + } + + @Override + public String getInstanceId() { + return instanceId; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return this.status; + } + + @Override + public String toString() { + return "EtcdInstance{" + + "serviceId='" + serviceId + '\'' + + ", instanceId='" + instanceId + '\'' + + ", environment='" + environment + '\'' + + ", application='" + application + '\'' + + ", serviceName='" + serviceName + '\'' + + ", alias='" + alias + '\'' + + ", version='" + version + '\'' + + ", description='" + description + '\'' + + ", dataCenterInfo=" + dataCenterInfo + + ", endpoints=" + endpoints + + ", schemas=" + schemas + + ", properties=" + properties + + '}'; + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistration.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistration.java new file mode 100644 index 00000000000..3fabfac4e23 --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistration.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import java.nio.charset.Charset; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.foundation.common.utils.MuteExceptionUtil; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KV; +import io.etcd.jetcd.Lease; +import io.etcd.jetcd.kv.PutResponse; +import io.etcd.jetcd.options.PutOption; + +public class EtcdRegistration implements Registration { + + private EtcdInstance etcdInstance; + + private Environment environment; + + private String basePath; + + private RegistrationId registrationId; + + private DataCenterProperties dataCenterProperties; + + private EtcdRegistryProperties etcdRegistryProperties; + + private Client client; + + private ScheduledExecutorService executorService; + + private String keyPath; + + private Long leaseId; + + @Autowired + @SuppressWarnings("unused") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + @SuppressWarnings("unused") + public void setEtcdRegistryProperties(EtcdRegistryProperties etcdRegistryProperties) { + this.etcdRegistryProperties = etcdRegistryProperties; + } + + @Autowired + public void setRegistrationId(RegistrationId registrationId) { + this.registrationId = registrationId; + } + + @Autowired + @SuppressWarnings("unused") + public void setDataCenterProperties(DataCenterProperties dataCenterProperties) { + this.dataCenterProperties = dataCenterProperties; + } + + @Override + public String name() { + return EtcdConst.ETCD_REGISTRY_NAME; + } + + @Override + public EtcdRegistrationInstance getMicroserviceInstance() { + return new EtcdRegistrationInstance(etcdInstance); + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + this.etcdInstance.setStatus(status); + String valueJson = MuteExceptionUtil.builder().withLog("to json, key:{}, value:{}", keyPath, etcdInstance) + .executeFunction(JsonUtils::writeValueAsString, etcdInstance); + register(ByteSequence.from(keyPath, Charset.defaultCharset()), + ByteSequence.from(valueJson, Charset.defaultCharset())); + return true; + } + + @Override + public void addSchema(String schemaId, String content) { + if (etcdRegistryProperties.isEnableSwaggerRegistration()) { + etcdInstance.addSchema(schemaId, content); + } + } + + @Override + public void addEndpoint(String endpoint) { + etcdInstance.addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + etcdInstance.addProperty(key, value); + } + + @Override + public boolean enabled() { + return etcdRegistryProperties.isEnabled(); + } + + @Override + public void init() { + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = EtcdConst.ETCD_DEFAULT_ENVIRONMENT; + } + basePath = String.format(EtcdConst.ETCD_DISCOVERY_ROOT, env); + etcdInstance = new EtcdInstance(); + etcdInstance.setInstanceId(registrationId.getInstanceId()); + etcdInstance.setEnvironment(env); + etcdInstance.setApplication(BootStrapProperties.readApplication(environment)); + etcdInstance.setServiceName(BootStrapProperties.readServiceName(environment)); + etcdInstance.setAlias(BootStrapProperties.readServiceAlias(environment)); + etcdInstance.setDescription(BootStrapProperties.readServiceDescription(environment)); + if (StringUtils.isNotEmpty(dataCenterProperties.getName())) { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setName(dataCenterProperties.getName()); + dataCenterInfo.setRegion(dataCenterProperties.getRegion()); + dataCenterInfo.setAvailableZone(dataCenterProperties.getAvailableZone()); + etcdInstance.setDataCenterInfo(dataCenterInfo); + } + etcdInstance.setProperties(BootStrapProperties.readServiceProperties(environment)); + etcdInstance.setVersion(BootStrapProperties.readServiceVersion(environment)); + etcdInstance.setStatus( + MicroserviceInstanceStatus.valueOf(BootStrapProperties.readServiceInstanceInitialStatus(environment))); + } + + @Override + public void run() { + client = Client.builder().endpoints(etcdRegistryProperties.getConnectString()) + .build(); + keyPath = basePath + "/" + + BootStrapProperties.readApplication(environment) + "/" + + BootStrapProperties.readServiceName(environment) + "/" + + registrationId.getInstanceId(); + + String valueJson = MuteExceptionUtil.builder().withLog("to json, key:{}, value:{}", keyPath, etcdInstance) + .executeFunction(JsonUtils::writeValueAsString, etcdInstance); + register(ByteSequence.from(keyPath, Charset.defaultCharset()), + ByteSequence.from(valueJson, Charset.defaultCharset())); + } + + public void register(ByteSequence key, ByteSequence value) { + + Lease leaseClient = client.getLeaseClient(); + leaseId = MuteExceptionUtil.builder().withLog("get lease id, key:{}, value:{}", keyPath, etcdInstance) + .executeCompletableFuture(leaseClient.grant(60)).getID(); + KV kvClient = client.getKVClient(); + + PutOption putOption = PutOption.builder().withLeaseId(leaseId).build(); + CompletableFuture putResponse = kvClient.put(key, value, putOption); + putResponse.thenRun(() -> { + executorService = Executors.newSingleThreadScheduledExecutor(); + executorService.scheduleAtFixedRate( + () -> MuteExceptionUtil.builder().withLog("reRegister, {}, {}", keyPath, etcdInstance) + .executeFunction(leaseClient::keepAliveOnce, leaseId), 0, 5, TimeUnit.SECONDS); + }); + } + + private void unregister() { + // close job + executorService.shutdownNow(); + + // close etcd node + Lease leaseClient = client.getLeaseClient(); + leaseClient.revoke(leaseId); + client.getKVClient().delete(ByteSequence.from(keyPath, Charset.defaultCharset())); + } + + @Override + public void destroy() { + if (client != null) { + unregister(); + client.close(); + } + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistrationInstance.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistrationInstance.java new file mode 100644 index 00000000000..3dfa78c338e --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistrationInstance.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +import org.apache.servicecomb.registry.api.RegistrationInstance; + +public class EtcdRegistrationInstance extends EtcdInstance implements RegistrationInstance { + public EtcdRegistrationInstance(EtcdInstance instance) { + super(instance); + } +} diff --git a/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistryProperties.java b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistryProperties.java new file mode 100644 index 00000000000..c4d61094bfc --- /dev/null +++ b/service-registry/registry-etcd/src/main/java/org/apache/servicecomb/registry/etcd/EtcdRegistryProperties.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.etcd; + +public class EtcdRegistryProperties { + private boolean enabled = true; + + private boolean ephemeral = true; + + private String connectString = "http://127.0.0.1:2379"; + + private String authenticationSchema; + + private String authenticationInfo; + + private int connectionTimeoutMillis = 1000; + + private int sessionTimeoutMillis = 60000; + + private boolean enableSwaggerRegistration = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEphemeral() { + return ephemeral; + } + + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; + } + + public String getConnectString() { + return connectString; + } + + public void setConnectString(String connectString) { + this.connectString = connectString; + } + + public int getConnectionTimeoutMillis() { + return connectionTimeoutMillis; + } + + public void setConnectionTimeoutMillis(int connectionTimeoutMillis) { + this.connectionTimeoutMillis = connectionTimeoutMillis; + } + + public int getSessionTimeoutMillis() { + return sessionTimeoutMillis; + } + + public void setSessionTimeoutMillis(int sessionTimeoutMillis) { + this.sessionTimeoutMillis = sessionTimeoutMillis; + } + + public boolean isEnableSwaggerRegistration() { + return enableSwaggerRegistration; + } + + public void setEnableSwaggerRegistration(boolean enableSwaggerRegistration) { + this.enableSwaggerRegistration = enableSwaggerRegistration; + } + + public String getAuthenticationSchema() { + return authenticationSchema; + } + + public void setAuthenticationSchema(String authenticationSchema) { + this.authenticationSchema = authenticationSchema; + } + + public String getAuthenticationInfo() { + return authenticationInfo; + } + + public void setAuthenticationInfo(String authenticationInfo) { + this.authenticationInfo = authenticationInfo; + } +} diff --git a/service-registry/registry-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..999ffb6b04b --- /dev/null +++ b/service-registry/registry-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.etcd.EtcdConfiguration diff --git a/service-registry/registry-lightweight/pom.xml b/service-registry/registry-lightweight/pom.xml new file mode 100644 index 00000000000..43a27c5cfe6 --- /dev/null +++ b/service-registry/registry-lightweight/pom.xml @@ -0,0 +1,52 @@ + + + + + + service-registry-parent + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-lightweight + Java Chassis::Service Registry::lightweight + + + + org.apache.servicecomb + registry-local + + + org.apache.servicecomb + provider-jaxrs + + + org.apache.servicecomb + provider-pojo + + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightDiscovery.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightDiscovery.java new file mode 100644 index 00000000000..f52e8345534 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightDiscovery.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.registry.lightweight.store.Store; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; + +public abstract class AbstractLightweightDiscovery implements Discovery { + public static final String ZERO_DISCOVERY_ENABLED = "servicecomb.registry.zero-config.%s.%s.enabled"; + + protected EventBus eventBus; + + protected Store store; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public AbstractLightweightDiscovery setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + return this; + } + + @Autowired + public AbstractLightweightDiscovery setStore(Store store) { + this.store = store; + return this; + } + + @Override + public void init() { + eventBus.register(this); + } + + @Override + public void destroy() { + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(ZERO_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightRegistration.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightRegistration.java new file mode 100644 index 00000000000..06aa7c9b73f --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/AbstractLightweightRegistration.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.io.IOException; +import java.time.Duration; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.EventBus; + +@SuppressWarnings("UnstableApiUsage") +public abstract class AbstractLightweightRegistration implements Registration { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLightweightRegistration.class); + + protected EventBus eventBus; + + protected StoreService storeService; + + protected Self self; + + @Autowired + public AbstractLightweightRegistration setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + return this; + } + + @Autowired + public AbstractLightweightRegistration setStoreService(StoreService storeService) { + this.storeService = storeService; + return this; + } + + @Autowired + public AbstractLightweightRegistration setSelf(Self self) { + this.self = self; + return this; + } + + @Override + public void init() { + + } + + protected void startRegister(Duration interval) { + Executors + .newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, name())) + .scheduleAtFixedRate(this::sendRegister, 0, interval.getSeconds(), TimeUnit.SECONDS); + } + + + protected void sendRegister() { + try { + doSendRegister(); + } catch (Exception e) { + LOGGER.error("register failed.", e); + } + } + + protected abstract void doSendRegister() throws IOException; + + @Override + public void addSchema(String schemaId, String content) { + self.addSchema(schemaId, content); + } + + @Override + public void addEndpoint(String endpoint) { + self.getInstance().getEndpoints().add(endpoint); + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + return true; + } + + @Override + public void addProperty(String key, String value) { + + } + + @Override + public void run() { + storeService.registerSelf(self); + } + + @Override + public void destroy() { + try { + doSendUnregister(); + } catch (Exception e) { + LOGGER.error("unregister failed.", e); + } + } + + protected abstract void doSendUnregister() throws IOException; +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryClient.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryClient.java new file mode 100644 index 00000000000..3d6a769d821 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryClient.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +import io.swagger.v3.oas.annotations.Operation; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; + +@Path("/v1/discovery") +public interface DiscoveryClient { + @Path("/info") + @GET + @Operation(summary = "", operationId = "getInfo") + CompletableFuture getInfoAsync(Endpoint endpoint, @QueryParam("service-id") String serviceId); + + + default MicroserviceInfo getInfo(Endpoint endpoint, String serviceId) { + return AsyncUtils.toSync(getInfoAsync(endpoint, serviceId)); + } + + @Path("/microservice") + @GET + @Operation(summary = "", operationId = "getMicroservice") + CompletableFuture getMicroserviceAsync(Endpoint endpoint, @QueryParam("service-id") String serviceId); + + default Microservice getMicroservice(Endpoint endpoint, String serviceId) { + return AsyncUtils.toSync(getMicroserviceAsync(endpoint, serviceId)); + } + + @Path("/instance") + @GET + @Operation(summary = "", operationId = "getInstance") + CompletableFuture getInstanceAsync(Endpoint endpoint, + @QueryParam("service-id") String serviceId); + + default MicroserviceInstance getInstance(Endpoint endpoint, String serviceId) { + return AsyncUtils.toSync(getInstanceAsync(endpoint, serviceId)); + } + + @Path("/schemas/{schema-id}") + @GET + @Produces(MediaType.TEXT_PLAIN) + @Operation(summary = "", operationId = "getSchema") + CompletableFuture getSchemaAsync(Endpoint endpoint, @QueryParam("service-id") String serviceId, + @PathParam("schema-id") String schemaId); + + default String getSchema(Endpoint endpoint, String serviceId, String schemaId) { + return AsyncUtils.toSync(getSchemaAsync(endpoint, serviceId, schemaId)); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryEndpoint.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryEndpoint.java new file mode 100644 index 00000000000..a1e2d0ccb50 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/DiscoveryEndpoint.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import static org.apache.servicecomb.registry.lightweight.DiscoveryEndpoint.SCHEMA_ID; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@RestSchema(schemaId = SCHEMA_ID) +@Path("/v1/discovery") +public class DiscoveryEndpoint { + public static final String SCHEMA_ID = "scb-discovery"; + + private final Self self; + + public DiscoveryEndpoint(Self self) { + this.self = self; + } + + @Parameters( + { + @Parameter(name = "service-id", in = ParameterIn.QUERY, schema = @Schema(implementation = String.class), + description = "just make it possible to mock many instances by one real instance for performance test") + } + ) + @Path("/info") + @GET + public CompletableFuture getInfo() { + return CompletableFuture.completedFuture(self.getMicroserviceInfo()); + } + + @Parameters( + { + @Parameter(name = "service-id", in = ParameterIn.QUERY, schema = @Schema(implementation = String.class), + description = "just make it possible to mock many instances by one real instance for performance test") + } + ) + @Path("/microservice") + @GET + public CompletableFuture getMicroservice() { + return CompletableFuture.completedFuture(self.getMicroservice()); + } + + @Parameters( + { + @Parameter(name = "service-id", in = ParameterIn.QUERY, schema = @Schema(implementation = String.class), + description = "just make it possible to mock many instances by one real instance for performance test") + } + ) + @Path("/instance") + @GET + public CompletableFuture getInstance() { + return CompletableFuture.completedFuture(self.getInstance()); + } + + @Parameters( + { + @Parameter(name = "service-id", in = ParameterIn.QUERY, schema = @Schema(implementation = String.class), + description = "just make it possible to mock many instances by one real instance for performance test") + } + ) + @Path("/schemas/{schema-id}") + @GET + @Produces(MediaType.TEXT_PLAIN) + public CompletableFuture getSchema(@PathParam("schema-id") String schemaId) { + return CompletableFuture.completedFuture(self.getMicroservice().getSchemaMap().get(schemaId)); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/LightWeightRegistryConfiguration.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/LightWeightRegistryConfiguration.java new file mode 100644 index 00000000000..862356d0dba --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/LightWeightRegistryConfiguration.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.lightweight; + +import java.util.Collections; +import java.util.List; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.localregistry.RegistryBean; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.apache.servicecomb.localregistry.RegistryBean.Instances; +import org.apache.servicecomb.provider.pojo.Invoker; +import org.apache.servicecomb.registry.lightweight.store.Store; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; + +@Configuration +@SuppressWarnings("unused") +public class LightWeightRegistryConfiguration { + + public static final String ZERO_CONFIG_DISCOVERY_CLIENT = "zero-config-discovery-client"; + + @Bean + public Store zeroConfigStore() { + return new Store(); + } + + @Bean + public MessageExecutor zeroConfigMessageExecutor(Self self, StoreService storeService) { + return new MessageExecutor(self, storeService); + } + + @Bean + public Self zeroConfigSelf() { + return new Self(); + } + + @Bean + public StoreService zeroConfigStoreService(EventBus eventBus, Store store, DiscoveryClient discoveryClient) { + return new StoreService(eventBus, store, discoveryClient); + } + + @Bean + public DiscoveryEndpoint zeroConfigDiscoveryEndpoint(Self self) { + return new DiscoveryEndpoint(self); + } + + @Bean + public RegistryBean zeroConfigDiscoveryServer(Environment environment) { + return new RegistryBean().setAppId(BootStrapProperties.readApplication(environment)) + .setServiceName(ZERO_CONFIG_DISCOVERY_CLIENT) + .addSchemaInterface(ZERO_CONFIG_DISCOVERY_CLIENT, DiscoveryClient.class) + // add an empty instance endpoint so that can invoke by endpoint + .setInstances(new Instances().setInstances(List.of(new Instance().setEndpoints(Collections.emptyList())))); + } + + @Bean + public DiscoveryClient zeroConfigDiscoveryClient() { + return Invoker.createProxy(ZERO_CONFIG_DISCOVERY_CLIENT, + ZERO_CONFIG_DISCOVERY_CLIENT, DiscoveryClient.class); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Message.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Message.java new file mode 100644 index 00000000000..eda811f2d48 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Message.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +import io.vertx.core.json.jackson.DatabindCodec; + +public class Message { + public static Message of(MessageType type, T body) { + return new Message() + .setType(type) + .setBody(body); + } + + private MessageType type; + + @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY) + @JsonSubTypes( + { + @Type(name = "REGISTER", value = RegisterRequest.class), + @Type(name = "UNREGISTER", value = UnregisterRequest.class) + } + ) + private T body; + + public MessageType getType() { + return type; + } + + public Message setType(MessageType type) { + this.type = type; + return this; + } + + public T getBody() { + return body; + } + + public Message setBody(T body) { + this.body = body; + return this; + } + + public byte[] encode() throws IOException { + return DatabindCodec.mapper().writeValueAsBytes(this); + } + + public static Message decode(byte[] bytes, int length) throws IOException { + return DatabindCodec.mapper() + .readValue(bytes, 0, length, Message.class); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageExecutor.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageExecutor.java new file mode 100644 index 00000000000..d2d550bf79a --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageExecutor.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(MessageExecutor.class); + + private final Self self; + + private final StoreService storeService; + + private final Map> messageProcessors = new HashMap<>(); + + private final ScheduledExecutorService taskExecutor = Executors + .newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "lightweight-message-executor")); + + public MessageExecutor(Self self, StoreService storeService) { + this.self = self; + this.storeService = storeService; + + addMessageProcessor(MessageType.REGISTER, this::register); + addMessageProcessor(MessageType.UNREGISTER, storeService::unregister); + } + + public void startCheckDeadInstances(Duration interval) { + taskExecutor.scheduleAtFixedRate( + () -> storeService.deleteDeadInstances(interval), + 0, interval.getSeconds(), TimeUnit.SECONDS); + } + + private void register(RegisterRequest request) { + if (request.isCrossApp() || Objects.equals(request.getAppId(), self.getAppId())) { + storeService.register(request); + } + } + + private void addMessageProcessor(MessageType messageType, Consumer messageProcessor) { + messageProcessors.put(messageType, messageProcessor); + } + + @SuppressWarnings("unchecked") + public void processMessage(Message message) { + Consumer consumer = (Consumer) messageProcessors.get(message.getType()); + + taskExecutor.execute(() -> { + try { + consumer.accept(message.getBody()); + } catch (Throwable e) { + LOGGER.error("process message error. ", e); + } + }); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageType.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageType.java new file mode 100644 index 00000000000..d3287ef00e8 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MessageType.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +public enum MessageType { + REGISTER, + UNREGISTER +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MicroserviceInfo.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MicroserviceInfo.java new file mode 100644 index 00000000000..92e605bae2e --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/MicroserviceInfo.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.util.Map; + +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +public class MicroserviceInfo { + private Microservice microservice; + + private MicroserviceInstance instance; + + private Map schemasById; + + public Microservice getMicroservice() { + return microservice; + } + + public MicroserviceInfo setMicroservice(Microservice microservice) { + this.microservice = microservice; + return this; + } + + public Map getSchemasById() { + return schemasById; + } + + public MicroserviceInfo setSchemasById(Map schemasById) { + this.schemasById = schemasById; + return this; + } + + public MicroserviceInstance getInstance() { + return instance; + } + + public MicroserviceInfo setInstance(MicroserviceInstance instance) { + this.instance = instance; + return this; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterException.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterException.java new file mode 100644 index 00000000000..68ed59393e0 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterException.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +public class RegisterException extends RuntimeException { + private static final long serialVersionUID = 4130899909889771251L; + + public RegisterException(String message) { + super(message); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterInstanceEvent.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterInstanceEvent.java new file mode 100644 index 00000000000..c8186037bd1 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterInstanceEvent.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +/** + * post when a new instance registered
+ * to notify registration send a new register message
+ * currently, only "zero config" need this + */ +public class RegisterInstanceEvent { + private final Microservice microservice; + + private final MicroserviceInstance instance; + + public RegisterInstanceEvent(Microservice microservice, MicroserviceInstance instance) { + this.microservice = microservice; + this.instance = instance; + } + + public Microservice getMicroservice() { + return microservice; + } + + public MicroserviceInstance getInstance() { + return instance; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterRequest.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterRequest.java new file mode 100644 index 00000000000..2fffe6da802 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/RegisterRequest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.util.List; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.invocation.endpoint.EndpointCacheUtils; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; + +public class RegisterRequest { + private String appId; + + private String serviceId; + + private boolean crossApp; + + private String schemasSummary; + + private String instanceId; + + private MicroserviceInstanceStatus status; + + private List endpoints; + + public String getAppId() { + return appId; + } + + public RegisterRequest setAppId(String appId) { + this.appId = appId; + return this; + } + + public String getServiceId() { + return serviceId; + } + + public RegisterRequest setServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + public boolean isCrossApp() { + return crossApp; + } + + public RegisterRequest setCrossApp(boolean crossApp) { + this.crossApp = crossApp; + return this; + } + + public String getSchemasSummary() { + return schemasSummary; + } + + public RegisterRequest setSchemasSummary(String schemasSummary) { + this.schemasSummary = schemasSummary; + return this; + } + + public String getInstanceId() { + return instanceId; + } + + public RegisterRequest setInstanceId(String instanceId) { + this.instanceId = instanceId; + return this; + } + + public MicroserviceInstanceStatus getStatus() { + return status; + } + + public RegisterRequest setStatus(MicroserviceInstanceStatus status) { + this.status = status; + return this; + } + + public List getEndpoints() { + return endpoints; + } + + public RegisterRequest setEndpoints(List endpoints) { + this.endpoints = endpoints; + return this; + } + + public Endpoint selectFirstEndpoint() { + return endpoints.stream() + .findFirst() + .map(EndpointCacheUtils::getOrCreate) + .orElse(null); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/SchemaChangedEvent.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/SchemaChangedEvent.java new file mode 100644 index 00000000000..9836448d889 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/SchemaChangedEvent.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import org.apache.servicecomb.registry.lightweight.model.Microservice; + +public class SchemaChangedEvent { + private final Microservice microservice; + + public SchemaChangedEvent(Microservice microservice) { + this.microservice = microservice; + } + + public Microservice getMicroservice() { + return microservice; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Self.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Self.java new file mode 100644 index 00000000000..d6acccbf737 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/Self.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import org.apache.servicecomb.core.BootListener; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceFactory; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.annotations.VisibleForTesting; + +public class Self implements InitializingBean, BootListener { + private Microservice microservice; + + // Whether to allow cross-app calls to me + private boolean crossApp; + + private MicroserviceInstance instance; + + private final MicroserviceInfo microserviceInfo = new MicroserviceInfo(); + + private Environment environment; + + private RegistrationId registrationId; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setRegistrationId(RegistrationId registrationId) { + this.registrationId = registrationId; + } + + @Override + public void afterPropertiesSet() { + init(environment); + } + + @VisibleForTesting + public Self init(Environment environment) { + microservice = new MicroserviceFactory().create(environment); + microservice.serviceId(String.format("%s/%s/%s/%s", + microservice.getEnvironment(), + microservice.getAppId(), + microservice.getServiceName(), + microservice.getVersion())); + + instance = microservice.getInstance() + .instanceId(registrationId.getInstanceId()) + .serviceId(microservice.getServiceId()); + + microserviceInfo + .setMicroservice(microservice) + .setSchemasById(microservice.getSchemaMap()) + .setInstance(instance); + + return this; + } + + @Override + public int getOrder() { + return Integer.MAX_VALUE; + } + + @Override + public void onBeforeRegistry(BootEvent event) { + crossApp = microservice.allowCrossApp(); + } + + public Microservice getMicroservice() { + return microservice; + } + + public String getAppId() { + return microservice.getAppId(); + } + + public Microservice setServiceName(String serviceName) { + return microservice.serviceName(serviceName); + } + + public String getVersion() { + return microservice.getVersion(); + } + + public String getInstanceId() { + return instance.getInstanceId(); + } + + public String getServiceId() { + return instance.getServiceId(); + } + + public MicroserviceInstance getInstance() { + return instance; + } + + public MicroserviceInfo getMicroserviceInfo() { + return microserviceInfo; + } + + public Self addSchema(String schemaId, String content) { + microservice.addSchema(schemaId, content); + return this; + } + + public Self addEndpoint(String endpoint) { + instance.getEndpoints().add(endpoint); + return this; + } + + public RegisterRequest buildRegisterRequest() { + return createRegisterRequest() + .setAppId(microservice.getAppId()) + .setServiceId(microservice.getServiceId()) + .setCrossApp(crossApp) + .setInstanceId(instance.getInstanceId()) + .setStatus(instance.getStatus()) + .setEndpoints(instance.getEndpoints()); + } + + protected RegisterRequest createRegisterRequest() { + return new RegisterRequest(); + } + + public UnregisterRequest buildUnregisterRequest() { + return createUnregisterRequest() + .setServiceId(microservice.getServiceId()) + .setInstanceId(instance.getInstanceId()); + } + + protected UnregisterRequest createUnregisterRequest() { + return new UnregisterRequest(); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/StoreService.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/StoreService.java new file mode 100644 index 00000000000..851386844e0 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/StoreService.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; +import org.apache.servicecomb.registry.lightweight.store.InstanceStore; +import org.apache.servicecomb.registry.lightweight.store.MicroserviceStore; +import org.apache.servicecomb.registry.lightweight.store.Store; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +public class StoreService { + private static final Logger LOGGER = LoggerFactory.getLogger(StoreService.class); + + private final EventBus eventBus; + + private final Store store; + + private final DiscoveryClient discoveryClient; + + public StoreService(EventBus eventBus, Store store, DiscoveryClient discoveryClient) { + this.store = store; + this.discoveryClient = discoveryClient; + this.eventBus = eventBus; + } + + public void registerSelf(Self self) { + MicroserviceStore microserviceStore = store.addMicroservice(self.getMicroservice()); + addInstance(microserviceStore, self.getInstance()); + } + + public InstanceStore register(RegisterRequest request) { + return AsyncUtils.toSync(registerAsync(request)); + } + + public CompletableFuture registerAsync(RegisterRequest request) { + return doRegisterAsync(request) + .whenComplete((r, e) -> logFailedRegister(request, e)); + } + + private void logFailedRegister(RegisterRequest request, Throwable throwable) { + if (throwable == null) { + return; + } + + LOGGER.error("register instance failed, serviceId={}, instanceId={}, endpoints={}.", + request.getServiceId(), + request.getInstanceId(), + request.getEndpoints(), + throwable); + } + + private CompletableFuture doRegisterAsync(RegisterRequest request) { + InstanceStore instanceStore = store.findInstanceStore(request.getInstanceId()); + if (instanceStore == null) { + return addInstance(request); + } + + if (instanceStore.isStatusChanged(request.getStatus())) { + updateInstanceStatus(request, instanceStore); + } + return heartbeat(instanceStore); + } + + private CompletableFuture addInstance(RegisterRequest request) { + Endpoint endpoint = request.selectFirstEndpoint(); + if (endpoint == null) { + return AsyncUtils.completeExceptionally(new RegisterException("can not select endpoint")); + } + + MicroserviceStore microserviceStore = this.store.findMicroserviceStore(request.getServiceId()); + if (microserviceStore == null) { + return addMicroserviceAndInstance(endpoint, request); + } + + return CompletableFuture.completedFuture(null).thenCompose(v -> + discoveryClient.getInstanceAsync(endpoint, request.getServiceId())) + .thenApply(instance -> addInstance(microserviceStore, instance)); + } + + private CompletableFuture addMicroserviceAndInstance(Endpoint endpoint, RegisterRequest request) { + return discoveryClient.getInfoAsync(endpoint, request.getServiceId()) + .thenApply(info -> { + info.getMicroservice().getSchemaMap().putAll(info.getSchemasById()); + MicroserviceStore microserviceStore = store + .addMicroservice(info.getMicroservice()); + + LOGGER.info("add microservice and instance, serviceId={}, instanceId={}, endpoints={}", + request.getServiceId(), + request.getInstanceId(), + request.getEndpoints()); + return doAddInstance(microserviceStore, info.getInstance()); + }); + } + + private InstanceStore addInstance(MicroserviceStore microserviceStore, MicroserviceInstance instance) { + LOGGER.info("add instance, serviceId={}, instanceId={}, endpoints={}", + instance.getServiceId(), + instance.getInstanceId(), + instance.getEndpoints()); + + return doAddInstance(microserviceStore, instance); + } + + private InstanceStore doAddInstance(MicroserviceStore microserviceStore, MicroserviceInstance instance) { + InstanceStore instanceStore = store.addInstance(microserviceStore, instance); + eventBus.post(new RegisterInstanceEvent(microserviceStore.getMicroservice(), instance)); + return instanceStore; + } + + private void updateInstanceStatus(RegisterRequest request, InstanceStore instanceStore) { + LOGGER.info("update instance status, old status={}, new status={}, serviceId={}, instanceId={}, endpoints={}", + instanceStore.getStatus(), + request.getStatus(), + instanceStore.getServiceId(), + instanceStore.getInstanceId(), + instanceStore.getEndpoints()); + + store.findMicroserviceStore(instanceStore.getServiceId()) + .updateInstanceStatus(instanceStore, request.getStatus()); + } + + private CompletableFuture heartbeat(InstanceStore instanceStore) { + instanceStore.updateLastHeartBeat(); + + LOGGER.debug("instance heartbeat, serviceId={}, instanceId={}, endpoints={}", + instanceStore.getServiceId(), + instanceStore.getInstanceId(), + instanceStore.getEndpoints()); + + return CompletableFuture.completedFuture(instanceStore); + } + + public Void unregister(UnregisterRequest request) { + return AsyncUtils.toSync(unregisterAsync(request)); + } + + public CompletableFuture unregisterAsync(UnregisterRequest request) { + deleteInstance("unregister", request.getServiceId(), request.getInstanceId()); + return CompletableFuture.completedFuture(null); + } + + public void deleteInstance(String action, String serviceId, String instanceId) { + InstanceStore instanceStore = store.deleteInstance(serviceId, instanceId); + if (instanceStore == null) { + return; + } + + LOGGER.info("{} instance, serviceId={}, instanceId={}, endpoints={}", + action, + instanceStore.getServiceId(), + instanceStore.getInstanceId(), + instanceStore.getEndpoints()); + } + + public void deleteDeadInstances(Duration timeout) { + store.findDeadInstances(timeout) + .forEach(instance -> deleteInstance("delete dead", instance.getServiceId(), instance.getInstanceId())); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/UnregisterRequest.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/UnregisterRequest.java new file mode 100644 index 00000000000..33c9e561a50 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/UnregisterRequest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +public class UnregisterRequest { + private String serviceId; + + private String instanceId; + + public String getServiceId() { + return serviceId; + } + + public UnregisterRequest setServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + public String getInstanceId() { + return instanceId; + } + + public UnregisterRequest setInstanceId(String instanceId) { + this.instanceId = instanceId; + return this; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/AbstractPropertiesLoader.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/AbstractPropertiesLoader.java new file mode 100644 index 00000000000..5153e09a634 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/AbstractPropertiesLoader.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.registry.api.PropertyExtended; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +/** + * Loading microservice properties + */ +public abstract class AbstractPropertiesLoader { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractPropertiesLoader.class); + + public Map loadProperties(Environment environment) { + Map propertiesMap = new HashMap<>(); + loadPropertiesFromConfigMap(environment, propertiesMap); + loadPropertiesFromExtendedClass(environment, propertiesMap); + + return propertiesMap; + } + + protected abstract Map readProperties(Environment environment); + + protected abstract String readPropertiesExtendedClass(Environment environment); + + private void loadPropertiesFromConfigMap(Environment environment, Map propertiesMap) { + propertiesMap.putAll(readProperties(environment)); + } + + private void loadPropertiesFromExtendedClass(Environment environment, Map propertiesMap) { + String extendedPropertyClass = readPropertiesExtendedClass(environment); + + if (StringUtils.isEmpty(extendedPropertyClass)) { + return; + } + + try { + Class classExternalProperty = Class.forName(extendedPropertyClass); + if (!PropertyExtended.class.isAssignableFrom(classExternalProperty)) { + String errMsg = String.format( + "Define propertyExtendedClass %s in yaml, but not implement the interface PropertyExtended.", + extendedPropertyClass); + LOGGER.error(errMsg); + throw new Error(errMsg); + } + + PropertyExtended instance = (PropertyExtended) classExternalProperty.getDeclaredConstructor().newInstance(); + Map extendedPropertiesMap = instance.getExtendedProperties(); + if (extendedPropertiesMap != null && !extendedPropertiesMap.isEmpty()) { + propertiesMap.putAll(extendedPropertiesMap); + } + } catch (ReflectiveOperationException e) { + String errMsg = "Fail to create instance of class: " + extendedPropertyClass; + LOGGER.error(errMsg); + throw new Error(errMsg, e); + } + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/FindInstancesResponse.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/FindInstancesResponse.java new file mode 100644 index 00000000000..61bc4fb9df3 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/FindInstancesResponse.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.List; + +public class FindInstancesResponse { + private List instances; + + public List getInstances() { + return instances; + } + + public FindInstancesResponse setInstances(List instances) { + this.instances = instances; + return this; + } + + public void mergeInstances(List instances) { + if (this.instances == null) { + this.instances = instances; + } else { + this.instances.addAll(instances); + } + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheck.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheck.java new file mode 100644 index 00000000000..b3f3d1ee47d --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheck.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Created by on 2017/1/13. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class HealthCheck { + private HealthCheckMode mode; + + private int port; + + private int interval; + + private int times; + + public int getInterval() { + return interval; + } + + public void setInterval(int interval) { + this.interval = interval; + } + + public int getTimes() { + return times; + } + + public void setTimes(int times) { + this.times = times; + } + + public HealthCheckMode getMode() { + return mode; + } + + public void setMode(HealthCheckMode mode) { + this.mode = mode; + } + + public int getTTL() { + if (this.mode != HealthCheckMode.HEARTBEAT) { + return 0; + } + return getInterval() * (getTimes() + 1); + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheckMode.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheckMode.java new file mode 100644 index 00000000000..d13d1e815b9 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/HealthCheckMode.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Created by on 2017/1/25. + */ +public enum HealthCheckMode { + UNKNOWN("unknown"), + HEARTBEAT("push"), + PLATFORM("pull"); + + private final String name; + + HealthCheckMode(String name) { + this.name = name; + } + + @JsonValue + public String getName() { + return name; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/InstancePropertiesLoader.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/InstancePropertiesLoader.java new file mode 100644 index 00000000000..a4dd1d30d83 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/InstancePropertiesLoader.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.springframework.core.env.Environment; + +public final class InstancePropertiesLoader extends AbstractPropertiesLoader { + + public static final InstancePropertiesLoader INSTANCE = new InstancePropertiesLoader(); + + private InstancePropertiesLoader() { + } + + + @Override + protected Map readProperties(Environment environment) { + return BootStrapProperties.readServiceInstanceProperties(environment); + } + + @Override + protected String readPropertiesExtendedClass(Environment environment) { + return BootStrapProperties.readServiceInstanceExtendedClass(environment); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/Microservice.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/Microservice.java new file mode 100644 index 00000000000..3033ff60d49 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/Microservice.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.definition.DefinitionConst; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Created by on 2016/12/5. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Microservice { + // service center rule: max length: 64 + // two way to generate service id + // 1. microservice instance generate by some rule, ex: env/app/name/version + // and then register to service center with the id + // 2. register to service center with the id to be null, and then service center generate by UUID + private String serviceId; + + private String registerBy; + + private String environment; + + // service center rule: max length: 160 + private String appId; + + // service center rule: max length: 128 + private String serviceName; + + /** + * for governance + * when invoke cross app, if not use alias name, then {microservice}.{schema}.{operation} will conflict + */ + private String alias; + + private String version; + + private String description; + + private String level; + + private List schemas = new ArrayList<>(); + + @JsonIgnore + private final Map schemaMap = new HashMap<>(); + + + private Map properties = new HashMap<>(); + + @JsonIgnore + private MicroserviceInstance instance; + + /** + * Currently this field only exists in ServiceComb-Java-Chassis, + * and ServiceComb-Service-Center does not hold this field. + * Once the 3rd party services are supported to be registered into ServiceComb-Service-Center, + * the corresponding field should be added into Service-Center. + */ + private boolean thirdPartyService; + + public Microservice() { + } + + public MicroserviceInstance getInstance() { + return instance; + } + + public void setInstance(MicroserviceInstance instance) { + this.instance = instance; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public Microservice serviceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public Microservice appId(String appId) { + this.appId = appId; + return this; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public Microservice serviceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Microservice version(String version) { + this.version = version; + return this; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public List getSchemas() { + return schemas; + } + + public void setSchemas(List schemas) { + this.schemas = schemas; + } + + public void addSchema(String schemaId, String content) { + this.schemaMap.put(schemaId, content); + schemas.add(schemaId); + } + + public Map getSchemaMap() { + return schemaMap; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public static String generateAbsoluteMicroserviceName(String appId, String microserviceName) { + StringBuilder sb = new StringBuilder(appId.length() + microserviceName.length() + 1); + sb.append(appId).append(DefinitionConst.APP_SERVICE_SEPARATOR).append(microserviceName); + return sb.toString(); + } + + + public String getRegisterBy() { + return registerBy; + } + + public void setRegisterBy(String registerBy) { + this.registerBy = registerBy; + } + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public boolean isThirdPartyService() { + return thirdPartyService; + } + + public void setThirdPartyService(boolean thirdPartyService) { + this.thirdPartyService = thirdPartyService; + } + + // Whether to allow cross-app calls to me + public boolean allowCrossApp() { + return Boolean.parseBoolean(properties.get(DefinitionConst.CONFIG_ALLOW_CROSS_APP_KEY)); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceFactory.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceFactory.java new file mode 100644 index 00000000000..fed3b9a282a --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceFactory.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.lightweight.model; + +import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.APP_MAPPING; +import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_DEFAULT_REGISTER_BY; +import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.SERVICE_MAPPING; +import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.VERSION_MAPPING; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.foundation.common.Version; +import org.springframework.core.env.Environment; + +public class MicroserviceFactory { + public Microservice create(Environment environment) { + Microservice microservice = createMicroserviceFromConfiguration(environment); + microservice.setInstance(MicroserviceInstance.createFromDefinition(environment)); + return microservice; + } + + private Microservice createMicroserviceFromConfiguration(Environment environment) { + Microservice microservice = new Microservice(); + + if (!StringUtils.isEmpty(environment.getProperty(APP_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(APP_MAPPING)))) { + microservice.setAppId(environment.getProperty(environment.getProperty(APP_MAPPING))); + } else { + microservice.setAppId(BootStrapProperties.readApplication(environment)); + } + if (!StringUtils.isEmpty(environment.getProperty(SERVICE_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(SERVICE_MAPPING)))) { + microservice.setServiceName(environment.getProperty(environment.getProperty(SERVICE_MAPPING))); + } else { + microservice.setServiceName(BootStrapProperties.readServiceName(environment)); + } + String version; + if (!StringUtils.isEmpty(environment.getProperty(VERSION_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(VERSION_MAPPING)))) { + version = environment.getProperty(environment.getProperty(VERSION_MAPPING)); + } else { + version = BootStrapProperties.readServiceVersion(environment); + } + // just check version format + new Version(version); + microservice.setVersion(version); + + microservice.setDescription(BootStrapProperties.readServiceDescription(environment)); + microservice.setLevel(BootStrapProperties.readServiceRole(environment)); + Map propertiesMap = MicroservicePropertiesLoader.INSTANCE.loadProperties(environment); + microservice.setProperties(propertiesMap); + microservice.setEnvironment(BootStrapProperties.readServiceEnvironment(environment)); + + // set alias name when allow cross app + if (microservice.allowCrossApp()) { + microservice.setAlias(Microservice.generateAbsoluteMicroserviceName(microservice.getAppId(), + microservice.getServiceName())); + } + + microservice.setRegisterBy(CONFIG_DEFAULT_REGISTER_BY); + + return microservice; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstance.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstance.java new file mode 100644 index 00000000000..2d919281737 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstance.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.springframework.core.env.Environment; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Created by on 2016/12/5. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class MicroserviceInstance { + // even disconnected from service center + // instanceId will not be changed + // when register to service center again, use the old instanceId. + private String instanceId; + + // service center rule: max length: 64 + private String serviceId; + + private List endpoints = new ArrayList<>(); + + private String hostName; + + private MicroserviceInstanceStatus status = MicroserviceInstanceStatus.UP; + + private Map properties = new HashMap<>(); // reserved key list: region|az|stage|group + + private HealthCheck healthCheck; + + private String stage; + + private DataCenterInfo dataCenterInfo; + + private String timestamp; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("instanceId=" + instanceId + ";"); + sb.append("serviceId=" + serviceId + ";"); + sb.append("status=" + status + ";"); + sb.append("endpoints=" + endpoints.toString()); + return sb.toString(); + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public MicroserviceInstance instanceId(String instanceId) { + this.instanceId = instanceId; + return this; + } + + public String getServiceId() { + return serviceId; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public MicroserviceInstance serviceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public List getEndpoints() { + return endpoints; + } + + public void setEndpoints(List endpoints) { + this.endpoints = endpoints; + } + + public MicroserviceInstanceStatus getStatus() { + return status; + } + + public void setStatus(MicroserviceInstanceStatus status) { + this.status = status; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public HealthCheck getHealthCheck() { + return healthCheck; + } + + public void setHealthCheck(HealthCheck healthCheck) { + this.healthCheck = healthCheck; + } + + @Deprecated + public String getStage() { + return stage; + } + + @Deprecated + public void setStage(String stage) { + this.stage = stage; + } + + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo; + } + + @Override + public int hashCode() { + return this.instanceId.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MicroserviceInstance) { + return this.instanceId.equals(((MicroserviceInstance) obj).instanceId); + } + return false; + } + + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { + this.dataCenterInfo = dataCenterInfo; + } + + // Some properties of microservice instance are dynamic changed, not cover them all now. + public static MicroserviceInstance createFromDefinition(Environment environment) { + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + // default hard coded values + microserviceInstance.setStage(DefinitionConst.DEFAULT_STAGE); + microserviceInstance.setStatus(MicroserviceInstanceStatus + .valueOf(BootStrapProperties.readServiceInstanceInitialStatus(environment))); + HealthCheck healthCheck = new HealthCheck(); + healthCheck.setMode(HealthCheckMode.HEARTBEAT); + microserviceInstance.setHealthCheck(healthCheck); + + // load properties + Map propertiesMap = InstancePropertiesLoader.INSTANCE.loadProperties(environment); + microserviceInstance.setProperties(propertiesMap); + + // load data center information + loadDataCenterInfo(environment, microserviceInstance); + return microserviceInstance; + } + + private static void loadDataCenterInfo(Environment environment, MicroserviceInstance microserviceInstance) { + String dataCenterName = environment.getProperty("servicecomb.datacenter.name"); + if (StringUtils.isEmpty(dataCenterName)) { + return; + } + String region = environment.getProperty("servicecomb.datacenter.region"); + String availableZone = environment.getProperty("servicecomb.datacenter.availableZone"); + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setName(dataCenterName); + dataCenterInfo.setRegion(region); + dataCenterInfo.setAvailableZone(availableZone); + microserviceInstance.setDataCenterInfo(dataCenterInfo); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstances.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstances.java new file mode 100644 index 00000000000..24fd45b5ec2 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroserviceInstances.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.nio.charset.StandardCharsets; + +import javax.crypto.Mac; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.HmacAlgorithms; +import org.apache.commons.codec.digest.HmacUtils; +import org.apache.commons.lang3.StringUtils; + +public class MicroserviceInstances { + private boolean microserviceNotExist; + + private boolean needRefresh = true; + + private String revision; + + private FindInstancesResponse instancesResponse; + + public boolean isMicroserviceNotExist() { + return microserviceNotExist; + } + + public MicroserviceInstances setMicroserviceNotExist(boolean microserviceNotExist) { + this.microserviceNotExist = microserviceNotExist; + return this; + } + + public boolean isNeedRefresh() { + return needRefresh; + } + + public MicroserviceInstances setNeedRefresh(boolean needRefresh) { + this.needRefresh = needRefresh; + return this; + } + + public String getRevision() { + return revision; + } + + public MicroserviceInstances setRevision(String revision) { + this.revision = revision; + return this; + } + + public FindInstancesResponse getInstancesResponse() { + return instancesResponse; + } + + public MicroserviceInstances setInstancesResponse(FindInstancesResponse instancesResponse) { + this.instancesResponse = instancesResponse; + return this; + } + + public void mergeMicroserviceInstances(MicroserviceInstances other) { + mergeNeedRefresh(other.needRefresh); + mergeMicroserviceNotExist(other.microserviceNotExist); + mergeRevision(other); + mergeInstanceResponse(other.getInstancesResponse()); + } + + private void mergeRevision(MicroserviceInstances other) { + if (!other.isMicroserviceNotExist() && other.needRefresh) { + Mac mac = HmacUtils.getInitializedMac(HmacAlgorithms.HMAC_SHA_1, stringToBytes(this.revision)); + this.revision = Base64.encodeBase64String(mac.doFinal(stringToBytes(other.revision))); + } + } + + private byte[] stringToBytes(String input) { + if (StringUtils.isEmpty(input)) { + input = "@"; + } + return input.getBytes(StandardCharsets.UTF_8); + } + + private void mergeMicroserviceNotExist(boolean microserviceNotExist) { + // only is all not exists, set to not exits. + if (this.microserviceNotExist) { + this.microserviceNotExist = microserviceNotExist; + } + } + + private void mergeNeedRefresh(boolean needRefresh) { + // if one of discovery need refresh, all need refresh + if (!this.needRefresh) { + this.needRefresh = needRefresh; + } + } + + private void mergeInstanceResponse(FindInstancesResponse instancesResponse) { + if (instancesResponse == null) { + return; + } + + if (this.instancesResponse == null) { + this.instancesResponse = instancesResponse; + return; + } + + this.instancesResponse.mergeInstances(instancesResponse.getInstances()); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroservicePropertiesLoader.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroservicePropertiesLoader.java new file mode 100644 index 00000000000..ed6d181fb29 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/model/MicroservicePropertiesLoader.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.model; + +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.springframework.core.env.Environment; + +public final class MicroservicePropertiesLoader extends AbstractPropertiesLoader { + + public static final MicroservicePropertiesLoader INSTANCE = new MicroservicePropertiesLoader(); + + private MicroservicePropertiesLoader() { + } + + @Override + protected Map readProperties(Environment environment) { + return BootStrapProperties.readServiceProperties(environment); + } + + @Override + protected String readPropertiesExtendedClass(Environment environment) { + return BootStrapProperties.readServiceExtendedClass(environment); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/AppStore.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/AppStore.java new file mode 100644 index 00000000000..a068c10cb34 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/AppStore.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.store; + +import java.util.Map; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstances; + +public class AppStore { + private final Map microserviceByName = new ConcurrentHashMapEx<>(); + + public void addMicroservice(MicroserviceStore microserviceStore) { + microserviceByName.put(microserviceStore.getServiceName(), microserviceStore); + } + + public MicroserviceInstances findServiceInstances(String serviceName, String revision) { + MicroserviceStore microserviceStore = microserviceByName.get(serviceName); + if (microserviceStore == null) { + return new MicroserviceInstances() + .setMicroserviceNotExist(true); + } + + return microserviceStore.findServiceInstances(revision); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/InstanceStore.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/InstanceStore.java new file mode 100644 index 00000000000..6c2c96f5366 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/InstanceStore.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.store; + +import java.util.List; +import java.util.Objects; + +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +import com.google.common.base.Ticker; + +public class InstanceStore { + private final Ticker ticker; + + private MicroserviceInstance instance; + + private long lastHeartBeat; + + public InstanceStore(Ticker ticker, MicroserviceInstance instance) { + this.ticker = ticker; + this.instance = instance; + + this.updateLastHeartBeat(); + } + + public boolean isStatusChanged(MicroserviceInstanceStatus status) { + return !Objects.equals(instance.getStatus(), status); + } + + public MicroserviceInstance getInstance() { + return instance; + } + + public InstanceStore setInstance(MicroserviceInstance instance) { + this.instance = instance; + return this; + } + + public String getInstanceId() { + return getInstance().getInstanceId(); + } + + public String getServiceId() { + return getInstance().getServiceId(); + } + + public List getEndpoints() { + return getInstance().getEndpoints(); + } + + public MicroserviceInstanceStatus getStatus() { + return instance.getStatus(); + } + + public void setStatus(MicroserviceInstanceStatus status) { + instance.setStatus(status); + } + + public void updateLastHeartBeat() { + this.lastHeartBeat = ticker.read(); + } + + public long getLastHeartBeat() { + return lastHeartBeat; + } + + public boolean isHeartBeatTimeout(long nanoNow, long nanoTimeout) { + return (nanoNow - lastHeartBeat) > nanoTimeout; + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/MicroserviceStore.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/MicroserviceStore.java new file mode 100644 index 00000000000..aa58371ec8c --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/MicroserviceStore.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.store; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.lightweight.model.FindInstancesResponse; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstances; + +import com.google.common.base.Ticker; + +public class MicroserviceStore { + private final Ticker ticker; + + private final Microservice microservice; + + private final Map instancesById = new ConcurrentHashMapEx<>(); + + private String instancesRevision; + + public MicroserviceStore(Ticker ticker, Microservice microservice) { + this.ticker = ticker; + this.microservice = microservice; + + updateInstancesRevision(); + } + + public void updateInstancesRevision() { + this.instancesRevision = String.valueOf(ticker.read()); + } + + public String getServiceName() { + return microservice.getServiceName(); + } + + public String getServiceId() { + return microservice.getServiceId(); + } + + public Microservice getMicroservice() { + return microservice; + } + + public InstanceStore addInstance(MicroserviceInstance instance) { + InstanceStore instanceStore = new InstanceStore(ticker, instance); + + instancesById.put(instance.getInstanceId(), instanceStore); + + updateInstancesRevision(); + return instanceStore; + } + + public InstanceStore deleteInstance(String instanceId) { + InstanceStore instanceStore = instancesById.remove(instanceId); + if (instanceStore != null) { + updateInstancesRevision(); + } + return instanceStore; + } + + public void updateInstanceStatus(InstanceStore instanceStore, MicroserviceInstanceStatus status) { + instanceStore.setStatus(status); + updateInstancesRevision(); + } + + public MicroserviceInstances findServiceInstances(String revision) { + if (instancesRevision.equals(revision)) { + return new MicroserviceInstances() + .setRevision(instancesRevision) + .setNeedRefresh(false); + } + + List instances = instancesById.values().stream() + .map(InstanceStore::getInstance) + .collect(Collectors.toList()); + FindInstancesResponse response = new FindInstancesResponse() + .setInstances(instances); + return new MicroserviceInstances() + .setRevision(instancesRevision) + .setInstancesResponse(response); + } + + + public boolean hasInstance() { + return !instancesById.isEmpty(); + } + + public int getInstanceCount() { + return instancesById.size(); + } +} diff --git a/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/Store.java b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/Store.java new file mode 100644 index 00000000000..c2d31a579cb --- /dev/null +++ b/service-registry/registry-lightweight/src/main/java/org/apache/servicecomb/registry/lightweight/store/Store.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight.store; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstances; + +import com.google.common.base.Ticker; + +public class Store { + private Ticker ticker = Ticker.systemTicker(); + + private final Map appsById = new ConcurrentHashMapEx<>(); + + private final Map microservicesByName = new ConcurrentHashMapEx<>(); + + private final Map microservicesById = new ConcurrentHashMapEx<>(); + + private final Map instancesById = new ConcurrentHashMapEx<>(); + + public Store setTicker(Ticker ticker) { + this.ticker = ticker; + return this; + } + + public AppStore getOrCreateAppStore(String appId) { + return appsById.computeIfAbsent(appId, key -> new AppStore()); + } + + public MicroserviceStore findMicroserviceStore(String serviceId) { + return microservicesById.get(serviceId); + } + + public InstanceStore findInstanceStore(String instanceId) { + return instancesById.get(instanceId); + } + + public MicroserviceStore addMicroservice(Microservice microservice) { + MicroserviceStore microserviceStore = new MicroserviceStore(ticker, microservice); + + getOrCreateAppStore(microservice.getAppId()) + .addMicroservice(microserviceStore); + microservicesById.put(microservice.getServiceId(), microserviceStore); + microservicesByName.put(microservice.getServiceName(), microserviceStore); + + return microserviceStore; + } + + public InstanceStore addInstance(MicroserviceStore microserviceStore, MicroserviceInstance instance) { + InstanceStore instanceStore = microserviceStore.addInstance(instance); + instancesById.put(instance.getInstanceId(), instanceStore); + return instanceStore; + } + + public InstanceStore deleteInstance(String serviceId, String instanceId) { + MicroserviceStore microserviceStore = findMicroserviceStore(serviceId); + if (microserviceStore == null) { + return null; + } + + InstanceStore instanceStore = microserviceStore.deleteInstance(instanceId); + if (instanceStore != null) { + instancesById.remove(instanceId); + } + return instanceStore; + } + + public Optional getMicroservice(String microserviceId) { + return Optional.ofNullable(microservicesById.get(microserviceId)) + .map(MicroserviceStore::getMicroservice); + } + + public Optional getMicroserviceInstance(String instanceId) { + return Optional.ofNullable(instancesById.get(instanceId)) + .map(InstanceStore::getInstance); + } + + public MicroserviceInstances findServiceInstances(String appId, String serviceName, String revision) { + return Optional.ofNullable(appsById.get(appId)) + .map(appStore -> appStore.findServiceInstances(serviceName, revision)) + .orElse(new MicroserviceInstances() + .setMicroserviceNotExist(true)); + } + + public List getAllMicroservices() { + return microservicesByName.values().stream() + .map(MicroserviceStore::getMicroservice) + .collect(Collectors.toList()); + } + + public int getMicroserviceCount() { + return microservicesByName.size(); + } + + public int getInstanceCount() { + return instancesById.size(); + } + + public Stream findDeadInstances(Duration timeout) { + long nanoNow = ticker.read(); + long nanoTimeout = timeout.toNanos(); + return instancesById.values().stream() + .filter(instanceStore -> instanceStore.isHeartBeatTimeout(nanoNow, nanoTimeout)) + .map(InstanceStore::getInstance); + } +} diff --git a/service-registry/registry-lightweight/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-lightweight/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..793c96dc8e5 --- /dev/null +++ b/service-registry/registry-lightweight/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.lightweight.LightWeightRegistryConfiguration diff --git a/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/config/TestAbstractPropertiesLoader.java b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/config/TestAbstractPropertiesLoader.java new file mode 100644 index 00000000000..4e3ceafdc99 --- /dev/null +++ b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/config/TestAbstractPropertiesLoader.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.config; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.lightweight.model.AbstractPropertiesLoader; +import org.apache.servicecomb.registry.lightweight.model.MicroservicePropertiesLoader; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; + +public class TestAbstractPropertiesLoader { + @Test + public void testExtendedClassCompatible() { + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + EnumerablePropertySource propertySource = Mockito.mock(EnumerablePropertySource.class); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] {}); + + Mockito.when(environment.getProperty(BootStrapProperties.CONFIG_SERVICE_EXTENDED_CLASS)) + .thenReturn("invalidClass"); + AbstractPropertiesLoader loader = MicroservicePropertiesLoader.INSTANCE; + try { + loader.loadProperties(environment); + Assertions.fail("Must throw exception"); + } catch (Error e) { + Assertions.assertEquals(ClassNotFoundException.class, e.getCause().getClass()); + Assertions.assertEquals("invalidClass", e.getCause().getMessage()); + } + } +} diff --git a/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/MessageTest.java b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/MessageTest.java new file mode 100644 index 00000000000..0e79f3296c3 --- /dev/null +++ b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/MessageTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import org.junit.jupiter.api.Test; + +import io.vertx.core.json.Json; +import org.skyscreamer.jsonassert.JSONAssert; + +class MessageTest { + private String toLinuxPrettyJson(Object value) { + return Json.encodePrettily(value) + .replaceAll("\r\n", "\n"); + } + + @Test + void should_encode_register_type() { + Message msg = Message.of(MessageType.REGISTER, new RegisterRequest()); + + try { + JSONAssert.assertEquals(toLinuxPrettyJson(msg), "" + + "{\n" + + " \"type\" : \"REGISTER\",\n" + + " \"body\" : {\n" + + " \"appId\" : null,\n" + + " \"serviceId\" : null,\n" + + " \"crossApp\" : false,\n" + + " \"schemasSummary\" : null,\n" + + " \"instanceId\" : null,\n" + + " \"status\" : null,\n" + + " \"endpoints\" : null\n" + + " }\n" + + "}", false); + } catch (Exception e) { + fail("Failed to compare JSONs: " + e.getMessage(), e); + } + + } + + @Test + void should_decode_register_type() { + String json = Json.encode(Message.of(MessageType.REGISTER, new RegisterRequest())); + Message message = Json.decodeValue(json, Message.class); + + assertThat(message.getBody()).isInstanceOf(RegisterRequest.class); + } + + @Test + void should_encode_unregister_type() { + Message msg = Message.of(MessageType.UNREGISTER, new UnregisterRequest()); + + try { + JSONAssert.assertEquals(toLinuxPrettyJson(msg), "" + + "{\n" + + " \"type\" : \"UNREGISTER\",\n" + + " \"body\" : {\n" + + " \"serviceId\" : null,\n" + + " \"instanceId\" : null\n" + + " }\n" + + "}", false); + } catch (Exception e) { + fail("Failed to compare JSONs: " + e.getMessage(), e); + } + } + + @Test + void should_decode_unregister_type() { + String json = Json.encode(Message.of(MessageType.UNREGISTER, new UnregisterRequest())); + Message message = Json.decodeValue(json, Message.class); + + assertThat(message.getBody()).isInstanceOf(UnregisterRequest.class); + } +} diff --git a/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java new file mode 100644 index 00000000000..efaf9665dc5 --- /dev/null +++ b/service-registry/registry-lightweight/src/test/java/org/apache/servicecomb/registry/lightweight/StoreServiceTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.lightweight; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.foundation.test.scaffolding.time.MockTicker; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.store.InstanceStore; +import org.apache.servicecomb.registry.lightweight.store.Store; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; + +import com.google.common.eventbus.EventBus; + +import io.vertx.core.json.Json; + +public class StoreServiceTest { + static Endpoint endpoint = Mockito.mock(Endpoint.class); + + static class MockRegisterRequest extends RegisterRequest { + @Override + public Endpoint selectFirstEndpoint() { + return endpoint; + } + } + + static ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + + Self self; + + EventBus eventBus = new EventBus(); + + MockTicker ticker = new MockTicker(); + + Store store = new Store().setTicker(ticker); + + DiscoveryClient discoveryClient = Mockito.mock(DiscoveryClient.class); + + StoreService service = new StoreService(eventBus, store, discoveryClient); + + @BeforeEach + void setUp() { + MutablePropertySources mutablePropertySources = new MutablePropertySources(); + EnumerablePropertySource propertySource = Mockito.mock(EnumerablePropertySource.class); + mutablePropertySources.addLast(propertySource); + Mockito.when(environment.getPropertySources()).thenReturn(mutablePropertySources); + Mockito.when(propertySource.getPropertyNames()).thenReturn(new String[] {}); + Mockito.when(environment.getProperty("servicecomb.service.application")).thenReturn("app"); + Mockito.when(environment.getProperty("servicecomb.service.name")).thenReturn("svc"); + Mockito.when(environment.getProperty("servicecomb.service.version")).thenReturn("1.0.0.0"); + Mockito.when(environment.getProperty("servicecomb.instance.initialStatus")).thenReturn("UP"); + + self = new Self() { + @Override + protected RegisterRequest createRegisterRequest() { + return new MockRegisterRequest(); + } + }; + self.setRegistrationId(new RegistrationId()); + self.init(environment) + .addSchema("schema-1", "s1") + .addEndpoint("rest://1.1.1.1:80"); + + Mockito.when(discoveryClient.getInfoAsync(ArgumentMatchers.any(), ArgumentMatchers.any())) + .thenReturn(CompletableFuture.completedFuture(self.getMicroserviceInfo())); + Mockito.when(discoveryClient.getInstanceAsync(ArgumentMatchers.any(), ArgumentMatchers.any())) + .thenReturn(CompletableFuture.completedFuture(self.getInstance())); + } + + @Test + void should_register_microservice_and_instance_when_both_not_exist() { + RegisterRequest request = self.buildRegisterRequest(); + InstanceStore instanceStore = service.register(request); + + assertThat(store.findMicroserviceStore(self.getServiceId()).getMicroservice()) + .isSameAs(self.getMicroservice()); + assertThat(instanceStore.getInstance()).isSameAs(self.getInstance()); + assertThat(self.getInstance().getStatus()).isEqualTo(MicroserviceInstanceStatus.UP); + } + + @Test + void should_register_instance_when_microservice_exist() { + Microservice microservice = Json.decodeValue(Json.encode(self.getMicroservice()), Microservice.class); + store.addMicroservice(microservice); + + RegisterRequest request = self.buildRegisterRequest(); + InstanceStore instanceStore = service.register(request); + + assertThat(microservice).isNotSameAs(self.getMicroservice()); + assertThat(store.findMicroserviceStore(self.getServiceId()).getMicroservice()) + .isSameAs(microservice); + assertThat(instanceStore.getInstance()).isSameAs(self.getInstance()); + } + + + @Test + void should_allow_update_instance_status() { + should_register_microservice_and_instance_when_both_not_exist(); + + RegisterRequest request = self.buildRegisterRequest() + .setStatus(MicroserviceInstanceStatus.TESTING); + ticker.setValues(1L); + InstanceStore instanceStore = service.register(request); + + assertThat(self.getInstance().getStatus()).isEqualTo(MicroserviceInstanceStatus.TESTING); + assertThat(instanceStore.getLastHeartBeat()).isEqualTo(1); + } + + @Test + void should_process_as_heartbeat_when_nothing_changed() { + should_register_microservice_and_instance_when_both_not_exist(); + InstanceStore instanceStore = store.findInstanceStore(self.getInstanceId()); + assertThat(instanceStore.getLastHeartBeat()).isEqualTo(0); + + ticker.setValues(1L); + should_register_microservice_and_instance_when_both_not_exist(); + assertThat(instanceStore.getLastHeartBeat()).isEqualTo(1); + } +} diff --git a/service-registry/registry-local/pom.xml b/service-registry/registry-local/pom.xml new file mode 100644 index 00000000000..e3ddcc5510b --- /dev/null +++ b/service-registry/registry-local/pom.xml @@ -0,0 +1,85 @@ + + + + + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-local + Java Chassis::Java Chassis::Service Registry::Local + + + + org.apache.servicecomb + foundation-vertx + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + swagger-generator-core + + + org.apache.servicecomb + java-chassis-core + + + + org.apache.servicecomb + foundation-registry + + + + org.apache.commons + commons-lang3 + + + + io.vertx + vertx-codegen + provided + + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscovery.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscovery.java new file mode 100644 index 00000000000..4d3a0a6e822 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscovery.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.localregistry; + + +import java.util.List; + +import org.apache.servicecomb.registry.api.Discovery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class LocalDiscovery implements Discovery { + public static final String LOCAL_DISCOVERY_ENABLED = "servicecomb.registry.local.%s.%s.enabled"; + + private LocalRegistryStore localRegistryStore; + + private Environment environment; + + @Autowired + public void setLocalRegistryStore(LocalRegistryStore localRegistryStore) { + this.localRegistryStore = localRegistryStore; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public int getOrder() { + return -10000; + } + + @Override + public String name() { + return LocalRegistryConst.LOCAL_REGISTRY_NAME; + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(LOCAL_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + return this.localRegistryStore.findServiceInstances(application, serviceName); + } + + @Override + public List findServices(String application) { + return this.localRegistryStore.findServices(application); + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + + } + + @Override + public void init() { + this.localRegistryStore.init(); + } + + @Override + public void run() { + this.localRegistryStore.run(); + } + + @Override + public void destroy() { + } + + @Override + public boolean enabled() { + return this.environment.getProperty(LocalRegistryConst.LOCAL_REGISTRY_ENABLED, boolean.class, true); + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscoveryInstance.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscoveryInstance.java new file mode 100644 index 00000000000..ff8e10794f1 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalDiscoveryInstance.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.localregistry; + +import java.lang.management.ManagementFactory; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.models.OpenAPI; + +public class LocalDiscoveryInstance extends AbstractDiscoveryInstance { + private static final AtomicLong INSTANCE_ID = new AtomicLong(); + + private final RegistryBean registryBean; + + private final LocalRegistrationInstance localRegistrationInstance; + + private final List endpoints; + + private final String instanceId; + + public LocalDiscoveryInstance(LocalOpenAPIRegistry localOpenAPIRegistry, + RegistryBean registryBean, List endpoints, + LocalRegistrationInstance localRegistrationInstance) { + this.registryBean = registryBean; + this.localRegistrationInstance = localRegistrationInstance; + this.endpoints = endpoints; + this.instanceId = System.currentTimeMillis() + "-" + + ManagementFactory.getRuntimeMXBean().getPid() + "-" + INSTANCE_ID.getAndIncrement(); + + registryBean.getSchemaInterfaces().forEach((k, v) -> { + SwaggerGenerator generator = SwaggerGenerator.create(v); + OpenAPI openAPI = generator.generate(); + if (openAPI == null) { + throw new IllegalStateException(String.format("Generate schema for %s/%s/%s failed.", + registryBean.getAppId(), registryBean.getServiceName(), k)); + } + String schemaContent = SwaggerUtils.swaggerToString(openAPI); + if (StringUtils.isEmpty(schemaContent)) { + throw new IllegalStateException(String.format("Generate schema for %s/%s/%s failed.", + registryBean.getAppId(), registryBean.getServiceName(), k)); + } + localOpenAPIRegistry.registerOpenAPI(registryBean.getAppId(), registryBean.getServiceName(), + k, openAPI); + }); + } + + public LocalDiscoveryInstance(LocalRegistrationInstance registrationInstance) { + this.registryBean = new RegistryBean(); + this.registryBean.setAppId(registrationInstance.getApplication()); + this.registryBean.setServiceName(registrationInstance.getServiceName()); + this.registryBean.setVersion(registrationInstance.getVersion()); + this.localRegistrationInstance = registrationInstance; + this.endpoints = registrationInstance.getEndpoints(); + this.instanceId = registrationInstance.getInstanceId(); + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.UP; + } + + @Override + public String getRegistryName() { + return LocalRegistryConst.LOCAL_REGISTRY_NAME; + } + + @Override + public String getEnvironment() { + return localRegistrationInstance.getEnvironment(); + } + + @Override + public String getApplication() { + return registryBean.getAppId(); + } + + @Override + public String getServiceName() { + return registryBean.getServiceName(); + } + + @Override + public String getAlias() { + return null; + } + + @Override + public String getVersion() { + return registryBean.getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return null; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public Map getProperties() { + return null; + } + + @Override + public Map getSchemas() { + // not implement + return Collections.emptyMap(); + } + + @Override + public List getEndpoints() { + return endpoints; + } + + @Override + public String getInstanceId() { + return instanceId; + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistration.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistration.java new file mode 100644 index 00000000000..0269d7b8945 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistration.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.localregistry; + +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class LocalRegistration implements Registration { + private final LocalRegistrationInstance localRegistrationInstance; + + private Environment environment; + + public LocalRegistration(LocalRegistrationInstance localRegistrationInstance) { + this.localRegistrationInstance = localRegistrationInstance; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void init() { + + } + + @Override + public void run() { + + } + + @Override + public void destroy() { + + } + + @Override + public String name() { + return LocalRegistryConst.LOCAL_REGISTRY_NAME; + } + + @Override + public LocalRegistrationInstance getMicroserviceInstance() { + return localRegistrationInstance; + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + return true; + } + + @Override + public void addSchema(String schemaId, String content) { + // not implement + } + + @Override + public void addEndpoint(String endpoint) { + localRegistrationInstance.addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + localRegistrationInstance.addProperty(key, value); + } + + @Override + public boolean enabled() { + return this.environment.getProperty(LocalRegistryConst.LOCAL_REGISTRY_ENABLED, Boolean.class, true); + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistrationInstance.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistrationInstance.java new file mode 100644 index 00000000000..e07527636a9 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistrationInstance.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.localregistry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.springframework.core.env.Environment; + +public class LocalRegistrationInstance implements RegistrationInstance { + private final Environment environment; + + private final DataCenterInfo dataCenterInfo; + + private final LocalOpenAPIRegistry localOpenAPIRegistry; + + private final String instanceId; + + private final Map schemas = new HashMap<>(); + + private final List endpoints = new ArrayList<>(); + + private final Map properties = new HashMap<>(); + + public LocalRegistrationInstance( + Environment environment, + DataCenterProperties dataCenterProperties, + LocalOpenAPIRegistry localOpenAPIRegistry, + RegistrationId registrationId) { + this.environment = environment; + this.localOpenAPIRegistry = localOpenAPIRegistry; + + this.dataCenterInfo = new DataCenterInfo(); + this.dataCenterInfo.setName(dataCenterProperties.getName()); + this.dataCenterInfo.setRegion(dataCenterProperties.getRegion()); + this.dataCenterInfo.setAvailableZone(dataCenterProperties.getAvailableZone()); + + this.properties.putAll(BootStrapProperties.readServiceProperties(environment)); + + this.instanceId = registrationId.getInstanceId(); + } + + @Override + public String getEnvironment() { + return BootStrapProperties.readServiceEnvironment(environment); + } + + @Override + public String getApplication() { + return BootStrapProperties.readApplication(environment); + } + + @Override + public String getServiceName() { + return BootStrapProperties.readServiceName(environment); + } + + @Override + public String getAlias() { + return BootStrapProperties.readServiceAlias(environment); + } + + @Override + public String getVersion() { + return BootStrapProperties.readServiceVersion(environment); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo; + } + + @Override + public String getDescription() { + return BootStrapProperties.readServiceDescription(environment); + } + + @Override + public Map getProperties() { + return this.properties; + } + + @Override + public Map getSchemas() { + return this.schemas; + } + + @Override + public List getEndpoints() { + return this.endpoints; + } + + @Override + public String getInstanceId() { + return this.instanceId; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.UP; + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } + + public void addProperty(String key, String value) { + this.properties.put(key, value); + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConfiguration.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConfiguration.java new file mode 100644 index 00000000000..9ebdcca368b --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConfiguration.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.localregistry; + +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.registry.RegistrationId; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class LocalRegistryConfiguration { + @Bean + public LocalRegistrationInstance localRegistrationInstance( + Environment environment, + DataCenterProperties dataCenterProperties, + LocalOpenAPIRegistry localOpenAPIRegistry, + RegistrationId registrationId) { + return new LocalRegistrationInstance(environment, dataCenterProperties, localOpenAPIRegistry, registrationId); + } + + @Bean + public LocalRegistration localRegistration(LocalRegistrationInstance localRegistrationInstance) { + return new LocalRegistration(localRegistrationInstance); + } + + @Bean + public LocalDiscovery localDiscovery() { + return new LocalDiscovery(); + } + + @Bean + public LocalRegistryStore localRegistryStore() { + return new LocalRegistryStore(); + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConst.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConst.java new file mode 100644 index 00000000000..6e54b29e7cd --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryConst.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.localregistry; + +public class LocalRegistryConst { + public static final String LOCAL_REGISTRY_ENABLED = "servicecomb.registry.local.enabled"; + + public static final String LOCAL_REGISTRY_NAME = "local-registry"; +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java new file mode 100644 index 00000000000..3af782e5900 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/LocalRegistryStore.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.localregistry; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.servicecomb.config.YAMLUtil; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.common.utils.JvmUtils; +import org.apache.servicecomb.localregistry.RegistryBean.Instance; +import org.springframework.beans.factory.annotation.Autowired; + +public class LocalRegistryStore { + private static final String REGISTRY_FILE_NAME = "registry.yaml"; + + private LocalRegistrationInstance selfMicroserviceInstance; + + private LocalOpenAPIRegistry localOpenAPIRegistry; + + // application:serviceName + private final Map>> + microserviceInstanceMap = new ConcurrentHashMap<>(); + + public LocalRegistryStore() { + + } + + @Autowired + public void setLocalRegistrationInstance(LocalRegistrationInstance selfMicroserviceInstance) { + this.selfMicroserviceInstance = selfMicroserviceInstance; + } + + @Autowired + public void setLocalOpenAPIRegistry(LocalOpenAPIRegistry localOpenAPIRegistry) { + this.localOpenAPIRegistry = localOpenAPIRegistry; + } + + public void init() { + microserviceInstanceMap.clear(); + } + + public void run() { + List beans = loadYamlBeans(); + BeanUtils.getBeansOfType(RegistryBean.class).forEach((key, value) -> beans.add(value)); + + initRegistryFromBeans(beans); + + addSelf(); + } + + private void addSelf() { + microserviceInstanceMap.computeIfAbsent(selfMicroserviceInstance.getApplication(), key -> + new ConcurrentHashMapEx<>()).computeIfAbsent(selfMicroserviceInstance.getServiceName(), key -> + new ArrayList<>()).add(new LocalDiscoveryInstance(selfMicroserviceInstance)); + } + + private List loadYamlBeans() { + List beans = new ArrayList<>(); + + try { + ClassLoader loader = JvmUtils.findClassLoader(); + Enumeration urls = loader.getResources(REGISTRY_FILE_NAME); + + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + + try (InputStream is = url.openStream()) { + if (is != null) { + beans.addAll(initFromData(is)); + } + } + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + + return beans; + } + + private List initFromData(InputStream is) { + Map data = YAMLUtil.yaml2Properties(is); + return initFromData(data); + } + + @SuppressWarnings("unchecked") + private List initFromData(Map data) { + List beans = new ArrayList<>(); + + for (Entry entry : data.entrySet()) { + String name = entry.getKey(); + List> serviceConfigs = (List>) entry.getValue(); + for (Map serviceConfig : serviceConfigs) { + beans.add(RegistryBean.buildFromYamlModel(name, serviceConfig)); + } + } + return beans; + } + + private void initRegistryFromBeans(List beans) { + beans.forEach((bean -> { + List instances = microserviceInstanceMap.computeIfAbsent(bean.getAppId(), key -> + new ConcurrentHashMapEx<>()).computeIfAbsent(bean.getServiceName(), key -> + new ArrayList<>()); + if (bean.getInstances() == null) { + return; + } + for (Instance instance : bean.getInstances().getInstances()) { + instances.add(new LocalDiscoveryInstance(localOpenAPIRegistry, + bean, instance.getEndpoints(), selfMicroserviceInstance)); + } + })); + } + + public List findServiceInstances(String application, String serviceName) { + Map> app = microserviceInstanceMap.get(application); + if (app == null) { + return Collections.emptyList(); + } + List instances = app.get(serviceName); + if (instances == null) { + return Collections.emptyList(); + } + return instances; + } + + public List findServices(String application) { + if (microserviceInstanceMap.get(application) == null) { + return Collections.emptyList(); + } + return microserviceInstanceMap.get(application).keySet().stream().toList(); + } +} diff --git a/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/RegistryBean.java b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/RegistryBean.java new file mode 100644 index 00000000000..3a3ac85d457 --- /dev/null +++ b/service-registry/registry-local/src/main/java/org/apache/servicecomb/localregistry/RegistryBean.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.localregistry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; + +/** + * + * Configuration bean for local services. Bean configuration is token + * same as `registry.yaml` file configuration. + * + */ +public class RegistryBean { + public static class Instances { + private List instances; + + public List getInstances() { + return instances; + } + + public Instances setInstances(List instances) { + this.instances = instances; + return this; + } + } + + public static class Instance { + private List endpoints; + + public List getEndpoints() { + return endpoints; + } + + public Instance setEndpoints(List endpoints) { + this.endpoints = endpoints; + return this; + } + } + + private String id; + + private String serviceName; + + private String version; + + private String appId; + + /** + * Schema ids configured from RegistryBean. Generate schema content from Class. + */ + private final Map> schemaInterfaces = new HashMap<>(); + + /** + * Schema ids configured in yaml. Will load contents from local file. + */ + private List schemaIds = new ArrayList<>(); + + private Instances instances; + + @SuppressWarnings("unchecked") + public static RegistryBean buildFromYamlModel + (String serviceName, Map serviceConfig) { + return new RegistryBean() + .setId(validId((String) serviceConfig.get("id"))) + .setServiceName(serviceName) + .setVersion((String) serviceConfig.get("version")) + .setAppId(validAppId((String) serviceConfig.get("appid"))) + .setSchemaIds(validListsValue((List) serviceConfig.get("schemaIds"))) + .setInstances( + new Instances() + .setInstances(validInstances((List>) serviceConfig.get("instances")))); + } + + @SuppressWarnings("unchecked") + private static List validInstances(List> instancesConfig) { + if (instancesConfig == null) { + return Collections.emptyList(); + } + + List instances = new ArrayList<>(); + for (Map instanceConfig : instancesConfig) { + instances.add(new Instance().setEndpoints( + validListsValue((List) instanceConfig.get("endpoints")))); + } + return instances; + } + + private static List validListsValue(List listsValue) { + return listsValue == null ? Collections.emptyList() : listsValue; + } + + private static String validId(String serviceId) { + return StringUtils.isEmpty(serviceId) ? UUID.randomUUID().toString() : serviceId; + } + + private static String validAppId(String configAppId) { + if (!StringUtils.isEmpty(configAppId)) { + return configAppId; + } + return BootStrapProperties.DEFAULT_APPLICATION; + } + + public String getId() { + return id; + } + + public RegistryBean setId(String id) { + this.id = id; + return this; + } + + public String getServiceName() { + return serviceName; + } + + public RegistryBean setServiceName(String serviceName) { + this.serviceName = serviceName; + return this; + } + + public String getVersion() { + return version; + } + + public RegistryBean setVersion(String version) { + this.version = version; + return this; + } + + public String getAppId() { + return appId; + } + + public RegistryBean setAppId(String appId) { + this.appId = appId; + return this; + } + + public RegistryBean addSchemaInterface(String schemaId, Class schemaInterface) { + this.schemaInterfaces.put(schemaId, schemaInterface); + return this; + } + + public RegistryBean addSchemaId(String schemaId) { + this.schemaIds.add(schemaId); + return this; + } + + public RegistryBean setSchemaIds(List schemaIds) { + this.schemaIds = schemaIds; + return this; + } + + public List getSchemaIds() { + return this.schemaIds; + } + + public Map> getSchemaInterfaces() { + return this.schemaInterfaces; + } + + public Instances getInstances() { + return instances; + } + + public RegistryBean setInstances(Instances instances) { + this.instances = instances; + return this; + } +} diff --git a/service-registry/registry-local/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-local/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..39d17511373 --- /dev/null +++ b/service-registry/registry-local/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.localregistry.LocalRegistryConfiguration diff --git a/service-registry/registry-nacos/pom.xml b/service-registry/registry-nacos/pom.xml new file mode 100644 index 00000000000..11e58275235 --- /dev/null +++ b/service-registry/registry-nacos/pom.xml @@ -0,0 +1,51 @@ + + + + + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-nacos + Java Chassis::Service Registry::Nacos + + + + com.alibaba.nacos + nacos-client + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + java-chassis-core + + + + diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConfiguration.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConfiguration.java new file mode 100644 index 00000000000..24eaf50a33d --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConfiguration.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.registry.RegistrationId; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class NacosConfiguration { + @Bean + @ConfigurationProperties(prefix = NacosConst.NACOS_REGISTRY_PREFIX) + public NacosDiscoveryProperties nacosDiscoveryProperties() { + return new NacosDiscoveryProperties(); + } + + @Bean + public NacosRegistration nacosRegistration( + DataCenterProperties dataCenterProperties, + @Qualifier("nacosDiscoveryProperties") NacosDiscoveryProperties nacosDiscoveryProperties, + Environment environment, RegistrationId registrationId) { + return new NacosRegistration(dataCenterProperties, nacosDiscoveryProperties, environment, registrationId); + } + + @Bean + public NacosDiscovery nacosDiscovery( + @Qualifier("nacosDiscoveryProperties") NacosDiscoveryProperties nacosDiscoveryProperties) { + return new NacosDiscovery(nacosDiscoveryProperties); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConst.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConst.java new file mode 100644 index 00000000000..563d1726095 --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosConst.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +public class NacosConst { + public static final String PROPERTY_VERSION = "scb-version"; + + public static final String PROPERTY_ALIAS = "scb-alias"; + + public static final String PROPERTY_DESCRIPTION = "scb-description"; + + public static final String PROPERTY_ENDPOINT = "scb-endpoint"; + + public static final String PROPERTY_REGION = "scb-region"; + + public static final String PROPERTY_ZONE = "scb-zone"; + + public static final String PROPERTY_DATACENTER = "scb-datacenter"; + + public static final String PROPERTY_SCHEMA_PREFIX = "scb-schema-"; + + public static final String ENDPOINT_PROPERTY_SEPARATOR = ","; + + public static final String NACOS_REGISTRY_PREFIX = "servicecomb.registry.nacos"; + + public static final String SERVER_ADDR = "serverAddr"; + + public static final String USERNAME = "username"; + + public static final String PASSWORD = "password"; + + public static final String NAMESPACE = "namespace"; + + public static final String NACOS_NAMING_LOG_NAME = "com.alibaba.nacos.naming.log.filename"; + + public static final String ACCESS_KEY = "accessKey"; + + public static final String SECRET_KEY = "secretKey"; + + public static final String CLUSTER_NAME = "clusterName"; + + public static final String NAMING_LOAD_CACHE_AT_START = "namingLoadCacheAtStart"; + + public static final String NACOS_REGISTRY_NAME = "nacos-registry"; + + public static final String NACOS_STATUS = "nacos-status"; +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscovery.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscovery.java new file mode 100644 index 00000000000..dfe2a5739eb --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscovery.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.alibaba.nacos.api.exception.NacosException; + +import org.apache.servicecomb.registry.api.Discovery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.alibaba.nacos.api.naming.pojo.Instance; + +public class NacosDiscovery implements Discovery { + public static final String NACOS_DISCOVERY_ENABLED = "servicecomb.registry.nacos.%s.%s.enabled"; + + private static final Map> SUBSCRIBES = new HashMap<>(); + + private final Object lock = new Object(); + + private final NacosDiscoveryProperties nacosDiscoveryProperties; + + private Environment environment; + + private NamingService namingService; + + private InstanceChangedListener instanceChangedListener; + + @Autowired + public NacosDiscovery(NacosDiscoveryProperties nacosDiscoveryProperties) { + this.nacosDiscoveryProperties = nacosDiscoveryProperties; + } + + @Autowired + @SuppressWarnings("unused") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public String name() { + return NacosConst.NACOS_REGISTRY_NAME; + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(NACOS_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + try { + // Get the instance first, and the Listener will not be executed for the first subscribe. + List instances = namingService.getAllInstances(serviceName, application, true); + + AtomicBoolean result = SUBSCRIBES.computeIfAbsent(application, + k -> new HashMap<>()).computeIfAbsent(serviceName, k -> new AtomicBoolean(true)); + if (result.get()) { + synchronized (lock) { + if (result.get()) { + namingService.subscribe(serviceName, application, (event) -> { + if (event instanceof NamingEvent) { + this.instanceChangedListener.onInstanceChanged(name(), application, serviceName, + convertServiceInstanceList(((NamingEvent) event).getInstances(), application, serviceName)); + } + }); + result.set(false); + } + } + } + return convertServiceInstanceList(instances, application, serviceName); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public List findServices(String application) { + try { + return namingService.getServicesOfServer(0, Integer.MAX_VALUE, application) + .getData(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private List convertServiceInstanceList( + List instances, String application, String serviceName) { + if (CollectionUtils.isEmpty(instances)) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (Instance instance : instances) { + result.add(new NacosDiscoveryInstance(instance, application, serviceName, environment)); + } + return result; + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + this.instanceChangedListener = instanceChangedListener; + } + + @Override + public void init() { + namingService = NamingServiceManager.buildNamingService(environment, nacosDiscoveryProperties); + } + + @Override + public void run() { + + } + + @Override + public void destroy() { + if (namingService != null) { + try { + namingService.shutDown(); + } catch (NacosException e) { + throw new IllegalStateException("destroy process is interrupted."); + } + } + } + + @Override + public boolean enabled() { + return nacosDiscoveryProperties.isEnabled(); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryInstance.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryInstance.java new file mode 100644 index 00000000000..6360d012012 --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryInstance.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.springframework.core.env.Environment; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +public class NacosDiscoveryInstance extends AbstractDiscoveryInstance { + private final Instance instance; + + private final String application; + + private final String serviceName; + + private final Environment environment; + + private final Map schemas; + + private final List endpoints; + + public NacosDiscoveryInstance(Instance instance, String application, String serviceName, + Environment environment) { + this.instance = instance; + this.environment = environment; + this.application = application; + this.serviceName = serviceName; + this.endpoints = readEndpoints(instance); + this.schemas = readSchemas(instance); + } + + @Override + public MicroserviceInstanceStatus getStatus() { + if (instance.isEnabled()) { + String instanceStatus = instance.getMetadata().get(NacosConst.NACOS_STATUS); + if (StringUtils.isBlank(instanceStatus)) { + return MicroserviceInstanceStatus.UP; + } + return MicroserviceInstanceStatus.valueOf(instanceStatus); + } else { + return MicroserviceInstanceStatus.DOWN; + } + } + + @Override + public String getRegistryName() { + return NacosConst.NACOS_REGISTRY_NAME; + } + + @Override + public String getEnvironment() { + return BootStrapProperties.readServiceEnvironment(environment); + } + + @Override + public String getApplication() { + return this.application; + } + + @Override + public String getServiceName() { + // nacos instance service name may contain group and `@` annotations + return this.serviceName; + } + + @Override + public String getAlias() { + return instance.getMetadata().get(NacosConst.PROPERTY_ALIAS); + } + + @Override + public String getVersion() { + return instance.getMetadata().get(NacosConst.PROPERTY_VERSION); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setRegion(instance.getMetadata().get(NacosConst.PROPERTY_REGION)); + dataCenterInfo.setAvailableZone(instance.getMetadata().get(NacosConst.PROPERTY_ZONE)); + dataCenterInfo.setName(instance.getMetadata().get(NacosConst.PROPERTY_DATACENTER)); + return dataCenterInfo; + } + + @Override + public String getDescription() { + return instance.getMetadata().get(NacosConst.PROPERTY_DESCRIPTION); + } + + @Override + public Map getProperties() { + return instance.getMetadata(); + } + + @Override + public Map getSchemas() { + return schemas; + } + + private static Map readSchemas(Instance instance) { + Map metaData = instance.getMetadata(); + Map instanceSchemas = new HashMap<>(); + for (Map.Entry entry : metaData.entrySet()) { + if (entry.getKey().startsWith(NacosConst.PROPERTY_SCHEMA_PREFIX)) { + instanceSchemas.put(entry.getKey().substring(NacosConst.PROPERTY_SCHEMA_PREFIX.length()), + entry.getValue()); + } + } + return instanceSchemas; + } + + @Override + public List getEndpoints() { + return endpoints; + } + + private static List readEndpoints(Instance instance) { + if (StringUtils.isEmpty(instance.getMetadata().get(NacosConst.PROPERTY_ENDPOINT))) { + // interoperate with spring cloud using nacos + if (StringUtils.isNotEmpty(instance.getIp()) && instance.getPort() > 0) { + return List.of("rest://" + instance.getIp() + ":" + instance.getPort()); + } + return Collections.emptyList(); + } + return Arrays.asList(instance.getMetadata().get(NacosConst.PROPERTY_ENDPOINT) + .split(NacosConst.ENDPOINT_PROPERTY_SEPARATOR)); + } + + @Override + public String getInstanceId() { + return instance.getInstanceId(); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryProperties.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryProperties.java new file mode 100644 index 00000000000..70ff0cee500 --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosDiscoveryProperties.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.HashMap; +import java.util.Map; + +public class NacosDiscoveryProperties { + private boolean enabled = true; + + private String serverAddr = "http://127.0.0.1:8848"; + + private Map metadata = new HashMap<>(); + + private boolean ephemeral = true; + + private String username; + + private String password; + + private String accessKey; + + private String secretKey; + + private String namingLoadCacheAtStart = "false"; + + private String clusterName = "DEFAULT"; + + private float weight = 1; + + private boolean instanceEnabled = true; + + private String logName; + + private boolean enableSwaggerRegistration = false; + + public String getServerAddr() { + return serverAddr; + } + + public void setServerAddr(String serverAddr) { + this.serverAddr = serverAddr; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public boolean isEphemeral() { + return ephemeral; + } + + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getNamingLoadCacheAtStart() { + return namingLoadCacheAtStart; + } + + public void setNamingLoadCacheAtStart(String namingLoadCacheAtStart) { + this.namingLoadCacheAtStart = namingLoadCacheAtStart; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public boolean isInstanceEnabled() { + return instanceEnabled; + } + + public void setInstanceEnabled(boolean instanceEnabled) { + this.instanceEnabled = instanceEnabled; + } + + public String getLogName() { + return logName; + } + + public void setLogName(String logName) { + this.logName = logName; + } + + public boolean isEnableSwaggerRegistration() { + return enableSwaggerRegistration; + } + + public void setEnableSwaggerRegistration(boolean enableSwaggerRegistration) { + this.enableSwaggerRegistration = enableSwaggerRegistration; + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosMicroserviceHandler.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosMicroserviceHandler.java new file mode 100644 index 00000000000..29aed07bffb --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosMicroserviceHandler.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.config.DataCenterProperties; +import org.springframework.core.env.Environment; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.utils.NamingUtils; + +public class NacosMicroserviceHandler { + private static final String VERSION_MAPPING = "VERSION_MAPPING"; + + private static final String CAS_APPLICATION_ID = "CAS_APPLICATION_ID"; + + private static final String CAS_COMPONENT_NAME = "CAS_COMPONENT_NAME"; + + private static final String CAS_INSTANCE_VERSION = "CAS_INSTANCE_VERSION"; + + private static final String CAS_INSTANCE_ID = "CAS_INSTANCE_ID"; + + private static final String CAS_ENVIRONMENT_ID = "CAS_ENVIRONMENT_ID"; + + private static final String INSTANCE_PROPS = "SERVICECOMB_INSTANCE_PROPS"; + + public static Instance createMicroserviceInstance( + DataCenterProperties dataCenterProperties, NacosDiscoveryProperties properties, Environment environment) { + Instance instance = new Instance(); + instance.setServiceName(NamingUtils.getGroupedName( + BootStrapProperties.readServiceName(environment), BootStrapProperties.readApplication(environment))); + instance.setWeight(properties.getWeight()); + instance.setEnabled(properties.isInstanceEnabled()); + instance.setClusterName(properties.getClusterName()); + instance.setEphemeral(properties.isEphemeral()); + + Map metadata = properties.getMetadata(); + metadata.put(NacosConst.PROPERTY_VERSION, BootStrapProperties.readServiceVersion(environment)); + metadata.put(NacosConst.PROPERTY_ALIAS, BootStrapProperties.readServiceAlias(environment)); + metadata.put(NacosConst.PROPERTY_DESCRIPTION, BootStrapProperties.readServiceDescription(environment)); + metadata.put(NacosConst.PROPERTY_DATACENTER, dataCenterProperties.getName()); + metadata.put(NacosConst.PROPERTY_REGION, dataCenterProperties.getRegion()); + metadata.put(NacosConst.PROPERTY_ZONE, dataCenterProperties.getAvailableZone()); + if (!StringUtils.isEmpty(environment.getProperty(VERSION_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(VERSION_MAPPING)))) { + metadata.put("version", environment.getProperty(environment.getProperty(VERSION_MAPPING))); + } + metadata.putAll(genCasProperties(environment)); + instance.setMetadata(metadata); + return instance; + } + + private static Map genCasProperties(Environment environment) { + Map properties = new HashMap<>(); + if (!StringUtils.isEmpty(environment.getProperty(CAS_APPLICATION_ID))) { + properties.put(CAS_APPLICATION_ID, environment.getProperty(CAS_APPLICATION_ID)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_COMPONENT_NAME))) { + properties.put(CAS_COMPONENT_NAME, environment.getProperty(CAS_COMPONENT_NAME)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_INSTANCE_VERSION))) { + properties.put(CAS_INSTANCE_VERSION, environment.getProperty(CAS_INSTANCE_VERSION)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_INSTANCE_ID))) { + properties.put(CAS_INSTANCE_ID, environment.getProperty(CAS_INSTANCE_ID)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_ENVIRONMENT_ID))) { + properties.put(CAS_ENVIRONMENT_ID, environment.getProperty(CAS_ENVIRONMENT_ID)); + } + + String[] instancePropArray = ConfigUtil.parseArrayValue(environment.getProperty(INSTANCE_PROPS)) + .toArray(new String[0]); + if (instancePropArray.length != 0) { + properties.putAll(parseProps(instancePropArray)); + } + + return properties; + } + + private static Map parseProps(String... value) { + return Arrays.stream(value).map(v -> v.split(":")) + .filter(v -> v.length == 2) + .collect(Collectors.toMap(v -> v[0], v -> v[1])); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistration.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistration.java new file mode 100644 index 00000000000..96f41d0670e --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistration.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.invocation.endpoint.EndpointUtils; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; + +public class NacosRegistration implements Registration { + private final NacosDiscoveryProperties nacosDiscoveryProperties; + + private final Environment environment; + + private final String instanceId; + + private final DataCenterProperties dataCenterProperties; + + private NacosRegistrationInstance nacosRegistrationInstance; + + private Instance instance; + + private NamingService namingService; + + @Autowired + public NacosRegistration(DataCenterProperties dataCenterProperties, NacosDiscoveryProperties nacosDiscoveryProperties, + Environment environment, RegistrationId registrationId) { + this.instanceId = registrationId.getInstanceId(); + this.dataCenterProperties = dataCenterProperties; + this.nacosDiscoveryProperties = nacosDiscoveryProperties; + this.environment = environment; + } + + @Override + public void init() { + instance = NacosMicroserviceHandler.createMicroserviceInstance(dataCenterProperties, nacosDiscoveryProperties, + environment); + instance.setInstanceId(instanceId); + nacosRegistrationInstance = new NacosRegistrationInstance(instance, environment); + instance.getMetadata() + .put(NacosConst.NACOS_STATUS, BootStrapProperties.readServiceInstanceInitialStatus(environment)); + namingService = NamingServiceManager.buildNamingService(environment, nacosDiscoveryProperties); + } + + @Override + public void run() { + try { + if (nacosDiscoveryProperties.isEnableSwaggerRegistration()) { + addSchemas(nacosRegistrationInstance.getSchemas(), instance); + } + addEndpoints(nacosRegistrationInstance.getEndpoints(), instance); + namingService.registerInstance(nacosRegistrationInstance.getServiceName(), + nacosRegistrationInstance.getApplication(), instance); + } catch (NacosException e) { + throw new IllegalStateException(e); + } + } + + private static void addSchemas(Map schemas, Instance instance) { + if (CollectionUtils.isEmpty(schemas)) { + return; + } + for (Map.Entry entry : schemas.entrySet()) { + instance.addMetadata(NacosConst.PROPERTY_SCHEMA_PREFIX + entry.getKey(), entry.getValue()); + } + } + + private static void addEndpoints(List endpoints, Instance instance) { + if (endpoints.isEmpty()) { + return; + } + + for (String endpoint : endpoints) { + Endpoint temp = EndpointUtils.parse(endpoint); + if (temp.getAddress() instanceof URIEndpointObject) { + instance.setIp(((URIEndpointObject) temp.getAddress()).getHostOrIp()); + instance.setPort(((URIEndpointObject) temp.getAddress()).getPort()); + break; + } + } + + instance.addMetadata(NacosConst.PROPERTY_ENDPOINT, String.join(NacosConst.ENDPOINT_PROPERTY_SEPARATOR, endpoints)); + } + + @Override + public void destroy() { + try { + namingService.deregisterInstance(nacosRegistrationInstance.getServiceName(), + nacosRegistrationInstance.getApplication(), instance); + namingService.shutDown(); + } catch (NacosException e) { + throw new IllegalStateException("destroy process is interrupted."); + } + } + + @Override + public String name() { + return NacosConst.NACOS_REGISTRY_NAME; + } + + @Override + public NacosRegistrationInstance getMicroserviceInstance() { + return this.nacosRegistrationInstance; + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + try { + instance.getMetadata().put(NacosConst.NACOS_STATUS, status.name()); + namingService.registerInstance(nacosRegistrationInstance.getServiceName(), + nacosRegistrationInstance.getApplication(), instance); + return true; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void addSchema(String schemaId, String content) { + if (nacosDiscoveryProperties.isEnableSwaggerRegistration()) { + nacosRegistrationInstance.addSchema(schemaId, content); + } + } + + @Override + public void addEndpoint(String endpoint) { + nacosRegistrationInstance.addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + instance.addMetadata(key, value); + } + + @Override + public boolean enabled() { + return nacosDiscoveryProperties.isEnabled(); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistrationInstance.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistrationInstance.java new file mode 100644 index 00000000000..7a99f1b2dba --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NacosRegistrationInstance.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.springframework.core.env.Environment; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +public class NacosRegistrationInstance implements RegistrationInstance { + private final Instance instance; + + private final Map schemas = new HashMap<>(); + + private final List endpoints = new ArrayList<>(); + + private final Environment environment; + + public NacosRegistrationInstance(Instance instance, + Environment environment) { + this.instance = instance; + this.environment = environment; + } + + @Override + public String getEnvironment() { + return BootStrapProperties.readServiceEnvironment(environment); + } + + @Override + public String getApplication() { + return BootStrapProperties.readApplication(environment); + } + + @Override + public String getServiceName() { + return BootStrapProperties.readServiceName(environment); + } + + @Override + public String getAlias() { + return BootStrapProperties.readServiceAlias(environment); + } + + @Override + public String getVersion() { + return instance.getMetadata().get(NacosConst.PROPERTY_VERSION); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setRegion(instance.getMetadata().get(NacosConst.PROPERTY_REGION)); + dataCenterInfo.setAvailableZone(instance.getMetadata().get(NacosConst.PROPERTY_ZONE)); + return dataCenterInfo; + } + + @Override + public String getDescription() { + return BootStrapProperties.readServiceDescription(environment); + } + + @Override + public Map getProperties() { + return instance.getMetadata(); + } + + @Override + public Map getSchemas() { + return schemas; + } + + @Override + public List getEndpoints() { + return endpoints; + } + + @Override + public String getInstanceId() { + return instance.getInstanceId(); + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.valueOf(instance.getMetadata().get(NacosConst.NACOS_STATUS)); + } + + public void addSchema(String schemaId, String content) { + this.schemas.put(schemaId, content); + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } +} diff --git a/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NamingServiceManager.java b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NamingServiceManager.java new file mode 100644 index 00000000000..635a7c48565 --- /dev/null +++ b/service-registry/registry-nacos/src/main/java/org/apache/servicecomb/registry/nacos/NamingServiceManager.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.nacos; + +import java.util.Objects; +import java.util.Properties; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.springframework.core.env.Environment; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.client.naming.NacosNamingService; + +public class NamingServiceManager { + private static volatile NamingService namingService; + + public static NamingService buildNamingService(Environment environment, NacosDiscoveryProperties properties) { + if (Objects.isNull(namingService)) { + synchronized (NamingServiceManager.class) { + if (Objects.isNull(namingService)) { + try { + namingService = new NacosNamingService(getProperties(environment, properties)); + } catch (NacosException e) { + throw new IllegalStateException("build namingService failed."); + } + } + } + } + return namingService; + } + + private static Properties getProperties(Environment environment, + NacosDiscoveryProperties nacosDiscoveryProperties) { + Properties properties = new Properties(); + properties.put(NacosConst.NAMESPACE, BootStrapProperties.readServiceEnvironment(environment)); + properties.put(NacosConst.SERVER_ADDR, nacosDiscoveryProperties.getServerAddr()); + if (nacosDiscoveryProperties.getUsername() != null) { + properties.put(NacosConst.USERNAME, nacosDiscoveryProperties.getUsername()); + } + if (nacosDiscoveryProperties.getPassword() != null) { + properties.put(NacosConst.PASSWORD, nacosDiscoveryProperties.getPassword()); + } + if (nacosDiscoveryProperties.getAccessKey() != null) { + properties.put(NacosConst.ACCESS_KEY, nacosDiscoveryProperties.getAccessKey()); + } + if (nacosDiscoveryProperties.getSecretKey() != null) { + properties.put(NacosConst.SECRET_KEY, nacosDiscoveryProperties.getSecretKey()); + } + if (nacosDiscoveryProperties.getLogName() != null) { + properties.put(NacosConst.NACOS_NAMING_LOG_NAME, nacosDiscoveryProperties.getLogName()); + } + + properties.put(NacosConst.CLUSTER_NAME, nacosDiscoveryProperties.getClusterName()); + properties.put(NacosConst.NAMING_LOAD_CACHE_AT_START, nacosDiscoveryProperties.getNamingLoadCacheAtStart()); + return properties; + } +} diff --git a/service-registry/registry-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..a53926ddf0c --- /dev/null +++ b/service-registry/registry-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.nacos.NacosConfiguration diff --git a/service-registry/registry-service-center/pom.xml b/service-registry/registry-service-center/pom.xml new file mode 100644 index 00000000000..97910c29054 --- /dev/null +++ b/service-registry/registry-service-center/pom.xml @@ -0,0 +1,86 @@ + + + + + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-service-center + Java Chassis::Service Registry::Service Center + + + + org.apache.servicecomb + foundation-vertx + + + org.apache.servicecomb + foundation-config + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + swagger-generator-core + + + + org.apache.servicecomb + java-chassis-core + + + + org.apache.servicecomb + service-center-client + + + + org.apache.commons + commons-lang3 + + + + io.vertx + vertx-codegen + provided + + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/MicroserviceHandler.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/MicroserviceHandler.java new file mode 100644 index 00000000000..7ffa409a089 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/MicroserviceHandler.java @@ -0,0 +1,182 @@ +/* + + * Copyright (C) 2020-2022 Huawei Technologies Co., Ltd. All rights reserved. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.sc; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.foundation.common.net.NetUtils; +import org.apache.servicecomb.service.center.client.model.DataCenterInfo; +import org.apache.servicecomb.service.center.client.model.Framework; +import org.apache.servicecomb.service.center.client.model.HealthCheck; +import org.apache.servicecomb.service.center.client.model.HealthCheckMode; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus; +import org.apache.servicecomb.service.center.client.model.MicroserviceStatus; +import org.springframework.core.env.Environment; + +public class MicroserviceHandler { + private static final String SERVICE_MAPPING = "SERVICE_MAPPING"; + + private static final String VERSION_MAPPING = "VERSION_MAPPING"; + + private static final String APP_MAPPING = "APP_MAPPING"; + + private static final String CAS_APPLICATION_ID = "CAS_APPLICATION_ID"; + + private static final String CAS_COMPONENT_NAME = "CAS_COMPONENT_NAME"; + + private static final String CAS_INSTANCE_VERSION = "CAS_INSTANCE_VERSION"; + + private static final String CAS_INSTANCE_ID = "CAS_INSTANCE_ID"; + + private static final String CAS_ENVIRONMENT_ID = "CAS_ENVIRONMENT_ID"; + + private static final String SERVICE_PROPS = "SERVICECOMB_SERVICE_PROPS"; + + private static final String INSTANCE_PROPS = "SERVICECOMB_INSTANCE_PROPS"; + + public static Microservice createMicroservice( + Environment environment) { + Microservice microservice = new Microservice(); + microservice.setProperties(BootStrapProperties.readServiceProperties(environment)); + if (!StringUtils.isEmpty(environment.getProperty(APP_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(APP_MAPPING)))) { + microservice.setAppId(environment.getProperty(environment.getProperty(APP_MAPPING))); + } else { + microservice.setAppId(BootStrapProperties.readApplication(environment)); + } + if (!StringUtils.isEmpty(environment.getProperty(SERVICE_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(SERVICE_MAPPING)))) { + microservice.setServiceName(environment.getProperty(environment.getProperty(SERVICE_MAPPING))); + } else { + microservice.setServiceName(BootStrapProperties.readServiceName(environment)); + } + if (!StringUtils.isEmpty(environment.getProperty(VERSION_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(VERSION_MAPPING)))) { + microservice.setVersion(environment.getProperty(environment.getProperty(VERSION_MAPPING))); + } else { + microservice.setVersion(BootStrapProperties.readServiceVersion(environment)); + } + microservice.setEnvironment(BootStrapProperties.readServiceEnvironment(environment)); + + Framework framework = createFramework(); + microservice.setFramework(framework); + String[] servicePropArray = ConfigUtil.parseArrayValue(environment.getProperty(SERVICE_PROPS)) + .toArray(new String[0]); + if (servicePropArray.length != 0) { + microservice.getProperties().putAll(parseProps(servicePropArray)); + } + + microservice.setStatus(MicroserviceStatus.UP); + return microservice; + } + + private static Framework createFramework() { + Framework framework = new Framework(); + framework.setName("ServiceComb"); + framework.setVersion(MicroserviceHandler.class.getPackage().getImplementationVersion()); + return framework; + } + + public static MicroserviceInstance createMicroserviceInstance( + Environment environment, + SCConfigurationProperties scConfigurationProperties, + DataCenterProperties dataCenterProperties) { + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + String hostName = StringUtils.isEmpty(scConfigurationProperties.getHostname()) ? NetUtils.getHostName() + : scConfigurationProperties.getHostname(); + if (hostName.length() > 64) { + hostName = hostName.substring(0, 64); + } + microserviceInstance.setHostName(hostName); + + if (StringUtils.isNotEmpty(dataCenterProperties.getName())) { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setName(dataCenterProperties.getName()); + dataCenterInfo.setRegion(dataCenterProperties.getRegion()); + dataCenterInfo.setAvailableZone(dataCenterProperties.getAvailableZone()); + microserviceInstance.setDataCenterInfo(dataCenterInfo); + } + + HealthCheck healthCheck = new HealthCheck(); + healthCheck.setMode(HealthCheckMode.push); + healthCheck.setInterval(scConfigurationProperties.getHealthCheckIntervalInSeconds()); + healthCheck.setTimes(scConfigurationProperties.getHealthCheckTimes()); + microserviceInstance.setHealthCheck(healthCheck); + String currTime = String.valueOf(System.currentTimeMillis()); + microserviceInstance.setTimestamp(currTime); + microserviceInstance.setModTimestamp(currTime); + + // what's MicroserviceInstance doing? same sa Microservice? + if (!StringUtils.isEmpty(environment.getProperty(VERSION_MAPPING)) && + !StringUtils.isEmpty(environment.getProperty(environment.getProperty(VERSION_MAPPING)))) { + microserviceInstance.setVersion(environment.getProperty(environment.getProperty(VERSION_MAPPING))); + } else { + microserviceInstance.setVersion(BootStrapProperties.readServiceVersion(environment)); + } + + Map properties = new HashMap<>(); + properties.putAll(BootStrapProperties.readServiceProperties(environment)); + properties.putAll(genCasProperties(environment)); + microserviceInstance.setProperties(properties); + microserviceInstance.setStatus( + MicroserviceInstanceStatus.valueOf(BootStrapProperties.readServiceInstanceInitialStatus(environment))); + return microserviceInstance; + } + + private static Map genCasProperties(Environment environment) { + Map properties = new HashMap<>(); + if (!StringUtils.isEmpty(environment.getProperty(CAS_APPLICATION_ID))) { + properties.put(CAS_APPLICATION_ID, environment.getProperty(CAS_APPLICATION_ID)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_COMPONENT_NAME))) { + properties.put(CAS_COMPONENT_NAME, environment.getProperty(CAS_COMPONENT_NAME)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_INSTANCE_VERSION))) { + properties.put(CAS_INSTANCE_VERSION, environment.getProperty(CAS_INSTANCE_VERSION)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_INSTANCE_ID))) { + properties.put(CAS_INSTANCE_ID, environment.getProperty(CAS_INSTANCE_ID)); + } + if (!StringUtils.isEmpty(environment.getProperty(CAS_ENVIRONMENT_ID))) { + properties.put(CAS_ENVIRONMENT_ID, environment.getProperty(CAS_ENVIRONMENT_ID)); + } + + String[] instancePropArray = ConfigUtil.parseArrayValue(environment.getProperty(INSTANCE_PROPS)) + .toArray(new String[0]); + if (instancePropArray.length != 0) { + properties.putAll(parseProps(instancePropArray)); + } + + return properties; + } + + private static Map parseProps(String... value) { + return Arrays.stream(value).map(v -> v.split(":")) + .filter(v -> v.length == 2) + .collect(Collectors.toMap(v -> v[0], v -> v[1])); + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java new file mode 100644 index 00000000000..1c8ec27c8a8 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCAddressManager.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.sc; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.http.client.event.RefreshEndpointEvent; +import org.apache.servicecomb.service.center.client.RegistrationEvents.HeartBeatEvent; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.exception.OperationException; +import org.apache.servicecomb.service.center.client.model.DataCenterInfo; +import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.Subscribe; + +/** + * Support auto discovery of service center addresses. + */ +public class SCAddressManager { + public enum Type { + SERVICECENTER, + KIE, + CseConfigCenter, + } + + private static final Logger LOGGER = LoggerFactory.getLogger(SCAddressManager.class); + + private final ServiceCenterClient serviceCenterClient; + + private final SCRegistration scRegistration; + + private final SCConfigurationProperties configurationProperties; + + private final Map> lastEngineEndpointsCache = new HashMap<>(); + + public SCAddressManager(SCConfigurationProperties configurationProperties, + ServiceCenterClient serviceCenterClient, + SCRegistration scRegistration) { + this.configurationProperties = configurationProperties; + this.serviceCenterClient = serviceCenterClient; + this.scRegistration = scRegistration; + scRegistration.getEventBus().register(this); + } + + @Subscribe + public void onHeartBeatEvent(HeartBeatEvent event) { + if (event.isSuccess() && configurationProperties.isAutoDiscovery()) { + for (Type type : Type.values()) { + initEndPort(type.name()); + } + } + } + + private void initEndPort(String key) { + List instances = findServiceInstance("default", key, "0+"); + HashSet currentEngineEndpoints = new HashSet<>(); + Map> zoneAndRegion = generateZoneAndRegionAddress(instances, currentEngineEndpoints); + if (zoneAndRegion == null) { + return; + } + if (isEngineEndpointsChanged(lastEngineEndpointsCache.get(key), currentEngineEndpoints)) { + LOGGER.info("auto discovery service [{}] addresses: [{}]", key, zoneAndRegion); + lastEngineEndpointsCache.put(key, currentEngineEndpoints); + EventManager.post(new RefreshEndpointEvent(zoneAndRegion, key)); + } + } + + private boolean isEngineEndpointsChanged(Set lastEngineEndpoints, Set currentEngineEndpoints) { + if (lastEngineEndpoints == null || lastEngineEndpoints.isEmpty()) { + return true; + } + HashSet compareTemp = new HashSet<>(lastEngineEndpoints); + compareTemp.removeAll(currentEngineEndpoints); + return !compareTemp.isEmpty() || lastEngineEndpoints.size() != currentEngineEndpoints.size(); + } + + private Map> generateZoneAndRegionAddress(List instances, + HashSet currentEngineEndpoints) { + if (instances.isEmpty()) { + return null; + } + + Map> zoneAndRegion = new HashMap<>(); + DataCenterInfo dataCenterInfo = findRegion(instances); + + Set sameZone = new HashSet<>(); + Set sameRegion = new HashSet<>(); + for (MicroserviceInstance microserviceInstance : instances) { + if (regionAndAZMatch(dataCenterInfo, microserviceInstance)) { + sameZone.addAll(microserviceInstance.getEndpoints()); + } else { + sameRegion.addAll(microserviceInstance.getEndpoints()); + } + currentEngineEndpoints.addAll(microserviceInstance.getEndpoints()); + } + zoneAndRegion.put("sameZone", new ArrayList<>(sameZone)); + zoneAndRegion.put("sameRegion", new ArrayList<>(sameRegion)); + return zoneAndRegion; + } + + private DataCenterInfo findRegion(List microserviceInstances) { + for (MicroserviceInstance microserviceInstance : microserviceInstances) { + boolean isMatch = microserviceInstance.getEndpoints().get(0) + .contains(scRegistration.getBackendMicroserviceInstance() + .getEndpoints().get(0)); + if (isMatch && microserviceInstance.getDataCenterInfo() != null) { + return microserviceInstance.getDataCenterInfo(); + } + } + + if (scRegistration.getBackendMicroserviceInstance().getDataCenterInfo() == null) { + return null; + } + return scRegistration.getBackendMicroserviceInstance().getDataCenterInfo(); + } + + private List findServiceInstance(String appId, String serviceName, String versionRule) { + try { + FindMicroserviceInstancesResponse instancesResponse = serviceCenterClient + .findMicroserviceInstance(scRegistration.getBackendMicroserviceInstance().getServiceId(), + appId, serviceName, versionRule, null); + return instancesResponse.getMicroserviceInstancesResponse().getInstances(); + } catch (OperationException operationException) { + LOGGER.warn("not find the Microservice instance of {}", serviceName); + return new ArrayList<>(); + } + } + + private boolean regionAndAZMatch(DataCenterInfo myself, MicroserviceInstance target) { + if (myself == null) { + return true; + } + if (target.getDataCenterInfo() != null) { + return myself.getRegion().equals(target.getDataCenterInfo().getRegion()) && + myself.getAvailableZone().equals(target.getDataCenterInfo().getAvailableZone()); + } + return false; + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java new file mode 100644 index 00000000000..f9371926a1d --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCClientUtils.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.registry.sc; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.foundation.ssl.SSLCustom; +import org.apache.servicecomb.foundation.ssl.SSLOption; +import org.apache.servicecomb.foundation.ssl.SSLOptionFactory; +import org.apache.servicecomb.foundation.vertx.VertxConst; +import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider; +import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties; +import org.apache.servicecomb.http.client.common.HttpTransport; +import org.apache.servicecomb.http.client.common.HttpTransportFactory; +import org.apache.servicecomb.service.center.client.ServiceCenterAddressManager; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterRawClient; +import org.apache.servicecomb.service.center.client.ServiceCenterWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +public class SCClientUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(SCClientUtils.class); + + // Compatible chassis multi-registration center + private static final Map serviceAddressManagers = new ConcurrentHashMap<>(); + + public static ServiceCenterAddressManager createAddressManager(SCConfigurationProperties discoveryProperties, + Environment environment) { + List addresses = ConfigUtil.parseArrayValue(discoveryProperties.getAddress()); + return createAddressManager("default", addresses, environment); + } + + /** + * Ensure that the ServiceCenterAddressManager in the client created for RBAC authentication and registry discovery + * is the same. This ensures that when an error is reported due to the registry center address being unavailable, + * the authentication and registry discovery remain consistent. + * + * @param projectName projectName + * @param addresses engine address + * @param environment environment + * @return Service Center Address Manager + */ + public static ServiceCenterAddressManager createAddressManager(String projectName, List addresses, + Environment environment) { + if (getServiceCenterAddressManager(addresses) == null) { + synchronized (SCClientUtils.class) { + if (getServiceCenterAddressManager(addresses) == null) { + String key = String.join(",", addresses); + LOGGER.info("initialize discovery server={}", addresses); + String region = environment.getProperty("servicecomb.datacenter.region"); + String availableZone = environment.getProperty("servicecomb.datacenter.availableZone"); + ServiceCenterAddressManager addressManager = new ServiceCenterAddressManager(projectName, addresses, + EventManager.getEventBus(), region, availableZone); + serviceAddressManagers.put(key, addressManager); + return addressManager; + } + } + } + return getServiceCenterAddressManager(addresses); + } + + private static ServiceCenterAddressManager getServiceCenterAddressManager(List addresses) { + String forwardKey = String.join(",", addresses); + List tempAddr = new ArrayList<>(addresses); + Collections.reverse(tempAddr); + String reverseKey = String.join(",", tempAddr); + if (serviceAddressManagers.get(forwardKey) != null) { + return serviceAddressManagers.get(forwardKey); + } + if (serviceAddressManagers.get(reverseKey) != null) { + return serviceAddressManagers.get(reverseKey); + } + return null; + } + + // add other headers needed for registration by new ServiceCenterClient(...) + public static ServiceCenterClient serviceCenterClient(SCConfigurationProperties discoveryProperties, + Environment environment) { + ServiceCenterAddressManager addressManager = createAddressManager(discoveryProperties, environment); + + SSLProperties sslProperties = buildSslProperties(addressManager, environment); + + return new ServiceCenterClient(new ServiceCenterRawClient.Builder() + .setTenantName("default") + .setAddressManager(addressManager) + .setHttpTransport(createHttpTransport(environment, sslProperties)).build(), addressManager); + } + + private static HttpTransport createHttpTransport(Environment environment, SSLProperties sslProperties) { + List authHeaderProviders = SPIServiceUtils.getOrLoadSortedService(AuthHeaderProvider.class); + + if (isProxyEnable(environment)) { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(). + setDefaultRequestConfig(HttpTransportFactory.defaultRequestConfig().build()); + HttpHost proxy = new HttpHost(getProxyHost(environment), + getProxyPort(environment), "http"); // now only support http proxy + httpClientBuilder.setProxy(proxy); + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxy), + new UsernamePasswordCredentials(getProxyUsername(environment), + getProxyPasswd(environment))); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + return HttpTransportFactory + .createHttpTransport(sslProperties, + getRequestAuthHeaderProvider(authHeaderProviders), httpClientBuilder); + } + + return HttpTransportFactory + .createHttpTransport(sslProperties, + getRequestAuthHeaderProvider(authHeaderProviders), HttpTransportFactory.defaultRequestConfig().build()); + } + + public static Boolean isProxyEnable(Environment environment) { + return environment.getProperty(VertxConst.PROXY_ENABLE, boolean.class, false); + } + + public static String getProxyHost(Environment environment) { + return environment.getProperty(VertxConst.PROXY_HOST, "127.0.0.1"); + } + + public static int getProxyPort(Environment environment) { + return environment.getProperty(VertxConst.PROXY_PORT, int.class, 8080); + } + + public static String getProxyUsername(Environment environment) { + return environment.getProperty(VertxConst.PROXY_USERNAME); + } + + public static String getProxyPasswd(Environment environment) { + return environment.getProperty(VertxConst.PROXY_PASSWD); + } + + private static SSLProperties buildSslProperties(ServiceCenterAddressManager addressManager, + Environment environment) { + SSLOptionFactory factory = SSLOptionFactory.createSSLOptionFactory(SCConst.SC_SSL_TAG, + environment); + SSLOption sslOption; + if (factory == null) { + sslOption = SSLOption.build(SCConst.SC_SSL_TAG, environment); + } else { + sslOption = factory.createSSLOption(); + } + SSLCustom sslCustom = SSLCustom.createSSLCustom(sslOption.getSslCustomClass()); + + SSLProperties sslProperties = new SSLProperties(); + sslProperties.setSslCustom(sslCustom); + sslProperties.setSslOption(sslOption); + sslProperties.setEnabled(addressManager.sslEnabled()); + return sslProperties; + } + + public static ServiceCenterWatch serviceCenterWatch(SCConfigurationProperties discoveryProperties, + List authHeaderProviders, Environment environment) { + ServiceCenterAddressManager addressManager = createAddressManager(discoveryProperties, environment); + SSLProperties sslProperties = buildSslProperties(addressManager, environment); + return new ServiceCenterWatch(addressManager, sslProperties, getRequestAuthHeaderProvider(authHeaderProviders), + "default", new HashMap<>(), EventManager.getEventBus()); + } + + private static RequestAuthHeaderProvider getRequestAuthHeaderProvider(List authHeaderProviders) { + return signRequest -> { + String host = signRequest != null && signRequest.getEndpoint() != null ? signRequest.getEndpoint().getHost() : ""; + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.authHeaders(host))); + return headers; + }; + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfiguration.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfiguration.java new file mode 100644 index 00000000000..6cd8965c8a2 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfiguration.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import java.util.List; + +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterWatch; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@SuppressWarnings("unused") +public class SCConfiguration { + @Bean + @ConfigurationProperties(prefix = SCConst.SC_REGISTRY_PREFIX) + public SCConfigurationProperties scConfigurationProperties() { + return new SCConfigurationProperties(); + } + + @Bean + public ServiceCenterClient serviceCenterClient( + @Qualifier("scConfigurationProperties") SCConfigurationProperties scConfigurationProperties, + Environment environment) { + return SCClientUtils.serviceCenterClient(scConfigurationProperties, environment); + } + + @Bean + public ServiceCenterWatch serviceCenterWatch( + @Qualifier("scConfigurationProperties") SCConfigurationProperties scConfigurationProperties, + List authHeaderProviders, Environment environment) { + return SCClientUtils.serviceCenterWatch(scConfigurationProperties, authHeaderProviders, environment); + } + + @Bean + public SCRegistration scRegistration( + @Qualifier("scConfigurationProperties") SCConfigurationProperties scConfigurationProperties, + @Qualifier("serviceCenterClient") ServiceCenterClient serviceCenterClient, + @Qualifier("serviceCenterWatch") ServiceCenterWatch serviceCenterWatch) { + return new SCRegistration(scConfigurationProperties, serviceCenterClient, serviceCenterWatch); + } + + @Bean + public SCDiscovery scDiscovery( + @Qualifier("scConfigurationProperties") SCConfigurationProperties scConfigurationProperties, + @Qualifier("serviceCenterClient") ServiceCenterClient serviceCenterClient) { + return new SCDiscovery(scConfigurationProperties, serviceCenterClient); + } + + @Bean + public SCAddressManager scAddressManager( + @Qualifier("scConfigurationProperties") SCConfigurationProperties scConfigurationProperties, + SCRegistration scRegistration, + @Qualifier("serviceCenterClient") ServiceCenterClient serviceCenterClient) { + return new SCAddressManager(scConfigurationProperties, + serviceCenterClient, scRegistration); + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfigurationProperties.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfigurationProperties.java new file mode 100644 index 00000000000..5ac431406a3 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConfigurationProperties.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import org.apache.commons.lang3.StringUtils; + +/** + * Configurations for Service Center registration and discovery. + */ +public class SCConfigurationProperties { + private boolean enabled = true; + + private String address = null; + + private boolean enableSwaggerRegistration = false; + + /** + * for registration service + * when swagger is different between local with remote serviceCenter. if ignoreSwaggerDifferent is true. + * it will ignore the different and continue the program. otherwise, the program will stop. + */ + private boolean ignoreSwaggerDifferent = true; + + private boolean canOverwriteSwagger = true; + + private String hostname; + + private int healthCheckIntervalInSeconds = 15; + + private int healthCheckTimes = 3; + + private int healthCheckRequestTimeoutInMillis = 5000; + + private int pollIntervalInMillis = 15000; + + private boolean autoDiscovery = false; + + private boolean watch = false; + + private long registrationWaitTimeInMillis = 30000; + + public String getAddress() { + if (StringUtils.isEmpty(address)) { + throw new IllegalStateException( + "Address is required in configuration. NOTICE: since 3.0.0, only support " + + SCConst.SC_REGISTRY_PREFIX + ".address to configure service center address."); + } + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isIgnoreSwaggerDifferent() { + return ignoreSwaggerDifferent; + } + + public void setIgnoreSwaggerDifferent(boolean ignoreSwaggerDifferent) { + this.ignoreSwaggerDifferent = ignoreSwaggerDifferent; + } + + public boolean isCanOverwriteSwagger() { + return canOverwriteSwagger; + } + + public void setCanOverwriteSwagger(boolean canOverwriteSwagger) { + this.canOverwriteSwagger = canOverwriteSwagger; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public int getHealthCheckIntervalInSeconds() { + return healthCheckIntervalInSeconds; + } + + public void setHealthCheckIntervalInSeconds(int healthCheckIntervalInSeconds) { + this.healthCheckIntervalInSeconds = healthCheckIntervalInSeconds; + } + + public int getHealthCheckRequestTimeoutInMillis() { + return healthCheckRequestTimeoutInMillis; + } + + public void setHealthCheckRequestTimeoutInMillis(int healthCheckRequestTimeoutInMillis) { + this.healthCheckRequestTimeoutInMillis = healthCheckRequestTimeoutInMillis; + } + + public int getPollIntervalInMillis() { + return pollIntervalInMillis; + } + + public void setPollIntervalInMillis(int pollIntervalInMillis) { + this.pollIntervalInMillis = pollIntervalInMillis; + } + + public boolean isAutoDiscovery() { + return autoDiscovery; + } + + public void setAutoDiscovery(boolean autoDiscovery) { + this.autoDiscovery = autoDiscovery; + } + + public int getHealthCheckTimes() { + return healthCheckTimes; + } + + public void setHealthCheckTimes(int healthCheckTimes) { + this.healthCheckTimes = healthCheckTimes; + } + + public boolean isWatch() { + return watch; + } + + public void setWatch(boolean watch) { + this.watch = watch; + } + + public long getRegistrationWaitTimeInMillis() { + return registrationWaitTimeInMillis; + } + + public void setRegistrationWaitTimeInMillis(long registrationWaitTimeInMillis) { + this.registrationWaitTimeInMillis = registrationWaitTimeInMillis; + } + + public boolean isEnableSwaggerRegistration() { + return enableSwaggerRegistration; + } + + public void setEnableSwaggerRegistration(boolean enableSwaggerRegistration) { + this.enableSwaggerRegistration = enableSwaggerRegistration; + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConst.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConst.java new file mode 100644 index 00000000000..612f52c5589 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCConst.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +public class SCConst { + public static final String SC_REGISTRY_NAME = "sc-registry"; + + public static final String SC_REGISTRY_PREFIX = "servicecomb.registry.sc"; + + public static final String SC_SSL_TAG = "sc.consumer"; + + public static final String SC_ALLOW_CROSS_APP = "allowCrossApp"; + + public static final String SC_DEFAULT_PROJECT = "default"; +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscovery.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscovery.java new file mode 100644 index 00000000000..8cffa504705 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscovery.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.event.SimpleEventBus; +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.servicecomb.service.center.client.DiscoveryEvents.InstanceChangedEvent; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterDiscovery; +import org.apache.servicecomb.service.center.client.ServiceCenterDiscovery.SubscriptionKey; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class SCDiscovery implements Discovery { + public static final String SC_DISCOVERY_ENABLED = "servicecomb.registry.sc.%s.%s.enabled"; + + private final EventBus eventBus = new SimpleEventBus(); + + private final SCConfigurationProperties configurationProperties; + + private final ServiceCenterClient serviceCenterClient; + + private SCRegistration scRegistration; + + private ServiceCenterDiscovery serviceCenterDiscovery; + + private InstanceChangedListener instanceChangedListener; + + private Environment environment; + + @Autowired + public SCDiscovery(SCConfigurationProperties configurationProperties, + ServiceCenterClient serviceCenterClient) { + this.configurationProperties = configurationProperties; + this.serviceCenterClient = serviceCenterClient; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setScRegistration(SCRegistration scRegistration) { + this.scRegistration = scRegistration; + } + + @Override + public String name() { + return SCConst.SC_REGISTRY_NAME; + } + + @Override + public int getOrder() { + return -9000; + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(SC_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + SubscriptionKey subscriptionKey = new SubscriptionKey(application, serviceName); + serviceCenterDiscovery.registerIfNotPresent(subscriptionKey); + List instances = serviceCenterDiscovery.getInstanceCache(subscriptionKey); + + return toDiscoveryInstances(instances); + } + + @Override + public List findServices(String application) { + return serviceCenterClient.getMicroserviceList().getServices().stream() + .filter(e -> e.getAppId().equals(application)).map(Microservice::getServiceName) + .collect(Collectors.toList()); + } + + private List toDiscoveryInstances(List instances) { + if (CollectionUtils.isEmpty(instances)) { + return Collections.emptyList(); + } + + Map schemaResult; + if (configurationProperties.isEnableSwaggerRegistration()) { + List schemas = serviceCenterClient.getServiceSchemasList(instances.get(0).getServiceId(), true); + if (schemas == null) { + schemaResult = Collections.emptyMap(); + } else { + schemaResult = new HashMap<>(schemas.size()); + schemas.forEach(info -> schemaResult.put(info.getSchemaId(), info.getSchema())); + } + } else { + schemaResult = new HashMap<>(); + } + List result = new ArrayList<>(instances.size()); + instances.forEach(instance -> result.add(new SCDiscoveryInstance(instance, schemaResult))); + return result; + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + this.instanceChangedListener = instanceChangedListener; + } + + @Subscribe + @SuppressWarnings("unused") + public void onInstanceChangedEvent(InstanceChangedEvent event) { + this.instanceChangedListener.onInstanceChanged(name(), event.getAppName(), event.getServiceName(), + toDiscoveryInstances(event.getInstances())); + } + + @Override + public void init() { + serviceCenterDiscovery = new ServiceCenterDiscovery(serviceCenterClient, eventBus); + serviceCenterDiscovery.setPollInterval(configurationProperties.getPollIntervalInMillis()); + + eventBus.register(this); + } + + @Override + public void run() { + // SCDiscovery.run is called after SCRegistration.run + serviceCenterDiscovery.updateMyselfServiceId(scRegistration.getBackendMicroservice().getServiceId()); + // startDiscovery will check if already started, can call several times + serviceCenterDiscovery.startDiscovery(); + } + + @Override + public void destroy() { + if (serviceCenterDiscovery != null) { + serviceCenterDiscovery.stop(); + } + } + + @Override + public boolean enabled() { + return this.configurationProperties.isEnabled(); + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscoveryInstance.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscoveryInstance.java new file mode 100644 index 00000000000..f3b7ffe4403 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCDiscoveryInstance.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; + +public class SCDiscoveryInstance extends AbstractDiscoveryInstance { + private final Microservice microservice; + + private final MicroserviceInstance microserviceInstance; + + private final Map schemas; + + public SCDiscoveryInstance(MicroserviceInstance microserviceInstance, + Map schemas) { + this.microservice = microserviceInstance.getMicroservice(); + this.microserviceInstance = microserviceInstance; + this.schemas = schemas; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.valueOf(microserviceInstance.getStatus().name()); + } + + @Override + public String getRegistryName() { + return SCConst.SC_REGISTRY_NAME; + } + + @Override + public String getEnvironment() { + return microservice.getEnvironment(); + } + + @Override + public String getApplication() { + return microservice.getAppId(); + } + + @Override + public String getServiceName() { + return microservice.getServiceName(); + } + + @Override + public String getAlias() { + return microservice.getAlias(); + } + + @Override + public String getVersion() { + return microservice.getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + if (microserviceInstance.getDataCenterInfo() != null) { + return new DataCenterInfo(microserviceInstance.getDataCenterInfo().getName(), + microserviceInstance.getDataCenterInfo().getRegion(), + microserviceInstance.getDataCenterInfo().getAvailableZone()); + } + return new DataCenterInfo(); + } + + @Override + public String getDescription() { + return microservice.getDescription(); + } + + @Override + public Map getProperties() { + return microserviceInstance.getProperties(); + } + + @Override + public Map getSchemas() { + return schemas; + } + + @Override + public List getEndpoints() { + return microserviceInstance.getEndpoints(); + } + + @Override + public String getInstanceId() { + return microserviceInstance.getInstanceId(); + } + + @Override + public String getServiceId() { + return microservice.getServiceId(); + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistration.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistration.java new file mode 100644 index 00000000000..6692f61c6c7 --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistration.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.foundation.common.event.SimpleEventBus; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.servicecomb.service.center.client.RegistrationEvents.MicroserviceInstanceRegistrationEvent; +import org.apache.servicecomb.service.center.client.ServiceCenterClient; +import org.apache.servicecomb.service.center.client.ServiceCenterRegistration; +import org.apache.servicecomb.service.center.client.ServiceCenterWatch; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; +import org.apache.servicecomb.service.center.client.model.SchemaInfo; +import org.apache.servicecomb.service.center.client.model.ServiceCenterConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import com.google.common.base.Charsets; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import com.google.common.hash.Hashing; + +public class SCRegistration implements Registration { + private final EventBus eventBus = new SimpleEventBus(); + + private Microservice microservice; + + private MicroserviceInstance microserviceInstance; + + private ServiceCenterRegistration serviceCenterRegistration; + + private final ServiceCenterClient serviceCenterClient; + + private final ServiceCenterWatch serviceCenterWatch; + + private final SCConfigurationProperties configurationProperties; + + private SCRegistrationInstance registrationInstance; + + private DataCenterProperties dataCenterProperties; + + private Environment environment; + + private RegistrationId registrationId; + + private CountDownLatch readyWaiter = new CountDownLatch(1); + + @Autowired + public SCRegistration(SCConfigurationProperties configurationProperties, + ServiceCenterClient serviceCenterClient, ServiceCenterWatch serviceCenterWatch) { + this.configurationProperties = configurationProperties; + this.serviceCenterClient = serviceCenterClient; + this.serviceCenterWatch = serviceCenterWatch; + } + + @Autowired + public void setDataCenterProperties(DataCenterProperties dataCenterProperties) { + this.dataCenterProperties = dataCenterProperties; + } + + @Autowired + public void setRegistrationId(RegistrationId registrationId) { + this.registrationId = registrationId; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void init() { + microservice = MicroserviceHandler.createMicroservice( + environment); + microserviceInstance = MicroserviceHandler.createMicroserviceInstance( + environment, + configurationProperties, + dataCenterProperties); + microserviceInstance.setInstanceId(registrationId.getInstanceId()); + serviceCenterRegistration = new ServiceCenterRegistration(serviceCenterClient, + new ServiceCenterConfiguration().setCanOverwriteSwagger( + this.configurationProperties.isCanOverwriteSwagger()) + .setCanOverwriteSwagger(this.configurationProperties.isCanOverwriteSwagger()), + eventBus); + serviceCenterRegistration.setMicroservice(microservice); + serviceCenterRegistration.setMicroserviceInstance(microserviceInstance); + serviceCenterRegistration.setHeartBeatInterval( + TimeUnit.SECONDS.toMillis(configurationProperties.getHealthCheckIntervalInSeconds())); + serviceCenterRegistration.setHeartBeatRequestTimeout( + configurationProperties.getHealthCheckRequestTimeoutInMillis()); + registrationInstance = new SCRegistrationInstance(microservice, microserviceInstance, serviceCenterRegistration); + eventBus.register(this); + } + + @Override + public void run() { + try { + serviceCenterRegistration.startRegistration(); + if (!readyWaiter.await(configurationProperties.getRegistrationWaitTimeInMillis(), TimeUnit.MILLISECONDS)) { + throw new IllegalStateException( + String.format("registration timeout after %s milli seconds.", + configurationProperties.getRegistrationWaitTimeInMillis())); + } + } catch (InterruptedException e) { + throw new IllegalStateException("registration process is interrupted."); + } + } + + @Subscribe + public void onMicroserviceInstanceRegistrationEvent(MicroserviceInstanceRegistrationEvent event) { + if (!event.isSuccess()) { + return; + } + readyWaiter.countDown(); + if (configurationProperties.isWatch()) { + serviceCenterWatch.startWatch(SCConst.SC_DEFAULT_PROJECT, microservice.getServiceId()); + } + } + + @Override + public void destroy() { + if (serviceCenterRegistration != null) { + serviceCenterRegistration.stop(); + } + } + + @Override + public String name() { + return SCConst.SC_REGISTRY_NAME; + } + + @Override + public SCRegistrationInstance getMicroserviceInstance() { + return registrationInstance; + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + return serviceCenterClient.updateMicroserviceInstanceStatus(microservice.getServiceId(), + microserviceInstance.getInstanceId(), + org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus.valueOf(status.name())); + } + + @Override + public void addSchema(String schemaId, String content) { + if (configurationProperties.isEnableSwaggerRegistration()) { + this.microservice.addSchema(schemaId); + + this.serviceCenterRegistration.addSchemaInfo( + new SchemaInfo(schemaId, content, calcSchemaSummary(content))); + } + } + + @SuppressWarnings("UnstableApiUsage") + public static String calcSchemaSummary(String schemaContent) { + return Hashing.sha256().newHasher().putString(schemaContent, Charsets.UTF_8).hash().toString(); + } + + @Override + public void addEndpoint(String endpoint) { + this.microserviceInstance.addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + this.microserviceInstance.addProperty(key, value); + } + + @Override + public boolean enabled() { + return this.configurationProperties.isEnabled(); + } + + public Microservice getBackendMicroservice() { + return microservice; + } + + public MicroserviceInstance getBackendMicroserviceInstance() { + return microserviceInstance; + } + + EventBus getEventBus() { + return eventBus; + } +} diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistrationInstance.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistrationInstance.java new file mode 100644 index 00000000000..cfe53692eeb --- /dev/null +++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/registry/sc/SCRegistrationInstance.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.sc; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.apache.servicecomb.service.center.client.ServiceCenterRegistration; +import org.apache.servicecomb.service.center.client.model.Microservice; +import org.apache.servicecomb.service.center.client.model.MicroserviceInstance; + +public class SCRegistrationInstance implements RegistrationInstance { + private final Microservice microservice; + + private final MicroserviceInstance microserviceInstance; + + private final ServiceCenterRegistration serviceCenterRegistration; + + public SCRegistrationInstance(Microservice microservice, MicroserviceInstance microserviceInstance, + ServiceCenterRegistration serviceCenterRegistration) { + this.microservice = microservice; + this.microserviceInstance = microserviceInstance; + this.serviceCenterRegistration = serviceCenterRegistration; + } + + @Override + public String getEnvironment() { + return microservice.getEnvironment(); + } + + @Override + public String getApplication() { + return microservice.getAppId(); + } + + @Override + public String getServiceName() { + return microservice.getServiceName(); + } + + @Override + public String getAlias() { + return microservice.getAlias(); + } + + @Override + public String getVersion() { + return microservice.getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return new DataCenterInfo(microserviceInstance.getDataCenterInfo().getName(), + microserviceInstance.getDataCenterInfo().getRegion(), + microserviceInstance.getDataCenterInfo().getAvailableZone()); + } + + @Override + public String getDescription() { + return microservice.getDescription(); + } + + @Override + public Map getProperties() { + return microserviceInstance.getProperties(); + } + + @Override + public Map getSchemas() { + Map result = new HashMap<>(); + serviceCenterRegistration.getSchemaInfos().forEach(info -> result.put(info.getSchemaId(), info.getSchema())); + return result; + } + + @Override + public List getEndpoints() { + return microserviceInstance.getEndpoints(); + } + + @Override + public String getInstanceId() { + return microserviceInstance.getInstanceId(); + } + + @Override + public String getServiceId() { + return microservice.getServiceId(); + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.valueOf(microserviceInstance.getStatus().name()); + } + + public Microservice getBackendMicroservice() { + return microservice; + } + + public MicroserviceInstance getBackendMicroserviceInstance() { + return microserviceInstance; + } +} diff --git a/service-registry/registry-service-center/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-service-center/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..5d260c3aba6 --- /dev/null +++ b/service-registry/registry-service-center/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.sc.SCConfiguration diff --git a/service-registry/registry-zero-config/pom.xml b/service-registry/registry-zero-config/pom.xml new file mode 100644 index 00000000000..c9a6569f1bc --- /dev/null +++ b/service-registry/registry-zero-config/pom.xml @@ -0,0 +1,38 @@ + + + + + + service-registry-parent + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-zero-config + Java Chassis::Service Registry::Zero Config + + + + org.apache.servicecomb + registry-lightweight + + + diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/AbstractZeroConfigRegistration.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/AbstractZeroConfigRegistration.java new file mode 100644 index 00000000000..b6e577e44a2 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/AbstractZeroConfigRegistration.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.zeroconfig; + +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.ORDER; + +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.apache.servicecomb.registry.lightweight.AbstractLightweightRegistration; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class AbstractZeroConfigRegistration + extends AbstractLightweightRegistration { + protected Config config; + + @Autowired + public AbstractZeroConfigRegistration setConfig(Config config) { + this.config = config; + return this; + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean enabled() { + return config.isEnabled(); + } + + @Override + public void run() { + super.run(); + + startRegister(config.getHeartbeatInterval()); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/Config.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/Config.java new file mode 100644 index 00000000000..a68d89793d9 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/Config.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.zeroconfig; + +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_ENABLED; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_HEARTBEAT_INTERVAL; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_HEARTBEAT_LOST_TIMES; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_MULTICAST_ADDRESS; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_MULTICAST_GROUP; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.CFG_PULL_INTERVAL; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.DEFAULT_ADDRESS; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.DEFAULT_GROUP; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.DEFAULT_HEARTBEAT_INTERVAL; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.DEFAULT_HEARTBEAT_LOST_TIMES; +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.DEFAULT_PULL_INTERVAL; + +import java.time.Duration; + +import org.apache.servicecomb.config.DynamicProperties; +import org.springframework.beans.factory.annotation.Autowired; + +public class Config { + private DynamicProperties dynamicProperties; + + @Autowired + public Config setDynamicProperties(DynamicProperties dynamicProperties) { + this.dynamicProperties = dynamicProperties; + return this; + } + + public boolean isEnabled() { + return dynamicProperties.getBooleanProperty(CFG_ENABLED, true); + } + + public String getMulticastAddress() { + return dynamicProperties.getStringProperty(CFG_MULTICAST_ADDRESS, DEFAULT_ADDRESS); + } + + // (224.0.0.0, 239.255.255.255] + public String getMulticastGroup() { + return dynamicProperties.getStringProperty(CFG_MULTICAST_GROUP, DEFAULT_GROUP); + } + + public Duration getHeartbeatInterval() { + String interval = dynamicProperties.getStringProperty(CFG_HEARTBEAT_INTERVAL, DEFAULT_HEARTBEAT_INTERVAL); + return toDuration(interval); + } + + public Duration getCheckDeadInstancesInterval() { + int lostTimes = dynamicProperties.getIntProperty(CFG_HEARTBEAT_LOST_TIMES, DEFAULT_HEARTBEAT_LOST_TIMES); + return getHeartbeatInterval().multipliedBy(lostTimes); + } + + public Duration getPullInterval() { + String interval = dynamicProperties.getStringProperty(CFG_PULL_INTERVAL, DEFAULT_PULL_INTERVAL); + return toDuration(interval); + } + + private Duration toDuration(String interval) { + return Duration.parse("PT" + interval); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigConst.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigConst.java new file mode 100644 index 00000000000..8ebcf99dd53 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigConst.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.zeroconfig; + +public interface ZeroConfigConst { + String ZERO_CONFIG_REGISTRY_NAME = "zero-config-registry"; + + int MAX_PACKET_SIZE = 1024; + + String PREFIX = "servicecomb.registry.zero-config."; + + String CFG_ENABLED = PREFIX + "enabled"; + + String CFG_MULTICAST_GROUP = PREFIX + "multicast.group"; + + String CFG_MULTICAST_ADDRESS = PREFIX + "multicast.address"; + + String CFG_HEARTBEAT_INTERVAL = PREFIX + "heartbeat.interval"; + + String CFG_HEARTBEAT_LOST_TIMES = PREFIX + "heartbeat.lost-times"; + + String CFG_PULL_INTERVAL = PREFIX + "pull-interval"; + + String DEFAULT_GROUP = "225.6.7.8"; + + String DEFAULT_ADDRESS = "0.0.0.0:6666"; + + String DEFAULT_HEARTBEAT_INTERVAL = "30s"; + + int DEFAULT_HEARTBEAT_LOST_TIMES = 3; + + String DEFAULT_PULL_INTERVAL = "3s"; + + int ORDER = -8000; +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscovery.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscovery.java new file mode 100644 index 00000000000..70b54f8a079 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscovery.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.zeroconfig; + +import static org.apache.servicecomb.zeroconfig.ZeroConfigConst.ORDER; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.servicecomb.registry.lightweight.AbstractLightweightDiscovery; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstances; +import org.springframework.beans.factory.annotation.Autowired; + +public class ZeroConfigDiscovery extends AbstractLightweightDiscovery { + private Config config; + + @Autowired + public ZeroConfigDiscovery setConfig(Config config) { + this.config = config; + return this; + } + + @Override + public String name() { + return ZeroConfigConst.ZERO_CONFIG_REGISTRY_NAME; + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean enabled() { + return config.isEnabled(); + } + + @Override + public void run() { + + } + + @Override + public List findServiceInstances(String application, String serviceName) { + MicroserviceInstances microserviceInstances = + store.findServiceInstances(application, serviceName, "0"); + if (microserviceInstances.isMicroserviceNotExist() || microserviceInstances.getInstancesResponse() == null) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (MicroserviceInstance instance : microserviceInstances.getInstancesResponse().getInstances()) { + result.add(new ZeroConfigDiscoveryInstance(store.getMicroservice(instance.getServiceId()).get(), instance)); + } + return result; + } + + @Override + public List findServices(String application) { + List microservices = store.getAllMicroservices(); + return microservices.stream().filter(e -> e.getAppId().equals(application)) + .map(Microservice::getServiceName).collect(Collectors.toList()); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscoveryInstance.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscoveryInstance.java new file mode 100644 index 00000000000..e42e0ae0dd2 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigDiscoveryInstance.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.zeroconfig; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.AbstractDiscoveryInstance; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.lightweight.model.Microservice; +import org.apache.servicecomb.registry.lightweight.model.MicroserviceInstance; + +public class ZeroConfigDiscoveryInstance extends AbstractDiscoveryInstance { + private final Microservice microservice; + + private final MicroserviceInstance microserviceInstance; + + public ZeroConfigDiscoveryInstance(Microservice microservice, + MicroserviceInstance microserviceInstance) { + this.microservice = microservice; + this.microserviceInstance = microserviceInstance; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return microserviceInstance.getStatus(); + } + + @Override + public String getRegistryName() { + return ZeroConfigConst.ZERO_CONFIG_REGISTRY_NAME; + } + + @Override + public String getEnvironment() { + return microservice.getEnvironment(); + } + + @Override + public String getApplication() { + return microservice.getAppId(); + } + + @Override + public String getServiceName() { + return microservice.getServiceName(); + } + + @Override + public String getAlias() { + return microservice.getAlias(); + } + + @Override + public String getVersion() { + return microservice.getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return microserviceInstance.getDataCenterInfo(); + } + + @Override + public String getDescription() { + return microservice.getDescription(); + } + + @Override + public Map getProperties() { + return microserviceInstance.getProperties(); + } + + @Override + public Map getSchemas() { + return microservice.getSchemaMap(); + } + + @Override + public List getEndpoints() { + return microserviceInstance.getEndpoints(); + } + + @Override + public String getInstanceId() { + return microserviceInstance.getInstanceId(); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistration.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistration.java new file mode 100644 index 00000000000..1b2383e28f5 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistration.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.zeroconfig; + +import java.io.IOException; + +import org.apache.servicecomb.registry.lightweight.MessageType; +import org.apache.servicecomb.registry.lightweight.RegisterInstanceEvent; +import org.apache.servicecomb.zeroconfig.multicast.Multicast; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.Subscribe; + +@SuppressWarnings("UnstableApiUsage") +public class ZeroConfigRegistration extends AbstractZeroConfigRegistration implements + InitializingBean { + protected Multicast multicast; + + @Autowired + public ZeroConfigRegistration setMulticast(Multicast multicast) { + this.multicast = multicast; + return this; + } + + @Override + public String name() { + return ZeroConfigConst.ZERO_CONFIG_REGISTRY_NAME; + } + + // delete after support @Conditional + @Override + public boolean enabled() { + return true; + } + + @Override + public void afterPropertiesSet() { + eventBus.register(this); + } + + @Override + protected void doSendRegister() throws IOException { + multicast.send(MessageType.REGISTER, self.buildRegisterRequest()); + } + + @Override + protected void doSendUnregister() throws IOException { + multicast.send(MessageType.UNREGISTER, self.buildUnregisterRequest()); + } + + @Override + public ZeroConfigRegistrationInstance getMicroserviceInstance() { + return new ZeroConfigRegistrationInstance(self); + } + + @SuppressWarnings("unused") + @Subscribe + public void onRegisterInstance(RegisterInstanceEvent event) { + if (event.getInstance().getInstanceId().equals(self.getInstance().getInstanceId())) { + return; + } + + sendRegister(); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistrationInstance.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistrationInstance.java new file mode 100644 index 00000000000..9e1955b24a8 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistrationInstance.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.zeroconfig; + +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.RegistrationInstance; +import org.apache.servicecomb.registry.lightweight.Self; + +public class ZeroConfigRegistrationInstance implements RegistrationInstance { + private final Self self; + + public ZeroConfigRegistrationInstance(Self self) { + this.self = self; + } + + @Override + public String getEnvironment() { + return self.getMicroservice().getEnvironment(); + } + + @Override + public String getApplication() { + return self.getMicroservice().getAppId(); + } + + @Override + public String getServiceName() { + return self.getMicroservice().getServiceName(); + } + + @Override + public String getAlias() { + return self.getMicroservice().getAlias(); + } + + @Override + public String getVersion() { + return self.getMicroservice().getVersion(); + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return self.getInstance().getDataCenterInfo(); + } + + @Override + public String getDescription() { + return self.getMicroservice().getDescription(); + } + + @Override + public Map getProperties() { + return self.getInstance().getProperties(); + } + + @Override + public Map getSchemas() { + return this.self.getMicroservice().getSchemaMap(); + } + + @Override + public List getEndpoints() { + return this.self.getInstance().getEndpoints(); + } + + @Override + public String getInstanceId() { + return this.self.getInstanceId(); + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return MicroserviceInstanceStatus.UP; + } + + public void addSchema(String schemaId, String content) { + this.self.getMicroservice().addSchema(schemaId, content); + } + + public void addEndpoint(String endpoint) { + this.self.getInstance().getEndpoints().add(endpoint); + } + + public void addProperty(String key, String value) { + this.self.getInstance().getProperties().put(key, value); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistryConfiguration.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistryConfiguration.java new file mode 100644 index 00000000000..fa2ba2c5d58 --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/ZeroConfigRegistryConfiguration.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.zeroconfig; + +import java.io.IOException; + +import org.apache.servicecomb.registry.lightweight.MessageExecutor; +import org.apache.servicecomb.zeroconfig.multicast.Multicast; +import org.apache.servicecomb.zeroconfig.multicast.MulticastServer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeroConfigRegistryConfiguration { + @Bean + public ZeroConfigRegistration zeroConfigRegistration() { + return new ZeroConfigRegistration(); + } + + @Bean + public MulticastServer multicastServer(Config config, Multicast multicast, MessageExecutor messageExecutor) { + return new MulticastServer(config, multicast, messageExecutor); + } + + @Bean + public ZeroConfigDiscovery zeroConfigDiscovery() { + return new ZeroConfigDiscovery(); + } + + @Bean + public Multicast zeroConfigMulticast(Config config) throws IOException { + return new Multicast(config); + } + + @Bean + public Config zeroConfigModel() { + return new Config(); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/Multicast.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/Multicast.java new file mode 100644 index 00000000000..c0c37f97ebf --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/Multicast.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.zeroconfig.multicast; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MulticastSocket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.concurrent.TimeUnit; + +import org.apache.servicecomb.registry.lightweight.Message; +import org.apache.servicecomb.registry.lightweight.MessageType; +import org.apache.servicecomb.zeroconfig.Config; +import org.apache.servicecomb.zeroconfig.ZeroConfigConst; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.net.HostAndPort; + +public class Multicast { + private static final Logger LOGGER = LoggerFactory.getLogger(Multicast.class); + + private final InetSocketAddress bindAddress; + + // (224.0.0.0, 239.255.255.255] + private final InetAddress group; + + private final MulticastSocket multicastSocket; + + private final byte[] recvBuffer = new byte[ZeroConfigConst.MAX_PACKET_SIZE]; + + private final DatagramPacket recvPacket = new DatagramPacket(recvBuffer, recvBuffer.length); + + @SuppressWarnings("deprecation") + public Multicast(Config config) throws IOException { + this.bindAddress = initBindAddress(config); + this.group = initGroup(config); + LOGGER.info("zero config, address: {}", bindAddress); + LOGGER.info("zero config, group: {}", group); + + this.multicastSocket = new MulticastSocket(bindAddress); + this.multicastSocket.joinGroup(group); + this.multicastSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(5)); + } + + public Multicast setSendBufferSize(int size) throws SocketException { + multicastSocket.setSendBufferSize(size); + return this; + } + + public Multicast setReceiveBufferSize(int size) throws SocketException { + multicastSocket.setReceiveBufferSize(size); + return this; + } + + @SuppressWarnings("UnstableApiUsage") + private InetSocketAddress initBindAddress(Config config) { + HostAndPort hostAndPort = HostAndPort.fromString(config.getMulticastAddress()); + return new InetSocketAddress(hostAndPort.getHost(), hostAndPort.getPort()); + } + + private InetAddress initGroup(Config config) throws UnknownHostException { + return InetAddress.getByName(config.getMulticastGroup()); + } + + public void send(MessageType type, T body) throws IOException { + byte[] buffer = Message.of(type, body).encode(); + DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, bindAddress.getPort()); + multicastSocket.send(packet); + } + + public Message recv() throws IOException { + multicastSocket.receive(recvPacket); + + return Message.decode(recvPacket.getData(), recvPacket.getLength()); + } +} diff --git a/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/MulticastServer.java b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/MulticastServer.java new file mode 100644 index 00000000000..f86299173ba --- /dev/null +++ b/service-registry/registry-zero-config/src/main/java/org/apache/servicecomb/zeroconfig/multicast/MulticastServer.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.zeroconfig.multicast; + +import java.net.SocketTimeoutException; +import java.util.concurrent.Executors; + +import org.apache.servicecomb.registry.lightweight.Message; +import org.apache.servicecomb.registry.lightweight.MessageExecutor; +import org.apache.servicecomb.zeroconfig.Config; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("unused") +public class MulticastServer { + private static final Logger LOGGER = LoggerFactory.getLogger(MulticastServer.class); + + private final Multicast multicast; + + private final MessageExecutor messageExecutor; + + public MulticastServer(Config config, Multicast multicast, MessageExecutor messageExecutor) { + this.multicast = multicast; + this.messageExecutor = messageExecutor; + + Executors + .newSingleThreadExecutor(runnable -> new Thread(runnable, "multicast-server-recv")) + .execute(this::recv); + messageExecutor.startCheckDeadInstances(config.getCheckDeadInstancesInterval()); + } + + @SuppressWarnings("InfiniteLoopStatement") + private void recv() { + for (; ; ) { + Message message = recvMsg(); + if (message == null) { + continue; + } + + messageExecutor.processMessage(message); + } + } + + private Message recvMsg() { + try { + return multicast.recv(); + } catch (SocketTimeoutException ignore) { + return null; + } catch (Exception e) { + LOGGER.error("failed to receive or decode message.", e); + return null; + } + } +} diff --git a/service-registry/registry-zero-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-zero-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..fb2fe90754d --- /dev/null +++ b/service-registry/registry-zero-config/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.zeroconfig.ZeroConfigRegistryConfiguration diff --git a/service-registry/registry-zookeeper/pom.xml b/service-registry/registry-zookeeper/pom.xml new file mode 100644 index 00000000000..e5ba4236e18 --- /dev/null +++ b/service-registry/registry-zookeeper/pom.xml @@ -0,0 +1,55 @@ + + + + + + org.apache.servicecomb + service-registry-parent + 3.4.0-SNAPSHOT + + 4.0.0 + + registry-zookeeper + Java Chassis::Service Registry::Zookeeper + + + + org.apache.curator + curator-x-discovery + + + org.apache.curator + curator-framework + + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + foundation-registry + + + org.apache.servicecomb + java-chassis-core + + + + diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConfiguration.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConfiguration.java new file mode 100644 index 00000000000..39c9fd176ad --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConfiguration.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZookeeperConfiguration { + @Bean + @ConfigurationProperties(prefix = ZookeeperConst.ZOOKEEPER_REGISTRY_PREFIX) + public ZookeeperRegistryProperties zookeeperRegistryProperties() { + return new ZookeeperRegistryProperties(); + } + + @Bean + public ZookeeperDiscovery zookeeperDiscovery() { + return new ZookeeperDiscovery(); + } + + @Bean + public ZookeeperRegistration zookeeperRegistration() { + return new ZookeeperRegistration(); + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConst.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConst.java new file mode 100644 index 00000000000..1d6d5d14117 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperConst.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +public class ZookeeperConst { + public static final String ZOOKEEPER_REGISTRY_NAME = "zookeeper-registry"; + + public static final String ZOOKEEPER_DISCOVERY_ROOT = "/servicecomb/registry/%s"; + + public static final String ZOOKEEPER_REGISTRY_PREFIX = "servicecomb.registry.zk"; + + public static final String ZOOKEEPER_DISCOVERY_ENABLED = ZOOKEEPER_REGISTRY_PREFIX + ".%s.%s.enabled"; + + public static final String ZOOKEEPER_DEFAULT_ENVIRONMENT = "production"; +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java new file mode 100644 index 00000000000..ab601e11783 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.state.ConnectionState; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.curator.utils.CloseableUtils; +import org.apache.curator.x.discovery.ServiceCache; +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; +import org.apache.curator.x.discovery.ServiceInstance; +import org.apache.curator.x.discovery.details.JsonInstanceSerializer; +import org.apache.curator.x.discovery.details.ServiceCacheListener; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.registry.api.Discovery; +import org.apache.zookeeper.server.auth.DigestLoginModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class ZookeeperDiscovery implements Discovery { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperDiscovery.class); + + private final Map>> serviceDiscoveries = + new ConcurrentHashMapEx<>(); + + private final Map> serviceNameDiscoveries = + new ConcurrentHashMapEx<>(); + + private Environment environment; + + private ZookeeperRegistryProperties zookeeperRegistryProperties; + + private String basePath; + + private CuratorFramework client; + + private InstanceChangedListener instanceChangedListener; + + @Autowired + @SuppressWarnings("unused") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + @SuppressWarnings("unused") + public void setZookeeperRegistryProperties(ZookeeperRegistryProperties zookeeperRegistryProperties) { + this.zookeeperRegistryProperties = zookeeperRegistryProperties; + } + + @Override + public String name() { + return ZookeeperConst.ZOOKEEPER_REGISTRY_NAME; + } + + @Override + public boolean enabled(String application, String serviceName) { + return environment.getProperty(String.format(ZookeeperConst.ZOOKEEPER_DISCOVERY_ENABLED, application, serviceName), + boolean.class, true); + } + + @Override + public List findServiceInstances(String application, String serviceName) { + try { + ServiceCache discovery = serviceDiscoveries.computeIfAbsent(application, app -> + new ConcurrentHashMapEx<>()).computeIfAbsent(serviceName, name -> { + JsonInstanceSerializer serializer = + new JsonInstanceSerializer<>(ZookeeperInstance.class); + ServiceDiscovery dis = ServiceDiscoveryBuilder.builder(ZookeeperInstance.class) + .client(client) + .basePath(basePath + "/" + application) + .serializer(serializer) + .build(); + ServiceCache cache = + dis.serviceCacheBuilder().name(serviceName).build(); + cache.addListener(new ServiceCacheListener() { + @Override + public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) { + LOGGER.warn("zookeeper discovery state changed {}", connectionState); + } + + @Override + public void cacheChanged() { + instanceChangedListener.onInstanceChanged(name(), application, serviceName, + toDiscoveryInstances(cache.getInstances())); + } + }); + try { + CountDownLatch latch = cache.startImmediate(); + if (!latch.await(5000, TimeUnit.SECONDS)) { + throw new IllegalStateException("cache start failed."); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + return cache; + }); + List> instances = discovery.getInstances(); + return toDiscoveryInstances(instances); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public List findServices(String application) { + try { + ServiceDiscovery discovery = serviceNameDiscoveries + .computeIfAbsent(application, app -> { + JsonInstanceSerializer serializer = + new JsonInstanceSerializer<>(ZookeeperInstance.class); + ServiceDiscovery dis = ServiceDiscoveryBuilder.builder(ZookeeperInstance.class) + .client(client) + .basePath(basePath + "/" + application) + .serializer(serializer) + .build(); + try { + dis.start(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return dis; + }); + return discovery.queryForNames().stream().toList(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private List toDiscoveryInstances( + List> instances) { + return instances.stream().map(instance -> + new ZookeeperDiscoveryInstance(instance.getPayload())).collect(Collectors.toList()); + } + + @Override + public void setInstanceChangedListener(InstanceChangedListener instanceChangedListener) { + this.instanceChangedListener = instanceChangedListener; + } + + @Override + public void init() { + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ZookeeperConst.ZOOKEEPER_DEFAULT_ENVIRONMENT; + } + basePath = String.format(ZookeeperConst.ZOOKEEPER_DISCOVERY_ROOT, env); + } + + @Override + public void run() { + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperRegistryProperties.getConnectString()) + .sessionTimeoutMs(zookeeperRegistryProperties.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperRegistryProperties.getAuthenticationSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperRegistryProperties.getAuthenticationInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperRegistryProperties.getAuthenticationInfo().split(":"); + Configuration.setConfiguration(new ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + client = builder.build(); + client.start(); + } + + @Override + public void destroy() { + if (client != null) { + CloseableUtils.closeQuietly(client); + } + } + + @Override + public boolean enabled() { + return zookeeperRegistryProperties.isEnabled(); + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscoveryInstance.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscoveryInstance.java new file mode 100644 index 00000000000..b01ad50830e --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscoveryInstance.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import org.apache.servicecomb.registry.api.DiscoveryInstance; + +public class ZookeeperDiscoveryInstance extends ZookeeperInstance implements DiscoveryInstance { + public ZookeeperDiscoveryInstance(ZookeeperInstance other) { + super(other); + } + + @Override + public String getRegistryName() { + return ZookeeperConst.ZOOKEEPER_REGISTRY_NAME; + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperInstance.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperInstance.java new file mode 100644 index 00000000000..b919d97855f --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperInstance.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstance; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; + +public class ZookeeperInstance implements MicroserviceInstance { + private String serviceId; + + private String instanceId; + + private String environment; + + private String application; + + private String serviceName; + + private String alias; + + private String version; + + private String description; + + private DataCenterInfo dataCenterInfo; + + private List endpoints = new ArrayList<>(); + + private Map schemas = new HashMap<>(); + + private Map properties = new HashMap<>(); + + private MicroserviceInstanceStatus status; + + public ZookeeperInstance() { + + } + + public ZookeeperInstance(ZookeeperInstance other) { + this.serviceId = other.serviceId; + this.instanceId = other.instanceId; + this.environment = other.environment; + this.application = other.application; + this.serviceName = other.serviceName; + this.alias = other.alias; + this.version = other.version; + this.description = other.description; + this.dataCenterInfo = other.dataCenterInfo; + this.endpoints = other.endpoints; + this.schemas = other.schemas; + this.properties = other.properties; + this.status = other.status; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public void setApplication(String application) { + this.application = application; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { + this.dataCenterInfo = dataCenterInfo; + } + + public void setEndpoints(List endpoints) { + this.endpoints = endpoints; + } + + public void setSchemas(Map schemas) { + this.schemas = schemas; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setStatus(MicroserviceInstanceStatus status) { + this.status = status; + } + + @Override + public String getEnvironment() { + return this.environment; + } + + @Override + public String getApplication() { + return this.application; + } + + @Override + public String getServiceName() { + return this.serviceName; + } + + @Override + public String getAlias() { + return alias; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public DataCenterInfo getDataCenterInfo() { + return dataCenterInfo == null ? new DataCenterInfo() : dataCenterInfo; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public Map getProperties() { + return properties; + } + + @Override + public Map getSchemas() { + return schemas; + } + + @Override + public List getEndpoints() { + return endpoints; + } + + public void addSchema(String schemaId, String content) { + this.schemas.put(schemaId, content); + } + + public void addEndpoint(String endpoint) { + this.endpoints.add(endpoint); + } + + public void addProperty(String key, String value) { + this.properties.put(key, value); + } + + @Override + public String getInstanceId() { + return instanceId; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public MicroserviceInstanceStatus getStatus() { + return this.status; + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java new file mode 100644 index 00000000000..55df0d42702 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +import org.apache.commons.lang3.StringUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.curator.utils.CloseableUtils; +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; +import org.apache.curator.x.discovery.ServiceInstance; +import org.apache.curator.x.discovery.details.JsonInstanceSerializer; +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.config.DataCenterProperties; +import org.apache.servicecomb.registry.RegistrationId; +import org.apache.servicecomb.registry.api.DataCenterInfo; +import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; +import org.apache.servicecomb.registry.api.Registration; +import org.apache.zookeeper.server.auth.DigestLoginModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +public class ZookeeperRegistration implements Registration { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + + private Environment environment; + + private ZookeeperRegistryProperties zookeeperRegistryProperties; + + private DataCenterProperties dataCenterProperties; + + private String basePath; + + private CuratorFramework client; + + private ServiceInstance instance; + + private RegistrationId registrationId; + + private ServiceDiscovery dis; + + @Autowired + @SuppressWarnings("unused") + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + @SuppressWarnings("unused") + public void setZookeeperRegistryProperties(ZookeeperRegistryProperties zookeeperRegistryProperties) { + this.zookeeperRegistryProperties = zookeeperRegistryProperties; + } + + @Autowired + public void setRegistrationId(RegistrationId registrationId) { + this.registrationId = registrationId; + } + + @Autowired + @SuppressWarnings("unused") + public void setDataCenterProperties(DataCenterProperties dataCenterProperties) { + this.dataCenterProperties = dataCenterProperties; + } + + @Override + public void init() { + String env = BootStrapProperties.readServiceEnvironment(environment); + if (StringUtils.isEmpty(env)) { + env = ZookeeperConst.ZOOKEEPER_DEFAULT_ENVIRONMENT; + } + basePath = String.format(ZookeeperConst.ZOOKEEPER_DISCOVERY_ROOT, env); + ZookeeperInstance zookeeperInstance = new ZookeeperInstance(); + zookeeperInstance.setInstanceId(registrationId.getInstanceId()); + zookeeperInstance.setEnvironment(env); + zookeeperInstance.setApplication(BootStrapProperties.readApplication(environment)); + zookeeperInstance.setServiceName(BootStrapProperties.readServiceName(environment)); + zookeeperInstance.setAlias(BootStrapProperties.readServiceAlias(environment)); + zookeeperInstance.setDescription(BootStrapProperties.readServiceDescription(environment)); + if (StringUtils.isNotEmpty(dataCenterProperties.getName())) { + DataCenterInfo dataCenterInfo = new DataCenterInfo(); + dataCenterInfo.setName(dataCenterProperties.getName()); + dataCenterInfo.setRegion(dataCenterProperties.getRegion()); + dataCenterInfo.setAvailableZone(dataCenterProperties.getAvailableZone()); + zookeeperInstance.setDataCenterInfo(dataCenterInfo); + } + zookeeperInstance.setProperties(BootStrapProperties.readServiceProperties(environment)); + zookeeperInstance.setVersion(BootStrapProperties.readServiceVersion(environment)); + + zookeeperInstance.setStatus( + MicroserviceInstanceStatus.valueOf(BootStrapProperties.readServiceInstanceInitialStatus(environment))); + try { + this.instance = ServiceInstance.builder().name(zookeeperInstance.getServiceName()) + .id(zookeeperInstance.getInstanceId()).payload(zookeeperInstance).build(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public void run() { + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperRegistryProperties.getConnectString()) + .sessionTimeoutMs(zookeeperRegistryProperties.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperRegistryProperties.getAuthenticationSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperRegistryProperties.getAuthenticationInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperRegistryProperties.getAuthenticationInfo().split(":"); + Configuration.setConfiguration(new ZookeeperDiscovery.ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + client = builder.build(); + client.start(); + JsonInstanceSerializer serializer = + new JsonInstanceSerializer<>(ZookeeperInstance.class); + dis = ServiceDiscoveryBuilder.builder(ZookeeperInstance.class) + .client(client) + .basePath(basePath + "/" + BootStrapProperties.readApplication(environment)) + .serializer(serializer) + .thisInstance(instance) + .build(); + try { + dis.start(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public void destroy() { + if (client != null) { + CloseableUtils.closeQuietly(client); + } + } + + @Override + public String name() { + return ZookeeperConst.ZOOKEEPER_REGISTRY_NAME; + } + + @Override + public ZookeeperRegistrationInstance getMicroserviceInstance() { + return new ZookeeperRegistrationInstance(instance.getPayload()); + } + + @Override + public boolean updateMicroserviceInstanceStatus(MicroserviceInstanceStatus status) { + this.instance.getPayload().setStatus(status); + try { + dis.updateService(instance); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return true; + } + + @Override + public void addSchema(String schemaId, String content) { + if (zookeeperRegistryProperties.isEnableSwaggerRegistration()) { + instance.getPayload().addSchema(schemaId, content); + } + } + + @Override + public void addEndpoint(String endpoint) { + instance.getPayload().addEndpoint(endpoint); + } + + @Override + public void addProperty(String key, String value) { + instance.getPayload().addProperty(key, value); + } + + @Override + public boolean enabled() { + return zookeeperRegistryProperties.isEnabled(); + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistrationInstance.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistrationInstance.java new file mode 100644 index 00000000000..e5caed18960 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistrationInstance.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +import org.apache.servicecomb.registry.api.RegistrationInstance; + +public class ZookeeperRegistrationInstance extends ZookeeperInstance implements RegistrationInstance { + public ZookeeperRegistrationInstance(ZookeeperInstance instance) { + super(instance); + } +} diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java new file mode 100644 index 00000000000..0f74278fb58 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.registry.zookeeper; + +public class ZookeeperRegistryProperties { + private boolean enabled = true; + + private boolean ephemeral = true; + + private String connectString = "127.0.0.1:2181"; + + private String authenticationSchema; + + private String authenticationInfo; + + private int connectionTimeoutMillis = 1000; + + private int sessionTimeoutMillis = 60000; + + private boolean enableSwaggerRegistration = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEphemeral() { + return ephemeral; + } + + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; + } + + public String getConnectString() { + return connectString; + } + + public void setConnectString(String connectString) { + this.connectString = connectString; + } + + public int getConnectionTimeoutMillis() { + return connectionTimeoutMillis; + } + + public void setConnectionTimeoutMillis(int connectionTimeoutMillis) { + this.connectionTimeoutMillis = connectionTimeoutMillis; + } + + public int getSessionTimeoutMillis() { + return sessionTimeoutMillis; + } + + public void setSessionTimeoutMillis(int sessionTimeoutMillis) { + this.sessionTimeoutMillis = sessionTimeoutMillis; + } + + public boolean isEnableSwaggerRegistration() { + return enableSwaggerRegistration; + } + + public void setEnableSwaggerRegistration(boolean enableSwaggerRegistration) { + this.enableSwaggerRegistration = enableSwaggerRegistration; + } + + public String getAuthenticationSchema() { + return authenticationSchema; + } + + public void setAuthenticationSchema(String authenticationSchema) { + this.authenticationSchema = authenticationSchema; + } + + public String getAuthenticationInfo() { + return authenticationInfo; + } + + public void setAuthenticationInfo(String authenticationInfo) { + this.authenticationInfo = authenticationInfo; + } +} diff --git a/service-registry/registry-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/service-registry/registry-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..3fd671eac61 --- /dev/null +++ b/service-registry/registry-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.registry.zookeeper.ZookeeperConfiguration diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/Features.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/Features.java deleted file mode 100644 index 48f6db4d784..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/Features.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry; - -public class Features { - private boolean canEncodeEndpoint; - - public boolean isCanEncodeEndpoint() { - return canEncodeEndpoint; - } - - public void setCanEncodeEndpoint(boolean canEncodeEndpoint) { - this.canEncodeEndpoint = canEncodeEndpoint; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java deleted file mode 100644 index 1853578331c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry; - -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Map; - -import org.apache.http.client.utils.URIBuilder; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Charsets; -import com.google.common.hash.Hashing; -import com.netflix.config.DynamicPropertyFactory; - -public final class RegistryUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(RegistryUtils.class); - - private static ServiceRegistry serviceRegistry; - - // value is ip or {interface name} - public static final String PUBLISH_ADDRESS = "servicecomb.service.publishAddress"; - - private static final String PUBLISH_PORT = "servicecomb.{transport_name}.publishPort"; - - private RegistryUtils() { - } - - public static void init() { - MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(); - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels()); - serviceRegistry = - ServiceRegistryFactory - .getOrCreate(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition); - serviceRegistry.init(); - } - - public static void run() { - serviceRegistry.run(); - } - - public static void destroy() { - serviceRegistry.destroy(); - } - - /** - * @deprecated Replace by {@link #destroy()} - */ - @Deprecated - public static void destory() { - destroy(); - } - - public static ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - - public static void setServiceRegistry(ServiceRegistry serviceRegistry) { - RegistryUtils.serviceRegistry = serviceRegistry; - } - - public static ServiceRegistryClient getServiceRegistryClient() { - return serviceRegistry.getServiceRegistryClient(); - } - - public static InstanceCacheManager getInstanceCacheManager() { - return serviceRegistry.getInstanceCacheManager(); - } - - public static String getAppId() { - return serviceRegistry.getMicroservice().getAppId(); - } - - public static Microservice getMicroservice() { - return serviceRegistry.getMicroservice(); - } - - public static MicroserviceInstance getMicroserviceInstance() { - return serviceRegistry.getMicroserviceInstance(); - } - - public static String getPublishAddress() { - String publicAddressSetting = - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, "").get(); - publicAddressSetting = publicAddressSetting.trim(); - if (publicAddressSetting.isEmpty()) { - return NetUtils.getHostAddress(); - } - - // placeholder is network interface name - if (publicAddressSetting.startsWith("{") && publicAddressSetting.endsWith("}")) { - return NetUtils - .ensureGetInterfaceAddress(publicAddressSetting.substring(1, publicAddressSetting.length() - 1)) - .getHostAddress(); - } - - return publicAddressSetting; - } - - public static String getPublishHostName() { - String publicAddressSetting = - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, "").get(); - publicAddressSetting = publicAddressSetting.trim(); - if (publicAddressSetting.isEmpty()) { - return NetUtils.getHostName(); - } - - if (publicAddressSetting.startsWith("{") && publicAddressSetting.endsWith("}")) { - return NetUtils - .ensureGetInterfaceAddress(publicAddressSetting.substring(1, publicAddressSetting.length() - 1)) - .getHostName(); - } - - return publicAddressSetting; - } - - /** - * 对于配置为0.0.0.0的地址,通过查询网卡地址,转换为实际监听的地址。 - */ - public static String getPublishAddress(String schema, String address) { - if (address == null) { - return address; - } - - try { - URI originalURI = new URI(schema + "://" + address); - IpPort ipPort = NetUtils.parseIpPort(originalURI.getAuthority()); - if (ipPort == null) { - LOGGER.warn("address {} not valid.", address); - return null; - } - - IpPort publishIpPort = genPublishIpPort(schema, ipPort); - URIBuilder builder = new URIBuilder(originalURI); - return builder.setHost(publishIpPort.getHostOrIp()).setPort(publishIpPort.getPort()).build().toString(); - } catch (URISyntaxException e) { - LOGGER.warn("address {} not valid.", address); - return null; - } - } - - private static IpPort genPublishIpPort(String schema, IpPort ipPort) { - String publicAddressSetting = DynamicPropertyFactory.getInstance() - .getStringProperty(PUBLISH_ADDRESS, "") - .get(); - publicAddressSetting = publicAddressSetting.trim(); - - if (publicAddressSetting.isEmpty()) { - InetSocketAddress socketAddress = ipPort.getSocketAddress(); - if (socketAddress.getAddress().isAnyLocalAddress()) { - String host = NetUtils.getHostAddress(); - LOGGER.warn("address {}, auto select a host address to publish {}:{}, maybe not the correct one", - socketAddress, - host, - socketAddress.getPort()); - return new IpPort(host, ipPort.getPort()); - } - - return ipPort; - } - - if (publicAddressSetting.startsWith("{") && publicAddressSetting.endsWith("}")) { - publicAddressSetting = NetUtils - .ensureGetInterfaceAddress( - publicAddressSetting.substring(1, publicAddressSetting.length() - 1)) - .getHostAddress(); - } - - String publishPortKey = PUBLISH_PORT.replace("{transport_name}", schema); - int publishPortSetting = DynamicPropertyFactory.getInstance() - .getIntProperty(publishPortKey, 0) - .get(); - int publishPort = publishPortSetting == 0 ? ipPort.getPort() : publishPortSetting; - return new IpPort(publicAddressSetting, publishPort); - } - - public static List findServiceInstance(String appId, String serviceName, - String versionRule) { - return serviceRegistry.findServiceInstance(appId, serviceName, versionRule); - } - - // update microservice instance properties - public static boolean updateInstanceProperties(Map instanceProperties) { - return serviceRegistry.updateInstanceProperties(instanceProperties); - } - - public static Microservice getMicroservice(String microserviceId) { - return serviceRegistry.getRemoteMicroservice(microserviceId); - } - - public static MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return serviceRegistry.findServiceInstances(appId, serviceName, versionRule, revision); - } - - public static String calcSchemaSummary(String schemaContent) { - return Hashing.sha256().newHasher().putString(schemaContent, Charsets.UTF_8).hash().toString(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java deleted file mode 100644 index a249b488334..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; - -public interface ServiceRegistry { - void init(); - - void run(); - - void destroy(); - - Set getCombinedMicroserviceNames(); - - Microservice getMicroservice(); - - MicroserviceInstance getMicroserviceInstance(); - - ServiceRegistryClient getServiceRegistryClient(); - - AppManager getAppManager(); - - InstanceCacheManager getInstanceCacheManager(); - - List findServiceInstance(String appId, String microserviceName, - String microserviceVersionRule); - - MicroserviceInstances findServiceInstances(String appId, String microserviceName, - String microserviceVersionRule, String revision); - - boolean updateMicroserviceProperties(Map properties); - - boolean updateInstanceProperties(Map instanceProperties); - - Microservice getRemoteMicroservice(String microserviceId); - - /** - *

- * if connect to normal ServiceCenter, same with the method - * {@linkplain org.apache.servicecomb.serviceregistry.ServiceRegistry#getRemoteMicroservice(String)} } - * if connect to ServiceCenter Aggregator, not only contain the target ServiceCenter but also other ServiceCenter clusters - *

- */ - Microservice getAggregatedRemoteMicroservice(String microserviceId); - - Features getFeatures(); - - /** - *

- * Register a third party service if not registered before, and set it's instances into - * {@linkplain org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersions StaticMicroserviceVersions}. - *

- *

- * The registered third party service has the same {@code appId} and {@code environment} as this microservice instance has, - * and there is only one schema represented by {@code schemaIntfCls}, whose name is the same as {@code microserviceName}. - *

- * - * This method is for initializing 3rd party service endpoint config. - * i.e. If this service has not been registered before, this service will be registered and the instances will be set; - * otherwise, NOTHING will happen. - * - * - * @param microserviceName name of the 3rd party service, and this param also specifies the schemaId - * @param version version of this 3rd party service - * @param instances the instances of this 3rd party service. Users only need to specify the endpoint information, other - * necessary information will be generate and set in the implementation of this method. - * @param schemaIntfCls the producer interface of the service. This interface is used to generate swagger schema and - * can also be used for the proxy interface of RPC style invocation. - */ - void registerMicroserviceMapping(String microserviceName, String version, List instances, - Class schemaIntfCls); - - /** - * @see #registerMicroserviceMapping(String, String, List, Class) - * @param endpoints the endpoints of 3rd party service. Each of endpoints will be treated as a separated instance. - * Format of the endpoints is the same as the endpoints that ServiceComb microservices register in service-center, - * like {@code rest://127.0.0.1:8080} - */ - void registerMicroserviceMappingByEndpoints(String microserviceName, String version, - List endpoints, Class schemaIntfCls); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Const.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Const.java deleted file mode 100644 index 1092f05e803..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Const.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api; - -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; - -/** - * Created by on 2017/1/9. - */ -public final class Const { - private Const() { - } - - public static final class REGISTRY_API { - public static final String DOMAIN_NAME = ServiceRegistryConfig.INSTANCE.getDomainName(); - - public static final String CURRENT_VERSION = ServiceRegistryConfig.INSTANCE.getRegistryApiVersion(); - - // 2017-10-21 add new implementations for v4. We can remove v3 support after a period. - public static final String VERSION_V3 = "v3"; - - public static final String LATEST_API_VERSION = "v4"; - - public static final String V4_PREFIX = String.format("/v4/%s/registry", DOMAIN_NAME); - - public static final String MICROSERVICE_OPERATION_ALL; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_OPERATION_ALL = "/registry/v3/microservices"; - } else { - MICROSERVICE_OPERATION_ALL = V4_PREFIX + "/microservices"; - } - } - - public static final String MICROSERVICE_OPERATION_ONE; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_OPERATION_ONE = "/registry/v3/microservices/%s"; - } else { - MICROSERVICE_OPERATION_ONE = V4_PREFIX + "/microservices/%s"; - } - } - - public static final String MICROSERVICE_INSTANCE_OPERATION_ALL; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_INSTANCE_OPERATION_ALL = "/registry/v3/microservices/%s/instances"; - } else { - MICROSERVICE_INSTANCE_OPERATION_ALL = V4_PREFIX + "/microservices/%s/instances"; - } - } - - public static final String MICROSERVICE_INSTANCE_OPERATION_ONE; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_INSTANCE_OPERATION_ONE = "/registry/v3/microservices/%s/instances/%s"; - } else { - MICROSERVICE_INSTANCE_OPERATION_ONE = V4_PREFIX + "/microservices/%s/instances/%s"; - } - } - - public static final String MICROSERVICE_INSTANCES; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_INSTANCES = "/registry/v3/instances"; - } else { - MICROSERVICE_INSTANCES = V4_PREFIX + "/instances"; - } - } - - public static final String MICROSERVICE_PROPERTIES; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_PROPERTIES = "/registry/v3/microservices/%s/properties"; - } else { - MICROSERVICE_PROPERTIES = V4_PREFIX + "/microservices/%s/properties"; - } - } - - public static final String MICROSERVICE_INSTANCE_PROPERTIES; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_INSTANCE_PROPERTIES = "/registry/v3/microservices/%s/instances/%s/properties"; - } else { - MICROSERVICE_INSTANCE_PROPERTIES = V4_PREFIX + "/microservices/%s/instances/%s/properties"; - } - } - - public static final String MICROSERVICE_HEARTBEAT; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_HEARTBEAT = "/registry/v3/microservices/%s/instances/%s/heartbeat"; - } else { - MICROSERVICE_HEARTBEAT = V4_PREFIX + "/microservices/%s/instances/%s/heartbeat"; - } - } - - public static final String MICROSERVICE_EXISTENCE; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_EXISTENCE = "/registry/v3/existence"; - } else { - MICROSERVICE_EXISTENCE = V4_PREFIX + "/existence"; - } - } - - public static final String MICROSERVICE_ALL_SCHEMAs; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_ALL_SCHEMAs = "/registry/v3/microservices/%s/schemas"; - } else { - MICROSERVICE_ALL_SCHEMAs = V4_PREFIX + "/microservices/%s/schemas"; - } - } - - public static final String MICROSERVICE_SCHEMA; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_SCHEMA = "/registry/v3/microservices/%s/schemas/%s"; - } else { - MICROSERVICE_SCHEMA = V4_PREFIX + "/microservices/%s/schemas/%s"; - } - } - - public static final String MICROSERVICE_WATCH; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - MICROSERVICE_WATCH = "/registry/v3/microservices/%s/watcher"; - } else { - MICROSERVICE_WATCH = V4_PREFIX + "/microservices/%s/watcher"; - } - } - - public static final String SERVICECENTER_VERSION; - - static { - if (VERSION_V3.equals(CURRENT_VERSION)) { - SERVICECENTER_VERSION = "/version"; - } else { - SERVICECENTER_VERSION = V4_PREFIX + "/version"; - } - } - } - - public static final String REGISTRY_APP_ID = "default"; - - public static final String REGISTRY_SERVICE_NAME = "SERVICECENTER"; - - public static final String APP_SERVICE_SEPARATOR = ":"; - - public static final String PATH_CHECKSESSION = "checksession"; - - public static final String URL_PREFIX = "urlPrefix"; - - public static final String INSTANCE_PUBKEY_PRO = "publickey"; - - public static final String SERVICECENTER_FRAMEWORK_VERSION = "1.0.0"; - - public static final String REGISTER_SERVICE_PATH = "servicecomb.service.registry.registerPath"; - - public static final String REGISTER_URL_PREFIX = "servicecomb.service.registry.registerUrlPrefix"; -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Versions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Versions.java deleted file mode 100644 index 5e4adfb6108..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/Versions.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api; - -import java.util.Map; - -public interface Versions { - public Map loadVersion(); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/DataCenterInfo.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/DataCenterInfo.java deleted file mode 100644 index 066ca84f8e2..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/DataCenterInfo.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.registry; - -public class DataCenterInfo { - - private String name; - - private String region; - - private String availableZone; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public String getAvailableZone() { - return availableZone; - } - - public void setAvailableZone(String availableZone) { - this.availableZone = availableZone; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/FrameworkVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/FrameworkVersions.java deleted file mode 100644 index 6e102415c4b..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/FrameworkVersions.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.ServiceLoader; - -import org.apache.servicecomb.serviceregistry.api.Versions; - -public class FrameworkVersions { - private static final ServiceLoader frameworkVersions = ServiceLoader.load(Versions.class); - - public static String allVersions() { - StringBuffer sb = new StringBuffer(); - frameworkVersions.forEach(version -> version.loadVersion().forEach((key, value) -> { - sb.append(key).append(":").append(value).append(";"); - })); - if (sb.length() > 0) { - sb.setLength(sb.length() - 1); - } - return sb.toString(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheck.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheck.java deleted file mode 100644 index 4c7367344f4..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheck.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * Created by on 2017/1/13. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class HealthCheck { - private HealthCheckMode mode; - - private int port; - - private int interval; - - private int times; - - public int getInterval() { - return interval; - } - - public void setInterval(int interval) { - this.interval = interval; - } - - public int getTimes() { - return times; - } - - public void setTimes(int times) { - this.times = times; - } - - public HealthCheckMode getMode() { - return mode; - } - - public void setMode(HealthCheckMode mode) { - this.mode = mode; - } - - public int getTTL() { - if (this.mode != HealthCheckMode.HEARTBEAT) { - return 0; - } - return getInterval() * (getTimes() + 1); - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheckMode.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheckMode.java deleted file mode 100644 index b0aff79a209..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/HealthCheckMode.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import com.fasterxml.jackson.annotation.JsonValue; - -/** - * Created by on 2017/1/25. - */ -public enum HealthCheckMode { - UNKNOWN("unknown"), - HEARTBEAT("push"), - PLATFORM("pull"); - - private String name; - - HealthCheckMode(String name) { - this.name = name; - } - - @JsonValue - public String getName() { - return name; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Microservice.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Microservice.java deleted file mode 100644 index 6e90072595d..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/Microservice.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.api.Const; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * Created by on 2016/12/5. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Microservice { - private String serviceId; - - private Framework framework; - - private String registerBy; - - private String environment; - - private String appId; - - private String serviceName; - - private String alias; - - private String version; - - private String description; - - private String level; - - private List schemas = new ArrayList<>(); - - @JsonIgnore - private Map schemaMap = new HashMap<>(); - - private List paths = new ArrayList<>(); - - private MicroserviceStatus status = MicroserviceStatus.UP; - - private Map properties = new HashMap<>(); - - @JsonIgnore - private MicroserviceInstance instance; - - public Microservice() { - } - - public MicroserviceInstance getInstance() { - return instance; - } - - /** - * @deprecated Replace by {@link #getInstance()} - */ - @Deprecated - public MicroserviceInstance getIntance() { - return getInstance(); - } - - public void setInstance(MicroserviceInstance instance) { - this.instance = instance; - } - - /** - * @deprecated Replace by {@link #setInstance(MicroserviceInstance)} - */ - @Deprecated - public void setIntance(MicroserviceInstance instance) { - setInstance(instance); - } - - public String getServiceId() { - return serviceId; - } - - public void setServiceId(String serviceId) { - this.serviceId = serviceId; - } - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public String getAlias() { - return alias; - } - - public void setAlias(String alias) { - this.alias = alias; - } - - public String getServiceName() { - return serviceName; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLevel() { - return level; - } - - public void setLevel(String level) { - this.level = level; - } - - public List getSchemas() { - return schemas; - } - - public void setSchemas(List schemas) { - this.schemas = schemas; - } - - public void addSchema(String schemaId, String content) { - this.schemaMap.put(schemaId, content); - schemas.add(schemaId); - } - - public Map getSchemaMap() { - return schemaMap; - } - - public String getStatus() { - return status.toString(); - } - - public void setStatus(String status) { - this.status = MicroserviceStatus.valueOf(status); - } - - public Map getProperties() { - return properties; - } - - public void setProperties(Map properties) { - this.properties = properties; - } - - public static String generateAbsoluteMicroserviceName(String appId, String microserviceName) { - StringBuilder sb = new StringBuilder(appId.length() + microserviceName.length() + 1); - sb.append(appId).append(Const.APP_SERVICE_SEPARATOR).append(microserviceName); - return sb.toString(); - } - - public List getPaths() { - return paths; - } - - public void setPaths(List paths) { - this.paths = paths; - } - - public Framework getFramework() { - return framework; - } - - public void setFramework(Framework framework) { - this.framework = framework; - } - - public String getRegisterBy() { - return registerBy; - } - - public void setRegisterBy(String registerBy) { - this.registerBy = registerBy; - } - - public String getEnvironment() { - return environment; - } - - public void setEnvironment(String environment) { - this.environment = environment; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceFactory.java deleted file mode 100644 index 2ace55f91a2..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceFactory.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.registry; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_APPLICATION_ID_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_ROLE_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_MICROSERVICE_NAME; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_SERVICECOMB_ENV; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.SERVICECOMB_ENV; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.CONFIG_ALLOW_CROSS_APP_KEY; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_APPLICATION_ID; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_MICROSERVICE_VERSION; - -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.serviceregistry.config.ConfigurePropertyUtils; -import org.apache.servicecomb.serviceregistry.config.MicroservicePropertiesLoader; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.version.Version; - -public class MicroserviceFactory { - public Microservice create(String appId, String microserviceName) { - MicroserviceDefinition microserviceDefinition = MicroserviceDefinition.create(appId, microserviceName); - return create(microserviceDefinition); - } - - public Microservice create(MicroserviceDefinition microserviceDefinition) { - Configuration configuration = microserviceDefinition.getConfiguration(); - Microservice microservice = createMicroserviceFromDefinition(configuration); - microservice.setInstance(MicroserviceInstance.createFromDefinition(configuration)); - return microservice; - } - - private Microservice createMicroserviceFromDefinition(Configuration configuration) { - Microservice microservice = new Microservice(); - microservice.setServiceName(configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, - DEFAULT_MICROSERVICE_NAME)); - microservice.setAppId(configuration.getString(CONFIG_APPLICATION_ID_KEY, DEFAULT_APPLICATION_ID)); - String version = configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY, - DEFAULT_MICROSERVICE_VERSION); - // just check version format - new Version(version); - microservice.setVersion(version); - setDescription(configuration, microservice); - microservice.setLevel(configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_ROLE_KEY, "FRONT")); - microservice.setPaths(ConfigurePropertyUtils.getMicroservicePaths(configuration)); - Map propertiesMap = MicroservicePropertiesLoader.INSTANCE.loadProperties(configuration); - microservice.setProperties(propertiesMap); - microservice.setEnvironment(configuration.getString(SERVICECOMB_ENV, DEFAULT_SERVICECOMB_ENV)); - - // set alias name when allow cross app - if (allowCrossApp(propertiesMap)) { - microservice.setAlias(Microservice.generateAbsoluteMicroserviceName(microservice.getAppId(), - microservice.getServiceName())); - } - - return microservice; - } - - /** - * {@code service_description.description} is split by {@code ,}, - * need to combine the description array to raw description. - */ - private void setDescription(Configuration configuration, Microservice microservice) { - String[] descriptionArray = configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY); - if (null == descriptionArray || descriptionArray.length < 1) { - return; - } - - StringBuilder rawDescriptionBuilder = new StringBuilder(); - for (String desc : descriptionArray) { - rawDescriptionBuilder.append(desc).append(","); - } - - microservice.setDescription(rawDescriptionBuilder.substring(0, rawDescriptionBuilder.length() - 1)); - } - - private boolean allowCrossApp(Map propertiesMap) { - return Boolean.valueOf(propertiesMap.get(CONFIG_ALLOW_CROSS_APP_KEY)); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java deleted file mode 100644 index 8d4d7f769b3..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstance.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.CONFIG_QUALIFIED_INSTANCE_ENVIRONMENT_KEY; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_INSTANCE_ENVIRONMENT; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_STAGE; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.lang.StringUtils; -import org.apache.servicecomb.serviceregistry.config.InstancePropertiesLoader; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.netflix.config.DynamicPropertyFactory; - -/** - * Created by on 2016/12/5. - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class MicroserviceInstance { - // even disconnected from service center - // instanceId will not be changed - // when register to service center again, use the old instanceId. - private String instanceId; - - private String serviceId; - - private List endpoints = new ArrayList<>(); - - private String hostName; - - private MicroserviceInstanceStatus status = MicroserviceInstanceStatus.UP; - - private Map properties = new HashMap<>(); // reserved key list: region|az|stage|group - - private HealthCheck healthCheck; - - /** - * Will be abandoned, use {@link Microservice#environment} instead - */ - @Deprecated - private String environment; - - private String stage; - - private DataCenterInfo dataCenterInfo; - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public String getServiceId() { - return serviceId; - } - - public void setServiceId(String serviceId) { - this.serviceId = serviceId; - } - - public String getHostName() { - return hostName; - } - - public void setHostName(String hostName) { - this.hostName = hostName; - } - - public List getEndpoints() { - return endpoints; - } - - public void setEndpoints(List endpoints) { - this.endpoints = endpoints; - } - - public MicroserviceInstanceStatus getStatus() { - return status; - } - - public void setStatus(MicroserviceInstanceStatus status) { - this.status = status; - } - - public Map getProperties() { - return properties; - } - - public void setProperties(Map properties) { - this.properties = properties; - } - - public HealthCheck getHealthCheck() { - return healthCheck; - } - - public void setHealthCheck(HealthCheck healthCheck) { - this.healthCheck = healthCheck; - } - - public String getEnvironment() { - return environment; - } - - public void setEnvironment(String environment) { - this.environment = environment; - } - - @Deprecated - public String getStage() { - return stage; - } - - @Deprecated - public void setStage(String stage) { - this.stage = stage; - } - - public DataCenterInfo getDataCenterInfo() { - return dataCenterInfo; - } - - @Override - public int hashCode() { - return this.instanceId.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof MicroserviceInstance) { - return this.instanceId.equals(((MicroserviceInstance) obj).instanceId); - } - return false; - } - - public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { - this.dataCenterInfo = dataCenterInfo; - } - - // Some properties of microservice instance are dynamic changed, not cover them all now. - public static MicroserviceInstance createFromDefinition(Configuration configuration) { - MicroserviceInstance microserviceInstance = new MicroserviceInstance(); - // default hard coded values - microserviceInstance.setStage(DEFAULT_STAGE); - microserviceInstance - .setEnvironment( - configuration.getString(CONFIG_QUALIFIED_INSTANCE_ENVIRONMENT_KEY, DEFAULT_INSTANCE_ENVIRONMENT)); - HealthCheck healthCheck = new HealthCheck(); - healthCheck.setMode(HealthCheckMode.HEARTBEAT); - microserviceInstance.setHealthCheck(healthCheck); - - // load properties - Map propertiesMap = InstancePropertiesLoader.INSTANCE.loadProperties(configuration); - microserviceInstance.setProperties(propertiesMap); - - // load data center information - loadDataCenterInfo(microserviceInstance); - return microserviceInstance; - } - - private static void loadDataCenterInfo(MicroserviceInstance microserviceInstance) { - String dataCenterName = DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.datacenter.name", null) - .get(); - if (StringUtils.isNotEmpty(dataCenterName)) { - DataCenterInfo dataCenterInfo = new DataCenterInfo(); - dataCenterInfo.setName(dataCenterName); - dataCenterInfo - .setRegion(DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.datacenter.region", null).get()); - dataCenterInfo.setAvailableZone( - DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.datacenter.availableZone", null).get()); - microserviceInstance.setDataCenterInfo(dataCenterInfo); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstanceStatus.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstanceStatus.java deleted file mode 100644 index 58b3642f5be..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/MicroserviceInstanceStatus.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -/** - * Created by on 2016/12/5. - */ -public enum MicroserviceInstanceStatus { - UNKNOWN, - UP, - DOWN, - STARTING, - OUTOFSERVICE -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterConfig.java deleted file mode 100644 index 26049e149e4..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterConfig.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -public class ServiceCenterConfig { - private int maxHeaderBytes; - - private int maxBodyBytes; - - private String readHeaderTimeout; - - private String readTimeout; - - private String idleTimeout; - - private String writeTimeout; - - private String limitTTLUnit; - - private int limitConnections; - - private String limitIPLookup; - - private String sslEnabled; - - private String sslMinVersion; - - private String sslVerifyPeer; - - private String sslCiphers; - - private String autoSyncInterval; - - private int compactIndexDelta; - - private String compactInterval; - - private int logRotateSize; - - private int logBackupCount; - - public int getMaxHeaderBytes() { - return maxHeaderBytes; - } - - public void setMaxHeaderBytes(int maxHeaderBytes) { - this.maxHeaderBytes = maxHeaderBytes; - } - - public int getMaxBodyBytes() { - return maxBodyBytes; - } - - public void setMaxBodyBytes(int maxBodyBytes) { - this.maxBodyBytes = maxBodyBytes; - } - - public String getReadHeaderTimeout() { - return readHeaderTimeout; - } - - public void setReadHeaderTimeout(String readHeaderTimeout) { - this.readHeaderTimeout = readHeaderTimeout; - } - - public String getReadTimeout() { - return readTimeout; - } - - public void setReadTimeout(String readTimeout) { - this.readTimeout = readTimeout; - } - - public String getIdleTimeout() { - return idleTimeout; - } - - public void setIdleTimeout(String idleTimeout) { - this.idleTimeout = idleTimeout; - } - - public String getWriteTimeout() { - return writeTimeout; - } - - public void setWriteTimeout(String writeTimeout) { - this.writeTimeout = writeTimeout; - } - - public String getLimitTTLUnit() { - return limitTTLUnit; - } - - public void setLimitTTLUnit(String limitTTLUnit) { - this.limitTTLUnit = limitTTLUnit; - } - - public int getLimitConnections() { - return limitConnections; - } - - public void setLimitConnections(int limitConnections) { - this.limitConnections = limitConnections; - } - - public String getLimitIPLookup() { - return limitIPLookup; - } - - public void setLimitIPLookup(String limitIPLookup) { - this.limitIPLookup = limitIPLookup; - } - - public String getSslEnabled() { - return sslEnabled; - } - - public void setSslEnabled(String sslEnabled) { - this.sslEnabled = sslEnabled; - } - - public String getSslMinVersion() { - return sslMinVersion; - } - - public void setSslMinVersion(String sslMinVersion) { - this.sslMinVersion = sslMinVersion; - } - - public String getSslVerifyPeer() { - return sslVerifyPeer; - } - - public void setSslVerifyPeer(String sslVerifyPeer) { - this.sslVerifyPeer = sslVerifyPeer; - } - - public String getSslCiphers() { - return sslCiphers; - } - - public void setSslCiphers(String sslCiphers) { - this.sslCiphers = sslCiphers; - } - - public String getAutoSyncInterval() { - return autoSyncInterval; - } - - public void setAutoSyncInterval(String autoSyncInterval) { - this.autoSyncInterval = autoSyncInterval; - } - - public int getCompactIndexDelta() { - return compactIndexDelta; - } - - public void setCompactIndexDelta(int compactIndexDelta) { - this.compactIndexDelta = compactIndexDelta; - } - - public String getCompactInterval() { - return compactInterval; - } - - public void setCompactInterval(String compactInterval) { - this.compactInterval = compactInterval; - } - - public int getLogRotateSize() { - return logRotateSize; - } - - public void setLogRotateSize(int logRotateSize) { - this.logRotateSize = logRotateSize; - } - - public int getLogBackupCount() { - return logBackupCount; - } - - public void setLogBackupCount(int logBackupCount) { - this.logBackupCount = logBackupCount; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterInfo.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterInfo.java deleted file mode 100644 index 65dca2b074a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCenterInfo.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -public class ServiceCenterInfo { - private String version; - - private String buildTag; - - private String runMode; - - private String apiVersion; - - private ServiceCenterConfig config; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getBuildTag() { - return buildTag; - } - - public void setBuildTag(String buildTag) { - this.buildTag = buildTag; - } - - public String getRunMode() { - return runMode; - } - - public void setRunMode(String runMode) { - this.runMode = runMode; - } - - public String getApiVersion() { - return apiVersion; - } - - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - public ServiceCenterConfig getConfig() { - return config; - } - - public void setConfig(ServiceCenterConfig config) { - this.config = config; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCombVersion.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCombVersion.java deleted file mode 100644 index 1e6aa4387e5..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/ServiceCombVersion.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.api.Versions; - -public class ServiceCombVersion implements Versions { - - @Override - public Map loadVersion() { - Map map = new HashMap<>(); - map.put("ServiceComb", this.getClass().getPackage().getImplementationVersion()); - - return map; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/StaticMicroservice.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/StaticMicroservice.java deleted file mode 100644 index 60d5900dfef..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/StaticMicroservice.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -public class StaticMicroservice extends Microservice { - private Class schemaIntfCls; - - public Class getSchemaIntfCls() { - return schemaIntfCls; - } - - public void setSchemaIntfCls(Class schemaIntfCls) { - this.schemaIntfCls = schemaIntfCls; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/WatchAction.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/WatchAction.java deleted file mode 100644 index bf9360cab3e..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/registry/WatchAction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import com.fasterxml.jackson.annotation.JsonValue; - -/** - * Created by on 2017/2/21. - */ -public enum WatchAction { - CREATE("CREATE"), - UPDATE("UPDATE"), - // When SC send an EXPIRE action, which means client should clean up all local instance cache and fetch again. - // This usually happens when SC adds new WHITE/BLACK rules or changes TAGS of instance - EXPIRE("EXPIRE"), - DELETE("DELETE"); - - private String name; - - WatchAction(String name) { - this.name = name; - } - - @JsonValue - public String getName() { - return name; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateServiceRequest.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateServiceRequest.java deleted file mode 100644 index 7a6b73ed029..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/CreateServiceRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.request; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -/** - * Created by on 2016/12/5. - */ -public class CreateServiceRequest { - private Microservice service; - - public Microservice getService() { - return service; - } - - public void setService(Microservice service) { - this.service = service; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/RegisterInstanceRequest.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/RegisterInstanceRequest.java deleted file mode 100644 index 2179573c4a1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/request/RegisterInstanceRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.request; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * Created by on 2016/12/6. - */ -public class RegisterInstanceRequest { - private MicroserviceInstance instance; - - public MicroserviceInstance getInstance() { - return instance; - } - - public void setInstance(MicroserviceInstance instance) { - this.instance = instance; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/CreateServiceResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/CreateServiceResponse.java deleted file mode 100644 index 8b1303faa2a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/CreateServiceResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -/** - * Created by on 2016/12/5. - */ -public class CreateServiceResponse { - private String serviceId; - - public String getServiceId() { - return serviceId; - } - - public void setServiceId(String serviceId) { - this.serviceId = serviceId; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/FindInstancesResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/FindInstancesResponse.java deleted file mode 100644 index b4a2e8a772a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/FindInstancesResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * Created by on 2016/12/8. - */ -public class FindInstancesResponse { - private List instances; - - public List getInstances() { - return instances; - } - - public void setInstances(List instances) { - this.instances = instances; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetAllServicesResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetAllServicesResponse.java deleted file mode 100644 index a5f822e294a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetAllServicesResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -/** - * Created by on 2016/12/8. - */ -public class GetAllServicesResponse { - private List services; - - public List getServices() { - return services; - } - - public void setServices(List services) { - this.services = services; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetExistenceResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetExistenceResponse.java deleted file mode 100644 index 10e9afd4b04..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetExistenceResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -/** - * Created by on 2016/12/8. - */ -public class GetExistenceResponse { - private String serviceId; - - private String schemaId; - - public String getServiceId() { - return serviceId; - } - - public void setServiceId(String serviceId) { - this.serviceId = serviceId; - } - - public String getSchemaId() { - return schemaId; - } - - public void setSchemaId(String schemaId) { - this.schemaId = schemaId; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetInstancesResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetInstancesResponse.java deleted file mode 100644 index 4acc1ac0b98..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetInstancesResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * Created by on 2016/12/6. - */ -public class GetInstancesResponse { - private List instances; - - public List getInstances() { - return instances; - } - - public void setInstances(List instances) { - this.instances = instances; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemaResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemaResponse.java deleted file mode 100644 index d54bc767d92..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemaResponse.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -public class GetSchemaResponse { - private String schema; - - private String schemaId; - - private String summary; - - public String getSchema() { - return schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public String getSchemaId() { - return schemaId; - } - - public void setSchemaId(String schemaId) { - this.schemaId = schemaId; - } - - public String getSummary() { - return summary; - } - - public void setSummary(String summary) { - this.summary = summary; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemasResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemasResponse.java deleted file mode 100644 index 382909faa00..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetSchemasResponse.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.List; - -public class GetSchemasResponse { - - //to compatible service center interface, cur version return schema, but next version will change to schemas - private List schema; - - private List schemas; - - public List getSchema() { - return schema; - } - - public void setSchema(List schema) { - this.schema = schema; - } - - public List getSchemas() { - return schemas; - } - - public void setSchemas(List schemas) { - this.schemas = schemas; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetServiceResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetServiceResponse.java deleted file mode 100644 index 051cbb266cf..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/GetServiceResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -/** - * Created by on 2016/12/8. - */ -public class GetServiceResponse { - private Microservice service; - - public Microservice getService() { - return service; - } - - public void setService(Microservice service) { - this.service = service; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/HeartbeatResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/HeartbeatResponse.java deleted file mode 100644 index e000a7393af..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/HeartbeatResponse.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -/** - * Created by on 2017/3/13. - */ -public class HeartbeatResponse { - private boolean ok; - - private String message; - - public boolean isOk() { - return ok; - } - - public void setOk(boolean ok) { - this.ok = ok; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceChangedEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceChangedEvent.java deleted file mode 100644 index 738ec6120be..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/MicroserviceInstanceChangedEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.MicroserviceKey; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.WatchAction; - -/** - * Created by on 2016/12/25. - */ -public class MicroserviceInstanceChangedEvent { - private WatchAction action; - - private MicroserviceKey key; - - private MicroserviceInstance instance; - - public MicroserviceInstance getInstance() { - return instance; - } - - public void setInstance(MicroserviceInstance instance) { - this.instance = instance; - } - - public MicroserviceKey getKey() { - return key; - } - - public void setKey(MicroserviceKey key) { - this.key = key; - } - - public WatchAction getAction() { - return action; - } - - public void setAction(WatchAction action) { - this.action = action; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/RegisterInstanceResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/RegisterInstanceResponse.java deleted file mode 100644 index 4afb94cbdb5..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/api/response/RegisterInstanceResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -/** - * Created by on 2016/12/6. - */ -public class RegisterInstanceResponse { - private String instanceId; - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/CacheEndpoint.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/CacheEndpoint.java deleted file mode 100644 index 87596baa3e5..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/CacheEndpoint.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -public class CacheEndpoint { - // 所属的服务实例 - private final MicroserviceInstance instance; - - private final String endpoint; - - public CacheEndpoint(String endpoint, MicroserviceInstance instance) { - this.endpoint = endpoint; - this.instance = instance; - } - - public String getEndpoint() { - return endpoint; - } - - public MicroserviceInstance getInstance() { - return instance; - } - - public String toString() { - return endpoint; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCache.java deleted file mode 100644 index 20583e833a4..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCache.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 缓存指定微服务的所有实例 - * 当实例状态变化时,需要重新创建InstanceCache,由外部控制 - */ -public class InstanceCache { - private static final Logger LOGGER = LoggerFactory.getLogger(InstanceCache.class); - - // 引入这个原子变量,是为了避免一个服务长期不用,缓存被删除,下次再初始化的初始版本号,有极小概率等于被删除前的版本号的问题 - // 如果相等,可能会导致其他没感知删除的模块,在更新流程上,遇到问题 - private static final AtomicInteger VERSION = new AtomicInteger(); - - private int cacheVersion; - - private String appId; - - private String microserviceName; - - // 1.0或1.0+或latest等等,只是规则,不一定表示一个确定的版本 - private String microserviceVersionRule; - - // key为instanceId - private Map instanceMap; - - private VersionedCache versionedCache; - - // 缓存CacheEndpoint - private volatile Map> transportMap; - - private Object lockObj = new Object(); - - /** - * 用于初始化场景 - */ - public InstanceCache(String appId, String microserviceName, String microserviceVersionRule, - Map instanceMap) { - cacheVersion = VERSION.getAndIncrement(); - this.appId = appId; - this.microserviceName = microserviceName; - this.microserviceVersionRule = microserviceVersionRule; - this.instanceMap = instanceMap; - this.versionedCache = new VersionedCache() - .name(microserviceVersionRule) - .autoCacheVersion() - .data(instanceMap); - } - - public VersionedCache getVersionedCache() { - return versionedCache; - } - - public boolean cacheChanged(InstanceCache newCache) { - return newCache != null - && newCache.instanceMap != null - && newCache.cacheVersion != cacheVersion; - } - - public Map> getOrCreateTransportMap() { - if (transportMap == null) { - synchronized (lockObj) { - if (transportMap == null) { - transportMap = createTransportMap(); - } - } - } - return transportMap; - } - - protected Map> createTransportMap() { - Map> transportMap = new HashMap<>(); - for (MicroserviceInstance instance : instanceMap.values()) { - // 过滤到不可用实例 - if (instance.getStatus() != MicroserviceInstanceStatus.UP) { - continue; - } - for (String endpoint : instance.getEndpoints()) { - try { - URI uri = URI.create(endpoint); - String transportName = uri.getScheme(); - - List cacheEndpointList = transportMap.computeIfAbsent(transportName, k -> new ArrayList<>()); - cacheEndpointList.add(new CacheEndpoint(endpoint, instance)); - } catch (Exception e) { - LOGGER.warn("unrecognized address find, ignore " + endpoint); - } - } - } - return transportMap; - } - - public Map getInstanceMap() { - return instanceMap; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public String getMicroserviceVersionRule() { - return microserviceVersionRule; - } - - public String getAppId() { - return appId; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManager.java deleted file mode 100644 index 43a73773680..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; - -public interface InstanceCacheManager { - InstanceCache getOrCreate(String appId, String microserviceName, String microserviceVersionRule); - - VersionedCache getOrCreateVersionedCache(String appId, String microserviceName, String microserviceVersionRule); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManagerNew.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManagerNew.java deleted file mode 100644 index 5b0d839beb1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/InstanceCacheManagerNew.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; - -public class InstanceCacheManagerNew implements InstanceCacheManager { - private AppManager appManager; - - public InstanceCacheManagerNew(AppManager appManager) { - this.appManager = appManager; - } - - @Override - public InstanceCache getOrCreate(String appId, String microserviceName, String microserviceVersionRule) { - return appManager.getOrCreateMicroserviceVersionRule(appId, microserviceName, microserviceVersionRule) - .getInstanceCache(); - } - - @Override - public VersionedCache getOrCreateVersionedCache(String appId, String microserviceName, - String microserviceVersionRule) { - return appManager.getOrCreateMicroserviceVersionRule(appId, microserviceName, microserviceVersionRule) - .getVersionedCache(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java deleted file mode 100644 index 16a03819ace..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.util.concurrent.UncheckedExecutionException; - -/** - * 微服务实例缓存 key为:serviceId@instanceId 缓存limit:1000 缓存老化策略:30分钟没有访问就过期。 - * - */ -public class MicroserviceInstanceCache { - - private static final Logger logger = LoggerFactory.getLogger(MicroserviceInstanceCache.class); - - private static Cache instances = CacheBuilder.newBuilder() - .maximumSize(1000) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build(); - - private static final Cache microservices = CacheBuilder.newBuilder() - .maximumSize(1000) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build(); - - public static Microservice getOrCreate(String serviceId) { - try { - return microservices.get(serviceId, () -> { - Microservice microservice = RegistryUtils.getServiceRegistryClient().getAggregatedMicroservice(serviceId); - if (microservice == null) { - throw new IllegalArgumentException("service id not exists."); - } - return microservice; - }); - } catch (ExecutionException | UncheckedExecutionException e) { - logger.error("get microservice from cache failed, {}, {}", serviceId, e.getMessage()); - return null; - } - } - - public static MicroserviceInstance getOrCreate(String serviceId, String instanceId) { - try { - String key = String.format("%s@%s", serviceId, instanceId); - return instances.get(key, new Callable() { - - @Override - public MicroserviceInstance call() throws Exception { - MicroserviceInstance instance = RegistryUtils.getServiceRegistryClient() - .findServiceInstance(serviceId, instanceId); - if (instance == null) { - throw new IllegalArgumentException("instance id not exists."); - } - return instance; - } - }); - } catch (ExecutionException | UncheckedExecutionException e) { - logger.error("get microservice instance from cache failed, {}, {}", String.format("%s@%s", serviceId, instanceId), - e.getMessage()); - return null; - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ClientException.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ClientException.java deleted file mode 100644 index 0529b41c4dc..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ClientException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -/** - * Created by on 2017/3/12. - */ -public class ClientException extends Exception { - - private static final long serialVersionUID = 4579811019552389524L; - - public ClientException(String message) { - super(message); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/Endpoints.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/Endpoints.java deleted file mode 100644 index 0decbd24d19..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/Endpoints.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * Created by on 2016/12/27. - */ -public class Endpoints { - private String appId; - - private String serviceName; - - private String version; - - private List instances; - - public String getServiceName() { - return serviceName; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public List getInstances() { - return instances; - } - - public void setInstances(List instances) { - this.instances = instances; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java deleted file mode 100644 index 1ff5be47db4..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import static org.apache.servicecomb.serviceregistry.api.Const.REGISTRY_APP_ID; -import static org.apache.servicecomb.serviceregistry.api.Const.REGISTRY_SERVICE_NAME; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class IpPortManager { - private static final Logger LOGGER = LoggerFactory.getLogger(IpPortManager.class); - - private ServiceRegistryConfig serviceRegistryConfig; - - private InstanceCacheManager instanceCacheManager; - - private String defaultTransport = "rest"; - - private ArrayList defaultIpPort; - - private AtomicInteger currentAvailableIndex; - - private boolean autoDiscoveryInited = false; - - private int maxRetryTimes; - - - public void setAutoDiscoveryInited(boolean autoDiscoveryInited) { - this.autoDiscoveryInited = autoDiscoveryInited; - } - - public int getMaxRetryTimes() { - return maxRetryTimes; - } - - public IpPortManager(ServiceRegistryConfig serviceRegistryConfig, InstanceCacheManager instanceCacheManager) { - this.serviceRegistryConfig = serviceRegistryConfig; - this.instanceCacheManager = instanceCacheManager; - - defaultTransport = serviceRegistryConfig.getTransport(); - defaultIpPort = serviceRegistryConfig.getIpPort(); - if (defaultIpPort.size() == 0) { - throw new IllegalArgumentException("Service center address is required to start the application."); - } - int initialIndex = new Random().nextInt(defaultIpPort.size()); - currentAvailableIndex = new AtomicInteger(initialIndex); - maxRetryTimes = defaultIpPort.size(); - } - - // we have to do this operation after the first time setup has already done - public void initAutoDiscovery() { - if (!autoDiscoveryInited && this.serviceRegistryConfig.isRegistryAutoDiscovery()) { - InstanceCache cache = instanceCacheManager.getOrCreate(REGISTRY_APP_ID, - REGISTRY_SERVICE_NAME, - DefinitionConst.VERSION_RULE_LATEST); - if (cache.getInstanceMap().size() > 0) { - setAutoDiscoveryInited(true); - } else { - setAutoDiscoveryInited(false); - } - } - } - - public IpPort getNextAvailableAddress(IpPort failedIpPort) { - int currentIndex = currentAvailableIndex.get(); - IpPort current = getAvailableAddress(currentIndex); - if (current.equals(failedIpPort)) { - currentAvailableIndex.compareAndSet(currentIndex, currentIndex + 1); - current = getAvailableAddress(); - } - - LOGGER.info("Change service center address from {} to {}", failedIpPort.toString(), current.toString()); - return current; - } - - public IpPort getAvailableAddress() { - return getAvailableAddress(currentAvailableIndex.get()); - } - - private IpPort getAvailableAddress(int index) { - if (index < defaultIpPort.size()) { - return defaultIpPort.get(index); - } - List endpoints = getDiscoveredIpPort(); - if (endpoints == null || (index >= defaultIpPort.size() + endpoints.size())) { - currentAvailableIndex.set(0); - return defaultIpPort.get(0); - } - maxRetryTimes = defaultIpPort.size() + endpoints.size(); - CacheEndpoint nextEndpoint = endpoints.get(index - defaultIpPort.size()); - return new URIEndpointObject(nextEndpoint.getEndpoint()); - } - - private List getDiscoveredIpPort() { - if (!autoDiscoveryInited || !this.serviceRegistryConfig.isRegistryAutoDiscovery()) { - return null; - } - InstanceCache instanceCache = instanceCacheManager.getOrCreate(REGISTRY_APP_ID, - REGISTRY_SERVICE_NAME, - DefinitionConst.VERSION_RULE_LATEST); - return instanceCache.getOrCreateTransportMap().get(defaultTransport); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java deleted file mode 100644 index 201ceb5f55c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_APPLICATION_ID; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterConfig; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.http.Holder; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.version.Version; -import org.apache.servicecomb.serviceregistry.version.VersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleUtils; -import org.apache.servicecomb.serviceregistry.version.VersionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; -import org.yaml.snakeyaml.Yaml; - -import com.google.common.base.Charsets; -import com.google.common.hash.Hashing; - -public class LocalServiceRegistryClientImpl implements ServiceRegistryClient { - private static final Logger LOGGER = LoggerFactory.getLogger(LocalServiceRegistryClientImpl.class); - - public static final String LOCAL_REGISTRY_FILE_KEY = "local.registry.file"; - - private final String LOCAL_REGISTRY_FILE = System.getProperty(LOCAL_REGISTRY_FILE_KEY); - - // key is microservice id - private Map microserviceIdMap = new ConcurrentHashMap<>(); - - // first key is microservice id - // second key is instance id - private Map> microserviceInstanceMap = new ConcurrentHashMap<>(); - - private AtomicInteger revision = new AtomicInteger(0); - - public LocalServiceRegistryClientImpl() { - if (StringUtils.isEmpty(LOCAL_REGISTRY_FILE)) { - LOGGER.info("create empty local registry."); - return; - } - - File file = new File(LOCAL_REGISTRY_FILE); - if (!file.exists()) { - return; - } - - try (InputStream is = new FileInputStream(file)) { - initFromData(is); - } catch (IOException e) { - LOGGER.error("can not load local registry file:" + LOCAL_REGISTRY_FILE, e); - } - } - - public LocalServiceRegistryClientImpl(InputStream is) { - initFromData(is); - } - - public LocalServiceRegistryClientImpl(Map data) { - initFromData(data); - } - - private void initFromData(InputStream is) { - Yaml yaml = new Yaml(); - @SuppressWarnings("unchecked") - Map data = yaml.loadAs(is, Map.class); - initFromData(data); - } - - private void initFromData(Map data) { - for (Entry entry : data.entrySet()) { - String name = entry.getKey(); - @SuppressWarnings("unchecked") - List> serviceConfigs = (List>) entry.getValue(); - for (Map serviceConfig : serviceConfigs) { - @SuppressWarnings("unchecked") - List> instancesConfig = - (List>) serviceConfig.get("instances"); - - String appId = (String) serviceConfig.get("appid"); - String version = (String) serviceConfig.get("version"); - String serviceId = (String) serviceConfig.get("id"); - @SuppressWarnings("unchecked") - List schemas = (List) serviceConfig.get("schemaIds"); - - Microservice microservice = new Microservice(); - microservice.setAppId(appId == null ? DEFAULT_APPLICATION_ID : appId); - microservice.setServiceName(name); - microservice.setVersion(version); - microservice.setServiceId(serviceId == null ? UUID.randomUUID().toString() : serviceId); - microserviceIdMap.put(microservice.getServiceId(), microservice); - if (schemas != null) { - microservice.setSchemas(schemas); - } - - Map instanceMap = new ConcurrentHashMap<>(); - for (Map instanceConfig : instancesConfig) { - @SuppressWarnings("unchecked") - List endpoints = (List) instanceConfig.get("endpoints"); - - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId(UUID.randomUUID().toString()); - instance.setEndpoints(endpoints); - instance.setServiceId(microservice.getServiceId()); - - instanceMap.put(instance.getInstanceId(), instance); - } - microserviceInstanceMap.put(microservice.getServiceId(), instanceMap); - } - } - - if (!data.isEmpty()) { - revision.incrementAndGet(); - } - } - - @Override - public void init() { - - } - - @Override - public List getAllMicroservices() { - return new ArrayList<>(microserviceIdMap.values()); - } - - @Override - public String getMicroserviceId(String appId, String microserviceName, String strVersionRule, String environment) { - VersionRule versionRule = VersionRuleUtils.getOrCreate(strVersionRule); - Microservice latest = findLatest(appId, microserviceName, versionRule); - return latest != null ? latest.getServiceId() : null; - } - - @Override - public String registerMicroservice(Microservice microservice) { - String serviceId = microservice.getServiceId(); - if (serviceId == null) { - serviceId = UUID.randomUUID().toString(); - microservice.setServiceId(serviceId); - } - microserviceIdMap.put(serviceId, microservice); - - microserviceInstanceMap.computeIfAbsent(serviceId, k -> new ConcurrentHashMap<>()); - revision.incrementAndGet(); - return serviceId; - } - - @Override - public Microservice getMicroservice(String microserviceId) { - return microserviceIdMap.get(microserviceId); - } - - @Override - public Microservice getAggregatedMicroservice(String microserviceId) { - return getMicroservice(microserviceId); - } - - @Override - public String registerMicroserviceInstance(MicroserviceInstance instance) { - Map instanceMap = microserviceInstanceMap.get(instance.getServiceId()); - if (instanceMap == null) { - throw new IllegalArgumentException("Invalid serviceId of instance, serviceId=" + instance.getServiceId()); - } - - String instanceId = - instance.getInstanceId() == null ? UUID.randomUUID().toString() : instance.getInstanceId(); - instanceMap.put(instanceId, instance); - revision.incrementAndGet(); - return instanceId; - } - - @Override - public List getMicroserviceInstance(String consumerId, String providerId) { - Map instanceMap = microserviceInstanceMap.get(providerId); - if (instanceMap == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + providerId); - } - - return new ArrayList<>(instanceMap.values()); - } - - @Override - public boolean unregisterMicroserviceInstance(String microserviceId, String microserviceInstanceId) { - if (microserviceId == null) { - return true; - } - Map instanceMap = microserviceInstanceMap.get(microserviceId); - if (instanceMap != null) { - instanceMap.remove(microserviceInstanceId); - revision.getAndIncrement(); - } - return true; - } - - @Override - public HeartbeatResponse heartbeat(String microserviceId, String microserviceInstanceId) { - HeartbeatResponse response = new HeartbeatResponse(); - response.setMessage("OK"); - response.setOk(true); - return response; - } - - @Override - public void watch(String selfMicroserviceId, AsyncResultCallback callback) { - watch(selfMicroserviceId, callback, v -> { - }, v -> { - }); - } - - @Override - public void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - - } - - protected boolean isSameMicroservice(Microservice microservice, String appId, String serviceName) { - return microservice.getAppId().equals(appId) && microservice.getServiceName().equals(serviceName); - } - - protected Microservice findLatest(String appId, String serviceName, VersionRule versionRule) { - Version latestVersion = null; - Microservice latest = null; - for (Entry entry : microserviceIdMap.entrySet()) { - Microservice microservice = entry.getValue(); - if (!isSameMicroservice(microservice, appId, serviceName)) { - continue; - } - - Version version = VersionUtils.getOrCreate(microservice.getVersion()); - if (!versionRule.isAccept(version)) { - continue; - } - - if (latestVersion == null || version.compareTo(latestVersion) > 0) { - latestVersion = version; - latest = microservice; - } - } - - return latest; - } - - @Override - public List findServiceInstance(String selfMicroserviceId, String appId, String serviceName, - String strVersionRule) { - MicroserviceInstances instances = - findServiceInstances(selfMicroserviceId, appId, serviceName, strVersionRule, null); - if(instances.isMicroserviceNotExist()) { - return null; - } - return instances.getInstancesResponse().getInstances(); - } - - @Override - public MicroserviceInstances findServiceInstances(String selfMicroserviceId, String appId, String serviceName, - String strVersionRule, String revision) { - int currentRevision = this.revision.get(); - List allInstances = new ArrayList<>(); - MicroserviceInstances microserviceInstances = new MicroserviceInstances(); - FindInstancesResponse response = new FindInstancesResponse(); - if (revision != null && currentRevision == Integer.parseInt(revision)) { - microserviceInstances.setNeedRefresh(false); - return microserviceInstances; - } - - microserviceInstances.setRevision(String.valueOf(currentRevision)); - VersionRule versionRule = VersionRuleUtils.getOrCreate(strVersionRule); - Microservice latestMicroservice = findLatest(appId, serviceName, versionRule); - if (latestMicroservice == null) { - microserviceInstances.setMicroserviceNotExist(true); - return microserviceInstances; - } - - Version latestVersion = VersionUtils.getOrCreate(latestMicroservice.getVersion()); - for (Entry entry : microserviceIdMap.entrySet()) { - Microservice microservice = entry.getValue(); - if (!isSameMicroservice(microservice, appId, serviceName)) { - continue; - } - - Version version = VersionUtils.getOrCreate(entry.getValue().getVersion()); - if (!versionRule.isMatch(version, latestVersion)) { - continue; - } - - Map instances = microserviceInstanceMap.get(entry.getValue().getServiceId()); - allInstances.addAll(instances.values()); - } - response.setInstances(allInstances); - microserviceInstances.setInstancesResponse(response); - - return microserviceInstances; - } - - @Override - public boolean isSchemaExist(String microserviceId, String schemaId) { - Microservice microservice = microserviceIdMap.get(microserviceId); - if (microservice == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - - return microservice.getSchemaMap().containsKey(schemaId); - } - - @Override - public boolean registerSchema(String microserviceId, String schemaId, String schemaContent) { - Microservice microservice = microserviceIdMap.get(microserviceId); - if (microservice == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - - microservice.getSchemaMap().put(schemaId, schemaContent); - return true; - } - - @Override - public String getSchema(String microserviceId, String schemaId) { - Microservice microservice = microserviceIdMap.get(microserviceId); - if (microservice == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - - return microservice.getSchemaMap().get(schemaId); - } - - @Override - public String getAggregatedSchema(String microserviceId, String schemaId) { - return getSchema(microserviceId, schemaId); - } - - @Override - public Holder> getSchemas(String microserviceId) { - Microservice microservice = microserviceIdMap.get(microserviceId); - if (microservice == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - List schemas = new ArrayList<>(); - microservice.getSchemaMap().forEach((key, val) -> { - GetSchemaResponse schema = new GetSchemaResponse(); - schema.setSchema(val); - schema.setSchemaId(key); - schema.setSummary(Hashing.sha256().newHasher().putString(val, Charsets.UTF_8).hash().toString()); - schemas.add(schema); - }); - Holder> resultHolder = new Holder<>(); - resultHolder.setStatusCode(Status.OK.getStatusCode()).setValue(schemas); - return resultHolder; - } - - @Override - public boolean updateMicroserviceProperties(String microserviceId, Map serviceProperties) { - Microservice microservice = microserviceIdMap.get(microserviceId); - if (microservice == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - - if (serviceProperties != null) { - microservice.getProperties().putAll(serviceProperties); - } - return true; - } - - @Override - public boolean updateInstanceProperties(String microserviceId, String microserviceInstanceId, - Map instanceProperties) { - Map instanceMap = microserviceInstanceMap.get(microserviceId); - if (instanceMap == null) { - throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); - } - - MicroserviceInstance microserviceInstance = instanceMap.get(microserviceInstanceId); - if (microserviceInstance == null) { - throw new IllegalArgumentException( - String.format("Invalid argument. microserviceId=%s, microserviceInstanceId=%s.", - microserviceId, - microserviceInstanceId)); - } - - if (instanceProperties != null) { - microserviceInstance.getProperties().putAll(instanceProperties); - } - return true; - } - - @Override - public MicroserviceInstance findServiceInstance(String serviceId, String instanceId) { - Map instances = microserviceInstanceMap.get(serviceId); - return instances.get(instanceId); - } - - @Override - public ServiceCenterInfo getServiceCenterInfo() { - ServiceCenterInfo info = new ServiceCenterInfo(); - info.setVersion("1.0.0"); - info.setBuildTag("20180312"); - info.setRunMode("dev"); - info.setApiVersion("4.0.0"); - info.setConfig(new ServiceCenterConfig()); - return info; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java deleted file mode 100644 index 90d145534ed..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.http.Holder; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; - -public interface ServiceRegistryClient { - void init(); - - /** - * get all microservices - */ - List getAllMicroservices(); - - /** - * - * 获取微服务唯一标识 - */ - String getMicroserviceId(String appId, String microserviceName, String versionRule, String environment); - - /** - * - * 注册微服务静态信息 - */ - String registerMicroservice(Microservice microservice); - - /** - * - * 根据微服务唯一标识查询微服务静态信息 - */ - Microservice getMicroservice(String microserviceId); - - /** - *

- * if connect to normal ServiceCenter, same with the method - * {@linkplain org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient#getMicroservice(String)} - * if connect to ServiceCenter Aggregator, not only contain the target ServiceCenter but also other ServiceCenter clusters - *

- */ - Microservice getAggregatedMicroservice(String microserviceId); - - /** - * 更新微服务properties - */ - boolean updateMicroserviceProperties(String microserviceId, Map serviceProperties); - - /** - * - * 判定schema是否已经注册 - */ - boolean isSchemaExist(String microserviceId, String schemaId); - - /** - * - * 注册schema - */ - boolean registerSchema(String microserviceId, String schemaId, String schemaContent); - - /** - * - * 获取schema内容 - */ - String getSchema(String microserviceId, String schemaId); - - /** - *

- * if connect to normal ServiceCenter, same with the method - * {@linkplain org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient#getSchema(String, String)} - * if connect to ServiceCenter Aggregator, not only contain the target ServiceCenter but also other ServiceCenter clusters - *

- */ - String getAggregatedSchema(String microserviceId, String schemaId); - - /** - * - * 批量获取schemas内容 - */ - Holder> getSchemas(String microserviceId); - - /** - * - * 注册微服务实例 - */ - String registerMicroserviceInstance(MicroserviceInstance instance); - - /** - * - * 根据多个微服务唯一标识查询所有微服务实例信息 - */ - List getMicroserviceInstance(String consumerId, String providerId); - - /** - * 更新微服务实例properties - */ - boolean updateInstanceProperties(String microserviceId, String microserviceInstanceId, - Map instanceProperties); - - /** - * - * 去注册微服务实例 - */ - boolean unregisterMicroserviceInstance(String microserviceId, String microserviceInstanceId); - - /** - * - * 服务端返回失败,表示需要重新注册,重新watch - */ - HeartbeatResponse heartbeat(String microserviceId, String microserviceInstanceId); - - /** - * - * watch实例变化 - */ - void watch(String selfMicroserviceId, AsyncResultCallback callback); - - /** - * - * watch实例变化 - */ - void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose); - - /** - * - * 按照app+interface+version查询实例endpoints信息 - */ - List findServiceInstance(String consumerId, String appId, String serviceName, - String versionRule); - - /** - * - * 按照app+interface+version+revision查询实例endpoints信息 - */ - MicroserviceInstances findServiceInstances(String consumerId, String appId, String serviceName, - String versionRule, String revision); - - /** - * 通过serviceId, instanceId 获取instance对象。 - * @param serviceId - * @param instanceId - * @return MicroserviceInstance - */ - MicroserviceInstance findServiceInstance(String serviceId, String instanceId); - - /** - * get ServiceCenterVersionInfo - */ - ServiceCenterInfo getServiceCenterInfo(); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java deleted file mode 100644 index a631b962796..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.vertx.AddressResolverConfig; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientPoolFactory; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.core.http.HttpClientOptions; - -/** - * Created by on 2017/4/28. - */ -public abstract class AbstractClientPool implements ClientPool { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientPool.class); - - protected static final String SSL_KEY = "sc.consumer"; - - public static final String PROXY_KEY = "sc.consumer"; - - private ClientPoolManager clientMgr; - - public AbstractClientPool() { - create(); - } - - public HttpClientWithContext getClient() { - return this.clientMgr.findThreadBindClientPool(); - } - - public void create() { - // 这里面是同步接口,且好像直接在事件线程中用,保险起见,先使用独立的vertx实例 - VertxOptions vertxOptions = new VertxOptions(); - vertxOptions.setAddressResolverOptions(AddressResolverConfig.getAddressResover(SSL_KEY)); - Vertx vertx = VertxUtils.getOrCreateVertxByName("registry", vertxOptions); - HttpClientOptions httpClientOptions = createHttpClientOptions(); - clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions)); - - DeploymentOptions deployOptions = - VertxUtils.createClientDeployOptions(this.clientMgr, - ServiceRegistryConfig.INSTANCE.getWorkerPoolSize()); - try { - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); - } catch (InterruptedException e) { - LOGGER.error("deploy a registry verticle failed, {}", e.getMessage()); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java deleted file mode 100644 index e5db5597bef..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; - -import io.vertx.core.http.HttpClientOptions; - -/** - * Created by on 2017/4/28. - */ -public interface ClientPool { - void create(); - - HttpClientOptions createHttpClientOptions(); - - HttpClientWithContext getClient(); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/EmptyAuthHeaderProvider.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/EmptyAuthHeaderProvider.java deleted file mode 100644 index 37828b4ad15..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/EmptyAuthHeaderProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; - -public class EmptyAuthHeaderProvider implements AuthHeaderProvider { - @Override - public Map authHeaders() { - return new HashMap<>(0); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/Holder.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/Holder.java deleted file mode 100644 index e63911a9336..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/Holder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -/** - * To carry the rest response information. - * @param Type of response body - */ -public class Holder { - T value; - - int statusCode; - - Throwable throwable; - - public T getValue() { - return value; - } - - public Holder setValue(T value) { - this.value = value; - return this; - } - - public int getStatusCode() { - return statusCode; - } - - public Holder setStatusCode(int statusCode) { - this.statusCode = statusCode; - return this; - } - - public Throwable getThrowable() { - return throwable; - } - - public Holder setThrowable(Throwable throwable) { - this.throwable = throwable; - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("Holder{"); - sb.append("value=").append(value); - sb.append(", statusCode=").append(statusCode); - sb.append(", throwable=").append(throwable); - sb.append('}'); - return sb.toString(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java deleted file mode 100644 index efbee4c3ea8..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.common.encrypt.Encryptions; -import org.apache.servicecomb.foundation.vertx.VertxTLSBuilder; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpVersion; -import io.vertx.core.net.ProxyOptions; - -/** - * Created by on 2017/4/28. - */ -public final class HttpClientPool extends AbstractClientPool { - - private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPool.class); - - public static final HttpClientPool INSTANCE = new HttpClientPool(); - - private HttpClientPool() { - } - - @Override - public HttpClientOptions createHttpClientOptions() { - HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion(); - HttpClientOptions httpClientOptions = new HttpClientOptions(); - httpClientOptions.setProtocolVersion(ver); - httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout()); - httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleConnectionTimeout()); - if (ServiceRegistryConfig.INSTANCE.isProxyEnable()) { - ProxyOptions proxy = new ProxyOptions(); - proxy.setHost(ServiceRegistryConfig.INSTANCE.getProxyHost()); - proxy.setPort(ServiceRegistryConfig.INSTANCE.getProxyPort()); - proxy.setUsername(ServiceRegistryConfig.INSTANCE.getProxyUsername()); - proxy.setPassword(Encryptions.decode(ServiceRegistryConfig.INSTANCE.getProxyPasswd(), PROXY_KEY)); - httpClientOptions.setProxyOptions(proxy); - } - if (ver == HttpVersion.HTTP_2) { - LOGGER.debug("service center client protocol version is HTTP/2"); - httpClientOptions.setHttp2ClearTextUpgrade(false); - } - if (ServiceRegistryConfig.INSTANCE.isSsl()) { - LOGGER.debug("service center client performs requests over TLS"); - VertxTLSBuilder.buildHttpClientOptions(SSL_KEY, httpClientOptions); - } - return httpClientOptions; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/MicroserviceInstances.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/MicroserviceInstances.java deleted file mode 100644 index 8a51e501e31..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/MicroserviceInstances.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; - -/** - * Created by on 2017/12/28. - */ -public class MicroserviceInstances { - private boolean microserviceNotExist; - - private boolean needRefresh = true; - - private String revision; - - private FindInstancesResponse instancesResponse; - - public boolean isMicroserviceNotExist() { - return microserviceNotExist; - } - - public void setMicroserviceNotExist(boolean microserviceNotExist) { - this.microserviceNotExist = microserviceNotExist; - } - - public boolean isNeedRefresh() { - return needRefresh; - } - - public void setNeedRefresh(boolean needRefresh) { - this.needRefresh = needRefresh; - } - - public String getRevision() { - return revision; - } - - public void setRevision(String revision) { - this.revision = revision; - } - - public FindInstancesResponse getInstancesResponse() { - return instancesResponse; - } - - public void setInstancesResponse(FindInstancesResponse instancesResponse) { - this.instancesResponse = instancesResponse; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestContext.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestContext.java deleted file mode 100644 index 91c858da631..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestContext.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.common.net.IpPort; - -import io.vertx.core.http.HttpMethod; - -/** - * Created by on 2017/1/9. - */ -public class RequestContext { - private IpPort ipPort; - - private String uri; - - private HttpMethod method; - - private RequestParam params; - - private int retryTimes = 0; - - public IpPort getIpPort() { - return ipPort; - } - - public void setIpPort(IpPort ipPort) { - this.ipPort = ipPort; - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public HttpMethod getMethod() { - return method; - } - - public void setMethod(HttpMethod method) { - this.method = method; - } - - public RequestParam getParams() { - return params; - } - - public void setParams(RequestParam params) { - this.params = params; - } - - - public int getRetryTimes() { - return retryTimes; - } - - public void incrementRetryTimes() { - ++this.retryTimes; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestParam.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestParam.java deleted file mode 100644 index 2a6568c65f3..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RequestParam.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Created by on 2016/12/25. - */ -public class RequestParam { - private static final Logger LOGGER = LoggerFactory.getLogger(RequestParam.class); - - private Map queryParams; - - private Map formFields; - - private byte[] body = null; - - private Map headers; - - private Map cookies; - - private long timeout; - - public Map getCookies() { - return cookies; - } - - public RequestParam setCookies(Map cookies) { - this.cookies = cookies; - return this; - } - - public Map getHeaders() { - return headers; - } - - public RequestParam setHeaders(Map headers) { - this.headers = headers; - return this; - } - - public byte[] getBody() { - return body; - } - - public RequestParam setBody(byte[] body) { - this.body = body; - return this; - } - - public Map getFormFields() { - return formFields; - } - - public RequestParam setFormFields(Map formFields) { - this.formFields = formFields; - return this; - } - - public Map getQueryParamsMap() { - return queryParams; - } - - public String getQueryParams() { - if (queryParams == null || queryParams.size() == 0) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - try { - for (Map.Entry query : queryParams.entrySet()) { - for (String val : query.getValue()) { - stringBuilder.append("&") - .append(URLEncoder.encode(query.getKey(), "UTF-8")); - - if (val != null && !val.isEmpty()) { - stringBuilder.append("=") - .append(URLEncoder.encode(val, "UTF-8")); - } - } - } - } catch (UnsupportedEncodingException e) { - LOGGER.error("get query params failed.", e); - return ""; - } - return stringBuilder.substring(1); - } - - public RequestParam setQueryParams(Map queryParams) { - this.queryParams = queryParams; - return this; - } - - public RequestParam addQueryParam(String key, String value) { - if (queryParams == null) { - queryParams = new HashMap<>(); - } - if (!queryParams.containsKey(key)) { - queryParams.put(key, new String[] {value}); - } else { - queryParams.put(key, (String[]) Arrays.asList(queryParams.get(key), value).toArray()); - } - return this; - } - - public RequestParam addHeader(String key, String value) { - if (headers == null) { - headers = new HashMap<>(); - } - headers.put(key, value); - return this; - } - - public long getTimeout() { - return timeout; - } - - public RequestParam setTimeout(long timeout) { - this.timeout = timeout; - return this; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestResponse.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestResponse.java deleted file mode 100644 index e1db3e2d56c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import io.vertx.core.http.HttpClientResponse; - -/** - * Created by on 2017/1/9. - */ -public class RestResponse { - - private RequestContext requestContext; - - private HttpClientResponse response; - - public RestResponse(RequestContext requestContext, HttpClientResponse response) { - this.requestContext = requestContext; - this.response = response; - } - - public RequestContext getRequestContext() { - return requestContext; - } - - public void setRequestContext(RequestContext requestContext) { - this.requestContext = requestContext; - } - - public HttpClientResponse getResponse() { - return response; - } - - public void setResponse(HttpClientResponse response) { - this.response = response; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java deleted file mode 100644 index f9db0c3887d..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.io.ByteArrayInputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; - -import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; -import org.apache.servicecomb.foundation.auth.SignRequest; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.CaseInsensitiveHeaders; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpMethod; - -final class RestUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(RestUtils.class); - - private static final String HEADER_CONTENT_TYPE = "Content-Type"; - - private static final String HEADER_USER_AGENT = "User-Agent"; - - private static final String HEADER_TENANT_NAME = "x-domain-name"; - - private static final ServiceLoader authHeaderProviders = - ServiceLoader.load(AuthHeaderProvider.class); - - private RestUtils() { - } - - public static void httpDo(RequestContext requestContext, Handler responseHandler) { - if (requestContext.getParams().getTimeout() != 0) { - httpDo(requestContext.getParams().getTimeout(), requestContext, responseHandler); - return; - } - httpDo(ServiceRegistryConfig.INSTANCE.getRequestTimeout(), requestContext, responseHandler); - } - - public static void httpDo(long timeout, RequestContext requestContext, Handler responseHandler) { - HttpClientWithContext vertxHttpClient = HttpClientPool.INSTANCE.getClient(); - vertxHttpClient.runOnContext(httpClient -> { - IpPort ipPort = requestContext.getIpPort(); - HttpMethod httpMethod = requestContext.getMethod(); - RequestParam requestParam = requestContext.getParams(); - - if (ipPort == null) { - LOGGER.error("request address is null"); - responseHandler.handle(new RestResponse(requestContext, null)); - return; - } - - // query params - StringBuilder url = new StringBuilder(requestContext.getUri()); - String queryParams = requestParam.getQueryParams(); - if (!queryParams.isEmpty()) { - url.append(url.lastIndexOf("?") > 0 ? "&" : "?") - .append(queryParams); - } - - HttpClientRequest httpClientRequest = httpClient - .request(httpMethod, ipPort.getPort(), ipPort.getHostOrIp(), url.toString(), response -> { - responseHandler.handle(new RestResponse(requestContext, response)); - }); - - httpClientRequest.setTimeout(timeout) - .exceptionHandler(e -> { - LOGGER.error("{} {} fail, endpoint is {}:{}, message: {}", - httpMethod, - url.toString(), - ipPort.getHostOrIp(), - ipPort.getPort(), - e.getMessage()); - responseHandler.handle(new RestResponse(requestContext, null)); - }); - - //headers - Map headers = defaultHeaders(); - httpClientRequest.headers().addAll(headers); - - if (requestParam.getHeaders() != null && requestParam.getHeaders().size() > 0) { - headers.putAll(requestParam.getHeaders()); - for (Map.Entry header : requestParam.getHeaders().entrySet()) { - httpClientRequest.putHeader(header.getKey(), header.getValue()); - } - } - - // cookies header - if (requestParam.getCookies() != null && requestParam.getCookies().size() > 0) { - StringBuilder stringBuilder = new StringBuilder(); - for (Map.Entry cookie : requestParam.getCookies().entrySet()) { - stringBuilder.append(cookie.getKey()) - .append("=") - .append(cookie.getValue()) - .append("; "); - } - httpClientRequest.putHeader("Cookie", stringBuilder.toString()); - headers.put("Cookie", stringBuilder.toString()); - } - - //SignAuth - SignRequest signReq = createSignRequest(requestContext.getMethod().toString(), - requestContext.getIpPort(), - requestContext.getParams(), - url.toString(), - headers); - httpClientRequest.headers().addAll(getSignAuthHeaders(signReq)); - - // body - if (httpMethod != HttpMethod.GET && requestParam.getBody() != null && requestParam.getBody().length > 0) { - httpClientRequest.end(Buffer.buffer(requestParam.getBody())); - } else { - httpClientRequest.end(); - } - }); - } - - public static RequestContext createRequestContext(HttpMethod method, IpPort ipPort, String uri, - RequestParam requestParam) { - RequestContext requestContext = new RequestContext(); - requestContext.setMethod(method); - requestContext.setIpPort(ipPort); - requestContext.setUri(uri); - requestContext.setParams(requestParam); - return requestContext; - } - - public static SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url, - Map headers) { - SignRequest signReq = new SignRequest(); - StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp()); - endpoint.append(":" + ipPort.getPort()); - endpoint.append(url); - try { - signReq.setEndpoint(new URI(endpoint.toString())); - } catch (URISyntaxException e) { - LOGGER.error("set uri failed, uri is {}, message: {}", endpoint.toString(), e.getMessage()); - } - signReq.setContent((requestParam.getBody() != null && requestParam.getBody().length > 0) - ? new ByteArrayInputStream(requestParam.getBody()) - : null); - signReq.setHeaders(headers); - signReq.setHttpMethod(method); - signReq.setQueryParams(requestParam.getQueryParamsMap()); - return signReq; - } - - public static void addDefaultHeaders(HttpClientRequest request) { - request.headers().addAll(getDefaultHeaders()); - } - - private static Map defaultHeaders() { - Map headers = new HashMap<>(); - headers.put(HEADER_CONTENT_TYPE, "application/json"); - headers.put(HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0"); - headers.put(HEADER_TENANT_NAME, ServiceRegistryConfig.INSTANCE.getTenantName()); - - return headers; - } - - public static MultiMap getDefaultHeaders() { - return new CaseInsensitiveHeaders().addAll(defaultHeaders()); - } - - public static void get(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - httpDo(createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler); - } - - public static void post(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - httpDo(createRequestContext(HttpMethod.POST, ipPort, uri, requestParam), responseHandler); - } - - public static void put(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - httpDo(createRequestContext(HttpMethod.PUT, ipPort, uri, requestParam), responseHandler); - } - - public static void delete(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - httpDo(createRequestContext(HttpMethod.DELETE, ipPort, uri, requestParam), responseHandler); - } - - public static Map getSignAuthHeaders(SignRequest signReq) { - Map headers = new HashMap<>(); - authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq))); - return headers; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java deleted file mode 100644 index 3ee0fe8183f..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java +++ /dev/null @@ -1,876 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import static java.util.Collections.emptyList; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.apache.servicecomb.serviceregistry.api.request.CreateSchemaRequest; -import org.apache.servicecomb.serviceregistry.api.request.CreateServiceRequest; -import org.apache.servicecomb.serviceregistry.api.request.RegisterInstanceRequest; -import org.apache.servicecomb.serviceregistry.api.request.UpdatePropertiesRequest; -import org.apache.servicecomb.serviceregistry.api.response.CreateServiceResponse; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetAllServicesResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetExistenceResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetInstancesResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemasResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetServiceResponse; -import org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceResponse; -import org.apache.servicecomb.serviceregistry.api.response.RegisterInstanceResponse; -import org.apache.servicecomb.serviceregistry.client.ClientException; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - -import io.netty.handler.codec.http.HttpStatusClass; -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClientResponse; - -public final class ServiceRegistryClientImpl implements ServiceRegistryClient { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryClientImpl.class); - - private IpPortManager ipPortManager; - - // key是本进程的微服务id和服务管理中心的id - // extract this, ServiceRegistryClient is better to be no status. - private Map watchServices = new ConcurrentHashMap<>(); - - public ServiceRegistryClientImpl(IpPortManager ipPortManager) { - this.ipPortManager = ipPortManager; - } - - private LoadingCache> schemaCache = CacheBuilder.newBuilder() - .expireAfterAccess(60, TimeUnit.SECONDS).build(new CacheLoader>() { - public Map load(String key) { - Holder> result = getSchemas(key, true, true); - Map schemas = new HashMap<>(); - if (result.getStatusCode() == Status.OK.getStatusCode() ) { - result.value.stream().forEach(r -> schemas.put(r.getSchemaId(), r.getSchema())); - } - return schemas; - } - }); - - @Override - public void init() { - } - - private void retry(RequestContext requestContext, Handler responseHandler) { - LOGGER.warn("invoke service [{}] failed, retry.", requestContext.getUri()); - requestContext.setIpPort(ipPortManager.getNextAvailableAddress(requestContext.getIpPort())); - requestContext.incrementRetryTimes(); - RestUtils.httpDo(requestContext, responseHandler); - } - - @VisibleForTesting - @SuppressWarnings("unchecked") - protected Handler syncHandler(CountDownLatch countDownLatch, Class cls, - Holder holder) { - return restResponse -> { - RequestContext requestContext = restResponse.getRequestContext(); - HttpClientResponse response = restResponse.getResponse(); - if (response == null) { - // 请求失败,触发请求SC的其他实例 - if (requestContext.getRetryTimes() <= ipPortManager.getMaxRetryTimes()) { - retry(requestContext, syncHandler(countDownLatch, cls, holder)); - } else { - countDownLatch.countDown(); - } - return; - } - holder.setStatusCode(response.statusCode()); - response.bodyHandler( - bodyBuffer -> { - if (cls.getName().equals(HttpClientResponse.class.getName())) { - holder.value = (T) response; - countDownLatch.countDown(); - return; - } - if (cls.equals(String.class)) { - holder.setValue((T) bodyBuffer.toString()); - countDownLatch.countDown(); - return; - } - - // no need to support 304 in this place - if (!HttpStatusClass.SUCCESS.equals(HttpStatusClass.valueOf(response.statusCode()))) { - LOGGER.warn("get response for {} failed, {}:{}, {}", - cls.getName(), - response.statusCode(), - response.statusMessage(), - bodyBuffer.toString()); - countDownLatch.countDown(); - return; - } - - try { - holder.value = - JsonUtils.readValue(bodyBuffer.getBytes(), cls); - } catch (Exception e) { - holder.setStatusCode(0).setThrowable(e); - LOGGER.warn("read value failed and response message is {}", - bodyBuffer.toString()); - } - countDownLatch.countDown(); - }); - }; - } - - static class ResponseWrapper { - HttpClientResponse response; - - Buffer bodyBuffer; - } - - // temporary copy from syncHandler - // we will use swagger invocation to replace RestUtils later. - private Handler syncHandlerEx(CountDownLatch countDownLatch, Holder holder) { - return restResponse -> { - RequestContext requestContext = restResponse.getRequestContext(); - HttpClientResponse response = restResponse.getResponse(); - if (response == null) { - // 请求失败,触发请求SC的其他实例 - if (requestContext.getRetryTimes() <= ipPortManager.getMaxRetryTimes()) { - retry(requestContext, syncHandlerEx(countDownLatch, holder)); - } else { - countDownLatch.countDown(); - } - - return; - } - - response.bodyHandler(bodyBuffer -> { - ResponseWrapper responseWrapper = new ResponseWrapper(); - responseWrapper.response = response; - responseWrapper.bodyBuffer = bodyBuffer; - holder.value = responseWrapper; - countDownLatch.countDown(); - }); - }; - } - - private Handler syncHandlerForInstances(CountDownLatch countDownLatch, - MicroserviceInstances mInstances) { - return restResponse -> { - RequestContext requestContext = restResponse.getRequestContext(); - HttpClientResponse response = restResponse.getResponse(); - if (response == null) { - // 请求失败,触发请求SC的其他实例 - if (requestContext.getRetryTimes() <= ipPortManager.getMaxRetryTimes()) { - retry(requestContext, syncHandlerForInstances(countDownLatch, mInstances)); - } else { - countDownLatch.countDown(); - } - return; - } - response.bodyHandler( - bodyBuffer -> { - try { - mInstances.setRevision(response.getHeader("X-Resource-Revision")); - switch (response.statusCode()) { - case 304: - mInstances.setNeedRefresh(false); - break; - case 200: - mInstances - .setInstancesResponse(JsonUtils.readValue(bodyBuffer.getBytes(), FindInstancesResponse.class)); - break; - case 400: { - @SuppressWarnings("unchecked") - Map error = JsonUtils.readValue(bodyBuffer.getBytes(), Map.class); - if ("400012".equals(error.get("errorCode"))) { - mInstances.setMicroserviceNotExist(true); - mInstances.setNeedRefresh(false); - } - LOGGER.warn("failed to findInstances: " + bodyBuffer.toString()); - } - break; - default: - LOGGER.warn("failed to findInstances: " + bodyBuffer.toString()); - break; - } - } catch (Exception e) { - LOGGER.warn("read value failed and response message is {}", bodyBuffer.toString()); - } - countDownLatch.countDown(); - }); - }; - } - - @Override - public List getAllMicroservices() { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL, - new RequestParam(), - syncHandler(countDownLatch, GetAllServicesResponse.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getServices(); - } - } catch (Exception e) { - LOGGER.error("query all microservices failed", e); - } - return emptyList(); - } - - @Override - public String getMicroserviceId(String appId, String microserviceName, String versionRule, String environment) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - Const.REGISTRY_API.MICROSERVICE_EXISTENCE, - new RequestParam().addQueryParam("type", "microservice") - .addQueryParam("appId", appId) - .addQueryParam("serviceName", microserviceName) - .addQueryParam("version", versionRule) - .addQueryParam("env", environment), - syncHandler(countDownLatch, GetExistenceResponse.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getServiceId(); - } - } catch (Exception e) { - LOGGER.error("query microservice id {}/{}/{} fail", - appId, - microserviceName, - versionRule, - e); - } - return null; - } - - @Override - public boolean isSchemaExist(String microserviceId, String schemaId) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - Const.REGISTRY_API.MICROSERVICE_EXISTENCE, - new RequestParam().addQueryParam("type", "schema") - .addQueryParam("serviceId", microserviceId) - .addQueryParam("schemaId", schemaId), - syncHandler(countDownLatch, GetExistenceResponse.class, holder)); - try { - countDownLatch.await(); - } catch (Exception e) { - LOGGER.error("query schema exist {}/{} fail", - microserviceId, - schemaId, - e); - } - return holder.value != null && schemaId.equals(holder.value.getSchemaId()); - } - - @Override - public boolean registerSchema(String microserviceId, String schemaId, String schemaContent) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - try { - CreateSchemaRequest request = new CreateSchemaRequest(); - request.setSchema(schemaContent); - request.setSummary(RegistryUtils.calcSchemaSummary(schemaContent)); - byte[] body = JsonUtils.writeValueAsBytes(request); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId), - new RequestParam().setBody(body), - syncHandlerEx(countDownLatch, holder)); - countDownLatch.await(); - - if (holder.value == null) { - LOGGER.error("Register schema {}/{} failed.", microserviceId, schemaId); - return false; - } - - if (!Status.Family.SUCCESSFUL.equals(Status.Family.familyOf(holder.value.response.statusCode()))) { - LOGGER.error("Register schema {}/{} failed, statusCode: {}, statusMessage: {}, description: {}.", - microserviceId, - schemaId, - holder.value.response.statusCode(), - holder.value.response.statusMessage(), - holder.value.bodyBuffer.toString()); - return false; - } - - LOGGER.info("register schema {}/{} success.", - microserviceId, - schemaId); - return true; - } catch (Exception e) { - LOGGER.error("register schema {}/{} fail.", - microserviceId, - schemaId, - e); - } - return false; - } - - @Override - public String getSchema(String microserviceId, String schemaId) { - return doGetSchema(microserviceId, schemaId, false); - } - - private String doGetSchema(String microserviceId, String schemaId, boolean global) { - try { - // avoid query too many times of schema when first time loading - String cachedSchema = schemaCache.get(microserviceId).get(schemaId); - if (cachedSchema != null) { - return cachedSchema; - } - } catch (ExecutionException e) { - // ignore this error. - } - - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RequestParam param = new RequestParam(); - if (global) { - param.addQueryParam("global", "true"); - } - RestUtils.get(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId), - param, - syncHandler(countDownLatch, GetSchemaResponse.class, holder)); - try { - countDownLatch.await(); - } catch (Exception e) { - LOGGER.error("query schema exist {}/{} failed", - schemaId, - e); - } - if (holder.value != null) { - return holder.value.getSchema(); - } - - return null; - } - - @Override - public String getAggregatedSchema(String microserviceId, String schemaId) { - return doGetSchema(microserviceId, schemaId, true); - } - - @Override - public Holder> getSchemas(String microserviceId) { - return getSchemas(microserviceId, false, false); - } - - private Holder> getSchemas(String microserviceId, boolean withSchema, boolean global) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - Holder> resultHolder = new Holder<>(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - String url = Const.REGISTRY_API.MICROSERVICE_ALL_SCHEMAs; - RequestParam requestParam = new RequestParam(); - if (withSchema) { - url = Const.REGISTRY_API.MICROSERVICE_ALL_SCHEMAs + "?withSchema=1"; - } - if (global) { - requestParam.addQueryParam("global", "true"); - } - - RestUtils.get(ipPort, - String.format(url, microserviceId), - requestParam, - syncHandler(countDownLatch, GetSchemasResponse.class, holder)); - try { - countDownLatch.await(); - } catch (Exception e) { - LOGGER.error("query all schemas {} failed", - microserviceId, - e); - } - resultHolder.setStatusCode(holder.getStatusCode()).setThrowable(holder.getThrowable()); - if (holder.value != null) { - return resultHolder.setValue( - holder.value.getSchema() != null ? - holder.value.getSchema() : - holder.value.getSchemas()); - } - - return resultHolder; - } - - @Override - public String registerMicroservice(Microservice microservice) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - try { - CreateServiceRequest request = new CreateServiceRequest(); - request.setService(microservice); - byte[] body = JsonUtils.writeValueAsBytes(request); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("register microservice: {}", new String(body, Charset.defaultCharset())); - } - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.post(ipPort, - Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL, - new RequestParam().setBody(body), - syncHandler(countDownLatch, CreateServiceResponse.class, holder)); - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getServiceId(); - } - } catch (Exception e) { - LOGGER.error("register microservice {}/{}/{} failed", - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - e); - } - return null; - } - - @Override - public Microservice getMicroservice(String microserviceId) { - return doGetMicroservice(microserviceId, false); - } - - private Microservice doGetMicroservice(String microserviceId, boolean global) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RequestParam param = new RequestParam(); - if (global) { - param.addQueryParam("global", "true"); - } - RestUtils.get(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_OPERATION_ONE, microserviceId), - param, - syncHandler(countDownLatch, GetServiceResponse.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getService(); - } - } catch (Exception e) { - LOGGER.error("query microservice {} failed", microserviceId, e); - } - return null; - } - - @Override - public Microservice getAggregatedMicroservice(String microserviceId) { - return doGetMicroservice(microserviceId, true); - } - - @Override - public String registerMicroserviceInstance(MicroserviceInstance instance) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - try { - RegisterInstanceRequest request = new RegisterInstanceRequest(); - request.setInstance(instance); - byte[] body = JsonUtils.writeValueAsBytes(request); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("register microservice: {}", new String(body, Charset.defaultCharset())); - } - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.post(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, instance.getServiceId()), - new RequestParam().setBody(body), - syncHandler(countDownLatch, RegisterInstanceResponse.class, holder)); - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getInstanceId(); - } - } catch (Exception e) { - LOGGER.error("register microservice instance {} failed", instance.getServiceId(), e); - } - return null; - } - - @Override - public List getMicroserviceInstance(String consumerId, String providerId) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, providerId), - new RequestParam().addHeader("X-ConsumerId", consumerId), - syncHandler(countDownLatch, GetInstancesResponse.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - return holder.value.getInstances(); - } - } catch (Exception e) { - LOGGER.error("query microservice instances {} failed", providerId, e); - } - return null; - } - - @Override - public boolean unregisterMicroserviceInstance(String microserviceId, String microserviceInstanceId) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.delete(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, microserviceId, microserviceInstanceId), - new RequestParam(), - syncHandler(countDownLatch, HttpClientResponse.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - if (holder.value.statusCode() == Status.OK.getStatusCode()) { - return true; - } - LOGGER.warn(holder.value.statusMessage()); - } - } catch (Exception e) { - LOGGER.error("unregister microservice instance {}/{} failed", - microserviceId, - microserviceInstanceId, - e); - } - return false; - } - - @Override - public HeartbeatResponse heartbeat(String microserviceId, String microserviceInstanceId) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_HEARTBEAT, microserviceId, microserviceInstanceId), - new RequestParam().setTimeout(ServiceRegistryConfig.INSTANCE.getHeartBeatRequestTimeout()), - syncHandler(countDownLatch, HttpClientResponse.class, holder)); - - try { - countDownLatch.await(); - if (holder.value != null) { - HeartbeatResponse response = new HeartbeatResponse(); - response.setMessage(holder.value.statusMessage()); - if (holder.value.statusCode() == Status.OK.getStatusCode()) { - response.setOk(true); - return response; - } - LOGGER.warn(holder.value.statusMessage()); - return response; - } - } catch (Exception e) { - LOGGER.error("update microservice instance {}/{} heartbeat failed", - microserviceId, - microserviceInstanceId, - e); - } - return null; - } - - public void watch(String selfMicroserviceId, AsyncResultCallback callback) { - watch(selfMicroserviceId, callback, v -> { - }, v -> { - }); - } - - public void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - Boolean alreadyWatch = watchServices.get(selfMicroserviceId); - if (alreadyWatch == null) { - synchronized (ServiceRegistryClientImpl.class) { - alreadyWatch = watchServices.get(selfMicroserviceId); - if (alreadyWatch == null) { - watchServices.put(selfMicroserviceId, true); - - String url = String.format(Const.REGISTRY_API.MICROSERVICE_WATCH, selfMicroserviceId); - - IpPort ipPort = ipPortManager.getAvailableAddress(); - WebsocketUtils.open(ipPort, url, o -> { - onOpen.success(o); - LOGGER.info( - "watching microservice {} successfully, " - + "the chosen service center address is {}:{}", - selfMicroserviceId, - ipPort.getHostOrIp(), - ipPort.getPort()); - }, c -> { - watchErrorHandler(new ClientException("connection is closed accidentally"), - selfMicroserviceId, - callback); - onClose.success(null); - }, bodyBuffer -> { - MicroserviceInstanceChangedEvent response = null; - try { - response = JsonUtils.readValue(bodyBuffer.getBytes(), - MicroserviceInstanceChangedEvent.class); - } catch (Exception e) { - LOGGER.error("watcher handle microservice {} response failed, {}", - selfMicroserviceId, - bodyBuffer.toString()); - return; - } - try { - callback.success(response); - } catch (Exception e) { - LOGGER.error("notify watcher failed, microservice {}", - selfMicroserviceId, - e); - } - }, e -> { - watchErrorHandler(e, selfMicroserviceId, callback); - onClose.success(null); - }, f -> { - watchErrorHandler(f, selfMicroserviceId, callback); - }); - } - } - } - } - - @Override - public List findServiceInstance(String consumerId, String appId, String serviceName, - String versionRule) { - MicroserviceInstances instances = findServiceInstances(consumerId, appId, serviceName, versionRule, null); - if (instances == null) { - return null; - } - return instances.getInstancesResponse().getInstances(); - } - - @Override - public MicroserviceInstances findServiceInstances(String consumerId, String appId, String serviceName, - String versionRule, String revision) { - // must register self first, and then invoke findServiceInstances - if (consumerId == null) { - LOGGER.error("find microservice instance {}/{}/{} failed, not registered to serviceCenter.", - appId, - serviceName, - versionRule); - return null; - } - - MicroserviceInstances microserviceInstances = new MicroserviceInstances(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - - RequestParam requestParam = new RequestParam().addQueryParam("appId", appId) - .addQueryParam("serviceName", serviceName) - .addQueryParam("global", "true") - .addQueryParam("version", versionRule) - .addHeader("X-ConsumerId", consumerId); - if (revision != null) { - requestParam.addQueryParam("rev", revision); - } - - RestUtils.get(ipPort, - Const.REGISTRY_API.MICROSERVICE_INSTANCES, - requestParam, - syncHandlerForInstances(countDownLatch, microserviceInstances)); - try { - countDownLatch.await(); - if (!microserviceInstances.isNeedRefresh()) { - return microserviceInstances; - } - if (microserviceInstances.getInstancesResponse() == null) { - return null; // error - } - List list = microserviceInstances.getInstancesResponse().getInstances(); - if (list == null) { - microserviceInstances.getInstancesResponse().setInstances(new ArrayList<>()); - } - return microserviceInstances; - } catch (Exception e) { - LOGGER.error("find microservice instance {}/{}/{} failed", - appId, - serviceName, - versionRule, - e); - } - return null; - } - - private void watchErrorHandler(Throwable e, String selfMicroserviceId, - AsyncResultCallback callback) { - LOGGER.error( - "watcher connect to service center server failed, microservice {}, {}", - selfMicroserviceId, - e.getMessage()); - callback.fail(e); - watchServices.remove(selfMicroserviceId); - } - - @Override - public boolean updateMicroserviceProperties(String microserviceId, Map serviceProperties) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - try { - UpdatePropertiesRequest request = new UpdatePropertiesRequest(); - request.setProperties(serviceProperties); - byte[] body = JsonUtils.writeValueAsBytes(request); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("update properties of microservice: {}", new String(body, Charset.defaultCharset())); - } - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_PROPERTIES, microserviceId), - new RequestParam().setBody(body), - syncHandler(countDownLatch, HttpClientResponse.class, holder)); - - countDownLatch.await(); - if (holder.value != null) { - if (holder.value.statusCode() == Status.OK.getStatusCode()) { - return true; - } - LOGGER.warn(holder.value.statusMessage()); - } - } catch (Exception e) { - LOGGER.error("update properties of microservice {} failed", - microserviceId, - e); - } - return false; - } - - @Override - public boolean updateInstanceProperties(String microserviceId, String microserviceInstanceId, - Map instanceProperties) { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - try { - UpdatePropertiesRequest request = new UpdatePropertiesRequest(); - request.setProperties(instanceProperties); - byte[] body = JsonUtils.writeValueAsBytes(request); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("update properties of microservice instance: {}", - new String(body, Charset.defaultCharset())); - } - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_PROPERTIES, microserviceId, microserviceInstanceId), - new RequestParam().setBody(body), - syncHandler(countDownLatch, HttpClientResponse.class, holder)); - - countDownLatch.await(); - if (holder.value != null) { - if (holder.value.statusCode() == Status.OK.getStatusCode()) { - return true; - } - LOGGER.warn(holder.value.statusMessage()); - } - } catch (Exception e) { - LOGGER.error("update properties of microservice instance {}/{} failed", - microserviceId, - microserviceInstanceId, - e); - } - return false; - } - - @Override - public MicroserviceInstance findServiceInstance(String serviceId, String instanceId) { - try { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, serviceId, instanceId), - new RequestParam().addHeader("X-ConsumerId", serviceId).addQueryParam("global", "true"), - syncHandler(countDownLatch, MicroserviceInstanceResponse.class, holder)); - countDownLatch.await(); - if (null != holder.value) { - return holder.value.getInstance(); - } - return null; - } catch (Exception e) { - LOGGER.error("get instance from sc failed"); - return null; - } - } - - @Override - public ServiceCenterInfo getServiceCenterInfo() { - Holder holder = new Holder<>(); - IpPort ipPort = ipPortManager.getAvailableAddress(); - - CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, - Const.REGISTRY_API.SERVICECENTER_VERSION, - new RequestParam(), - syncHandler(countDownLatch, ServiceCenterInfo.class, holder)); - try { - countDownLatch.await(); - if (holder.value != null) { - return holder.value; - } - } catch (Exception e) { - LOGGER.error("query servicecenter version info failed.", e); - } - return null; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java deleted file mode 100644 index a8b14abc1db..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.vertx.VertxTLSBuilder; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpVersion; - -/** - * Created by on 2017/4/28. - */ -public final class WebsocketClientPool extends AbstractClientPool { - - private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientPool.class); - - public static final WebsocketClientPool INSTANCE = new WebsocketClientPool(); - - private WebsocketClientPool() { - } - - @Override - public HttpClientOptions createHttpClientOptions() { - HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion(); - HttpClientOptions httpClientOptions = new HttpClientOptions(); - httpClientOptions.setProtocolVersion(ver); - httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout()); - httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleWatchTimeout()); - if (ver == HttpVersion.HTTP_2) { - LOGGER.debug("service center ws client protocol version is HTTP/2"); - httpClientOptions.setHttp2ClearTextUpgrade(false); - } - if (ServiceRegistryConfig.INSTANCE.isSsl()) { - LOGGER.debug("service center ws client performs requests over TLS"); - VertxTLSBuilder.buildHttpClientOptions(SSL_KEY, httpClientOptions); - } - return httpClientOptions; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java deleted file mode 100644 index 70625dad263..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.util.HashMap; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; - -/** - * Created by on 2017/4/28. - */ -public final class WebsocketUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketUtils.class); - - private WebsocketUtils() { - } - - public static void open(IpPort ipPort, String url, Handler onOpen, Handler onClose, - Handler onMessage, Handler onException, - Handler onConnectFailed) { - HttpClientWithContext vertxHttpClient = WebsocketClientPool.INSTANCE.getClient(); - vertxHttpClient.runOnContext(client -> { - client.websocket(ipPort.getPort(), - ipPort.getHostOrIp(), - url, - RestUtils.getDefaultHeaders().addAll(RestUtils - .getSignAuthHeaders(RestUtils.createSignRequest(null, ipPort, new RequestParam(), url, new HashMap<>()))), - ws -> { - onOpen.handle(null); - - ws.exceptionHandler(v -> { - onException.handle(v); - try { - ws.close(); - } catch (Exception err) { - LOGGER.error("ws close error.", err); - } - }); - ws.closeHandler(v -> { - onClose.handle(v); - }); - ws.handler(onMessage); - }, - onConnectFailed); - }); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/AbstractPropertiesLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/AbstractPropertiesLoader.java deleted file mode 100644 index 8ec8891faee..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/AbstractPropertiesLoader.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.serviceregistry.api.PropertyExtended; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -/** - * 加载微服务和微服务实例的properties - */ -public abstract class AbstractPropertiesLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractPropertiesLoader.class); - - protected static final String PROPERTIES = ".properties"; - - protected static final String EXTENDED_CLASS_FOR_COMPATIBLE = ".propertyExtentedClass"; - - protected static final String EXTENDED_CLASS = ".propertyExtendedClass"; - - protected abstract String getConfigOptionPrefix(); - - public Map loadProperties(Configuration configuration) { - Map propertiesMap = new HashMap<>(); - loadPropertiesFromConfigMap(configuration, propertiesMap); - loadPropertiesFromExtendedClass(configuration, propertiesMap); - - return propertiesMap; - } - - protected void loadPropertiesFromConfigMap(Configuration configuration, Map propertiesMap) { - String configKeyPrefix = mergeStrings(getConfigOptionPrefix(), PROPERTIES); - propertiesMap.putAll(ConfigurePropertyUtils.getPropertiesWithPrefix(configuration, configKeyPrefix)); - } - - protected void loadPropertiesFromExtendedClass(Configuration configuration, Map propertiesMap) { - String extendedPropertyClass = readExtendedPropertyClassName(configuration, EXTENDED_CLASS); - if (StringUtils.isEmpty(extendedPropertyClass)) { - extendedPropertyClass = readExtendedPropertyClassName(configuration, EXTENDED_CLASS_FOR_COMPATIBLE); - if (StringUtils.isEmpty(extendedPropertyClass)) { - return; - } else { - LOGGER.warn("The property `{}` is deprecated and will be removed soon, please use the new property `{}`.", - EXTENDED_CLASS_FOR_COMPATIBLE, - EXTENDED_CLASS); - } - } - try { - Class classExternalProperty = Class.forName(extendedPropertyClass); - if (!PropertyExtended.class.isAssignableFrom(classExternalProperty)) { - String errMsg = String.format( - "Define propertyExtendedClass %s in yaml, but not implement the interface PropertyExtended.", - extendedPropertyClass); - LOGGER.error(errMsg); - throw new Error(errMsg); - } - - PropertyExtended instance = (PropertyExtended) classExternalProperty.newInstance(); - Map extendedPropertiesMap = instance.getExtendedProperties(); - if (extendedPropertiesMap != null && !extendedPropertiesMap.isEmpty()) { - propertiesMap.putAll(extendedPropertiesMap); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - String errMsg = "Fail to create instance of class: " + extendedPropertyClass; - LOGGER.error(errMsg); - throw new Error(errMsg, e); - } - } - - private String readExtendedPropertyClassName(Configuration configuration, String keyName) { - String configKey = mergeStrings(getConfigOptionPrefix(), keyName); - return configuration.getString(configKey, ""); - } - - protected static String mergeStrings(String... strArr) { - return String.join("", strArr); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java deleted file mode 100644 index 9d2ca05e51c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ConfigurePropertyUtils.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.lang.StringUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.BasePath; - -import com.netflix.config.DynamicPropertyFactory; - -public final class ConfigurePropertyUtils { - private ConfigurePropertyUtils() { - } - - /** - * 获取key包含prefix前缀的所有配置项 - */ - public static Map getPropertiesWithPrefix(String prefix) { - Object config = DynamicPropertyFactory.getBackingConfigurationSource(); - if (!Configuration.class.isInstance(config)) { - return new HashMap<>(); - } - - return getPropertiesWithPrefix((Configuration) config, prefix); - } - - // caller ensure configuration is valid - public static Map getPropertiesWithPrefix(Configuration configuration, String prefix) { - Map propertiesMap = new HashMap<>(); - - Iterator keysIterator = configuration.getKeys(prefix); - while (keysIterator.hasNext()) { - String key = keysIterator.next(); - propertiesMap.put(key.substring(prefix.length() + 1), String.valueOf(configuration.getProperty(key))); - } - return propertiesMap; - } - - @SuppressWarnings("unchecked") - public static List getMicroservicePaths(Configuration configuration) { - List basePaths = new ArrayList<>(); - for (Object path : configuration.getList("service_description.paths")) { - BasePath basePath = new BasePath(); - Map pathMap = (Map) path; - basePath.setPath(buildPath((String) pathMap.get("path"))); - basePath.setProperty((Map) pathMap.get("property")); - basePaths.add(basePath); - } - return basePaths; - } - - private static String buildPath(String path) { - String prefix = System.getProperty(Const.URL_PREFIX); - if (StringUtils.isNotEmpty(prefix)) { - if (!path.startsWith(prefix)) { - path = prefix + path; - } - } - return path; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/InstancePropertiesLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/InstancePropertiesLoader.java deleted file mode 100644 index 46f1e950abf..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/InstancePropertiesLoader.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -public final class InstancePropertiesLoader extends AbstractPropertiesLoader { - - public static final InstancePropertiesLoader INSTANCE = new InstancePropertiesLoader(); - - private InstancePropertiesLoader() { - } - - @Override - protected String getConfigOptionPrefix() { - return "instance_description"; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/MicroservicePropertiesLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/MicroservicePropertiesLoader.java deleted file mode 100644 index 0eef433cd1c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/MicroservicePropertiesLoader.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_SERVICE_DESCRIPTION_KEY; - -public final class MicroservicePropertiesLoader extends AbstractPropertiesLoader { - - public static final MicroservicePropertiesLoader INSTANCE = new MicroservicePropertiesLoader(); - - private MicroservicePropertiesLoader() { - } - - @Override - protected String getConfigOptionPrefix() { - return CONFIG_SERVICE_DESCRIPTION_KEY; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java deleted file mode 100644 index 6a7bc00229c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.deployment.Deployment; -import org.apache.servicecomb.deployment.DeploymentProvider; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicBooleanProperty; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; - -import io.vertx.core.http.HttpVersion; - -/** - * Created by on 2016/12/23. - */ -public final class ServiceRegistryConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfig.class); - - public static final ServiceRegistryConfig INSTANCE = new ServiceRegistryConfig(); - - private static final int DEFAULT_TIMEOUT_IN_MS = 30000; - - private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; - - private static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000; - - private static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000; - - private static final int DEFAULT_CHECK_INTERVAL_IN_S = 30; - - private static final int DEFAULT_CHECK_TIMES = 3; - - public static final String AUTH_ENABLED = "servicecomb.auth.enabled"; - - public static final String TENANT_ACCESS_KEY = "servicecomb.auth.accessKey"; - - public static final String TENANT_SECRET_KEY = "servicecomb.auth.secretKey"; - - public static final String REGISTRY_API_VERSION = "servicecomb.service.registry.api.version"; - - public static final String TENANT_NAME = "servicecomb.config.client.tenantName"; - - public static final String DOMAIN_NAME = "servicecomb.config.client.domainName"; - - public static final String NO_TENANT = "default"; - - public static final String NO_DOMAIN = "default"; - - public static final String MICROSERVICE_VERSION_FACTORY = "servicecomb.microserviceVersionFactory"; - - private boolean ssl = true; - - public static final String PROXY_PRE_NAME = "servicecomb.proxy."; - - public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable"; - - public static final String PROXY_HOST = PROXY_PRE_NAME + "host"; - - public static final String PROXY_PORT = PROXY_PRE_NAME + "port"; - - public static final String PROXY_USERNAME = PROXY_PRE_NAME + "username"; - - public static final String PROXY_PASSWD = PROXY_PRE_NAME + "passwd"; - - private ServiceRegistryConfig() { - - } - - public String getMicroserviceVersionFactory() { - return DynamicPropertyFactory.getInstance().getStringProperty(MICROSERVICE_VERSION_FACTORY, null).get(); - } - - /** - * Currently we don't provide configuration about {@link org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersionFactory} - */ - public String getStaticMicroserviceVersionFactory() { - return "org.apache.servicecomb.core.definition.StaticMicroserviceVersionMetaFactory"; - } - - public HttpVersion getHttpVersion() { - DynamicStringProperty property = - DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.service.registry.client.httpVersion", "HTTP_1_1"); - return HttpVersion.valueOf(property.get()); - } - - public int getWorkerPoolSize() { - String workerPoolSizeKey = "servicecomb.service.registry.client.workerPoolSize"; - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty(workerPoolSizeKey, 1); - int workerPoolSize = property.get(); - if (workerPoolSize <= 0) { - int nAvailableProcessors = Runtime.getRuntime().availableProcessors(); - LOGGER.warn("The property `{}` must be positive integer, fallback to use number of available processors: {}", - workerPoolSizeKey, - nAvailableProcessors); - return nAvailableProcessors; - } - return workerPoolSize; - } - - public boolean isSsl() { - getIpPort(); - return this.ssl; - } - - public ArrayList getIpPort() { - List uriList = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER).getAccessURL(); - ArrayList ipPortList = new ArrayList<>(); - uriList.forEach(anUriList -> { - try { - URI uri = new URI(anUriList.trim()); - this.ssl = "https".equals(uri.getScheme()); - ipPortList.add(NetUtils.parseIpPort(uri.getScheme(), uri.getAuthority())); - } catch (Exception e) { - LOGGER.error("servicecomb.service.registry.address invalid : {}", anUriList, e); - } - }); - return ipPortList; - } - - public String getTransport() { - return "rest"; - } - - public int getConnectionTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.connection", DEFAULT_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 0 ? DEFAULT_TIMEOUT_IN_MS : timeout; - } - - public int getIdleConnectionTimeout() { - // connection pool idle timeout based on client heart beat interval. Heart beat default value is 30. - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.idle", DEFAULT_TIMEOUT_IN_SECONDS * 2); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; - } - - public int getIdleWatchTimeout() { - // watch idle timeout based on SC PING/PONG interval. SC default value is 30. - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.watch", DEFAULT_TIMEOUT_IN_SECONDS * 2); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; - } - - public int getRequestTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.request", DEFAULT_REQUEST_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout; - } - - //Set the timeout of the heartbeat request - public int getHeartBeatRequestTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.heartbeat", - DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout; - } - - public int getHeartbeatInterval() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.healthCheck.interval", - DEFAULT_CHECK_INTERVAL_IN_S); - int interval = property.get(); - return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval; - } - - public int getInstancePullInterval() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.pull.interval", - DEFAULT_CHECK_INTERVAL_IN_S); - int interval = property.get(); - return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval; - } - - public boolean isRegistryAutoDiscovery() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.autodiscovery", - false); - return property.get(); - } - - public int getResendHeartBeatTimes() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.healthCheck.times", - DEFAULT_CHECK_TIMES); - int times = property.get(); - return times < 0 ? DEFAULT_CHECK_TIMES : times; - } - - public boolean isEmptyInstanceProtectionEnabled() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.empty.protection", - true); - return property.get(); - } - - public boolean isPreferIpAddress() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.preferIpAddress", - false); - return property.get(); - } - - public boolean isWatch() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.watch", - true); - return property.get(); - } - - public boolean isClientAuthEnabled() { - String isAuthEnabled = getProperty("false", AUTH_ENABLED); - return Boolean.parseBoolean(isAuthEnabled); - } - - public String getRegistryApiVersion() { - return getProperty("v4", REGISTRY_API_VERSION); - } - - public String getTenantName() { - return getProperty(NO_TENANT, TENANT_NAME); - } - - public String getDomainName() { - return getProperty(NO_DOMAIN, DOMAIN_NAME); - } - - public String getAccessKey() { - String tenantName = getProperty(null, TENANT_ACCESS_KEY); - return tenantName; - } - - public String getSecretKey() { - String tenantName = getProperty(null, TENANT_SECRET_KEY); - return tenantName; - } - - public Boolean isProxyEnable() { - String enable = getProperty("false", PROXY_ENABLE); - return Boolean.parseBoolean(enable); - } - - public String getProxyHost() { - String host = getProperty("127.0.0.1", PROXY_HOST); - return host; - } - - public int getProxyPort() { - String port = getProperty("8080", PROXY_PORT); - return Integer.parseInt(port); - } - - public String getProxyUsername() { - String username = getProperty("user", PROXY_USERNAME); - return username; - } - - public String getProxyPasswd() { - String passwd = getProperty("passwd", PROXY_PASSWD); - return passwd; - } - - private String getProperty(String defaultValue, String... keys) { - String property = null; - for (String key : keys) { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); - if (property != null) { - break; - } - } - - if (property != null) { - return property; - } else { - return defaultValue; - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java deleted file mode 100644 index 4eef10f6d0f..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Map; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; - -public class AppManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(AppManager.class); - - private EventBus eventBus; - - private MicroserviceVersionFactory microserviceVersionFactory = new DefaultMicroserviceVersionFactory(); - - // key: appId - private Map apps = new ConcurrentHashMapEx<>(); - - private volatile StaticMicroserviceVersionFactory staticMicroserviceVersionFactory; - - public AppManager(EventBus eventBus) { - this.eventBus = eventBus; - } - - public EventBus getEventBus() { - return eventBus; - } - - public MicroserviceVersionFactory getMicroserviceVersionFactory() { - return microserviceVersionFactory; - } - - public Map getApps() { - return apps; - } - - public void setMicroserviceVersionFactory(MicroserviceVersionFactory microserviceVersionFactory) { - this.microserviceVersionFactory = microserviceVersionFactory; - } - - // microserviceName maybe normal name or alias name - public MicroserviceVersionRule getOrCreateMicroserviceVersionRule(String appId, String microserviceName, - String versionRule) { - MicroserviceManager microserviceManager = getOrCreateMicroserviceManager(appId); - - return microserviceManager.getOrCreateMicroserviceVersionRule(microserviceName, versionRule); - } - - public MicroserviceManager getOrCreateMicroserviceManager(String appId) { - return apps.computeIfAbsent(appId, id -> new MicroserviceManager(this, appId)); - } - - public MicroserviceVersions getOrCreateMicroserviceVersions(String appId, String microserviceName) { - MicroserviceManager microserviceManager = getOrCreateMicroserviceManager(appId); - return microserviceManager.getOrCreateMicroserviceVersions(microserviceName); - } - - public StaticMicroserviceVersionFactory getStaticMicroserviceVersionFactory() { - if (null == staticMicroserviceVersionFactory) { - synchronized (this) { - if (null == staticMicroserviceVersionFactory) { - loadStaticMicroserviceVersionFactory(); - } - } - } - return staticMicroserviceVersionFactory; - } - - public void setStaticMicroserviceVersionFactory(StaticMicroserviceVersionFactory staticMicroserviceVersionFactory) { - this.staticMicroserviceVersionFactory = staticMicroserviceVersionFactory; - } - - private void loadStaticMicroserviceVersionFactory() { - String staticMicroserviceVersionFactoryClass = ServiceRegistryConfig.INSTANCE - .getStaticMicroserviceVersionFactory(); - try { - staticMicroserviceVersionFactory = (StaticMicroserviceVersionFactory) Class - .forName(staticMicroserviceVersionFactoryClass).newInstance(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - LOGGER.info("unable to load StaticMicroserviceVersionFactory", e); - // interrupt this loading process because this error cannot be covered by us. - throw new IllegalStateException("unable to load StaticMicroserviceVersionFactory", e); - } - LOGGER.info("staticMicroserviceVersionFactory is {}.", staticMicroserviceVersionFactoryClass); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/DefaultMicroserviceVersionFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/DefaultMicroserviceVersionFactory.java deleted file mode 100644 index 435a2c3e101..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/DefaultMicroserviceVersionFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -public class DefaultMicroserviceVersionFactory implements MicroserviceVersionFactory { - - @Override - public MicroserviceVersion create(String microserviceName, String microserviceId) { - return new MicroserviceVersion(microserviceId); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java deleted file mode 100644 index 7bbfa8c9a8b..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceInstancePing.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * SPI interface to ping microservice instance status in Instance Protection Mode, which means - * protection of instance removal and usually used in scenarios where instances are fixed and changed rarely. - */ -public interface MicroserviceInstancePing { - int getOrder(); - - /** - * check if this instance if valid to use - * @param instance - * @return - */ - boolean ping(MicroserviceInstance instance); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceManager.java deleted file mode 100644 index 2d16d0d95ec..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceManager.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Map; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.task.event.MicroserviceNotExistEvent; -import org.apache.servicecomb.serviceregistry.task.event.PeriodicPullEvent; -import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.Subscribe; - -public class MicroserviceManager { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceManager.class); - - private AppManager appManager; - - private String appId; - - // key: microserviceName - private Map versionsByName = new ConcurrentHashMapEx<>(); - - public MicroserviceManager(AppManager appManager, String appId) { - this.appManager = appManager; - this.appId = appId; - - appManager.getEventBus().register(this); - } - - public Map getVersionsByName() { - return versionsByName; - } - - public MicroserviceVersions getOrCreateMicroserviceVersions(String microserviceName) { - MicroserviceVersions microserviceVersions = versionsByName.computeIfAbsent(microserviceName, name -> { - MicroserviceVersions instance = new MicroserviceVersions(appManager, appId, microserviceName); - instance.submitPull(); - return instance; - }); - if (!microserviceVersions.isValidated()) { - // remove this microservice if it does not exist or not registered in order to get it back when access it again - removeMicroservice(microserviceName); - } - return microserviceVersions; - } - - protected void removeMicroservice(String microserviceName) { - // must use containsKey and then remove - // because removeMicroservice maybe invoked inside "versionsByName.computeIfAbsent" - // in this time, containsKey will return false, and will not invoke remove - // otherwise, remove will block the thread forever - if (versionsByName.containsKey(microserviceName)) { - MicroserviceVersions microserviceVersions = versionsByName.remove(microserviceName); - appManager.getEventBus().unregister(microserviceVersions); - LOGGER.info("remove microservice, appId={}, microserviceName={}.", appId, microserviceName); - } - } - - public MicroserviceVersionRule getOrCreateMicroserviceVersionRule(String microserviceName, - String versionRule) { - MicroserviceVersions microserviceVersions = getOrCreateMicroserviceVersions(microserviceName); - - return microserviceVersions.getOrCreateMicroserviceVersionRule(versionRule); - } - - @Subscribe - public void periodicPull(PeriodicPullEvent event) { - refreshInstances(); - } - - @Subscribe - public void serviceRegistryRecovery(RecoveryEvent event) { - refreshInstances(); - } - - protected void refreshInstances() { - for (MicroserviceVersions versions : versionsByName.values()) { - versions.submitPull(); - } - } - - @Subscribe - private void onMicroserviceNotExistEvent(MicroserviceNotExistEvent event) { - if (!appId.equals(event.getAppId())) { - return; - } - - removeMicroservice(event.getMicroserviceName()); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java deleted file mode 100644 index 9c882e6b5a1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.version.Version; - -public class MicroserviceVersion { - protected Version version; - - protected Microservice microservice; - - public MicroserviceVersion(String microserviceId) { - microservice = RegistryUtils.getServiceRegistry().getAggregatedRemoteMicroservice(microserviceId); - if (microservice == null) { - throw new IllegalStateException(String.format("Invalid microserviceId %s.", microserviceId)); - } - - this.version = new Version(microservice.getVersion()); - } - - public MicroserviceVersion(Microservice microservice) { - this.microservice = microservice; - this.version = new Version(microservice.getVersion()); - } - - public Microservice getMicroservice() { - return microservice; - } - - public Version getVersion() { - return version; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionFactory.java deleted file mode 100644 index f75cdf0723c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -public interface MicroserviceVersionFactory { - MicroserviceVersion create(String microserviceName, String microserviceId); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionRule.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionRule.java deleted file mode 100644 index cff2fae11a2..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionRule.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.apache.servicecomb.serviceregistry.version.VersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MicroserviceVersionRule { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceVersionRule.class); - - private final String appId; - - private final String microserviceName; - - private final VersionRule versionRule; - - private MicroserviceVersion latestVersion; - - // key is microserviceId - private Map versions = new ConcurrentHashMap<>(); - - // key is instanceId - private Map instances = Collections.emptyMap(); - - private InstanceCache instanceCache; - - private VersionedCache versionedCache; - - public MicroserviceVersionRule(String appId, String microserviceName, String strVersionRule) { - this.appId = appId; - this.microserviceName = microserviceName; - this.versionRule = VersionRuleUtils.getOrCreate(strVersionRule); - - resetInstanceCache(); - } - - public String getAppId() { - return appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - private void resetInstanceCache() { - instanceCache = new InstanceCache(appId, microserviceName, versionRule.getVersionRule(), instances); - versionedCache = new VersionedCache() - .name(versionRule.getVersionRule()) - .autoCacheVersion() - .data(instances); - } - - public void addMicroserviceVersion(MicroserviceVersion microserviceVersion) { - if (!versionRule.isAccept(microserviceVersion.getVersion())) { - return; - } - - versions.put(microserviceVersion.getMicroservice().getServiceId(), microserviceVersion); - resetLatestVersion(); - - LOGGER.info("add microserviceVersion, appId={}, microserviceName={}, version={}, versionRule={}.", - microserviceVersion.getMicroservice().getAppId(), - microserviceVersion.getMicroservice().getServiceName(), - microserviceVersion.getVersion().getVersion(), - versionRule.getVersionRule()); - } - - public void deleteMicroserviceVersion(MicroserviceVersion microserviceVersion) { - if (!versionRule.isAccept(microserviceVersion.getVersion())) { - return; - } - - if (versions.remove(microserviceVersion.getMicroservice().getServiceId()) == null) { - return; - } - - resetLatestVersion(); - LOGGER.info("delete microserviceVersion, appId={}, microserviceName={}, version={}, versionRule={}.", - microserviceVersion.getMicroservice().getAppId(), - microserviceVersion.getMicroservice().getServiceName(), - microserviceVersion.getVersion().getVersion(), - versionRule.getVersionRule()); - } - - protected void resetLatestVersion() { - Map tempVersions = new HashMap<>(); - instances.values().forEach(item -> { - MicroserviceVersion version = versions.get(item.getServiceId()); - if (version != null) { - tempVersions.put(item.getServiceId(), version); - } - }); - - MicroserviceVersion lastLatestVersion = latestVersion; - if (!tempVersions.isEmpty()) { - latestVersion = tempVersions.values().stream().max(Comparator.comparing(MicroserviceVersion::getVersion)).get(); - } else if (!versions.isEmpty()) { - latestVersion = versions.values().stream().max(Comparator.comparing(MicroserviceVersion::getVersion)).get(); - } - - if (lastLatestVersion != latestVersion) { - LOGGER.info("latestVersion changed from {} to {}, appId={}, microserviceName={}, versionRule={}.", - lastLatestVersion == null ? "null" : lastLatestVersion.getVersion(), - latestVersion == null ? "null" : latestVersion.getVersion(), - appId, - microserviceName, - versionRule.getVersionRule()); - } - } - - public VersionRule getVersionRule() { - return versionRule; - } - - @SuppressWarnings("unchecked") - public T getLatestMicroserviceVersion() { - return (T) latestVersion; - } - - public Map getInstances() { - return instances; - } - - public InstanceCache getInstanceCache() { - return instanceCache; - } - - public VersionedCache getVersionedCache() { - return versionedCache; - } - - public void setInstances(Collection newInstances) { - if (newInstances == null) { - return; - } - - Map tmpInstances = newInstances.stream().filter(instance -> { - MicroserviceVersion microserviceVersion = versions.get(instance.getServiceId()); - boolean isMatch = microserviceVersion != null - && versionRule.isMatch(microserviceVersion.getVersion(), latestVersion.getVersion()); - if (isMatch) { - LOGGER.info( - "set instances, appId={}, microserviceName={}, versionRule={}, instanceId={}, version={}, endpoints={}.", - appId, - microserviceName, - versionRule.getVersionRule(), - instance.getInstanceId(), - microserviceVersion.getVersion(), - instance.getEndpoints()); - } - return isMatch; - }).collect(Collectors.toMap(MicroserviceInstance::getInstanceId, Function.identity())); - instances = Collections.unmodifiableMap(tmpInstances); - - resetInstanceCache(); - resetLatestVersion(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java deleted file mode 100644 index e85c51311b5..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.task.event.MicroserviceNotExistEvent; -import org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.Subscribe; - -public class MicroserviceVersions { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceVersions.class); - - AppManager appManager; - - private String appId; - - private String microserviceName; - - // revision and pulledInstances directly equals to SC's response - private String revision = null; - - private List pulledInstances; - - // instances not always equals to pulledInstances - // in the future: - // pulledInstances means all instance - // instances means available instance - List instances; - - // key is service id - Map versions = new ConcurrentHashMapEx<>(); - - // key is version rule - Map versionRules = new ConcurrentHashMapEx<>(); - - // process pulled instances and create versionRule must be protected by lock - // otherwise maybe lost instance or version in versionRule - private final Object lock = new Object(); - - // to avoid pull too many time - // only pendingPullCount is 0, then do a real pull - private AtomicInteger pendingPullCount = new AtomicInteger(); - - boolean validated = false; - - public MicroserviceVersions(AppManager appManager, String appId, String microserviceName) { - this.appManager = appManager; - this.appId = appId; - this.microserviceName = microserviceName; - - LOGGER.info("create MicroserviceVersions, appId={}, microserviceName={}.", - appId, - microserviceName); - - appManager.getEventBus().register(this); - } - - public boolean isValidated() { - return validated; - } - - public String getAppId() { - return appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public Map getVersions() { - return versions; - } - - @SuppressWarnings("unchecked") - public T getVersion(String serviceId) { - return (T) versions.get(serviceId); - } - - public String getRevision() { - return revision; - } - - public void setRevision(String revision) { - this.revision = revision; - } - - public List getPulledInstances() { - return pulledInstances; - } - - public void submitPull() { - pendingPullCount.incrementAndGet(); - - pullInstances(); - } - - public void pullInstances() { - if (pendingPullCount.decrementAndGet() != 0) { - return; - } - - MicroserviceInstances microserviceInstances = RegistryUtils.findServiceInstances(appId, - microserviceName, - DefinitionConst.VERSION_RULE_ALL, - revision); - if (microserviceInstances == null) { - return; - } - if (microserviceInstances.isMicroserviceNotExist()) { - appManager.getEventBus().post(new MicroserviceNotExistEvent(appId, microserviceName)); - return; - } - - if (!microserviceInstances.isNeedRefresh()) { - return; - } - - pulledInstances = microserviceInstances.getInstancesResponse().getInstances(); - pulledInstances.sort(Comparator.comparing(MicroserviceInstance::getInstanceId)); - String rev = microserviceInstances.getRevision(); - - safeSetInstances(pulledInstances, rev); - } - - protected void safeSetInstances(List pulledInstances, String rev) { - try { - setInstances(pulledInstances, rev); - validated = true; - } catch (Throwable e) { - LOGGER.error("Failed to setInstances, appId={}, microserviceName={}.", - getAppId(), - getMicroserviceName(), - e); - } - } - - private void postPullInstanceEvent(long msTime) { - pendingPullCount.incrementAndGet(); - appManager.getEventBus().post(new PullMicroserviceVersionsInstancesEvent(this, msTime)); - } - - private void setInstances(List pulledInstances, String rev) { - synchronized (lock) { - instances = mergeInstances(pulledInstances, instances); - for (MicroserviceInstance instance : instances) { - // ensure microserviceVersion exists - versions.computeIfAbsent(instance.getServiceId(), microserviceId -> { - MicroserviceVersion microserviceVersion = - appManager.getMicroserviceVersionFactory().create(microserviceName, microserviceId); - for (MicroserviceVersionRule microserviceVersionRule : versionRules.values()) { - microserviceVersionRule.addMicroserviceVersion(microserviceVersion); - } - return microserviceVersion; - }); - } - - for (MicroserviceVersionRule microserviceVersionRule : versionRules.values()) { - microserviceVersionRule.setInstances(instances); - } - revision = rev; - } - } - - private List mergeInstances(List pulledInstances, - List inUseInstances) { - List upInstances = pulledInstances - .stream() - .filter(instance -> MicroserviceInstanceStatus.UP.equals(instance.getStatus())) - .collect(Collectors.toList()); - if (upInstances.isEmpty() && inUseInstances != null && ServiceRegistryConfig.INSTANCE - .isEmptyInstanceProtectionEnabled()) { - MicroserviceInstancePing ping = SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class); - inUseInstances.stream() - .forEach(instance -> { - if (!upInstances.contains(instance)) { - if (ping.ping(instance)) { - upInstances.add(instance); - } - } - }); - } - return upInstances; - } - - public MicroserviceVersionRule getOrCreateMicroserviceVersionRule(String versionRule) { - // do not use computeIfAbsent - MicroserviceVersionRule microserviceVersionRule = versionRules.get(versionRule); - if (microserviceVersionRule == null) { - synchronized (lock) { - microserviceVersionRule = versionRules.computeIfAbsent(versionRule, this::createAndInitMicroserviceVersionRule); - } - } - - return microserviceVersionRule; - } - - protected MicroserviceVersionRule createAndInitMicroserviceVersionRule(String strVersionRule) { - LOGGER.info("create MicroserviceVersionRule, appId={}, microserviceName={}, versionRule={}.", - appId, - microserviceName, - strVersionRule); - - MicroserviceVersionRule microserviceVersionRule = - new MicroserviceVersionRule(appId, microserviceName, strVersionRule); - for (MicroserviceVersion microserviceVersion : versions.values()) { - microserviceVersionRule.addMicroserviceVersion(microserviceVersion); - } - microserviceVersionRule.setInstances(instances); - return microserviceVersionRule; - } - - @Subscribe - public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) { - if (!isEventAccept(changedEvent)) { - return; - } - // pull instances always replace old instances, not append - // - // pull result and watch event sequence is not defined even inside SC. - // it's not safe to trust the event, so we just send a new pull request - // - // CREATE/UPDATE: - // if pull 1/2/3, and then add 4, but "add 4" received before pull result, will lost 4. - // DELETE: - // if pull 1/2/3, and then delete 3, but "delete 3" received before pull result, will have wrong 3. - // EXPIRE:: - // black/white config in SC changed, we must refresh all data from sc. - postPullInstanceEvent(0); - } - - protected boolean isEventAccept(MicroserviceInstanceChangedEvent changedEvent) { - return (appId.equals(changedEvent.getKey().getAppId()) && - microserviceName.equals(changedEvent.getKey().getServiceName())) || - microserviceName.equals( - changedEvent.getKey().getAppId() + Const.APP_SERVICE_SEPARATOR + changedEvent.getKey().getServiceName()); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java deleted file mode 100644 index 1290c971e7e..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/SimpleMicroserviceInstancePing.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.consumer; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; - -/** - * Simple implementation of .MicroserviceInstancePing using telnet - */ -public class SimpleMicroserviceInstancePing implements MicroserviceInstancePing { - @Override - public int getOrder() { - return 100; - } - - @Override - public boolean ping(MicroserviceInstance instance) { - if (instance.getEndpoints() != null && instance.getEndpoints().size() > 0) { - IpPort ipPort = NetUtils.parseIpPortFromURI(instance.getEndpoints().get(0)); - try (Socket s = new Socket()) { - s.connect(new InetSocketAddress(ipPort.getHostOrIp(), ipPort.getPort()), 3000); - return true; - } catch (IOException e) { - // ignore this error - } - } - return false; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionFactory.java deleted file mode 100644 index d2fb60d696f..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; - -public interface StaticMicroserviceVersionFactory { - MicroserviceVersion create(StaticMicroservice microservice); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java deleted file mode 100644 index 286ff95bbd6..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.serviceregistry.version.Version; - -public class StaticMicroserviceVersions extends MicroserviceVersions { - - private Class schemaIntfCls; - - private String environment; - - public StaticMicroserviceVersions(AppManager appManager, String appId, String microserviceName, - Class schemaIntfCls) { - super(appManager, appId, microserviceName); - - validated = true; - this.schemaIntfCls = schemaIntfCls; - this.environment = RegistryUtils.getMicroservice().getEnvironment(); - } - - @Override - public void pullInstances() { - // instance information is stored locally, do not pull from sc - } - - public void addInstances(String version, List addedInstances) { - Version parsedVersion = new Version(version); - String serviceId = computeServiceId(parsedVersion); - - for (MicroserviceInstance instance : addedInstances) { - instance.setServiceId(serviceId); - instance.setInstanceId(serviceId + "-" + UUID.randomUUID()); - } - - mergeInstances(addedInstances); - - // ensure microserviceVersion exists - versions.computeIfAbsent(serviceId, microserviceId -> { - StaticMicroservice microservice = createMicroservice(parsedVersion, serviceId); - MicroserviceVersion microserviceVersion = appManager.getStaticMicroserviceVersionFactory().create(microservice); - for (MicroserviceVersionRule microserviceVersionRule : versionRules.values()) { - microserviceVersionRule.addMicroserviceVersion(microserviceVersion); - } - return microserviceVersion; - }); - - for (MicroserviceVersionRule microserviceVersionRule : versionRules.values()) { - microserviceVersionRule.setInstances(this.instances); - } - } - - private void mergeInstances(List instances) { - if (null == this.instances) { - this.instances = new ArrayList<>(instances.size()); - } - this.instances.addAll(instances); - } - - private StaticMicroservice createMicroservice(Version parsedVersion, String serviceId) { - StaticMicroservice microservice = new StaticMicroservice(); - microservice.setAppId(this.getAppId()); - microservice.setServiceId(serviceId); - microservice.setServiceName(this.getMicroserviceName()); - microservice.setVersion(parsedVersion.getVersion()); - microservice.setEnvironment(RegistryUtils.getMicroservice().getEnvironment()); - microservice.setSchemaIntfCls(this.schemaIntfCls); - return microservice; - } - - private String computeServiceId(Version parsedVersion) { - return this.getAppId() + "-" - + this.environment + "-" - + this.getMicroserviceName() + "-" - + parsedVersion.getVersion(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/DefinitionConst.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/DefinitionConst.java deleted file mode 100644 index a51e3078d0d..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/DefinitionConst.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.definition; - -public interface DefinitionConst { - - String CONFIG_QUALIFIED_INSTANCE_ENVIRONMENT_KEY = "instance_description.environment"; - - String CONFIG_ALLOW_CROSS_APP_KEY = "allowCrossApp"; - - String DEFAULT_APPLICATION_ID = "default"; - - String DEFAULT_MICROSERVICE_VERSION = "1.0.0"; - - String DEFAULT_STAGE = "prod"; - - String DEFAULT_INSTANCE_ENVIRONMENT = "production"; - - String VERSION_RULE_LATEST = "latest"; - - String VERSION_RULE_ALL = "0.0.0+"; -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/MicroserviceDefinition.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/MicroserviceDefinition.java deleted file mode 100644 index 7f86fbd7e5b..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/definition/MicroserviceDefinition.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.definition; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_APPLICATION_ID_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_MICROSERVICE_NAME_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_SERVICE_DESCRIPTION_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_APPLICATION_ID; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_MICROSERVICE_NAME; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.config.archaius.sources.ConfigModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -public class MicroserviceDefinition { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceDefinition.class); - - // microservice maybe combined from many microservices - // if a and b combined to ab, then combinedFrom value is a,b - // if not combined, just only one microservice, then combinedFrom is empty - private Set combinedFrom = new HashSet<>(); - - private List configModels; - - private Configuration configuration; - - private String microserviceName; - - private String applicationId; - - public String getMicroserviceName() { - return microserviceName; - } - - public String getApplicationId() { - return applicationId; - } - - public static MicroserviceDefinition create(String appId, String microserviceName) { - ConfigModel configModel = createConfigModel(appId, microserviceName); - return new MicroserviceDefinition(Arrays.asList(configModel)); - } - - public static ConfigModel createConfigModel(String appId, String microserviceName) { - Map descMap = new HashMap<>(); - descMap.put(CONFIG_MICROSERVICE_NAME_KEY, microserviceName); - - Map config = new HashMap<>(); - config.put(CONFIG_APPLICATION_ID_KEY, appId); - config.put(CONFIG_SERVICE_DESCRIPTION_KEY, descMap); - - ConfigModel configModel = new ConfigModel(); - configModel.setConfig(config); - return configModel; - } - - public MicroserviceDefinition(List configModels) { - if (configModels == null) { - configModels = Collections.emptyList(); - } - - this.configModels = configModels; - this.configuration = ConfigUtil.createLocalConfig(configModels); - this.microserviceName = - configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, DEFAULT_MICROSERVICE_NAME); - - this.applicationId = configuration.getString(CONFIG_APPLICATION_ID_KEY, DEFAULT_APPLICATION_ID); - - // log paths first, even microserviceName is invalid, this can help user to find problems - logConfigPath(); - checkMicroserviceName(microserviceName); - - initCombinedFrom(configModels); - } - - public Set getCombinedFrom() { - return combinedFrom; - } - - private void initCombinedFrom(List configModels) { - for (ConfigModel model : configModels) { - Configuration conf = ConfigUtil.createLocalConfig(Arrays.asList(model)); - String name = - conf.getString(CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY, DEFAULT_MICROSERVICE_NAME); - if (!StringUtils.isEmpty(name)) { - checkMicroserviceName(name); - combinedFrom.add(name); - } - } - - combinedFrom.remove(microserviceName); - } - - private void checkMicroserviceName(String name) { - // the configuration we used - // when resolve placeholder failed - // the result will remains ${var} - if (StringUtils.isEmpty(name) || name.contains("${")) { - throw new IllegalArgumentException(String.format( - "MicroserviceName '%s' is invalid. you must configure '%s' or set the placeholder value.", - name, - CONFIG_QUALIFIED_MICROSERVICE_NAME_KEY)); - } - } - - // microserviceName maybe null - public void logConfigPath() { - List pathList = new ArrayList<>(); - for (ConfigModel configModel : configModels) { - if (configModel.getUrl() != null) { - pathList.add(configModel.getUrl().toString()); - } - } - LOGGER.info("load microservice config, name={}, paths={}", - microserviceName, - pathList); - } - - public List getConfigModels() { - return configModels; - } - - public Configuration getConfiguration() { - return configuration; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/Status.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/Status.java deleted file mode 100644 index 47aedd4fd8f..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/Status.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.diagnosis; - -public enum Status { - NORMAL, - ABNORMAL, - UNKNOWN -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java deleted file mode 100644 index b6dd6155c41..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.registry.RemoteServiceRegistry; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; - -import io.vertx.core.json.Json; - -public class InstanceCacheCheckTask implements ServiceRegistryTaskInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(InstanceCacheCheckTask.class); - - private static final int DEFAULT_DIAGNOSE_INSTANCE_CACHE_INTERVAL_IN_HOUR = 24; - - private static final String CONFIG_PREFIX = "servicecomb.service.registry.instance.diagnose."; - - public static final String MANUAL = CONFIG_PREFIX + "manual"; - - public static final String AUTO_INTERVAL = CONFIG_PREFIX + "interval"; - - // auto task - private ScheduledFuture scheduledFuture; - - private AppManager appManager; - - private ScheduledThreadPoolExecutor taskPool; - - private EventBus eventBus; - - private DynamicIntProperty autoCheckIntervalProperty; - - private DynamicStringProperty manualCheckProperty; - - private TimeUnit timeUnit = TimeUnit.HOURS; - - // make test easier - public void setTimeUnit(TimeUnit timeUnit) { - this.timeUnit = timeUnit; - } - - public void setAppManager(AppManager appManager) { - this.appManager = appManager; - } - - public void setTaskPool(ScheduledThreadPoolExecutor taskPool) { - this.taskPool = taskPool; - } - - public void setEventBus(EventBus eventBus) { - this.eventBus = eventBus; - } - - public DynamicStringProperty getManualCheckProperty() { - return manualCheckProperty; - } - - public DynamicIntProperty getAutoCheckIntervalProperty() { - return autoCheckIntervalProperty; - } - - @Override - public void init(RemoteServiceRegistry remoteServiceRegistry) { - appManager = remoteServiceRegistry.getAppManager(); - taskPool = remoteServiceRegistry.getTaskPool(); - eventBus = remoteServiceRegistry.getEventBus(); - - init(); - } - - protected void init() { - startAutoTask(); - registerManualTask(); - } - - private void registerManualTask() { - // if manual config item changed, then run task once - manualCheckProperty = DynamicPropertyFactory.getInstance().getStringProperty(MANUAL, null, this::runTask); - } - - protected void startAutoTask() { - autoCheckIntervalProperty = DynamicPropertyFactory.getInstance().getIntProperty(AUTO_INTERVAL, - DEFAULT_DIAGNOSE_INSTANCE_CACHE_INTERVAL_IN_HOUR, - this::doStartAutoTask); - doStartAutoTask(); - } - - private void doStartAutoTask() { - if (scheduledFuture != null) { - scheduledFuture.cancel(false); - scheduledFuture = null; - } - - int interval = autoCheckIntervalProperty.get(); - if (interval <= 0) { - LOGGER.info("disable instance cache check task, interval={}.", interval); - return; - } - - scheduledFuture = taskPool.scheduleAtFixedRate(this::runTask, interval, interval, timeUnit); - } - - protected void runTask() { - try { - InstanceCacheChecker checker = new InstanceCacheChecker(appManager); - InstanceCacheSummary instanceCacheSummary = checker.check(); - eventBus.post(instanceCacheSummary); - - LOGGER.info("check instance cache, result={}.", Json.encode(instanceCacheSummary)); - } catch (Throwable e) { - LOGGER.error("failed check instance cache..", e); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheChecker.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheChecker.java deleted file mode 100644 index 28fb4b66203..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheChecker.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.diagnosis.Status; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.json.Json; - -public class InstanceCacheChecker { - private static final Logger LOGGER = LoggerFactory.getLogger(InstanceCacheChecker.class); - - private AppManager appManager; - - private Set statuses = new HashSet<>(); - - private InstanceCacheSummary instanceCacheSummary = new InstanceCacheSummary(); - - public InstanceCacheChecker(AppManager appManager) { - this.appManager = appManager; - } - - public InstanceCacheSummary check() { - instanceCacheSummary.setAppId(RegistryUtils.getMicroservice().getAppId()); - instanceCacheSummary.setMicroserviceName(RegistryUtils.getMicroservice().getServiceName()); - instanceCacheSummary.setTimestamp(System.currentTimeMillis()); - - for (MicroserviceManager microserviceManager : appManager.getApps().values()) { - for (MicroserviceVersions microserviceVersions : microserviceManager.getVersionsByName().values()) { - InstanceCacheResult instanceCacheResult = check(microserviceVersions); - addInstanceCacheResult(instanceCacheResult); - } - } - - generateStatus(); - - return instanceCacheSummary; - } - - private void addInstanceCacheResult(InstanceCacheResult instanceCacheResult) { - statuses.add(instanceCacheResult.getStatus()); - instanceCacheSummary.getProducers().add(instanceCacheResult); - } - - protected InstanceCacheResult check(MicroserviceVersions microserviceVersions) { - InstanceCacheResult instanceCacheResult = new InstanceCacheResult(); - instanceCacheResult.setAppId(microserviceVersions.getAppId()); - instanceCacheResult.setMicroserviceName(microserviceVersions.getMicroserviceName()); - - MicroserviceInstances microserviceInstances = RegistryUtils - .findServiceInstances(microserviceVersions.getAppId(), - microserviceVersions.getMicroserviceName(), - DefinitionConst.VERSION_RULE_ALL, - null); - if (microserviceInstances == null) { - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail("failed to find instances from service center"); - return instanceCacheResult; - } - if (microserviceInstances.isMicroserviceNotExist()) { - // no problem, will be deleted from MicroserviceManager in next pull - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail("microservice is not exist anymore, will be deleted from memory in next pull"); - return instanceCacheResult; - } - - if (!Objects.equals(microserviceInstances.getRevision(), microserviceVersions.getRevision())) { - // maybe not pull, wait for next pull we get the same revision - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail(String.format( - "revision is different, will be synchronized in next pull. local revision=%s, remote revision=%s", - microserviceVersions.getRevision(), microserviceInstances.getRevision())); - return instanceCacheResult; - } - - // compare all instances - List remoteInstances = microserviceInstances.getInstancesResponse().getInstances(); -// if (RandomUtils.nextInt(0, 2) == 0) { -// MicroserviceInstance microserviceInstance = new MicroserviceInstance(); -// microserviceInstance.setInstanceId("abc"); -// remoteInstances.add(microserviceInstance); -// } - remoteInstances.sort(Comparator.comparing(MicroserviceInstance::getInstanceId)); - String local = Json.encode(microserviceVersions.getPulledInstances()); - String remote = Json.encode(remoteInstances); - if (local.equals(remote)) { - instanceCacheResult.setStatus(Status.NORMAL); - return instanceCacheResult; - } - - LOGGER.error("instance cache not match. appId={}, microservice={}.\n" - + "local cache: {}\n" - + "remote cache: {}", - microserviceVersions.getAppId(), - microserviceVersions.getMicroserviceName(), - local, - remote); - instanceCacheResult.setStatus(Status.ABNORMAL); - instanceCacheResult.setDetail("instance cache not match"); - - // auto fix, will do a full pull request when invoke MicroserviceVersions.pullInstances - microserviceVersions.setRevision(null); - - return instanceCacheResult; - } - - protected void generateStatus() { - if (statuses.contains(Status.ABNORMAL)) { - instanceCacheSummary.setStatus(Status.ABNORMAL); - } else if (statuses.contains(Status.UNKNOWN)) { - instanceCacheSummary.setStatus(Status.UNKNOWN); - } else { - instanceCacheSummary.setStatus(Status.NORMAL); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheResult.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheResult.java deleted file mode 100644 index a5ae3de639c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheResult.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import org.apache.servicecomb.serviceregistry.diagnosis.Status; - -public class InstanceCacheResult { - // producer appId and microserviceName - private String appId; - - private String microserviceName; - - private Status status; - - private String detail; - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public void setMicroserviceName(String microserviceName) { - this.microserviceName = microserviceName; - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public String getDetail() { - return detail; - } - - public void setDetail(String detail) { - this.detail = detail; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheSummary.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheSummary.java deleted file mode 100644 index 9a02cf8fc48..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheSummary.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.diagnosis.Status; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public class InstanceCacheSummary { - // consumer appId and microserviceName - @JsonIgnore - private String appId; - - @JsonIgnore - private String microserviceName; - - private Status status; - - private List producers = new ArrayList<>(); - - private long timestamp; - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public void setMicroserviceName(String microserviceName) { - this.microserviceName = microserviceName; - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public List getProducers() { - return producers; - } - - public void setProducers(List producers) { - this.producers = producers; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractDiscoveryFilter.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractDiscoveryFilter.java deleted file mode 100644 index f5cb20203ad..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractDiscoveryFilter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -public abstract class AbstractDiscoveryFilter implements DiscoveryFilter { - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - if (!parent.childrenInited()) { - synchronized (parent) { - if (!parent.childrenInited()) { - init(context, parent); - parent.childrenInited(true); - } - } - } - - String childName = findChildName(context, parent); - return parent.child(childName); - } - - protected abstract void init(DiscoveryContext context, DiscoveryTreeNode parent); - - protected abstract String findChildName(DiscoveryContext context, DiscoveryTreeNode parent); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractEndpointDiscoveryFilter.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractEndpointDiscoveryFilter.java deleted file mode 100644 index dd471af8e45..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/AbstractEndpointDiscoveryFilter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractEndpointDiscoveryFilter implements DiscoveryFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractEndpointDiscoveryFilter.class); - - private static final String ALL_TRANSPORT = ""; - - @Override - public boolean isGroupingFilter() { - return true; - } - - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - String expectTransportName = findTransportName(context, parent); - return parent.children() - .computeIfAbsent(expectTransportName, etn -> createDiscoveryTreeNode(expectTransportName, context, parent)); - } - - @SuppressWarnings("unchecked") - protected DiscoveryTreeNode createDiscoveryTreeNode(String expectTransportName, DiscoveryContext context, - DiscoveryTreeNode parent) { - List endpoints = new ArrayList<>(); - for (MicroserviceInstance instance : ((Map) parent.data()).values()) { - for (String endpoint : instance.getEndpoints()) { - try { - URI uri = URI.create(endpoint); - String transportName = uri.getScheme(); - if (!isTransportNameMatch(transportName, expectTransportName)) { - continue; - } - - Object objEndpoint = createEndpoint(transportName, endpoint, instance); - if (objEndpoint == null) { - continue; - } - - endpoints.add(objEndpoint); - } catch (Exception e) { - LOGGER.warn("unrecognized address find, ignore {}.", endpoint); - } - } - } - - return new DiscoveryTreeNode() - .subName(parent, expectTransportName) - .data(endpoints); - } - - protected boolean isTransportNameMatch(String transportName, String expectTransportName) { - return ALL_TRANSPORT.equals(expectTransportName) || transportName.equals(expectTransportName); - } - - protected abstract String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent); - - protected abstract Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryFilter.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryFilter.java deleted file mode 100644 index 100fa0795f7..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -// filter is stateless -public interface DiscoveryFilter { - default boolean enabled() { - return true; - } - - int getOrder(); - - // grouping filter, means grouping instances to some groups - // eg: operation/ZoneAware/transport - default boolean isGroupingFilter() { - return false; - } - - DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java deleted file mode 100644 index 7158913c3a1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * help to understand DiscoveryTree - *
- * DiscoveryTree is used to:
- * 1.get all instances by app/microserviceName/versionRule
- * 2.filter all instances set, and output another set, the output set is instance or something else, this depend on filter set
- *
- * DiscoveryFilter have different types:
- * 1.normal filter: just filter input set
- * 2.grouping filter: will split input set to groups
- * 3.convert filter: eg: convert from instance to endpoint
- * different types can composite in one filter
- *
- * features:
- * 1.every group combination(eg:1.0.0-2.0.0/1.0.0+/self/RESTful) relate to a loadBalancer instance
- * 2.if some filter output set is empty, DiscoveryTree can support try refilter logic
- *   eg: if there is no available instances in self AZ, can refilter in other AZ
- *   red arrows in help to understand DiscoveryTree, show the refilter logic
- * 3.every filter must try to cache result, avoid calculate every time.
- *
- * usage:
- * 1.declare a field: DiscoveryTree discoveryTree = new DiscoveryTree();
- * 2.initialize:
- *     discoveryTree.loadFromSPI(DiscoveryFilter.class);
- *     // add filters by your requirement
- *     discoveryTree.addFilter(new EndpointDiscoveryFilter());
- *     discoveryTree.sort();
- * 3.filter for a invocation:
- *     DiscoveryContext context = new DiscoveryContext();
- *     context.setInputParameters(invocation);
- *     VersionedCache endpointsVersionedCache = discoveryTree.discovery(context,
- *         invocation.getAppId(),
- *         invocation.getMicroserviceName(),
- *         invocation.getMicroserviceVersionRule());
- *     if (endpointsVersionedCache.isEmpty()) {
- *       // 404 not found logic
- *       ......
- *       return;
- *     }
- *
- *     // result is endpoints or something else, which is depends on your filter set
- *     List<Endpoint> endpoints = endpointsVersionedCache.data();
- *
- */ -public class DiscoveryTree { - private static final Logger LOGGER = LoggerFactory.getLogger(DiscoveryTree.class); - - private volatile DiscoveryTreeNode root; - - private final Object lock = new Object(); - - private List filters = new ArrayList<>(); - - public void loadFromSPI(Class cls) { - filters.addAll(SPIServiceUtils.getSortedService(cls)); - } - - public void addFilter(DiscoveryFilter filter) { - filters.add(filter); - } - - // group name are qualifiedName - // all leaf group will create a loadbalancer instance, groupName is loadBalancer key - public void sort() { - filters.sort(Comparator.comparingInt(DiscoveryFilter::getOrder)); - - Iterator iterator = filters.iterator(); - while (iterator.hasNext()) { - DiscoveryFilter filter = iterator.next(); - if (!filter.enabled()) { - iterator.remove(); - } - LOGGER.info("DiscoveryFilter {}, enabled {}.", filter.getClass().getName(), filter.enabled()); - } - } - - protected boolean isMatch(VersionedCache existing, VersionedCache inputCache) { - return existing != null && existing.isSameVersion(inputCache); - } - - protected boolean isExpired(VersionedCache existing, VersionedCache inputCache) { - return existing == null || existing.isExpired(inputCache); - } - - public DiscoveryTreeNode discovery(DiscoveryContext context, String appId, String microserviceName, - String versionRule) { - VersionedCache instanceVersionedCache = RegistryUtils - .getServiceRegistry() - .getInstanceCacheManager() - .getOrCreateVersionedCache(appId, microserviceName, versionRule); - - return discovery(context, instanceVersionedCache); - } - - public DiscoveryTreeNode discovery(DiscoveryContext context, VersionedCache inputCache) { - DiscoveryTreeNode tmpRoot = getOrCreateRoot(inputCache); - DiscoveryTreeNode parent = tmpRoot.children() - .computeIfAbsent(inputCache.name(), name -> new DiscoveryTreeNode().fromCache(inputCache)); - return doDiscovery(context, parent); - } - - protected DiscoveryTreeNode getOrCreateRoot(VersionedCache inputCache) { - DiscoveryTreeNode tmpRoot = root; - if (isMatch(tmpRoot, inputCache)) { - return tmpRoot; - } - - synchronized (lock) { - if (isExpired(root, inputCache)) { - // not initialized or inputCache newer than root, create new root - root = new DiscoveryTreeNode().cacheVersion(inputCache.cacheVersion()); - return root; - } - - if (root.isSameVersion(inputCache)) { - // reuse root directly - return root; - } - } - - // root newer than inputCache, it's a minimal probability event: - // 1) thread 1, use v1 inputCache, run into getOrCreateRoot, but did not run any code yet, suspend and switch to thread 2 - // 2) thread 2, use v2 inputCache, v2 > v1, create new root - // 3) thread 1 go on, then root is newer than inputCache - // but if create old children in new version root, it's a wrong logic - // so just create a temporary root for the inputCache, DO NOT assign to root - return new DiscoveryTreeNode().cacheVersion(inputCache.cacheVersion()); - } - - protected DiscoveryTreeNode doDiscovery(DiscoveryContext context, DiscoveryTreeNode parent) { - for (int idx = 0; idx < filters.size(); ) { - DiscoveryFilter filter = filters.get(idx); - context.setCurrentNode(parent); - - DiscoveryTreeNode child = filter.discovery(context, parent); - if (child == null) { - // impossible, throw exception to help fix bug - throw new ServiceCombException(filter.getClass().getName() + " discovery return null."); - } - - child.level(idx + 1); - if (!filter.isGroupingFilter()) { - child.name(parent.name()); - } - - if (child.isEmpty()) { - // maybe need to rerun some filter - DiscoveryTreeNode rerunNode = context.popRerunFilter(); - if (rerunNode != null) { - parent = rerunNode; - idx = parent.level(); - continue; - } - - // no rerun support, go on even result is empty - // because maybe some filter use other mechanism to create a instance(eg:domain name) - } - - parent = child; - idx++; - } - - return parent; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java deleted file mode 100644 index 4f658211405..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.registry; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_DEFAULT_REGISTER_BY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_FRAMEWORK_DEFAULT_NAME; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.servicecomb.serviceregistry.Features; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.BasePath; -import org.apache.servicecomb.serviceregistry.api.registry.Framework; -import org.apache.servicecomb.serviceregistry.api.registry.FrameworkVersions; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionFactory; -import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersions; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask; -import org.apache.servicecomb.serviceregistry.task.ServiceCenterTask; -import org.apache.servicecomb.serviceregistry.task.event.ShutdownEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; - -public abstract class AbstractServiceRegistry implements ServiceRegistry { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServiceRegistry.class); - - private Features features = new Features(); - - private MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - - protected EventBus eventBus; - - protected MicroserviceDefinition microserviceDefinition; - - protected Microservice microservice; - - protected AppManager appManager; - - protected InstanceCacheManager instanceCacheManager; - - protected IpPortManager ipPortManager; - - protected ServiceRegistryClient srClient; - - protected ServiceRegistryConfig serviceRegistryConfig; - - protected ServiceCenterTask serviceCenterTask; - - public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - this.eventBus = eventBus; - this.serviceRegistryConfig = serviceRegistryConfig; - this.microserviceDefinition = microserviceDefinition; - this.microservice = microserviceFactory.create(microserviceDefinition); - } - - @Override - public void init() { - try { - initAppManager(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new IllegalStateException("Failed to init appManager.", e); - } - - initCacheManager(); - - ipPortManager = new IpPortManager(serviceRegistryConfig, instanceCacheManager); - if (srClient == null) { - srClient = createServiceRegistryClient(); - } - - createServiceCenterTask(); - - eventBus.register(this); - } - - protected void initAppManager() throws InstantiationException, IllegalAccessException, ClassNotFoundException { - appManager = new AppManager(eventBus); - - // we did not remove old InstanceCacheManager now - // microserviceVersionFactoryClass is null, means use old InstanceCacheManager - // must not throw exception - String microserviceVersionFactoryClass = serviceRegistryConfig.getMicroserviceVersionFactory(); - if (microserviceVersionFactoryClass == null) { - return; - } - - MicroserviceVersionFactory microserviceVersionFactory = - (MicroserviceVersionFactory) Class.forName(microserviceVersionFactoryClass).newInstance(); - appManager.setMicroserviceVersionFactory(microserviceVersionFactory); - LOGGER.info("microserviceVersionFactory is {}.", microserviceVersionFactoryClass); - } - - protected void initCacheManager() { - instanceCacheManager = new InstanceCacheManagerNew(appManager); - } - - @Override - public AppManager getAppManager() { - return appManager; - } - - @Override - public Features getFeatures() { - return features; - } - - public EventBus getEventBus() { - return eventBus; - } - - @Override - public Set getCombinedMicroserviceNames() { - return microserviceDefinition.getCombinedFrom(); - } - - @Override - public ServiceRegistryClient getServiceRegistryClient() { - return srClient; - } - - public void setServiceRegistryClient(ServiceRegistryClient serviceRegistryClient) { - this.srClient = serviceRegistryClient; - } - - public IpPortManager getIpPortManager() { - return ipPortManager; - } - - @Override - public InstanceCacheManager getInstanceCacheManager() { - return instanceCacheManager; - } - - protected abstract ServiceRegistryClient createServiceRegistryClient(); - - @Override - public void run() { - loadStaticConfiguration(); - - loadFrameworkVersions(); - // try register - // if failed, then retry in thread - serviceCenterTask.init(); - } - - private void loadFrameworkVersions() { - Framework framework = new Framework(); - framework.setName(CONFIG_FRAMEWORK_DEFAULT_NAME); - framework.setVersion(FrameworkVersions.allVersions()); - microservice.setFramework(framework); - microservice.setRegisterBy(CONFIG_DEFAULT_REGISTER_BY); - } - - private void loadStaticConfiguration() { - // TODO 如果yaml定义了paths规则属性,替换默认值,现需要DynamicPropertyFactory支持数组获取 - List paths = microservice.getPaths(); - for (BasePath path : paths) { - if (path.getProperty() == null) { - path.setProperty(new HashMap<>()); - } - path.getProperty().put(Const.PATH_CHECKSESSION, "false"); - } - } - - private void createServiceCenterTask() { - MicroserviceServiceCenterTask task = - new MicroserviceServiceCenterTask(eventBus, serviceRegistryConfig, srClient, microservice); - serviceCenterTask = new ServiceCenterTask(eventBus, serviceRegistryConfig.getHeartbeatInterval(), task); - } - - public boolean unregisterInstance() { - MicroserviceInstance microserviceInstance = microservice.getInstance(); - if (microserviceInstance.getInstanceId() == null || microserviceInstance.getServiceId() == null) { - return true; - } - boolean result = srClient.unregisterMicroserviceInstance(microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId()); - if (!result) { - LOGGER.error("Unregister microservice instance failed. microserviceId={} instanceId={}", - microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId()); - return false; - } - LOGGER.info("Unregister microservice instance success. microserviceId={} instanceId={}", - microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId()); - return true; - } - - public List findServiceInstance(String appId, String serviceName, - String versionRule) { - MicroserviceInstances instances = findServiceInstances(appId, serviceName, versionRule, null); - if (instances == null || instances.isMicroserviceNotExist()) { - return null; - } - return instances.getInstancesResponse().getInstances(); - } - - public MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - MicroserviceInstances microserviceInstances = srClient.findServiceInstances(microservice.getServiceId(), - appId, - serviceName, - versionRule, - revision); - - if (microserviceInstances == null) { - LOGGER.error("Can not find any instances from service center due to previous errors. service={}/{}/{}", - appId, - serviceName, - versionRule); - return null; - } - - if (microserviceInstances.isMicroserviceNotExist()) { - return microserviceInstances; - } - - if (!microserviceInstances.isNeedRefresh()) { - LOGGER.debug("instances revision is not changed, service={}/{}/{}", appId, serviceName, versionRule); - return microserviceInstances; - } - - List instances = microserviceInstances.getInstancesResponse().getInstances(); - LOGGER.info("find instances[{}] from service center success. service={}/{}/{}, old revision={}, new revision={}", - instances.size(), - appId, - serviceName, - versionRule, - revision, - microserviceInstances.getRevision()); - for (MicroserviceInstance instance : instances) { - LOGGER.info("service id={}, instance id={}, endpoints={}", - instance.getServiceId(), - instance.getInstanceId(), - instance.getEndpoints()); - } - return microserviceInstances; - } - - @Override - public boolean updateMicroserviceProperties(Map properties) { - boolean success = srClient.updateMicroserviceProperties(microservice.getServiceId(), - properties); - if (success) { - microservice.setProperties(properties); - } - return success; - } - - public boolean updateInstanceProperties(Map instanceProperties) { - MicroserviceInstance microserviceInstance = microservice.getInstance(); - boolean success = srClient.updateInstanceProperties(microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId(), - instanceProperties); - if (success) { - microserviceInstance.setProperties(instanceProperties); - } - return success; - } - - public Microservice getRemoteMicroservice(String microserviceId) { - return srClient.getMicroservice(microserviceId); - } - - @Override - public Microservice getAggregatedRemoteMicroservice(String microserviceId) { - return srClient.getAggregatedMicroservice(microserviceId); - } - - public Microservice getMicroservice() { - return microservice; - } - - public MicroserviceInstance getMicroserviceInstance() { - return microservice.getInstance(); - } - - public void destroy() { - eventBus.post(new ShutdownEvent()); - unregisterInstance(); - } - - @Override - public void registerMicroserviceMapping(String microserviceName, String version, - List instances, Class schemaIntfCls) { - String app = RegistryUtils.getAppId(); - MicroserviceManager microserviceManager = appManager.getOrCreateMicroserviceManager(app); - microserviceManager.getVersionsByName() - .computeIfAbsent(microserviceName, - svcName -> { - StaticMicroserviceVersions microserviceVersions = new StaticMicroserviceVersions(this.appManager, - app, microserviceName, schemaIntfCls); - microserviceVersions.addInstances(version, instances); - return microserviceVersions; - }); - } - - @Override - public void registerMicroserviceMappingByEndpoints(String microserviceName, String version, - List endpoints, Class schemaIntfCls) { - ArrayList microserviceInstances = new ArrayList<>(); - for (String endpoint : endpoints) { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setEndpoints(Collections.singletonList(endpoint)); - microserviceInstances.add(instance); - } - - registerMicroserviceMapping(microserviceName, version, microserviceInstances, schemaIntfCls); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/LocalServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/LocalServiceRegistry.java deleted file mode 100644 index 7c3f32ab591..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/LocalServiceRegistry.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.registry; - -import org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; - -import com.google.common.eventbus.EventBus; - -public class LocalServiceRegistry extends AbstractServiceRegistry { - public LocalServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - super(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - protected ServiceRegistryClient createServiceRegistryClient() { - return new LocalServiceRegistryClientImpl(); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java deleted file mode 100644 index 1dc0be82005..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.registry; - -import java.util.List; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.task.HeartbeatResult; -import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceHeartbeatTask; -import org.apache.servicecomb.serviceregistry.task.event.PeriodicPullEvent; -import org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent; -import org.apache.servicecomb.serviceregistry.task.event.ShutdownEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -public class RemoteServiceRegistry extends AbstractServiceRegistry { - private static final Logger LOGGER = LoggerFactory.getLogger(RemoteServiceRegistry.class); - - private ScheduledThreadPoolExecutor taskPool; - - private List taskInitializers = SPIServiceUtils - .getOrLoadSortedService(ServiceRegistryTaskInitializer.class); - - public RemoteServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - super(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - @Override - public void init() { - super.init(); - taskPool = new ScheduledThreadPoolExecutor(2, - task -> new Thread(task, "Service Center Task"), - (task, executor) -> LOGGER.warn("Too many pending tasks, reject " + task.getClass().getName()) - ); - } - - @Override - protected ServiceRegistryClient createServiceRegistryClient() { - return new ServiceRegistryClientImpl(ipPortManager); - } - - @Subscribe - public void onShutdown(ShutdownEvent event) { - LOGGER.info("service center task is shutdown."); - taskPool.shutdownNow(); - } - - @Override - public void run() { - super.run(); - - taskPool.scheduleAtFixedRate(serviceCenterTask, - serviceRegistryConfig.getHeartbeatInterval(), - serviceRegistryConfig.getHeartbeatInterval(), - TimeUnit.SECONDS); - - taskPool.scheduleAtFixedRate( - () -> eventBus.post(new PeriodicPullEvent()), - serviceRegistryConfig.getInstancePullInterval(), - serviceRegistryConfig.getInstancePullInterval(), - TimeUnit.SECONDS); - - for (ServiceRegistryTaskInitializer initializer : taskInitializers) { - initializer.init(this); - } - } - - @Subscribe - public void onPullMicroserviceVersionsInstancesEvent(PullMicroserviceVersionsInstancesEvent event) { - taskPool.schedule(event.getMicroserviceVersions()::pullInstances, event.getMsDelay(), TimeUnit.MILLISECONDS); - } - - @Subscribe - public void onMicroserviceHeartbeatTask(MicroserviceInstanceHeartbeatTask event) { - if (HeartbeatResult.SUCCESS.equals(event.getHeartbeatResult())) { - ipPortManager.initAutoDiscovery(); - } - } - - public ScheduledThreadPoolExecutor getTaskPool() { - return this.taskPool; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java deleted file mode 100644 index a5d07ed6360..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.registry; - -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import com.google.common.eventbus.EventBus; - -/** - * Created by on 2017/3/31. - */ -public final class ServiceRegistryFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryFactory.class); - - private static final Object LOCK = new Object(); - - private static volatile ServiceRegistry serviceRegistry; - - private ServiceRegistryFactory() { - } - - public static ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - - public static ServiceRegistry getOrCreate(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - if (serviceRegistry == null) { - synchronized (LOCK) { - if (serviceRegistry == null) { - serviceRegistry = create(eventBus, serviceRegistryConfig, microserviceDefinition); - } - } - } - return serviceRegistry; - } - - public static ServiceRegistry createLocal() { - EventBus eventBus = new EventBus(); - ServiceRegistryConfig serviceRegistryConfig = ServiceRegistryConfig.INSTANCE; - MicroserviceConfigLoader loader = new MicroserviceConfigLoader(); - loader.loadAndSort(); - - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels()); - return new LocalServiceRegistry(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - public static ServiceRegistry create(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - String localModeFile = System.getProperty(LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY); - if (!StringUtils.isEmpty(localModeFile)) { - LOGGER.info( - "It is running in the local development mode, the local file {} is using as the local registry", - localModeFile); - - return new LocalServiceRegistry(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - LOGGER.info("It is running in the normal mode, a separated service registry is required"); - return new RemoteServiceRegistry(eventBus, serviceRegistryConfig, microserviceDefinition); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryTaskInitializer.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryTaskInitializer.java deleted file mode 100644 index 21cd84258e0..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryTaskInitializer.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.registry; - -public interface ServiceRegistryTaskInitializer { - default int getOrder() { - return 0; - } - - void init(RemoteServiceRegistry remoteServiceRegistry); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractRegisterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractRegisterTask.java deleted file mode 100644 index 5e1eb5d0e17..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractRegisterTask.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; - -import com.google.common.eventbus.EventBus; - -public abstract class AbstractRegisterTask extends AbstractTask { - protected boolean registered; - - public AbstractRegisterTask(EventBus eventBus, ServiceRegistryClient srClient, Microservice microservice) { - super(eventBus, srClient, microservice); - } - - public boolean isRegistered() { - return registered; - } - - @Override - public void doRun() { - if (registered) { - return; - } - - if (doRegister()) { - registered = true; - taskStatus = TaskStatus.FINISHED; - } - } - - protected abstract boolean doRegister(); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractTask.java deleted file mode 100644 index 272e414fd27..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/AbstractTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; - -import com.google.common.eventbus.EventBus; - -public abstract class AbstractTask implements Runnable { - protected TaskStatus taskStatus = TaskStatus.INIT; - - protected EventBus eventBus; - - protected ServiceRegistryClient srClient; - - protected Microservice microservice; - - public AbstractTask(EventBus eventBus, ServiceRegistryClient srClient, Microservice microservice) { - this.eventBus = eventBus; - this.srClient = srClient; - this.microservice = microservice; - - this.eventBus.register(this); - } - - public EventBus getEventBus() { - return eventBus; - } - - public Microservice getMicroservice() { - return microservice; - } - - @Override - public void run() { - if (taskStatus == TaskStatus.READY) { - // if this task is actually run, we send a notification - doRun(); - eventBus.post(this); - } - } - - - public TaskStatus getTaskStatus() { - return this.taskStatus; - } - - abstract protected void doRun(); - - protected boolean isSameMicroservice(Microservice otherMicroservice) { - return microservice.getServiceName().equals(otherMicroservice.getServiceName()); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/CompositeTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/CompositeTask.java deleted file mode 100644 index 01c5ed1bdd1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/CompositeTask.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import java.util.ArrayList; -import java.util.List; - -public class CompositeTask implements Runnable { - private List taskList = new ArrayList<>(); - - public void addTask(Runnable task) { - taskList.add(task); - } - - public int getTaskCount() { - return taskList.size(); - } - - public void run() { - for (Runnable task : taskList) { - task.run(); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/HeartbeatResult.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/HeartbeatResult.java deleted file mode 100644 index 11815176c12..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/HeartbeatResult.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -public enum HeartbeatResult { - DISCONNECTED, - SUCCESS, - INSTANCE_NOT_REGISTERED -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceHeartbeatTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceHeartbeatTask.java deleted file mode 100644 index 136c6abea1a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceHeartbeatTask.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.task.event.HeartbeatFailEvent; -import org.apache.servicecomb.serviceregistry.task.event.HeartbeatSuccEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -public class MicroserviceInstanceHeartbeatTask extends AbstractTask { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceInstanceHeartbeatTask.class); - - private MicroserviceInstance microserviceInstance; - - private HeartbeatResult heartbeatResult; - - public MicroserviceInstanceHeartbeatTask(EventBus eventBus, ServiceRegistryClient srClient, - Microservice microservice) { - super(eventBus, srClient, microservice); - this.microserviceInstance = microservice.getInstance(); - } - - @Subscribe - public void onMicroserviceWatchTask(MicroserviceWatchTask task) { - if (task.taskStatus == TaskStatus.READY && isSameMicroservice(task.getMicroservice())) { - this.taskStatus = TaskStatus.READY; - } - } - - public HeartbeatResult getHeartbeatResult() { - return heartbeatResult; - } - - // only got service center response, and result is not ok, means need to register instance again. - public boolean isNeedRegisterInstance() { - return HeartbeatResult.INSTANCE_NOT_REGISTERED.equals(heartbeatResult); - } - - @Override - public void doRun() { - // will always run heartbeat when it is ready - heartbeatResult = heartbeat(); - } - - private HeartbeatResult heartbeat() { - HeartbeatResponse response = - srClient.heartbeat(microserviceInstance.getServiceId(), microserviceInstance.getInstanceId()); - if (response == null) { - LOGGER.error("Disconnected from service center and heartbeat failed for microservice instance={}/{}", - microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId()); - EventManager.post(new HeartbeatFailEvent()); - return HeartbeatResult.DISCONNECTED; - } - - if (!response.isOk()) { - LOGGER.error("Update heartbeat to service center failed, microservice instance={}/{} does not exist", - microserviceInstance.getServiceId(), - microserviceInstance.getInstanceId()); - EventManager.post(new HeartbeatFailEvent()); - return HeartbeatResult.INSTANCE_NOT_REGISTERED; - } - EventManager.post(new HeartbeatSuccEvent()); - return HeartbeatResult.SUCCESS; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java deleted file mode 100644 index f0132b6359c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -public class MicroserviceInstanceRegisterTask extends AbstractRegisterTask { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceInstanceRegisterTask.class); - - private ServiceRegistryConfig serviceRegistryConfig; - - private MicroserviceInstance microserviceInstance; - - public MicroserviceInstanceRegisterTask(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - ServiceRegistryClient srClient, - Microservice microservice) { - super(eventBus, srClient, microservice); - - this.serviceRegistryConfig = serviceRegistryConfig; - this.microserviceInstance = microservice.getInstance(); - } - - @Subscribe - public void onMicroserviceRegisterTask(MicroserviceRegisterTask task) { - if (task.taskStatus == TaskStatus.FINISHED && isSameMicroservice(task.getMicroservice())) { - this.taskStatus = TaskStatus.READY; - this.registered = false; - } else { - this.taskStatus = TaskStatus.INIT; - } - } - - @Override - protected boolean doRegister() { - LOGGER.info("running microservice instance register task."); - String hostName = ""; - if (serviceRegistryConfig.isPreferIpAddress()) { - hostName = RegistryUtils.getPublishAddress(); - } else { - hostName = RegistryUtils.getPublishHostName(); - } - microserviceInstance.setHostName(hostName); - microserviceInstance.getHealthCheck().setInterval(serviceRegistryConfig.getHeartbeatInterval()); - microserviceInstance.getHealthCheck().setTimes(serviceRegistryConfig.getResendHeartBeatTimes()); - - String instanceId = srClient.registerMicroserviceInstance(microserviceInstance); - if (StringUtils.isEmpty(instanceId)) { - LOGGER.error("Register microservice instance failed,will back to register microservice again. microserviceId={}", - microserviceInstance.getServiceId()); - return false; - } - microserviceInstance.setInstanceId(instanceId); - LOGGER.info( - "Register microservice instance success. microserviceId={} instanceId={} endpoints={} lease {}s", - microserviceInstance.getServiceId(), - instanceId, - microserviceInstance.getEndpoints(), - microserviceInstance.getHealthCheck().getTTL()); - - return true; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java deleted file mode 100644 index 35ee1e6361e..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.base.ServiceCombConstants; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.Holder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; -import org.apache.commons.lang3.StringUtils; - -public class MicroserviceRegisterTask extends AbstractRegisterTask { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceRegisterTask.class); - - private boolean schemaIdSetMatch; - - public MicroserviceRegisterTask(EventBus eventBus, ServiceRegistryClient srClient, Microservice microservice) { - super(eventBus, srClient, microservice); - this.taskStatus = TaskStatus.READY; - } - - public boolean isSchemaIdSetMatch() { - return schemaIdSetMatch; - } - - @Subscribe - public void onMicroserviceInstanceHeartbeatTask(MicroserviceInstanceHeartbeatTask task) { - if (task.getHeartbeatResult() != HeartbeatResult.SUCCESS && isSameMicroservice(task.getMicroservice())) { - LOGGER.info("read MicroserviceInstanceHeartbeatTask status is {}", task.taskStatus); - this.taskStatus = TaskStatus.READY; - this.registered = false; - } - } - - @Subscribe - public void onInstanceRegistryFailed(MicroserviceInstanceRegisterTask task) { - if (task.taskStatus != TaskStatus.FINISHED) { - LOGGER.info("read MicroserviceInstanceRegisterTask status is {}", task.taskStatus); - this.taskStatus = TaskStatus.READY; - this.registered = false; - } - } - - @Override - protected boolean doRegister() { - LOGGER.info("running microservice register task."); - String serviceId = srClient.getMicroserviceId(microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment()); - if (!StringUtils.isEmpty(serviceId)) { - // This microservice has been registered, so we just use the serviceId gotten from service center - microservice.setServiceId(serviceId); - LOGGER.info( - "Microservice exists in service center, no need to register. id=[{}] appId=[{}], name=[{}], version=[{}], env=[{}]", - serviceId, - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment()); - - if (!checkSchemaIdSet()) { - return false; - } - } else { - serviceId = srClient.registerMicroservice(microservice); - if (StringUtils.isEmpty(serviceId)) { - LOGGER.error( - "Registry microservice failed. appId=[{}], name=[{}], version=[{}], env=[{}]", - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment()); - return false; - } - - // In re-register microservice case, the old instanceId should not be cached - microservice.getInstance().setInstanceId(null); - - LOGGER.info( - "Registry Microservice successfully. id=[{}] appId=[{}], name=[{}], version=[{}], schemaIds={}, env=[{}]", - serviceId, - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getSchemas(), - microservice.getEnvironment()); - } - - microservice.setServiceId(serviceId); - microservice.getInstance().setServiceId(microservice.getServiceId()); - - return registerSchemas(); - } - - private boolean checkSchemaIdSet() { - Microservice existMicroservice = srClient.getMicroservice(microservice.getServiceId()); - if (existMicroservice == null) { - LOGGER.error("Error to get microservice from service center when check schema set"); - return false; - } - Set existSchemas = new HashSet<>(existMicroservice.getSchemas()); - Set localSchemas = new HashSet<>(microservice.getSchemas()); - schemaIdSetMatch = existSchemas.equals(localSchemas); - - if (!schemaIdSetMatch) { - LOGGER.warn( - "SchemaIds is different between local and service center. " - + "serviceId=[{}] appId=[{}], name=[{}], version=[{}], env=[{}], local schemaIds={}, service center schemaIds={}", - microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment(), - localSchemas, - existSchemas); - return true; - } - - LOGGER.info( - "SchemaIds are equals to service center. serviceId=[{}], appId=[{}], name=[{}], version=[{}], env=[{}], schemaIds={}", - microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment(), - localSchemas); - return true; - } - - private boolean registerSchemas() { - Holder> scSchemaHolder = srClient.getSchemas(microservice.getServiceId()); - if (Status.OK.getStatusCode() != scSchemaHolder.getStatusCode()) { - LOGGER.error("failed to get schemas from service center, statusCode = [{}]", scSchemaHolder.getStatusCode()); - return false; - } - - Map scSchemaMap = convertScSchemaMap(scSchemaHolder); - // CHECK: local > sc, local != sc - for (Entry localSchemaEntry : microservice.getSchemaMap().entrySet()) { - if (!registerSchema(scSchemaMap, localSchemaEntry)) { - return false; - } - } - - // CHECK: local < sc - checkRemainingSchema(scSchemaMap); - - schemaIdSetMatch = true; - return true; - } - - /** - * Check whether a local schema is equal to a sc schema. - * @return true if the local schema is equal to a sc schema, or be registered to sc successfully; - * false if schema is registered to sc but failed. - * @throws IllegalStateException The environment is not modifiable, and the local schema is different from sc schema - * or not exist in sc. - */ - private boolean registerSchema(Map scSchemaMap, - Entry localSchemaEntry) { - GetSchemaResponse scSchema = scSchemaMap.get(localSchemaEntry.getKey()); - - boolean onlineSchemaExists = scSchema != null; - LOGGER.info("schemaId [{}] exists [{}], summary exists [{}]", - localSchemaEntry.getKey(), - onlineSchemaExists, - scSchema != null && scSchema.getSummary() != null); - if (!onlineSchemaExists) { - // local > sc - return registerNewSchema(localSchemaEntry); - } - - scSchemaMap.remove(localSchemaEntry.getKey()); - - // local != sc - return compareAndReRegisterSchema(localSchemaEntry, scSchema); - } - - /** - * Try to register a new schema to service center, or throw exception if cannot register. - * @param localSchemaEntry local schema to be registered. - * @return whether local schema is registered successfully. - * @throws IllegalStateException The environment is unmodifiable. - */ - private boolean registerNewSchema(Entry localSchemaEntry) { - // The ids of schemas are contained by microservice registry request, which means once a microservice - // is registered in the service center, the schemas that it contains are determined. - // If we get a microservice but cannot find the given schemaId in it's schemaId list, this means that - // the schemas of this microservice has been changed, and we should decide whether to register this new - // schema according to it's environment configuration. - if (onlineSchemaIsModifiable()) { - return registerSingleSchema(localSchemaEntry.getKey(), localSchemaEntry.getValue()); - } - - throw new IllegalStateException( - "There is a schema only existing in local microservice: [" + localSchemaEntry.getKey() - + "], which means there are interfaces changed. " - + "You need to increment microservice version before deploying, " - + "or you can configure service_description.environment=" - + ServiceCombConstants.DEVELOPMENT_SERVICECOMB_ENV - + " to work in development environment and ignore this error"); - } - - /** - * Compare schema summary and determine whether to re-register schema or throw exception. - * @param localSchemaEntry local schema - * @param scSchema schema in service center - * @return true if the two copies of schema are the same, or local schema is re-registered successfully, - * false if the local schema is re-registered to service center but failed. - * @throws IllegalStateException The two copies of schema are different and the environment is not modifiable. - */ - private boolean compareAndReRegisterSchema(Entry localSchemaEntry, GetSchemaResponse scSchema) { - String scSchemaSummary = getScSchemaSummary(scSchema); - - if (null == scSchemaSummary) { - // cannot get scSchemaSummary, which means there is no schema content in sc, register schema directly - return registerSingleSchema(localSchemaEntry.getKey(), localSchemaEntry.getValue()); - } - - String localSchemaSummary = RegistryUtils.calcSchemaSummary(localSchemaEntry.getValue()); - if (!localSchemaSummary.equals(scSchemaSummary)) { - if (onlineSchemaIsModifiable()) { - LOGGER.info( - "schema[{}]'s content is changed and the current environment is [{}], so re-register it!", - localSchemaEntry.getKey(), - ServiceCombConstants.DEVELOPMENT_SERVICECOMB_ENV); - return registerSingleSchema(localSchemaEntry.getKey(), localSchemaEntry.getValue()); - } - - //if local schema and service center schema is different then print the both schemas and print difference in local schema. - String scSchemaContent = srClient.getSchema(microservice.getServiceId(), scSchema.getSchemaId()); - String localSchemaContent = localSchemaEntry.getValue(); - - LOGGER.warn( - "service center schema and local schema both are different:\n service center schema:\n[{}\n local schema:\n[{}]", - scSchemaContent, - localSchemaContent); - String diffStringLocal = StringUtils.difference(scSchemaContent, localSchemaContent); - if (diffStringLocal.equals("")) { - LOGGER.warn("Some APIs are deleted in local schema which are present in service center schema \n"); - } else { - LOGGER.warn("The difference in local schema:\n[{}]", diffStringLocal); - } - - // env is not development, throw an exception and break the init procedure - throw new IllegalStateException( - "The schema(id=[" + localSchemaEntry.getKey() - + "]) content held by this instance and the service center is different. " - + "You need to increment microservice version before deploying. " - + "Or you can configure service_description.environment=" - + ServiceCombConstants.DEVELOPMENT_SERVICECOMB_ENV - + " to work in development environment and ignore this error"); - } - - // summaries are the same - return true; - } - - /** - * Try to get or calculate scSchema summary. - * @return summary of scSchema, - * or null if there is no schema content in service center - */ - private String getScSchemaSummary(GetSchemaResponse scSchema) { - String scSchemaSummary = scSchema.getSummary(); - if (null != scSchemaSummary) { - return scSchemaSummary; - } - - // if there is no online summery, query online schema content directly and calculate summary - String onlineSchemaContent = srClient.getSchema(microservice.getServiceId(), scSchema.getSchemaId()); - if (null != onlineSchemaContent) { - scSchemaSummary = RegistryUtils.calcSchemaSummary(onlineSchemaContent); - } - - return scSchemaSummary; - } - - /** - * Check whether there are schemas remaining in service center but not exist in local microservice. - * @throws IllegalStateException There are schemas only existing in service center, and the environment is unmodifiable. - */ - private void checkRemainingSchema(Map scSchemaMap) { - if (!scSchemaMap.isEmpty()) { - // there are some schemas only exist in service center - if (!onlineSchemaIsModifiable()) { - // env is not development, throw an exception and break the init procedure - throw new IllegalStateException("There are schemas only existing in service center: " + scSchemaMap.keySet() - + ", which means there are interfaces changed. " - + "You need to increment microservice version before deploying, " - + "or if service_description.environment=" - + ServiceCombConstants.DEVELOPMENT_SERVICECOMB_ENV - + ", you can delete microservice information in service center and restart this instance."); - } - - // Currently nothing to do but print a warning - LOGGER.warn("There are schemas only existing in service center: {}, which means there are interfaces changed. " - + "It's recommended to increment microservice version before deploying.", - scSchemaMap.keySet()); - LOGGER.warn("ATTENTION: The schemas in new version are less than the old version, " - + "which may cause compatibility problems."); - } - } - - private boolean onlineSchemaIsModifiable() { - return ServiceCombConstants.DEVELOPMENT_SERVICECOMB_ENV.equalsIgnoreCase(microservice.getEnvironment()); - } - - /** - * Register a schema directly. - * @return true if register success, otherwise false - */ - private boolean registerSingleSchema(String schemaId, String content) { - return srClient.registerSchema(microservice.getServiceId(), schemaId, content); - } - - private Map convertScSchemaMap(Holder> scSchemaHolder) { - Map scSchemaMap = new HashMap<>(); - List scSchemaList = scSchemaHolder.getValue(); - if (null == scSchemaList) { - return scSchemaMap; - } - - for (GetSchemaResponse scSchema : scSchemaList) { - scSchemaMap.put(scSchema.getSchemaId(), scSchema); - } - - return scSchemaMap; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceServiceCenterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceServiceCenterTask.java deleted file mode 100644 index 35b23ebd0e7..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceServiceCenterTask.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; - -import com.google.common.eventbus.EventBus; - -public class MicroserviceServiceCenterTask extends CompositeTask { - public MicroserviceServiceCenterTask(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - ServiceRegistryClient srClient, Microservice microservice) { - addTask(new MicroserviceRegisterTask(eventBus, srClient, microservice)); - addTask(new MicroserviceInstanceRegisterTask(eventBus, serviceRegistryConfig, srClient, microservice)); - addTask(new MicroserviceWatchTask(eventBus, serviceRegistryConfig, srClient, microservice)); - addTask(new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice)); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceWatchTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceWatchTask.java deleted file mode 100644 index ab613786ced..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceWatchTask.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.task.event.ExceptionEvent; -import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -public class MicroserviceWatchTask extends AbstractTask { - private static final Logger LOGGER = LoggerFactory.getLogger(MicroserviceWatchTask.class); - - private ServiceRegistryConfig serviceRegistryConfig; - - public MicroserviceWatchTask(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - ServiceRegistryClient srClient, Microservice microservice) { - super(eventBus, srClient, microservice); - this.serviceRegistryConfig = serviceRegistryConfig; - } - - @Subscribe - public void onMicroserviceInstanceRegisterTask(MicroserviceInstanceRegisterTask task) { - if (task.taskStatus == TaskStatus.FINISHED && isSameMicroservice(task.getMicroservice())) { - this.taskStatus = TaskStatus.READY; - } - } - - @Override - public void doRun() { - // will always run watch when it is ready - if (!needToWatch()) { - return; - } - - srClient.watch(microservice.getServiceId(), - (event) -> { - if (event.failed()) { - eventBus.post(new ExceptionEvent(event.cause())); - return; - } - - MicroserviceInstanceChangedEvent changedEvent = event.result(); - if (isProviderInstancesChanged(changedEvent) && !serviceRegistryConfig.isWatch()) { - return; - } - if (!isProviderInstancesChanged(changedEvent) - && !serviceRegistryConfig.isRegistryAutoDiscovery()) { - return; - } - - onMicroserviceInstanceChanged(changedEvent); - }, - open -> { - eventBus.post(new RecoveryEvent()); - }, - close -> { - }); - } - - private void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) { - switch (changedEvent.getAction()) { - case CREATE: - LOGGER.info("microservice {}/{}/{} REGISTERED an instance {}, {}.", - changedEvent.getKey().getAppId(), - changedEvent.getKey().getServiceName(), - changedEvent.getKey().getVersion(), - changedEvent.getInstance().getInstanceId(), - changedEvent.getInstance().getEndpoints()); - break; - case DELETE: - LOGGER.info("microservice {}/{}/{} UNREGISTERED an instance {}, {}.", - changedEvent.getKey().getAppId(), - changedEvent.getKey().getServiceName(), - changedEvent.getKey().getVersion(), - changedEvent.getInstance().getInstanceId(), - changedEvent.getInstance().getEndpoints()); - break; - case EXPIRE: - LOGGER.info("microservice {}/{} EXPIRE all instance.", - changedEvent.getKey().getAppId(), - changedEvent.getKey().getServiceName()); - break; - case UPDATE: - LOGGER.info("microservice {}/{}/{} UPDATE an instance {} status or metadata, {}.", - changedEvent.getKey().getAppId(), - changedEvent.getKey().getServiceName(), - changedEvent.getKey().getVersion(), - changedEvent.getInstance().getInstanceId(), - changedEvent.getInstance().getEndpoints()); - break; - default: - break; - } - - eventBus.post(changedEvent); - } - - private boolean needToWatch() { - return serviceRegistryConfig.isWatch(); - } - - private boolean isProviderInstancesChanged(MicroserviceInstanceChangedEvent changedEvent) { - return !Const.REGISTRY_APP_ID.equals(changedEvent.getKey().getAppId()) - && !Const.REGISTRY_SERVICE_NAME.equals(changedEvent.getKey().getServiceName()); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTask.java deleted file mode 100644 index 58f85d900a7..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTask.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.serviceregistry.task.event.ExceptionEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -public class ServiceCenterTask implements Runnable { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterTask.class); - - private EventBus eventBus; - - private int interval; - - private MicroserviceServiceCenterTask microserviceServiceCenterTask; - - private boolean registerInstanceSuccess = false; - - private ServiceCenterTaskMonitor serviceCenterTaskMonitor = new ServiceCenterTaskMonitor(); - - public ServiceCenterTask(EventBus eventBus, int interval, - MicroserviceServiceCenterTask microserviceServiceCenterTask) { - this.eventBus = eventBus; - this.interval = interval; - this.microserviceServiceCenterTask = microserviceServiceCenterTask; - - this.eventBus.register(this); - } - - // messages given in register error - @Subscribe - public void onRegisterTask(AbstractRegisterTask task) { - LOGGER.info("read {} status is {}", task.getClass().getSimpleName(), task.taskStatus); - if (task.getTaskStatus() == TaskStatus.FINISHED) { - registerInstanceSuccess = true; - } else { - onException(); - } - } - - // messages given in heartbeat - @Subscribe - public void onMicroserviceInstanceHeartbeatTask(MicroserviceInstanceHeartbeatTask task) { - if (task.getHeartbeatResult() != HeartbeatResult.SUCCESS) { - LOGGER.info("read MicroserviceInstanceHeartbeatTask status is {}", task.taskStatus); - onException(); - } - } - - // messages given in watch error - @Subscribe - public void onExceptionEvent(ExceptionEvent event) { - LOGGER.info("read exception event, message is :{}", event.getThrowable().getMessage()); - onException(); - } - - private void onException() { - if (registerInstanceSuccess) { - registerInstanceSuccess = false; - } - } - - public void init() { - microserviceServiceCenterTask.run(); - } - - @Override - public void run() { - try { - serviceCenterTaskMonitor.beginCycle(interval); - microserviceServiceCenterTask.run(); - serviceCenterTaskMonitor.endCycle(); - } catch (Throwable e) { - LOGGER.error("unexpected exception caught from service center task. ", e); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTaskMonitor.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTaskMonitor.java deleted file mode 100644 index 7faa91eb746..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/ServiceCenterTaskMonitor.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * monitor ServiceCenterTask status and print diagnosis data - */ -public class ServiceCenterTaskMonitor { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterTaskMonitor.class); - - private static final long MAX_TIME_TAKEN = 1000; - - private long beginTime = 0; - - private long lastEndTime = 0; - - private int interval = -1; - - public void beginCycle(int interval) { - this.beginTime = System.currentTimeMillis(); - if (this.interval != interval) { - LOGGER.info("sc task interval changed from {} to {}", this.interval, interval); - this.interval = interval; - } else { - if (this.beginTime - this.lastEndTime > interval * 1000 + MAX_TIME_TAKEN) { - LOGGER.warn("sc task postponed for {}ms for some reason.", this.beginTime - this.lastEndTime); - } - } - } - - public void endCycle() { - this.lastEndTime = System.currentTimeMillis(); - if (this.lastEndTime - this.beginTime > MAX_TIME_TAKEN) { - LOGGER.warn("sc task taken more than {}ms to execute", this.lastEndTime - this.beginTime); - } - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/TaskStatus.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/TaskStatus.java deleted file mode 100644 index b0958934719..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/TaskStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -public enum TaskStatus { - INIT, - READY, - FINISHED -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ExceptionEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ExceptionEvent.java deleted file mode 100644 index 46dc7d1ee30..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ExceptionEvent.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task.event; - -public class ExceptionEvent { - private Throwable throwable; - - public ExceptionEvent(Throwable throwable) { - this.throwable = throwable; - } - - public Throwable getThrowable() { - return throwable; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatFailEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatFailEvent.java deleted file mode 100644 index b5dd0333e0b..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatFailEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.task.event; - -/** - * Service Center Heart Beat failure event - * - */ -public class HeartbeatFailEvent { - -} - diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatSuccEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatSuccEvent.java deleted file mode 100644 index 70128452d98..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/HeartbeatSuccEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.task.event; - -/** - * Service Center Heart Beat success event - * - */ -public class HeartbeatSuccEvent { - -} - diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/MicroserviceNotExistEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/MicroserviceNotExistEvent.java deleted file mode 100644 index 2d8e00c976a..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/MicroserviceNotExistEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task.event; - -public class MicroserviceNotExistEvent { - private String appId; - - private String microserviceName; - - public MicroserviceNotExistEvent(String appId, String microserviceName) { - this.appId = appId; - this.microserviceName = microserviceName; - } - - public String getAppId() { - return appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public String getMicroserviceName() { - return microserviceName; - } - - public void setMicroserviceName(String microserviceName) { - this.microserviceName = microserviceName; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PeriodicPullEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PeriodicPullEvent.java deleted file mode 100644 index 72b6ffca7f7..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PeriodicPullEvent.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.task.event; - -public class PeriodicPullEvent { - -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PullMicroserviceVersionsInstancesEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PullMicroserviceVersionsInstancesEvent.java deleted file mode 100644 index cfc9a0ec545..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/PullMicroserviceVersionsInstancesEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.task.event; - -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; - -public class PullMicroserviceVersionsInstancesEvent { - private MicroserviceVersions microserviceVersions; - - private long msDelay; - - public PullMicroserviceVersionsInstancesEvent(MicroserviceVersions microserviceVersions, long msDelay) { - this.microserviceVersions = microserviceVersions; - this.msDelay = msDelay; - } - - public MicroserviceVersions getMicroserviceVersions() { - return microserviceVersions; - } - - public long getMsDelay() { - return msDelay; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/RecoveryEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/RecoveryEvent.java deleted file mode 100644 index 3fb6af9bb4c..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/RecoveryEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task.event; - -public class RecoveryEvent { - -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ShutdownEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ShutdownEvent.java deleted file mode 100644 index b4bab44f3ff..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/event/ShutdownEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task.event; - -public class ShutdownEvent { - -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRule.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRule.java deleted file mode 100644 index 9167dbf08d1..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRule.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -public abstract class VersionRule { - private final String versionRule; - - public VersionRule(String versionRule) { - this.versionRule = versionRule; - } - - public String getVersionRule() { - return versionRule; - } - - // equals isMatch except "latest" rule - public boolean isAccept(Version version) { - return isMatch(version, null); - } - - // latestVersion is only required for "latest" rule - // it's ugly, but simpler - public abstract boolean isMatch(Version version, Version latestVersion); - - @Override - public String toString() { - return versionRule; - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleFixedParser.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleFixedParser.java deleted file mode 100644 index 0a401b2f7ae..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleFixedParser.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -// fixed, this should be the last parser -// will not check version format -public class VersionRuleFixedParser implements VersionRuleParser { - class FixedVersionRule extends VersionRule { - private final Version version; - - public FixedVersionRule(String versionRule, Version version) { - super(versionRule); - - this.version = version; - } - - public boolean isMatch(Version version, Version latestVersion) { - return this.version.equals(version); - } - } - - @Override - public VersionRule parse(String strVersionRule) { - Version version = new Version(strVersionRule); - return new FixedVersionRule(version.getVersion(), version); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleLatestParser.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleLatestParser.java deleted file mode 100644 index eaf2280c3ee..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleLatestParser.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; - -public class VersionRuleLatestParser implements VersionRuleParser { - class LatestVersionRule extends VersionRule { - public LatestVersionRule(String versionRule) { - super(versionRule); - } - - @Override - public boolean isAccept(Version version) { - return true; - } - - public boolean isMatch(Version version, Version latestVersion) { - return version.equals(latestVersion); - } - } - - @Override - public VersionRule parse(String strVersionRule) { - if (!DefinitionConst.VERSION_RULE_LATEST.equals(strVersionRule)) { - return null; - } - - return new LatestVersionRule(strVersionRule); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleParser.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleParser.java deleted file mode 100644 index 7c109dc94de..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleParser.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -public interface VersionRuleParser { - // if can not parse, then return null - VersionRule parse(String strVersionRule); -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleRangeParser.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleRangeParser.java deleted file mode 100644 index c20b2b4a504..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleRangeParser.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -// 1.0.0-2.0.0 -public class VersionRuleRangeParser implements VersionRuleParser { - class RangeVersionRule extends VersionRule { - private final Version from; - - private final Version to; - - public RangeVersionRule(String versionRule, Version from, Version to) { - super(versionRule); - - this.from = from; - this.to = to; - } - - public boolean isMatch(Version version, Version latestVersion) { - return version.compareTo(from) >= 0 && version.compareTo(to) < 0; - } - } - - @Override - public VersionRule parse(String strVersionRule) { - int pos = strVersionRule.indexOf('-'); - if (pos <= 0 || pos == strVersionRule.length() - 1) { - return null; - } - - Version from = new Version(strVersionRule.substring(0, pos)); - Version to = new Version(strVersionRule.substring(pos + 1)); - return new RangeVersionRule(from.getVersion() + "-" + to.getVersion(), from, to); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleStartFromParser.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleStartFromParser.java deleted file mode 100644 index c8ab35387b2..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleStartFromParser.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -// 1.0.0+ -public class VersionRuleStartFromParser implements VersionRuleParser { - class StartFromVersionRule extends VersionRule { - private final Version from; - - public StartFromVersionRule(String versionRule, Version from) { - super(versionRule); - - this.from = from; - } - - public boolean isMatch(Version version, Version latestVersion) { - return version.compareTo(from) >= 0; - } - } - - @Override - public VersionRule parse(String strVersionRule) { - int pos = strVersionRule.indexOf('+'); - if (pos <= 0 || pos != strVersionRule.length() - 1) { - return null; - } - - Version from = new Version(strVersionRule.substring(0, pos)); - return new StartFromVersionRule(from.getVersion() + "+", from); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleUtils.java deleted file mode 100644 index f8d512e9111..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionRuleUtils.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; - -public final class VersionRuleUtils { - private static List parsers = new ArrayList<>(); - - private static Map versionRuleCache = new ConcurrentHashMapEx<>(); - - static { - parsers.add(new VersionRuleLatestParser()); - parsers.add(new VersionRuleStartFromParser()); - parsers.add(new VersionRuleRangeParser()); - parsers.add(new VersionRuleFixedParser()); - } - - //1.0 - //1.0.0+ - //1.0.0-2.0.0 - //latest - public static VersionRule getOrCreate(String strVersionRule) { - Objects.requireNonNull(strVersionRule); - - return versionRuleCache.computeIfAbsent(strVersionRule, VersionRuleUtils::create); - } - - public static VersionRule create(String strVersionRule) { - strVersionRule = strVersionRule.trim(); - for (VersionRuleParser parser : parsers) { - VersionRule versionRule = parser.parse(strVersionRule); - if (versionRule != null) { - return versionRule; - } - } - - throw new IllegalStateException("never run to here"); - } -} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionUtils.java deleted file mode 100644 index ef8ea3669f5..00000000000 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/version/VersionUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import java.util.Map; -import java.util.Objects; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; - -public final class VersionUtils { - private static Map versionCache = new ConcurrentHashMapEx<>(); - - public static Version getOrCreate(String strVersion) { - Objects.requireNonNull(strVersion); - - return versionCache.computeIfAbsent(strVersion, Version::new); - } -} diff --git a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider deleted file mode 100644 index ee17cf985de..00000000000 --- a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.serviceregistry.client.http.EmptyAuthHeaderProvider diff --git a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.api.Versions b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.api.Versions deleted file mode 100644 index 006f2297057..00000000000 --- a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.api.Versions +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.serviceregistry.api.registry.ServiceCombVersion diff --git a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing deleted file mode 100644 index ce06621e386..00000000000 --- a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.serviceregistry.consumer.SimpleMicroserviceInstancePing \ No newline at end of file diff --git a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer b/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer deleted file mode 100644 index 761ee02f57d..00000000000 --- a/service-registry/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.serviceregistry.diagnosis.instance.InstanceCacheCheckTask diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MicroServicePropertyExtendedStub.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MicroServicePropertyExtendedStub.java deleted file mode 100644 index 1d37245eb88..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MicroServicePropertyExtendedStub.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.api.PropertyExtended; - -public class MicroServicePropertyExtendedStub implements PropertyExtended { - - /* (non-Javadoc) - * @see org.apache.servicecomb.serviceregistry.api.PropertyExtended#getExtendedProperties() - */ - @Override - public Map getExtendedProperties() { - Map properties = new HashMap<>(); - properties.put("ek0", "ev0"); - return properties; - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java deleted file mode 100644 index 548f21e2331..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry; - -import static org.apache.servicecomb.serviceregistry.RegistryUtils.PUBLISH_ADDRESS; - -import java.net.InetAddress; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConcurrentMapConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestRegistry { - private static final AbstractConfiguration inMemoryConfig = new ConcurrentMapConfiguration(); - - @BeforeClass - public static void initSetup() throws Exception { - AbstractConfiguration dynamicConfig = ConfigUtil.createDynamicConfig(); - ConcurrentCompositeConfiguration configuration = new ConcurrentCompositeConfiguration(); - configuration.addConfiguration(dynamicConfig); - configuration.addConfiguration(inMemoryConfig); - - ConfigurationManager.install(configuration); - } - - @AfterClass - public static void classTeardown() { - Deencapsulation.setField(ConfigurationManager.class, "instance", null); - Deencapsulation.setField(ConfigurationManager.class, "customConfigurationInstalled", false); - Deencapsulation.setField(DynamicPropertyFactory.class, "config", null); - RegistryUtils.setServiceRegistry(null); - } - - @Before - public void setUp() throws Exception { - inMemoryConfig.clear(); - } - - @Test - public void testDelegate() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - serviceRegistry.run(); - - RegistryUtils.setServiceRegistry(serviceRegistry); - Assert.assertEquals(serviceRegistry, RegistryUtils.getServiceRegistry()); - - Assert.assertEquals(serviceRegistry.getServiceRegistryClient(), RegistryUtils.getServiceRegistryClient()); - Assert.assertEquals(serviceRegistry.getInstanceCacheManager(), RegistryUtils.getInstanceCacheManager()); - - Microservice microservice = RegistryUtils.getMicroservice(); - Assert.assertEquals(serviceRegistry.getMicroservice(), microservice); - Assert.assertEquals(serviceRegistry.getMicroserviceInstance(), RegistryUtils.getMicroserviceInstance()); - - List instanceList = RegistryUtils.findServiceInstance("default", "default", "0.0.1"); - Assert.assertEquals(1, instanceList.size()); - Assert.assertEquals(RegistryUtils.getMicroservice().getServiceId(), instanceList.get(0).getServiceId()); - - instanceList = RegistryUtils.findServiceInstance("default", "notExists", "0.0.1"); - Assert.assertEquals(null, instanceList); - - MicroserviceInstances microserviceInstances = - RegistryUtils.findServiceInstances("default", "default", "0.0.1", "0"); - List instanceLists = microserviceInstances.getInstancesResponse().getInstances(); - Assert.assertEquals(1, instanceLists.size()); - Assert.assertEquals(RegistryUtils.getMicroservice().getServiceId(), instanceLists.get(0).getServiceId()); - - Map properties = new HashMap<>(); - properties.put("k", "v"); - RegistryUtils.updateInstanceProperties(properties); - Assert.assertEquals(properties, RegistryUtils.getMicroserviceInstance().getProperties()); - - Assert.assertEquals(microservice, RegistryUtils.getMicroservice(microservice.getServiceId())); - - Assert.assertEquals("default", RegistryUtils.getAppId()); - } - - @Test - public void testRegistryUtilGetPublishAddress(@Mocked InetAddress ethAddress) { - new Expectations(NetUtils.class) { - { - NetUtils.getHostAddress(); - result = "1.1.1.1"; - } - }; - String address = RegistryUtils.getPublishAddress(); - Assert.assertEquals("1.1.1.1", address); - - new Expectations(DynamicPropertyFactory.getInstance()) { - { - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, ""); - result = new DynamicStringProperty(PUBLISH_ADDRESS, "") { - public String get() { - return "127.0.0.1"; - } - }; - } - }; - Assert.assertEquals("127.0.0.1", RegistryUtils.getPublishAddress()); - - new Expectations(DynamicPropertyFactory.getInstance()) { - { - ethAddress.getHostAddress(); - result = "1.1.1.1"; - NetUtils.ensureGetInterfaceAddress("eth100"); - result = ethAddress; - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, ""); - result = new DynamicStringProperty(PUBLISH_ADDRESS, "") { - public String get() { - return "{eth100}"; - } - }; - } - }; - Assert.assertEquals("1.1.1.1", RegistryUtils.getPublishAddress()); - } - - @Test - public void testRegistryUtilGetHostName(@Mocked InetAddress ethAddress) { - new Expectations(NetUtils.class) { - { - NetUtils.getHostName(); - result = "testHostName"; - } - }; - String host = RegistryUtils.getPublishHostName(); - Assert.assertEquals("testHostName", host); - - inMemoryConfig.addProperty(PUBLISH_ADDRESS, "127.0.0.1"); - Assert.assertEquals("127.0.0.1", RegistryUtils.getPublishHostName()); - - new Expectations(DynamicPropertyFactory.getInstance()) { - { - ethAddress.getHostName(); - result = "testHostName"; - NetUtils.ensureGetInterfaceAddress("eth100"); - result = ethAddress; - } - }; - inMemoryConfig.addProperty(PUBLISH_ADDRESS, "{eth100}"); - Assert.assertEquals("testHostName", RegistryUtils.getPublishHostName()); - } - - @Test - public void testGetRealListenAddress() throws Exception { - new Expectations(NetUtils.class) { - { - NetUtils.getHostAddress(); - result = "1.1.1.1"; - } - }; - - Assert.assertEquals("rest://172.0.0.0:8080", RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080")); - Assert.assertEquals(null, RegistryUtils.getPublishAddress("rest", null)); - - URI uri = new URI(RegistryUtils.getPublishAddress("rest", "0.0.0.0:8080")); - Assert.assertEquals("1.1.1.1:8080", uri.getAuthority()); - - new Expectations(DynamicPropertyFactory.getInstance()) { - { - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, ""); - result = new DynamicStringProperty(PUBLISH_ADDRESS, "") { - public String get() { - return "1.1.1.1"; - } - }; - } - }; - Assert.assertEquals("rest://1.1.1.1:8080", RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080")); - - InetAddress ethAddress = Mockito.mock(InetAddress.class); - Mockito.when(ethAddress.getHostAddress()).thenReturn("1.1.1.1"); - new Expectations(DynamicPropertyFactory.getInstance()) { - { - NetUtils.ensureGetInterfaceAddress("eth20"); - result = ethAddress; - DynamicPropertyFactory.getInstance().getStringProperty(PUBLISH_ADDRESS, ""); - result = new DynamicStringProperty(PUBLISH_ADDRESS, "") { - public String get() { - return "{eth20}"; - } - }; - } - }; - String query = URLEncodedUtils.format(Arrays.asList(new BasicNameValuePair("country", "中 国")), - StandardCharsets.UTF_8.name()); - Assert.assertEquals("rest://1.1.1.1:8080?" + query, - RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080?" + query)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestConst.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestConst.java deleted file mode 100644 index 443da848caf..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestConst.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api; - -import org.apache.servicecomb.config.ConfigUtil; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestConst { - @Before - public void setUp() { - System.setProperty("servicecomb.service.registry.api.version", "v4"); - System.setProperty("servicecomb.config.client.domainName", "testtenane"); - ConfigUtil.createLocalConfig(); - } - - @After - public void tearDown() { - System.getProperties().remove("servicecomb.service.registry.api.version"); - System.getProperties().remove("servicecomb.config.client.domainName"); - } - - @Test - public void testV4URL() { - - // this test case depends on class loading and java property may initialized after class loading, so we make to run in all cases. - if (Const.REGISTRY_API.CURRENT_VERSION.equals(Const.REGISTRY_API.VERSION_V3)) { - Assert.assertEquals("/registry/v3/microservices", Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL); - Assert.assertEquals("/registry/v3/microservices/%s", Const.REGISTRY_API.MICROSERVICE_OPERATION_ONE); - Assert.assertEquals("/registry/v3/microservices/%s/instances", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL); - Assert.assertEquals("/registry/v3/microservices/%s/instances/%s", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE); - Assert.assertEquals("/registry/v3/existence", Const.REGISTRY_API.MICROSERVICE_EXISTENCE); - Assert.assertEquals("/registry/v3/microservices/%s/schemas/%s", Const.REGISTRY_API.MICROSERVICE_SCHEMA); - Assert.assertEquals("/registry/v3/microservices/%s/instances/%s/heartbeat", - Const.REGISTRY_API.MICROSERVICE_HEARTBEAT); - Assert.assertEquals("/registry/v3/microservices/%s/watcher", Const.REGISTRY_API.MICROSERVICE_WATCH); - Assert.assertEquals("/registry/v3/instances", Const.REGISTRY_API.MICROSERVICE_INSTANCES); - Assert.assertEquals("/registry/v3/microservices/%s/properties", - Const.REGISTRY_API.MICROSERVICE_PROPERTIES); - Assert.assertEquals("/registry/v3/microservices/%s/instances/%s/properties", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_PROPERTIES); - } else { - String prefix = "/v4/" + Const.REGISTRY_API.DOMAIN_NAME + "/registry/"; - Assert.assertEquals(prefix + "microservices", Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL); - Assert.assertEquals(prefix + "microservices/%s", Const.REGISTRY_API.MICROSERVICE_OPERATION_ONE); - Assert.assertEquals(prefix + "microservices/%s/instances", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL); - Assert.assertEquals(prefix + "microservices/%s/instances/%s", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE); - Assert.assertEquals(prefix + "existence", Const.REGISTRY_API.MICROSERVICE_EXISTENCE); - Assert.assertEquals(prefix + "microservices/%s/schemas/%s", - Const.REGISTRY_API.MICROSERVICE_SCHEMA); - Assert.assertEquals(prefix + "microservices/%s/instances/%s/heartbeat", - Const.REGISTRY_API.MICROSERVICE_HEARTBEAT); - Assert.assertEquals(prefix + "microservices/%s/watcher", Const.REGISTRY_API.MICROSERVICE_WATCH); - Assert.assertEquals(prefix + "instances", Const.REGISTRY_API.MICROSERVICE_INSTANCES); - Assert.assertEquals(prefix + "microservices/%s/properties", - Const.REGISTRY_API.MICROSERVICE_PROPERTIES); - Assert.assertEquals(prefix + "microservices/%s/instances/%s/properties", - Const.REGISTRY_API.MICROSERVICE_INSTANCE_PROPERTIES); - } - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestMicroserviceKey.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestMicroserviceKey.java deleted file mode 100644 index ab5c35bf1e7..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/TestMicroserviceKey.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestMicroserviceKey { - - MicroserviceKey oMicroserviceKey = null; - - @Before - public void setUp() throws Exception { - oMicroserviceKey = new MicroserviceKey(); - } - - @After - public void tearDown() throws Exception { - oMicroserviceKey = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oMicroserviceKey.getAppId()); - Assert.assertNull(oMicroserviceKey.getTenant()); - Assert.assertNull(oMicroserviceKey.getServiceName()); - Assert.assertNull(oMicroserviceKey.getStage()); - Assert.assertNull(oMicroserviceKey.getVersion()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals("1", oMicroserviceKey.getVersion()); - Assert.assertEquals("testServiceName", oMicroserviceKey.getServiceName()); - Assert.assertEquals("Test", oMicroserviceKey.getStage()); - Assert.assertEquals("testTenantName", oMicroserviceKey.getTenant()); - Assert.assertEquals(Const.REGISTRY_APP_ID, oMicroserviceKey.getAppId()); - } - - private void initFields() { - oMicroserviceKey.setAppId(Const.REGISTRY_APP_ID); - oMicroserviceKey.setServiceName("testServiceName"); - oMicroserviceKey.setTenant("testTenantName"); - oMicroserviceKey.setVersion("1"); - oMicroserviceKey.setStage("Test"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestBasePath.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestBasePath.java deleted file mode 100644 index 4a8739e24cb..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestBasePath.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.HashMap; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Created by on 2017/3/29. - */ -public class TestBasePath { - private BasePath oBasePath; - - @Before - public void setUp() throws Exception { - oBasePath = new BasePath(); - } - - @After - public void tearDown() throws Exception { - oBasePath = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oBasePath.getPath()); - Assert.assertNull(oBasePath.getProperty()); - } - - @Test - public void testInitializedValues() { - initBasePath(); //Initialize the Values - Assert.assertEquals("a", oBasePath.getPath()); - Assert.assertNotNull(oBasePath.getProperty()); - } - - private void initBasePath() { - oBasePath.setPath("a"); - oBasePath.setProperty(new HashMap<>()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFramework.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFramework.java deleted file mode 100644 index bc04fb7de69..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFramework.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.Assert; -import org.junit.Test; - -public class TestFramework { - @Test - public void testDefaultValues() { - Framework framework = new Framework(); - Assert.assertNull(framework.getName()); - Assert.assertNull(framework.getVersion()); - } - - @Test - public void testInitializedValues() { - Framework framework = new Framework(); - framework.setName("JAVA-CHASSIS"); - framework.setVersion("x.x.x"); - Assert.assertEquals("JAVA-CHASSIS", framework.getName()); - Assert.assertEquals("x.x.x", framework.getVersion()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFrameworkVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFrameworkVersions.java deleted file mode 100644 index e0dde1a98cb..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestFrameworkVersions.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.Assert; -import org.junit.Test; - -public class TestFrameworkVersions { - @Test - public void testFrameworkVersions() { - Assert.assertEquals("ServiceComb:null", FrameworkVersions.allVersions()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestHealthCheck.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestHealthCheck.java deleted file mode 100644 index 7433f290d79..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestHealthCheck.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestHealthCheck { - - HealthCheck oHealthCheck = null; - - @Before - public void setUp() throws Exception { - oHealthCheck = new HealthCheck(); - } - - @After - public void tearDown() throws Exception { - oHealthCheck = null; - } - - @Test - public void testDefaultValues() { - Assert.assertEquals(0, oHealthCheck.getInterval()); - Assert.assertEquals(0, oHealthCheck.getPort()); - Assert.assertEquals(0, oHealthCheck.getTimes()); - Assert.assertNull(oHealthCheck.getMode()); - Assert.assertEquals(0, oHealthCheck.getTTL()); - } - - @Test - public void testInitializedValues() { - initHealthCheck(); //Initialize the Values - Assert.assertEquals(10, oHealthCheck.getInterval()); - Assert.assertEquals(8080, oHealthCheck.getPort()); - Assert.assertEquals(2, oHealthCheck.getTimes()); - Assert.assertEquals(HealthCheckMode.PLATFORM, oHealthCheck.getMode()); - Assert.assertEquals(0, oHealthCheck.getTTL()); //TTL Values will changes based on the Mode - Assert.assertEquals("pull", oHealthCheck.getMode().getName()); - - //Testing Different modes of the HealthCheckMode - oHealthCheck.setMode(HealthCheckMode.HEARTBEAT); - Assert.assertEquals(HealthCheckMode.HEARTBEAT, oHealthCheck.getMode()); - Assert.assertEquals(30, oHealthCheck.getTTL()); //TTL Values will changes based on the Mode - Assert.assertEquals("push", oHealthCheck.getMode().getName()); - - oHealthCheck.setMode(HealthCheckMode.UNKNOWN); - Assert.assertEquals(HealthCheckMode.UNKNOWN, oHealthCheck.getMode()); - Assert.assertEquals(0, oHealthCheck.getTTL()); //TTL Values will changes based on the Mode - Assert.assertEquals("unknown", oHealthCheck.getMode().getName()); - } - - private void initHealthCheck() { - oHealthCheck.setInterval(10); - oHealthCheck.setMode(HealthCheckMode.PLATFORM); - oHealthCheck.setPort(8080); - oHealthCheck.setTimes(2); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroService.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroService.java deleted file mode 100644 index c1ef3f5ab60..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroService.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestMicroService { - - Microservice oMicroservice = null; - - Map oMapProperties = null; - - List oListSchemas = null; - - @Before - public void setUp() throws Exception { - oMicroservice = new Microservice(); - oMapProperties = new HashMap<>(); - oListSchemas = new ArrayList<>(); - } - - @After - public void tearDown() throws Exception { - oMicroservice = null; - oMapProperties = null; - oListSchemas = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oMicroservice.getAppId()); - Assert.assertNull(oMicroservice.getDescription()); - Assert.assertNull(oMicroservice.getLevel()); - Assert.assertEquals(0, oMicroservice.getProperties().size()); - Assert.assertEquals(0, oMicroservice.getSchemas().size()); - Assert.assertNull(oMicroservice.getServiceId()); - Assert.assertNull(oMicroservice.getServiceName()); - Assert.assertEquals(MicroserviceInstanceStatus.UP.toString(), oMicroservice.getStatus()); - Assert.assertNull(oMicroservice.getVersion()); - Assert.assertEquals(0, oMicroservice.getPaths().size()); - Assert.assertNull(oMicroservice.getFramework()); - Assert.assertNull(oMicroservice.getEnvironment()); - } - - @Test - public void testInitializedValues() { - initMicroservice(); //Initialize the Object - Assert.assertEquals("testAppID", oMicroservice.getAppId()); - Assert.assertEquals("This is the test", oMicroservice.getDescription()); - Assert.assertEquals("INFO", oMicroservice.getLevel()); - Assert.assertEquals("testServiceID", oMicroservice.getServiceId()); - Assert.assertEquals("testServiceName", oMicroservice.getServiceName()); - Assert.assertEquals(MicroserviceInstanceStatus.DOWN.toString(), oMicroservice.getStatus()); - Assert.assertEquals("1.0.0", oMicroservice.getVersion()); - Assert.assertEquals("fakeProxy", oMicroservice.getProperties().get("proxy")); - Assert.assertEquals(1, oMicroservice.getSchemas().size()); - Assert.assertEquals(1, oMicroservice.getPaths().size()); - Assert.assertEquals("JAVA-CHASSIS", oMicroservice.getFramework().getName()); - Assert.assertEquals("x.x.x", oMicroservice.getFramework().getVersion()); - Assert.assertEquals("SDK", oMicroservice.getRegisterBy()); - Assert.assertEquals("development", oMicroservice.getEnvironment()); - } - - private void initMicroservice() { - oMicroservice.setAppId("testAppID"); - oMicroservice.setDescription("This is the test"); - oMicroservice.setLevel("INFO"); - oMicroservice.setServiceId("testServiceID"); - oMicroservice.setServiceName("testServiceName"); - oMicroservice.setStatus(MicroserviceInstanceStatus.DOWN.toString()); - oMicroservice.setVersion("1.0.0"); - oMapProperties.put("proxy", "fakeProxy"); - oListSchemas.add("testSchemas"); - oMicroservice.setProperties(oMapProperties); - oMicroservice.setSchemas(oListSchemas); - oMicroservice.getPaths().add(new BasePath()); - Framework framework = new Framework(); - framework.setName("JAVA-CHASSIS"); - framework.setVersion("x.x.x"); - oMicroservice.setFramework(framework); - oMicroservice.setRegisterBy("SDK"); - oMicroservice.setEnvironment("development"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java deleted file mode 100644 index affcf922839..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroServiceInstance.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; - -import mockit.Deencapsulation; - -public class TestMicroServiceInstance { - - MicroserviceInstance oMicroserviceInstance = null; - - Map oMapProperties = null; - - List oListEndpoints = null; - - HealthCheck oMockHealthCheck = null; - - @AfterClass - public static void classTeardown() { - Deencapsulation.setField(ConfigurationManager.class, "instance", null); - Deencapsulation.setField(ConfigurationManager.class, "customConfigurationInstalled", false); - Deencapsulation.setField(DynamicPropertyFactory.class, "config", null); - RegistryUtils.setServiceRegistry(null); - } - - @Before - public void setUp() throws Exception { - oMicroserviceInstance = new MicroserviceInstance(); - oMapProperties = new HashMap<>(); - oListEndpoints = new ArrayList<>(); - oMockHealthCheck = Mockito.mock(HealthCheck.class); - } - - @After - public void tearDown() throws Exception { - oMicroserviceInstance = null; - oMapProperties = null; - oListEndpoints = null; - oMockHealthCheck = null; - } - - @SuppressWarnings("deprecation") - @Test - public void testDefaultValues() { - Assert.assertNull(oMicroserviceInstance.getHostName()); - Assert.assertNull(oMicroserviceInstance.getInstanceId()); - Assert.assertNull(oMicroserviceInstance.getServiceId()); - Assert.assertEquals(0, oMicroserviceInstance.getProperties().size()); - Assert.assertEquals(0, oMicroserviceInstance.getEndpoints().size()); - Assert.assertNull(oMicroserviceInstance.getHealthCheck()); - Assert.assertNull(oMicroserviceInstance.getStage()); - Assert.assertEquals(MicroserviceInstanceStatus.UP, oMicroserviceInstance.getStatus()); - } - - @SuppressWarnings("deprecation") - @Test - public void testInitializedValues() { - initMicroserviceInstance(); //Initialize the Object - Assert.assertEquals("testHostName", oMicroserviceInstance.getHostName()); - Assert.assertEquals("testInstanceID", oMicroserviceInstance.getInstanceId()); - Assert.assertEquals(1, oMicroserviceInstance.getEndpoints().size()); - Assert.assertEquals("testServiceID", oMicroserviceInstance.getServiceId()); - Assert.assertEquals(oMockHealthCheck, oMicroserviceInstance.getHealthCheck()); - Assert.assertEquals(MicroserviceInstanceStatus.DOWN, oMicroserviceInstance.getStatus()); - Assert.assertEquals("Test", oMicroserviceInstance.getStage()); - Assert.assertEquals("china", oMicroserviceInstance.getProperties().get("region")); - - Assert.assertEquals(oMicroserviceInstance, oMicroserviceInstance); - MicroserviceInstance other = new MicroserviceInstance(); - other.setInstanceId("testInstanceIDOther"); - MicroserviceInstance same = new MicroserviceInstance(); - same.setInstanceId("testInstanceID"); - Assert.assertNotEquals(oMicroserviceInstance, other); - Assert.assertNotEquals(oMicroserviceInstance.hashCode(), other.hashCode()); - Assert.assertEquals(oMicroserviceInstance, same); - Assert.assertEquals(oMicroserviceInstance.hashCode(), same.hashCode()); - } - - @SuppressWarnings("deprecation") - private void initMicroserviceInstance() { - oMicroserviceInstance.setHostName("testHostName"); - oMicroserviceInstance.setInstanceId("testInstanceID"); - oMicroserviceInstance.setStage("Test"); - oMicroserviceInstance.setServiceId("testServiceID"); - oMicroserviceInstance.setStatus(MicroserviceInstanceStatus.DOWN); - oMapProperties.put("region", "china"); - oListEndpoints.add("testEndpoints"); - oMicroserviceInstance.setProperties(oMapProperties); - oMicroserviceInstance.setEndpoints(oListEndpoints); - oMicroserviceInstance.setHealthCheck(oMockHealthCheck); - } - - @Test - public void testCreateMicroserviceInstanceFromFile() { - AbstractConfiguration config = ConfigUtil.createDynamicConfig(); - ConcurrentCompositeConfiguration configuration = new ConcurrentCompositeConfiguration(); - configuration.addConfiguration(config); - ConfigurationManager.install(configuration); - MicroserviceInstance instance = MicroserviceInstance.createFromDefinition(config); - Assert.assertEquals(instance.getDataCenterInfo().getName(), "myDC"); - Assert.assertEquals(instance.getDataCenterInfo().getRegion(), "my-Region"); - Assert.assertEquals(instance.getDataCenterInfo().getAvailableZone(), "my-Zone"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroserviceFactory.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroserviceFactory.java deleted file mode 100644 index c735f9bf9c7..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestMicroserviceFactory.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY; -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.CONFIG_ALLOW_CROSS_APP_KEY; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_MICROSERVICE_VERSION; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceFactory { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void testAllowCrossApp() { - MicroserviceFactory factory = new MicroserviceFactory(); - Map propertiesMap = new HashMap<>(); - Assert.assertFalse(Deencapsulation.invoke(factory, "allowCrossApp", propertiesMap)); - - propertiesMap.put(CONFIG_ALLOW_CROSS_APP_KEY, "true"); - Assert.assertTrue(Deencapsulation.invoke(factory, "allowCrossApp", propertiesMap)); - - propertiesMap.put(CONFIG_ALLOW_CROSS_APP_KEY, "false"); - Assert.assertFalse(Deencapsulation.invoke(factory, "allowCrossApp", propertiesMap)); - - propertiesMap.put(CONFIG_ALLOW_CROSS_APP_KEY, "asfas"); - Assert.assertFalse(Deencapsulation.invoke(factory, "allowCrossApp", propertiesMap)); - } - - @Test - public void testInit() { - MicroserviceConfigLoader loader = new MicroserviceConfigLoader(); - loader.loadAndSort(); - - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels()); - MicroserviceFactory factory = new MicroserviceFactory(); - Microservice microservice = factory.create(microserviceDefinition); - - String microserviceName = "default"; - - Assert.assertEquals(microserviceName, microservice.getServiceName()); - } - - @Test - public void testSetDescription() { - Microservice microservice = new Microservice(); - MicroserviceFactory factory = new MicroserviceFactory(); - Configuration configuration = Mockito.mock(Configuration.class); - - Mockito.when(configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY)) - .thenReturn(new String[] {"test1", "test2"}); - - Deencapsulation.invoke(factory, "setDescription", configuration, microservice); - - Assert.assertEquals("test1,test2", microservice.getDescription()); - } - - @Test - public void testSetDescriptionOnNullDescription() { - Microservice microservice = new Microservice(); - MicroserviceFactory factory = new MicroserviceFactory(); - Configuration configuration = Mockito.mock(Configuration.class); - - Mockito.when(configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY)) - .thenReturn(null); - - Deencapsulation.invoke(factory, "setDescription", configuration, microservice); - - Assert.assertNull(microservice.getDescription()); - - Mockito.when(configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY)) - .thenReturn(new String[] {}); - - Deencapsulation.invoke(factory, "setDescription", configuration, microservice); - - Assert.assertNull(microservice.getDescription()); - } - - @Test - public void testSetDescriptionOnEmptyDescription() { - Microservice microservice = new Microservice(); - MicroserviceFactory factory = new MicroserviceFactory(); - Configuration configuration = Mockito.mock(Configuration.class); - - Mockito.when(configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY)) - .thenReturn(new String[] {"", ""}); - - Deencapsulation.invoke(factory, "setDescription", configuration, microservice); - - Assert.assertEquals(",", microservice.getDescription()); - } - - @Test - public void testSetDescriptionOnBlankDescription() { - Microservice microservice = new Microservice(); - MicroserviceFactory factory = new MicroserviceFactory(); - Configuration configuration = Mockito.mock(Configuration.class); - - Mockito.when(configuration.getStringArray(CONFIG_QUALIFIED_MICROSERVICE_DESCRIPTION_KEY)) - .thenReturn(new String[] {" ", " "}); - - Deencapsulation.invoke(factory, "setDescription", configuration, microservice); - - Assert.assertEquals(" , ", microservice.getDescription()); - } - - @Test - public void testCreateMicroserviceFromDefinitionWithInvalidVersion(@Mocked Configuration configuration, - @Mocked MicroserviceDefinition microserviceDefinition) { - - new Expectations() { - { - configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY, - DEFAULT_MICROSERVICE_VERSION); - result = "x.y.x.1"; - microserviceDefinition.getConfiguration(); - result = configuration; - } - }; - expectedException.equals(IllegalStateException.class); - expectedException.expectMessage("Invalid major \"x\", version \"x.y.x.1\"."); - MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - microserviceFactory.create(microserviceDefinition); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterConfig.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterConfig.java deleted file mode 100644 index 101385a4a93..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterConfig.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.Assert; -import org.junit.Test; - -public class TestServiceCenterConfig { - ServiceCenterConfig config = new ServiceCenterConfig(); - - @Test - public void testDefaultValues() { - Assert.assertEquals(0, config.getMaxHeaderBytes()); - Assert.assertEquals(0, config.getMaxBodyBytes()); - Assert.assertNull(config.getReadHeaderTimeout()); - Assert.assertNull(config.getReadTimeout()); - Assert.assertNull(config.getIdleTimeout()); - Assert.assertNull(config.getWriteTimeout()); - Assert.assertNull(config.getLimitTTLUnit()); - Assert.assertEquals(0, config.getLimitConnections()); - Assert.assertNull(config.getLimitIPLookup()); - Assert.assertNull(config.getSslEnabled()); - Assert.assertNull(config.getSslMinVersion()); - Assert.assertNull(config.getSslVerifyPeer()); - Assert.assertNull(config.getSslCiphers()); - Assert.assertNull(config.getAutoSyncInterval()); - Assert.assertEquals(0, config.getCompactIndexDelta()); - Assert.assertNull(config.getCompactInterval()); - Assert.assertEquals(0, config.getLogRotateSize()); - Assert.assertEquals(0, config.getLogBackupCount()); - } - - @Test - public void testInitializedValues() { - initMicroservice(); //Initialize the Object - Assert.assertEquals(10, config.getMaxHeaderBytes()); - Assert.assertEquals(10, config.getMaxBodyBytes()); - Assert.assertEquals("60s", config.getReadHeaderTimeout()); - Assert.assertEquals("60s", config.getReadTimeout()); - Assert.assertEquals("60s", config.getIdleTimeout()); - Assert.assertEquals("60s", config.getWriteTimeout()); - Assert.assertEquals("s", config.getLimitTTLUnit()); - Assert.assertEquals(0, config.getLimitConnections()); - Assert.assertEquals("xxx", config.getLimitIPLookup()); - Assert.assertEquals("false", config.getSslEnabled()); - Assert.assertEquals("xxx", config.getSslMinVersion()); - Assert.assertEquals("true", config.getSslVerifyPeer()); - Assert.assertEquals("xxx", config.getSslCiphers()); - Assert.assertEquals("30s", config.getAutoSyncInterval()); - Assert.assertEquals(100, config.getCompactIndexDelta()); - Assert.assertEquals("100", config.getCompactInterval()); - Assert.assertEquals(20, config.getLogRotateSize()); - Assert.assertEquals(50, config.getLogBackupCount()); - } - - private void initMicroservice() { - config.setMaxHeaderBytes(10); - config.setMaxBodyBytes(10); - config.setReadHeaderTimeout("60s"); - config.setReadTimeout("60s"); - config.setIdleTimeout("60s"); - config.setWriteTimeout("60s"); - config.setLimitTTLUnit("s"); - config.setLimitConnections(0); - config.setLimitIPLookup("xxx"); - config.setSslEnabled("false"); - config.setSslMinVersion("xxx"); - config.setSslVerifyPeer("true"); - config.setSslCiphers("xxx"); - config.setAutoSyncInterval("30s"); - config.setCompactIndexDelta(100); - config.setCompactInterval("100"); - config.setLogRotateSize(20); - config.setLogBackupCount(50); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterInfo.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterInfo.java deleted file mode 100644 index 97be9f8c36d..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCenterInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.Assert; -import org.junit.Test; - -public class TestServiceCenterInfo { - ServiceCenterInfo info = new ServiceCenterInfo(); - - ServiceCenterConfig config = new ServiceCenterConfig(); - - @Test - public void testDefaultValues() { - Assert.assertNull(info.getVersion()); - Assert.assertNull(info.getBuildTag()); - Assert.assertNull(info.getRunMode()); - Assert.assertNull(info.getApiVersion()); - Assert.assertNull(info.getConfig()); - } - - @Test - public void testInitializedValues() { - initMicroservice(); //Initialize the Object - Assert.assertEquals("x.x.x", info.getVersion()); - Assert.assertEquals("xxx", info.getBuildTag()); - Assert.assertEquals("dev", info.getRunMode()); - Assert.assertEquals("x.x.x", info.getApiVersion()); - Assert.assertNotNull(info.getConfig()); - } - - private void initMicroservice() { - info.setVersion("x.x.x"); - info.setBuildTag("xxx"); - info.setRunMode("dev"); - info.setApiVersion("x.x.x"); - info.setConfig(config); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCombVersion.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCombVersion.java deleted file mode 100644 index 62e722cd603..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/registry/TestServiceCombVersion.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.registry; - -import org.junit.Assert; -import org.junit.Test; - -public class TestServiceCombVersion { - - @Test - public void testServiceCombVersion() { - ServiceCombVersion version = new ServiceCombVersion(); - Assert.assertEquals("{ServiceComb=null}", version.loadVersion().toString()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateSchemaRequest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateSchemaRequest.java deleted file mode 100644 index 6d7cbacf2f7..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateSchemaRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.request; - -import org.junit.Assert; -import org.junit.Test; - -public class TestCreateSchemaRequest { - @Test - public void testProperties() { - CreateSchemaRequest request = new CreateSchemaRequest(); - - Assert.assertEquals(null, request.getSchema()); - - request.setSchema("schema"); - Assert.assertEquals("schema", request.getSchema()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateServiceRequest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateServiceRequest.java deleted file mode 100644 index cb9722715a4..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestCreateServiceRequest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.request; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestCreateServiceRequest { - - CreateServiceRequest oCreateServiceRequest = null; - - Microservice oMockMicroservice = null; - - @Before - public void setUp() throws Exception { - oCreateServiceRequest = new CreateServiceRequest(); - oMockMicroservice = Mockito.mock(Microservice.class); - } - - @After - public void tearDown() throws Exception { - oCreateServiceRequest = null; - oMockMicroservice = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oCreateServiceRequest.getService()); - } - - @Test - public void testInitializedValues() { - initCreateServiceRequest(); //Initialize the Object - Assert.assertEquals(oMockMicroservice, oCreateServiceRequest.getService()); - } - - private void initCreateServiceRequest() { - oCreateServiceRequest.setService(oMockMicroservice); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestRegisterInstanceRequest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestRegisterInstanceRequest.java deleted file mode 100644 index 66ecf676d18..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestRegisterInstanceRequest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.request; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestRegisterInstanceRequest { - - RegisterInstanceRequest oRegisterInstanceRequest = null; - - MicroserviceInstance oMockMicroserviceInstance = null; - - @Before - public void setUp() throws Exception { - oRegisterInstanceRequest = new RegisterInstanceRequest(); - oMockMicroserviceInstance = Mockito.mock(MicroserviceInstance.class); - } - - @After - public void tearDown() throws Exception { - oRegisterInstanceRequest = null; - oMockMicroserviceInstance = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oRegisterInstanceRequest.getInstance()); - } - - @Test - public void testInitializedValues() { - initRegisterInstanceRequest(); //Initialize the Object - Assert.assertEquals(oMockMicroserviceInstance, oRegisterInstanceRequest.getInstance()); - } - - private void initRegisterInstanceRequest() { - oRegisterInstanceRequest.setInstance(oMockMicroserviceInstance); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestUpdatePropertiesRequest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestUpdatePropertiesRequest.java deleted file mode 100644 index 5169b17caff..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/request/TestUpdatePropertiesRequest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.api.request; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - -public class TestUpdatePropertiesRequest { - @Test - public void testProperties() { - UpdatePropertiesRequest request = new UpdatePropertiesRequest(); - - Assert.assertEquals(null, request.getProperties()); - - Map properties = new HashMap<>(); - properties.put("k", "v"); - request.setProperties(properties); - Assert.assertEquals(properties, request.getProperties()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestCreateServiceResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestCreateServiceResponse.java deleted file mode 100644 index a4172154493..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestCreateServiceResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestCreateServiceResponse { - - CreateServiceResponse oCreateServiceResponse = null; - - @Before - public void setUp() throws Exception { - oCreateServiceResponse = new CreateServiceResponse(); - } - - @After - public void tearDown() throws Exception { - oCreateServiceResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oCreateServiceResponse.getServiceId()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals("testServiceId", oCreateServiceResponse.getServiceId()); - } - - private void initFields() { - oCreateServiceResponse.setServiceId("testServiceId"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestFindInstancesResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestFindInstancesResponse.java deleted file mode 100644 index e615fa80a9c..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestFindInstancesResponse.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestFindInstancesResponse { - - FindInstancesResponse oFindInstancesResponse = null; - - List oListMicroserviceInstance = null; - - @Before - public void setUp() throws Exception { - oFindInstancesResponse = new FindInstancesResponse(); - oListMicroserviceInstance = new ArrayList<>(); - oListMicroserviceInstance.add(Mockito.mock(MicroserviceInstance.class)); - } - - @After - public void tearDown() throws Exception { - oFindInstancesResponse = null; - oListMicroserviceInstance = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oFindInstancesResponse.getInstances()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals(1, oFindInstancesResponse.getInstances().size()); - } - - private void initFields() { - oFindInstancesResponse.setInstances(oListMicroserviceInstance); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetAllServicesResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetAllServicesResponse.java deleted file mode 100644 index 5982ebb137f..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetAllServicesResponse.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestGetAllServicesResponse { - - GetAllServicesResponse oGetAllServicesResponse = null; - - Microservice oMockMicroservice = null; - - @Before - public void setUp() throws Exception { - oGetAllServicesResponse = new GetAllServicesResponse(); - oMockMicroservice = Mockito.mock(Microservice.class); - } - - @After - public void tearDown() throws Exception { - oGetAllServicesResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oGetAllServicesResponse.getServices()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - List list = oGetAllServicesResponse.getServices(); - Assert.assertEquals(oMockMicroservice, list.get(0)); - } - - private void initFields() { - List list = new ArrayList<>(); - list.add(oMockMicroservice); - oGetAllServicesResponse.setServices(list); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetExistenceResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetExistenceResponse.java deleted file mode 100644 index 4a189a9ec2b..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetExistenceResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestGetExistenceResponse { - - GetExistenceResponse oGetExistenceResponse = null; - - @Before - public void setUp() throws Exception { - oGetExistenceResponse = new GetExistenceResponse(); - } - - @After - public void tearDown() throws Exception { - oGetExistenceResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oGetExistenceResponse.getSchemaId()); - Assert.assertNull(oGetExistenceResponse.getServiceId()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals("testSchemaId", oGetExistenceResponse.getSchemaId()); - Assert.assertEquals("testServiceId", oGetExistenceResponse.getServiceId()); - } - - private void initFields() { - oGetExistenceResponse.setSchemaId("testSchemaId"); - oGetExistenceResponse.setServiceId("testServiceId"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetInstancesResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetInstancesResponse.java deleted file mode 100644 index 9daffe56b30..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetInstancesResponse.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestGetInstancesResponse { - - GetInstancesResponse oGetInstancesResponse = null; - - List oListMicroserviceInstance = null; - - @Before - public void setUp() throws Exception { - oGetInstancesResponse = new GetInstancesResponse(); - oListMicroserviceInstance = new ArrayList<>(); - oListMicroserviceInstance.add(Mockito.mock(MicroserviceInstance.class)); - } - - @After - public void tearDown() throws Exception { - oGetInstancesResponse = null; - oListMicroserviceInstance = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oGetInstancesResponse.getInstances()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals(1, oGetInstancesResponse.getInstances().size()); - } - - private void initFields() { - oGetInstancesResponse.setInstances(oListMicroserviceInstance); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetServiceResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetServiceResponse.java deleted file mode 100644 index 6e95a993166..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestGetServiceResponse.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestGetServiceResponse { - - GetServiceResponse oGetServiceResponse = null; - - Microservice oMockMicroservice = null; - - @Before - public void setUp() throws Exception { - oGetServiceResponse = new GetServiceResponse(); - oMockMicroservice = Mockito.mock(Microservice.class); - } - - @After - public void tearDown() throws Exception { - oGetServiceResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oGetServiceResponse.getService()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals(oMockMicroservice, oGetServiceResponse.getService()); - } - - private void initFields() { - oGetServiceResponse.setService(oMockMicroservice); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestHeartbeatResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestHeartbeatResponse.java deleted file mode 100644 index 2fe32b07c76..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestHeartbeatResponse.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestHeartbeatResponse { - - HeartbeatResponse oHeartbeatResponse = null; - - @Before - public void setUp() throws Exception { - oHeartbeatResponse = new HeartbeatResponse(); - } - - @After - public void tearDown() throws Exception { - oHeartbeatResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oHeartbeatResponse.getMessage()); - Assert.assertEquals(false, oHeartbeatResponse.isOk()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals("testMessage", oHeartbeatResponse.getMessage()); - Assert.assertEquals(true, oHeartbeatResponse.isOk()); - } - - private void initFields() { - oHeartbeatResponse.setMessage("testMessage"); - oHeartbeatResponse.setOk(true); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceChangedEvent.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceChangedEvent.java deleted file mode 100644 index aee342d1df4..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceChangedEvent.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.MicroserviceKey; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.WatchAction; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestMicroserviceInstanceChangedEvent { - - MicroserviceInstanceChangedEvent oMicroserviceInstanceChangedEvent = null; - - MicroserviceKey oMockMicroserviceKey = null; - - MicroserviceInstance oMockMicroserviceInstance = null; - - @Before - public void setUp() throws Exception { - oMicroserviceInstanceChangedEvent = new MicroserviceInstanceChangedEvent(); - oMockMicroserviceKey = Mockito.mock(MicroserviceKey.class); - oMockMicroserviceInstance = Mockito.mock(MicroserviceInstance.class); - } - - @After - public void tearDown() throws Exception { - oMicroserviceInstanceChangedEvent = null; - oMockMicroserviceKey = null; - oMockMicroserviceInstance = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oMicroserviceInstanceChangedEvent.getAction()); - Assert.assertNull(oMicroserviceInstanceChangedEvent.getInstance()); - Assert.assertNull(oMicroserviceInstanceChangedEvent.getKey()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals(WatchAction.CREATE, oMicroserviceInstanceChangedEvent.getAction()); - Assert.assertEquals("CREATE", oMicroserviceInstanceChangedEvent.getAction().getName()); - Assert.assertEquals(oMockMicroserviceInstance, oMicroserviceInstanceChangedEvent.getInstance()); - Assert.assertEquals(oMockMicroserviceKey, oMicroserviceInstanceChangedEvent.getKey()); - - //Test Different Actions - oMicroserviceInstanceChangedEvent.setAction(WatchAction.UPDATE); - Assert.assertEquals("UPDATE", oMicroserviceInstanceChangedEvent.getAction().getName()); - - oMicroserviceInstanceChangedEvent.setAction(WatchAction.DELETE); - Assert.assertEquals("DELETE", oMicroserviceInstanceChangedEvent.getAction().getName()); - } - - private void initFields() { - oMicroserviceInstanceChangedEvent.setInstance(oMockMicroserviceInstance); - oMicroserviceInstanceChangedEvent.setKey(oMockMicroserviceKey); - oMicroserviceInstanceChangedEvent.setAction(WatchAction.CREATE); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java deleted file mode 100644 index 6283dda376e..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; - -public class TestMicroserviceInstanceResponse { - - - @Test - public void testMicroserviceInstanceResponse() { - MicroserviceInstance microserviceInstance = new MicroserviceInstance(); - MicroserviceInstanceResponse microserviceInstanceResponse = new MicroserviceInstanceResponse(); - microserviceInstanceResponse.setInstance(microserviceInstance); - Assert.assertNotNull(microserviceInstanceResponse.getInstance()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestRegisterInstanceResponse.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestRegisterInstanceResponse.java deleted file mode 100644 index 9638e9f81ab..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/api/response/TestRegisterInstanceResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.api.response; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestRegisterInstanceResponse { - - RegisterInstanceResponse oRegisterInstanceResponse = null; - - @Before - public void setUp() throws Exception { - oRegisterInstanceResponse = new RegisterInstanceResponse(); - } - - @After - public void tearDown() throws Exception { - oRegisterInstanceResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(oRegisterInstanceResponse.getInstanceId()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals("testInstanceID", oRegisterInstanceResponse.getInstanceId()); - } - - private void initFields() { - oRegisterInstanceResponse.setInstanceId("testInstanceID"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCache.java deleted file mode 100644 index cd296080dce..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCache.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestInstanceCache { - private static InstanceCache instanceCache = null; - - static Map instMap = new HashMap<>(); - - @BeforeClass - public static void beforeClass() { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setStatus(MicroserviceInstanceStatus.UP); - List endpoints = new ArrayList<>(); - endpoints.add("rest://127.0.0.1:8080"); - instance.setEndpoints(endpoints); - instance.setInstanceId("1"); - - instMap.put(instance.getInstanceId(), instance); - instanceCache = new InstanceCache("testAppID", "testMicroServiceName", "1.0", instMap); - } - - @Test - public void testGetMethod() { - Assert.assertEquals("testAppID", instanceCache.getAppId()); - Assert.assertEquals("testMicroServiceName", instanceCache.getMicroserviceName()); - Assert.assertEquals("1.0", instanceCache.getMicroserviceVersionRule()); - Assert.assertNotNull(instanceCache.getInstanceMap()); - } - - @Test - public void testGetOrCreateTransportMap() { - Map> transportMap = instanceCache.getOrCreateTransportMap(); - Assert.assertEquals(1, transportMap.size()); - } - - @Test - public void testCacheChanged() { - InstanceCache newCache = - new InstanceCache("testAppID", "testMicroServiceName", "1.0", instanceCache.getInstanceMap()); - Assert.assertTrue(instanceCache.cacheChanged(newCache)); - } - - @Test - public void getVersionedCache() { - VersionedCache versionedCache = instanceCache.getVersionedCache(); - Assert.assertEquals("1.0", versionedCache.name()); - Assert.assertSame(instMap, versionedCache.data()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCacheManagerNew.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCacheManagerNew.java deleted file mode 100644 index 54d0589cadf..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestInstanceCacheManagerNew.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestInstanceCacheManagerNew { - @Test - public void getOrCreate(@Mocked AppManager appManager, @Mocked MicroserviceVersionRule microserviceVersionRule, - @Mocked InstanceCache instanceCache) { - InstanceCacheManagerNew mgr = new InstanceCacheManagerNew(appManager); - String appId = "app"; - String microserviceName = "ms"; - String versionRule = DefinitionConst.VERSION_RULE_ALL; - new Expectations() { - { - appManager.getOrCreateMicroserviceVersionRule(appId, microserviceName, versionRule); - result = microserviceVersionRule; - microserviceVersionRule.getInstanceCache(); - result = instanceCache; - } - }; - - Assert.assertSame(instanceCache, mgr.getOrCreate(appId, microserviceName, versionRule)); - } - - @Test - public void getOrCreateVersionedCache(@Mocked AppManager appManager, - @Mocked MicroserviceVersionRule microserviceVersionRule, - @Mocked VersionedCache versionedCache) { - InstanceCacheManagerNew mgr = new InstanceCacheManagerNew(appManager); - String appId = "app"; - String microserviceName = "ms"; - String versionRule = DefinitionConst.VERSION_RULE_ALL; - new Expectations() { - { - appManager.getOrCreateMicroserviceVersionRule(appId, microserviceName, versionRule); - result = microserviceVersionRule; - microserviceVersionRule.getVersionedCache(); - result = versionedCache; - } - }; - - Assert.assertSame(versionedCache, mgr.getOrCreateVersionedCache(appId, microserviceName, versionRule)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java deleted file mode 100644 index 85da7fb0541..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.cache; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceInstanceCache { - @Test - public void testGetOrCreateMicroservice(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client, - @Mocked Microservice microservice) { - new Expectations() { - { - RegistryUtils.getServiceRegistryClient(); - result = client; - client.getAggregatedMicroservice("forkedid"); - result = microservice; - client.getAggregatedMicroservice("forkedidNull"); - result = null; - } - }; - Microservice cachedService = MicroserviceInstanceCache.getOrCreate("forkedid"); - Assert.assertNotNull(cachedService); - cachedService = MicroserviceInstanceCache.getOrCreate("forkedid"); - Assert.assertNotNull(cachedService); - cachedService = MicroserviceInstanceCache.getOrCreate("forkedidNull"); - Assert.assertNull(cachedService); - } - - @Test - public void testGetOrCreateMicroserviceInstance(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client, - @Mocked MicroserviceInstance instance) { - new Expectations() { - { - RegistryUtils.getServiceRegistryClient(); - result = client; - client.findServiceInstance("forkedserviceid", "forkedinstanceid"); - result = instance; - client.findServiceInstance("forkedserviceidNull", "forkedinstanceidNull"); - result = null; - } - }; - MicroserviceInstance cachedInstance = MicroserviceInstanceCache.getOrCreate("forkedserviceid", "forkedinstanceid"); - Assert.assertNotNull(cachedInstance); - cachedInstance = MicroserviceInstanceCache.getOrCreate("forkedserviceid", "forkedinstanceid"); - Assert.assertNotNull(cachedInstance); - cachedInstance = MicroserviceInstanceCache.getOrCreate("forkedserviceidNull", "forkedinstanceidNull"); - Assert.assertNull(cachedInstance); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java deleted file mode 100644 index e4fdc7dcfa5..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import java.io.InputStream; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.client.http.Holder; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.hamcrest.Matchers; -import org.hamcrest.core.Is; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class LocalServiceRegistryClientImplTest { - LocalServiceRegistryClientImpl registryClient; - - String appId = "appId"; - - String microserviceName = "ms"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void loadRegistryFile() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - InputStream is = loader.getResourceAsStream("registry.yaml"); - registryClient = new LocalServiceRegistryClientImpl(is); - } - - @Test - public void testLoadRegistryFile() { - Assert.assertNotNull(registryClient); - Assert.assertThat(registryClient.getAllMicroservices().size(), Is.is(1)); - List m = - registryClient.findServiceInstance("", "myapp", "springmvctest", DefinitionConst.VERSION_RULE_ALL); - Assert.assertEquals(1, m.size()); - - MicroserviceInstances microserviceInstances = - registryClient.findServiceInstances("", "myapp", "springmvctest", DefinitionConst.VERSION_RULE_ALL, null); - List mi = microserviceInstances.getInstancesResponse().getInstances(); - Assert.assertEquals(1, mi.size()); - } - - private Microservice mockRegisterMicroservice(String appId, String name, String version) { - Microservice microservice = new Microservice(); - microservice.setAppId(appId); - microservice.setServiceName(name); - microservice.setVersion(version); - - String serviceId = registryClient.registerMicroservice(microservice); - microservice.setServiceId(serviceId); - return microservice; - } - - @Test - public void getMicroserviceId_appNotMatch() { - mockRegisterMicroservice("otherApp", microserviceName, "1.0.0"); - - Assert.assertNull(registryClient.getMicroserviceId(appId, microserviceName, "1.0.0", "")); - } - - @Test - public void getMicroserviceId_nameNotMatch() { - mockRegisterMicroservice(appId, "otherName", "1.0.0"); - - Assert.assertNull(registryClient.getMicroserviceId(appId, microserviceName, "1.0.0", "")); - } - - @Test - public void getMicroserviceId_versionNotMatch() { - mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - Assert.assertNull(registryClient.getMicroserviceId(appId, microserviceName, "2.0.0", "")); - } - - @Test - public void getMicroserviceId_latest() { - Microservice v2 = mockRegisterMicroservice(appId, microserviceName, "2.0.0"); - mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - - String serviceId = - registryClient.getMicroserviceId(appId, microserviceName, DefinitionConst.VERSION_RULE_LATEST, ""); - Assert.assertEquals(v2.getServiceId(), serviceId); - } - - @Test - public void getMicroserviceId_fixVersion() { - Microservice v1 = mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - mockRegisterMicroservice(appId, microserviceName, "2.0.0"); - - String serviceId = registryClient.getMicroserviceId(appId, microserviceName, "1.0.0", ""); - Assert.assertEquals(v1.getServiceId(), serviceId); - } - - @Test - public void findServiceInstance_noInstances() { - List result = - registryClient.findServiceInstance("self", appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); - - Assert.assertThat(result, Matchers.nullValue()); - - MicroserviceInstances microserviceInstances = - registryClient.findServiceInstances("self", appId, microserviceName, DefinitionConst.VERSION_RULE_ALL, null); - Assert.assertThat(microserviceInstances.isMicroserviceNotExist(), Matchers.is(true)); - Assert.assertThat(microserviceInstances.getInstancesResponse(), Matchers.nullValue()); - } - - @Test - public void findServiceInstance_twoSelectOne() { - Microservice v1 = mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - mockRegisterMicroservice(appId, microserviceName, "2.0.0"); - - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("testid"); - instance.setServiceId(v1.getServiceId()); - registryClient.registerMicroserviceInstance(instance); - - List result = - registryClient.findServiceInstance("self", appId, microserviceName, "1.0.0"); - - Assert.assertThat(result, Matchers.contains(instance)); - - MicroserviceInstances microserviceInstances = - registryClient.findServiceInstances("self", appId, microserviceName, "1.0.0", "0"); - List results = microserviceInstances.getInstancesResponse().getInstances(); - - Assert.assertThat(results, Matchers.contains(instance)); - } - - @Test - public void registerSchema_microserviceNotExist() { - mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage(Matchers.is("Invalid serviceId, serviceId=notExist")); - - registryClient.registerSchema("notExist", "sid", "content"); - } - - @Test - public void registerSchema_normal() { - Microservice v1 = mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - - Assert.assertTrue(registryClient.registerSchema(v1.getServiceId(), "sid", "content")); - } - - @Test - public void testFindServiceInstance() { - Microservice microservice = mockRegisterMicroservice(appId, microserviceName, "1.0.0"); - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setServiceId(microservice.getServiceId()); - String instanceId = registryClient.registerMicroserviceInstance(instance); - Assert.assertNotNull(registryClient.findServiceInstance(microservice.getServiceId(), instanceId)); - } - - @Test - public void testGetServiceCenterInfo() { - ServiceCenterInfo serviceCenterInfo = registryClient.getServiceCenterInfo(); - Assert.assertEquals("1.0.0", serviceCenterInfo.getVersion()); - } - - @Test - public void testGetSchemas() { - Holder> schemasHolder = registryClient.getSchemas("001"); - Assert.assertEquals(200, schemasHolder.getStatusCode()); - Assert.assertTrue(schemasHolder.getValue().isEmpty()); - } - - @Test - public void testLoadSchemaIdsFromRegistryFile() { - Microservice microservice = registryClient.getMicroservice("001"); - Assert.assertThat(microservice.getSchemas().size(), Is.is(1)); - Assert.assertTrue(microservice.getSchemas().contains("springmvcHello")); - } -} - diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryDemo.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryDemo.java deleted file mode 100644 index b0e939ef3d6..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryDemo.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; - -public class ServiceRegistryDemo { - public static void main(String[] args) throws Exception { - Log4jUtils.init(); - BeanUtils.init(); - - // 1、自注册 2、服务心跳 3、实例变化监听 - RegistryUtils.init(); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestEndpoints.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestEndpoints.java deleted file mode 100644 index 97bcf663ebd..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestEndpoints.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.client; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; - -public class TestEndpoints { - @Test - public void testAll() { - Endpoints ep = new Endpoints(); - - List instances = new ArrayList<>(); - - ep.setAppId("appId"); - ep.setServiceName("sn"); - ep.setInstances(instances); - ep.setVersion("v1"); - - Assert.assertEquals("appId", ep.getAppId()); - Assert.assertEquals("sn", ep.getServiceName()); - Assert.assertEquals(instances, ep.getInstances()); - Assert.assertEquals("v1", ep.getVersion()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java deleted file mode 100644 index d619b830c5a..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestIpPortManager { - @Mocked - ServiceRegistryClient srClient; - - AbstractServiceRegistry serviceRegistry; - - IpPortManager manager; - - @Before - public void setup() { - ConfigUtil.createLocalConfig(); - serviceRegistry = (AbstractServiceRegistry) ServiceRegistryFactory.createLocal(); - serviceRegistry.setServiceRegistryClient(srClient); - serviceRegistry.init(); - - manager = serviceRegistry.getIpPortManager(); - } - - @Test - public void testGetAvailableAddress(@Injectable ServiceRegistryConfig config, - @Injectable InstanceCacheManager cacheManager, - @Injectable InstanceCache cache) { - ArrayList ipPortList = new ArrayList<>(); - ipPortList.add(new IpPort("127.0.0.1", 9980)); - ipPortList.add(new IpPort("127.0.0.1", 9981)); - - new Expectations() { - { - config.getIpPort(); - result = ipPortList; - config.getTransport(); - result = "rest"; - config.isRegistryAutoDiscovery(); - result = true; - } - }; - - IpPortManager manager = new IpPortManager(config, cacheManager); - IpPort address1 = manager.getAvailableAddress(); - - if (address1.getPort() == 9980) { - Assert.assertEquals("127.0.0.1", address1.getHostOrIp()); - Assert.assertEquals(9980, address1.getPort()); - } else { - Assert.assertEquals("127.0.0.1", address1.getHostOrIp()); - Assert.assertEquals(9981, address1.getPort()); - } - - IpPort address2 = manager.getNextAvailableAddress(address1); - if (address1.getPort() == 9980) { - Assert.assertEquals("127.0.0.1", address2.getHostOrIp()); - Assert.assertEquals(9981, address2.getPort()); - } else { - Assert.assertEquals("127.0.0.1", address2.getHostOrIp()); - Assert.assertEquals(9980, address2.getPort()); - } - - IpPort address3 = manager.getAvailableAddress(); - if (address1.getPort() == 9980) { - Assert.assertEquals("127.0.0.1", address3.getHostOrIp()); - Assert.assertEquals(9981, address3.getPort()); - } else { - Assert.assertEquals("127.0.0.1", address3.getHostOrIp()); - Assert.assertEquals(9980, address3.getPort()); - } - - Map> addresses = new HashMap<>(); - List instances = new ArrayList<>(); - instances.add(new CacheEndpoint("http://127.0.0.1:9982", null)); - addresses.put("rest", instances); - new Expectations() { - { - cacheManager.getOrCreate("default", "SERVICECENTER", "latest"); - result = cache; - cache.getOrCreateTransportMap(); - result = addresses; - } - }; - - manager.initAutoDiscovery(); //init result is false at first time - IpPort address4 = manager.getNextAvailableAddress(address3); - if (address1.getPort() == 9980) { - Assert.assertEquals("127.0.0.1", address4.getHostOrIp()); - Assert.assertEquals(9980, address4.getPort()); - } else { - address4 = manager.getNextAvailableAddress(address1); - Assert.assertEquals("127.0.0.1", address4.getHostOrIp()); - Assert.assertEquals(9980, address4.getPort()); - } - - IpPort address5 = manager.getNextAvailableAddress(address4); - Assert.assertEquals("127.0.0.1", address5.getHostOrIp()); - Assert.assertEquals(9981, address5.getPort()); - - manager.setAutoDiscoveryInited(true); - IpPort address6 = manager.getNextAvailableAddress(address3); - if (address1.getPort() == 9980) { - Assert.assertEquals("127.0.0.1", address6.getHostOrIp()); - Assert.assertEquals(9982, address6.getPort()); - } else { - address6 = manager.getNextAvailableAddress(address1); - Assert.assertEquals("127.0.0.1", address6.getHostOrIp()); - Assert.assertEquals(9982, address6.getPort()); - } - } - @Test - public void testCreateServiceRegistryCacheWithInstanceCache() { - - List list = new ArrayList<>(); - MicroserviceInstance e1 = new MicroserviceInstance(); - list.add(e1); - - new MockUp() { - - @Mock - public List findServiceInstance(String appId, String serviceName, - String versionRule) { - return list; - } - }; - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/MockAuthHeaderProvider.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/MockAuthHeaderProvider.java deleted file mode 100644 index ea210a6c197..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/MockAuthHeaderProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; - -public class MockAuthHeaderProvider implements AuthHeaderProvider { - @Override - public Map authHeaders() { - HashMap headers = new HashMap<>(); - headers.put("X-Service-AK", "blah..."); - return headers; - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java deleted file mode 100644 index ad72502a162..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -import java.util.HashMap; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.junit.Test; - -import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpMethod; - -public class RestUtilsTest { - @Test - public void defaultHeadersContainServiceRegistryAndAuthentication() throws Exception { - - MultiMap headers = RestUtils.getDefaultHeaders(); - headers.addAll(RestUtils.getSignAuthHeaders(RestUtils.createSignRequest(HttpMethod.GET.toString(), - new IpPort("127.0.0.1", 443), - new RequestParam().addQueryParam("testParam", "test"), - "test", - new HashMap<>()))); - assertThat(headers.get("Content-Type"), is("application/json")); - assertThat(headers.get("User-Agent"), is("cse-serviceregistry-client/1.0.0")); - assertThat(headers.get("x-domain-name"), is("default")); - assertThat(headers.get("X-Service-AK"), is("blah...")); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestAbstractClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestAbstractClientPool.java deleted file mode 100644 index 5187dc667f5..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestAbstractClientPool.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.AbstractVerticle; -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestAbstractClientPool { - @Mocked - Vertx vertx; - - String vertxName; - - VertxOptions vertxOptions; - - Class verticleCls; - - DeploymentOptions deployOptions; - - - @Before - public void setup() { - new MockUp() { - @Mock - Vertx getOrCreateVertxByName(String name, VertxOptions vertxOptions) { - TestAbstractClientPool.this.vertxName = name; - TestAbstractClientPool.this.vertxOptions = vertxOptions; - - return vertx; - } - - @Mock - boolean blockDeploy(Vertx vertx, - Class cls, - DeploymentOptions options) { - TestAbstractClientPool.this.verticleCls = cls; - TestAbstractClientPool.this.deployOptions = options; - - return true; - } - }; - ArchaiusUtils.resetConfig(); - } - - @After - public void teardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void create() { - HttpClientPool.INSTANCE.create(); - - Assert.assertEquals("registry", vertxName); - - Assert.assertEquals(ClientVerticle.class, verticleCls); - Assert.assertEquals(ClientPoolManager.class, - deployOptions.getConfig().getValue(ClientVerticle.CLIENT_MGR).getClass()); - System.out.println(deployOptions); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java deleted file mode 100644 index 96f2daf3e73..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.util.concurrent.CountDownLatch; - -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.client.Endpoints; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestClientHttp { - @SuppressWarnings("unchecked") - @Test - public void testServiceRegistryClientImpl(@Mocked IpPortManager manager) { - IpPort ipPort = new IpPort("127.0.0.1", 8853); - new Expectations() { - { - manager.getAvailableAddress(); - result = ipPort; - } - }; - - new MockUp() { - @Mock - public void await() throws InterruptedException { - } - }; - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - } - }; - - new MockUp() { - @Mock - void open(IpPort ipPort, String url, Handler onOpen, Handler onClose, - Handler onMessage, Handler onException, - Handler onConnectFailed) { - } - }; - - MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - Microservice microservice = microserviceFactory.create("app", "ms"); - - ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(manager); - oClient.init(); - oClient.registerMicroservice(microservice); - oClient.registerMicroserviceInstance(microservice.getInstance()); - Assert.assertEquals(null, oClient.getMicroservice(microservice.getServiceId())); - Assert.assertEquals(null, oClient.getMicroserviceInstance("testConsumerID", "testproviderID")); - Assert.assertEquals(null, - oClient.findServiceInstance(microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion())); - Assert.assertEquals(null, - oClient.findServiceInstances(microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - "0")); - Assert.assertEquals(null, - oClient.getMicroserviceId(microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment())); - Assert.assertEquals(null, - oClient.heartbeat(microservice.getServiceId(), - microservice.getInstance().getInstanceId())); - oClient.watch("", - Mockito.mock(AsyncResultCallback.class)); - Assert.assertEquals(false, - oClient.unregisterMicroserviceInstance(microservice.getServiceId(), - microservice.getInstance().getInstanceId())); - } - - @Test - public void testRequestContext() { - RequestContext oContext = new RequestContext(); - oContext.setUri("//test"); - oContext.setMethod(io.vertx.core.http.HttpMethod.POST); - oContext.setIpPort(new IpPort("145.0.0.1", 8080)); - oContext.setParams(null); - - Assert.assertEquals("//test", oContext.getUri()); - Assert.assertEquals(io.vertx.core.http.HttpMethod.POST, oContext.getMethod()); - Assert.assertEquals(8080, oContext.getIpPort().getPort()); - Assert.assertEquals(null, oContext.getParams()); - - RestResponse oResponse = new RestResponse(null, null); - oResponse.setRequestContext(oContext); - Assert.assertEquals(oContext, oResponse.getRequestContext()); - Assert.assertEquals(null, oResponse.getResponse()); - } - - @Test - public void testRequestParam() { - RequestParam oParam = new RequestParam(); - oParam.setCookies(null); - oParam.setBody(null); - oParam.setHeaders(null); - oParam.addHeader("testKey", "testValue"); - oParam.addQueryParam("testParam", "ValueParam"); - oParam.addQueryParam("testParam1", "ValueParam"); - Assert.assertEquals(null, oParam.getCookies()); - Assert.assertEquals(null, oParam.getBody()); - Assert.assertNotEquals(null, oParam.getHeaders()); - Assert.assertNotEquals(null, oParam.getQueryParams()); - oParam.setQueryParams(null); - Assert.assertEquals("", oParam.getQueryParams()); - oParam.setFormFields(null); - Assert.assertEquals(null, oParam.getFormFields()); - Endpoints oEndpoints = new Endpoints(); - oEndpoints.setInstances(null); - oEndpoints.setVersion("1.0"); - Assert.assertEquals(null, oEndpoints.getInstances()); - Assert.assertEquals("1.0", oEndpoints.getVersion()); - } - - @Test - public void testIpPortManager(@Mocked InstanceCacheManager instanceCacheManager) throws Exception { - IpPortManager oManager = new IpPortManager(ServiceRegistryConfig.INSTANCE, instanceCacheManager); - IpPort oIPPort = oManager.getNextAvailableAddress(new IpPort("", 33)); - Assert.assertEquals(oIPPort.getHostOrIp(), oManager.getAvailableAddress().getHostOrIp()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java deleted file mode 100644 index 1947141ec16..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpVersion; - -public class TestHttpClientPool { - @Before - public void setup() { - ArchaiusUtils.resetConfig(); - } - - @After - public void teardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void createHttpClientOptions_proxy() { - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_ENABLE, "true"); - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_HOST, "host"); - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_PORT, "1234"); - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_USERNAME, "user"); - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_PASSWD, "pass"); - - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertEquals( - "{" - + "\"host\":\"host\"," - + "\"password\":\"pass\"," - + "\"port\":1234," - + "\"type\":\"HTTP\"," - + "\"username\":\"user\"" - + "}", - httpClientOptions.getProxyOptions().toJson().toString()); - } - - @Test - public void createHttpClientOptions_noProxy() { - ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_ENABLE, "false"); - - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertNull(httpClientOptions.getProxyOptions()); - } - - @Test - public void createHttpClientOptions_http2() { - ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name()); - - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion()); - Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade()); - } - - @Test - public void createHttpClientOptions_notHttp2() { - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion()); - Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestMicroserviceInstances.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestMicroserviceInstances.java deleted file mode 100644 index 1cfc30ef5e4..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestMicroserviceInstances.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestMicroserviceInstances { - - MicroserviceInstances microserviceInstances = null; - - FindInstancesResponse findInstancesResponse = null; - - List instances = null; - - @Before - public void setUp() throws Exception { - microserviceInstances = new MicroserviceInstances(); - findInstancesResponse = new FindInstancesResponse(); - instances = new ArrayList<>(); - instances.add(Mockito.mock(MicroserviceInstance.class)); - } - - @After - public void tearDown() throws Exception { - instances = null; - microserviceInstances = null; - findInstancesResponse = null; - } - - @Test - public void testDefaultValues() { - Assert.assertNull(microserviceInstances.getInstancesResponse()); - Assert.assertTrue(microserviceInstances.isNeedRefresh()); - Assert.assertNull(microserviceInstances.getRevision()); - Assert.assertNull(findInstancesResponse.getInstances()); - } - - @Test - public void testInitializedValues() { - initFields(); //Initialize the Object - Assert.assertEquals(1, microserviceInstances.getInstancesResponse().getInstances().size()); - Assert.assertFalse(microserviceInstances.isNeedRefresh()); - Assert.assertEquals("1", microserviceInstances.getRevision()); - } - - private void initFields() { - findInstancesResponse.setInstances(instances); - microserviceInstances.setInstancesResponse(findInstancesResponse); - microserviceInstances.setNeedRefresh(false); - microserviceInstances.setRevision("1"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java deleted file mode 100644 index 900f534d665..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.client.http; - -import static org.hamcrest.core.Is.is; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.core.Response.Status; - -import org.apache.log4j.Appender; -import org.apache.log4j.Logger; -import org.apache.log4j.spi.LoggingEvent; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterConfig; -import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; -import org.apache.servicecomb.serviceregistry.api.response.GetExistenceResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemasResponse; -import org.apache.servicecomb.serviceregistry.api.response.GetServiceResponse; -import org.apache.servicecomb.serviceregistry.client.ClientException; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; -import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.ResponseWrapper; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.json.Json; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestServiceRegistryClientImpl { - @Mocked - private IpPortManager ipPortManager; - - private ServiceRegistryClientImpl oClient = null; - - @Before - public void setUp() throws Exception { - oClient = new ServiceRegistryClientImpl(ipPortManager); - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - } - }; - - new MockUp() { - @Mock - public void await() { - } - }; - } - - @After - public void tearDown() throws Exception { - oClient = null; - } - - @Test - public void testPrivateMethodCreateHttpClientOptions() { - MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - Microservice microservice = microserviceFactory.create("app", "ms"); - oClient.registerMicroservice(microservice); - oClient.registerMicroserviceInstance(microservice.getInstance()); - try { - oClient.init(); - HttpClientOptions httpClientOptions = Deencapsulation.invoke(oClient, "createHttpClientOptions"); - Assert.assertNotNull(httpClientOptions); - Assert.assertEquals(80, httpClientOptions.getDefaultPort()); - } catch (Exception e) { - Assert.assertNotNull(e); - } - } - - @Test - public void testException() { - MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - Microservice microservice = microserviceFactory.create("app", "ms"); - Assert.assertEquals(null, oClient.registerMicroservice(microservice)); - Assert.assertEquals(null, oClient.registerMicroserviceInstance(microservice.getInstance())); - oClient.init(); - Assert.assertEquals(null, - oClient.getMicroserviceId(microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment())); - Assert.assertThat(oClient.getAllMicroservices().isEmpty(), is(true)); - Assert.assertEquals(null, oClient.registerMicroservice(microservice)); - Assert.assertEquals(null, oClient.getMicroservice("microserviceId")); - Assert.assertEquals(null, oClient.getMicroserviceInstance("consumerId", "providerId")); - Assert.assertEquals(false, - oClient.unregisterMicroserviceInstance("microserviceId", "microserviceInstanceId")); - Assert.assertEquals(null, oClient.heartbeat("microserviceId", "microserviceInstanceId")); - Assert.assertEquals(null, - oClient.findServiceInstance("selfMicroserviceId", "appId", "serviceName", "versionRule")); - Assert.assertEquals(null, - oClient.findServiceInstances("selfMicroserviceId", "appId", "serviceName", "versionRule", "0")); - - Assert.assertEquals("a", new ClientException("a").getMessage()); - } - - static abstract class RegisterSchemaTester { - void run() { - Logger rootLogger = Logger.getRootLogger(); - - List events = new ArrayList<>(); - Appender appender = new MockUp() { - @Mock - public void doAppend(LoggingEvent event) { - events.add(event); - } - }.getMockInstance(); - rootLogger.addAppender(appender); - - doRun(events); - - rootLogger.removeAppender(appender); - } - - abstract void doRun(List events); - } - - @Test - public void testRegisterSchemaNoResponse() { - new RegisterSchemaTester() { - void doRun(java.util.List events) { - oClient.registerSchema("msid", "schemaId", "content"); - Assert.assertEquals("Register schema msid/schemaId failed.", events.get(0).getMessage()); - } - }.run(); - } - - @Test - public void testRegisterSchemaException() { - InterruptedException e = new InterruptedException(); - new MockUp() { - @Mock - public void await() throws InterruptedException { - throw e; - } - }; - - new RegisterSchemaTester() { - void doRun(java.util.List events) { - oClient.registerSchema("msid", "schemaId", "content"); - Assert.assertEquals( - "register schema msid/schemaId fail.", - events.get(0).getMessage()); - Assert.assertEquals(e, events.get(0).getThrowableInformation().getThrowable()); - } - }.run(); - } - - @Test - public void testRegisterSchemaErrorResponse() { - new MockUp() { - @Mock - Handler syncHandlerEx(CountDownLatch countDownLatch, Holder holder) { - return restResponse -> { - HttpClientResponse response = Mockito.mock(HttpClientResponse.class); - Mockito.when(response.statusCode()).thenReturn(400); - Mockito.when(response.statusMessage()).thenReturn("client error"); - - Buffer bodyBuffer = Buffer.buffer(); - bodyBuffer.appendString("too big"); - - ResponseWrapper responseWrapper = new ResponseWrapper(); - responseWrapper.response = response; - responseWrapper.bodyBuffer = bodyBuffer; - holder.value = responseWrapper; - }; - } - }; - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - responseHandler.handle(null); - } - }; - - new RegisterSchemaTester() { - void doRun(java.util.List events) { - oClient.registerSchema("msid", "schemaId", "content"); - Assert.assertEquals( - "Register schema msid/schemaId failed, statusCode: 400, statusMessage: client error, description: too big.", - events.get(0).getMessage()); - } - }.run(); - } - - @Test - public void testRegisterSchemaSuccess() { - new MockUp() { - @Mock - Handler syncHandlerEx(CountDownLatch countDownLatch, Holder holder) { - return restResponse -> { - HttpClientResponse response = Mockito.mock(HttpClientResponse.class); - Mockito.when(response.statusCode()).thenReturn(200); - - ResponseWrapper responseWrapper = new ResponseWrapper(); - responseWrapper.response = response; - holder.value = responseWrapper; - }; - } - }; - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - responseHandler.handle(null); - } - }; - - new RegisterSchemaTester() { - void doRun(java.util.List events) { - oClient.registerSchema("msid", "schemaId", "content"); - Assert.assertEquals( - "register schema msid/schemaId success.", - events.get(0).getMessage()); - } - }.run(); - } - - @Test - public void syncHandler_failed(@Mocked RequestContext requestContext, - @Mocked HttpClientResponse response) { - CountDownLatch countDownLatch = new CountDownLatch(1); - Class cls = GetExistenceResponse.class; - Holder holder = new Holder<>(); - Handler handler = oClient.syncHandler(countDownLatch, cls, holder); - - Holder> bodyHandlerHolder = new Holder<>(); - new MockUp(response) { - @Mock - HttpClientResponse bodyHandler(Handler bodyHandler) { - bodyHandlerHolder.value = bodyHandler; - return null; - } - }; - new Expectations() { - { - response.statusCode(); - result = 400; - response.statusMessage(); - result = Status.BAD_REQUEST.getReasonPhrase(); - } - }; - - RestResponse event = new RestResponse(requestContext, response); - handler.handle(event); - - Buffer bodyBuffer = Buffer.buffer("{}"); - bodyHandlerHolder.value.handle(bodyBuffer); - - Assert.assertNull(holder.value); - } - - @Test - public void isSchemaExist() { - String microserviceId = "msId"; - String schemaId = "schemaId"; - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - holder.value = new GetExistenceResponse(); - } - }; - Assert.assertFalse(oClient.isSchemaExist(microserviceId, schemaId)); - } - - @Test - public void getAggregatedMicroservice() { - String microserviceId = "msId"; - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetServiceResponse serviceResp = Json - .decodeValue( - "{\"service\":{\"serviceId\":\"serviceId\",\"framework\":null" - + ",\"registerBy\":null,\"environment\":null,\"appId\":\"appId\",\"serviceName\":null," - + "\"alias\":null,\"version\":null,\"description\":null,\"level\":null,\"schemas\":[]," - + "\"paths\":[],\"status\":\"UP\",\"properties\":{},\"intance\":null}}", - GetServiceResponse.class); - holder.value = serviceResp; - RequestParam requestParam = requestContext.getParams(); - Assert.assertEquals("global=true", requestParam.getQueryParams()); - } - }; - Microservice aggregatedMicroservice = oClient.getAggregatedMicroservice(microserviceId); - Assert.assertEquals("serviceId", aggregatedMicroservice.getServiceId()); - Assert.assertEquals("appId", aggregatedMicroservice.getAppId()); - } - - @Test - public void getAggregatedSchema() { - String microserviceId = "msId"; - String schemaId = "schemaId"; - - new MockUp() { - - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetSchemaResponse schemasResp = Json - .decodeValue( - "{ \"schema\": \"schema\", \"schemaId\":\"metricsEndpoint\",\"summary\":\"c1188d709631a9038874f9efc6eb894f\"}", - GetSchemaResponse.class); - holder.value = schemasResp; - RequestParam requestParam = requestContext.getParams(); - Assert.assertEquals("global=true", requestParam.getQueryParams()); - } - }; - - LoadingCache> oldCache = Deencapsulation.getField(oClient, "schemaCache"); - LoadingCache> newCache = CacheBuilder.newBuilder() - .expireAfterAccess(60, TimeUnit.SECONDS).build(new CacheLoader>() { - public Map load(String key) { - Map schemas = new HashMap<>(); - return schemas; - } - }); - Deencapsulation.setField(oClient, "schemaCache", newCache); - - String str = oClient.getAggregatedSchema(microserviceId, schemaId); - Assert.assertEquals("schema", str); - - Deencapsulation.setField(oClient, "schemaCache", oldCache); - } - - @Test - public void getSchemas() { - String microserviceId = "msId"; - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetSchemasResponse schemasResp = Json.decodeValue( - "{\"schema\":[{\"schemaId\":\"metricsEndpoint\",\"summary\":\"c1188d709631a9038874f9efc6eb894f\"},{\"schemaId\":\"comment\",\"summary\":\"bfa81d625cfbd3a57f38745323e16824\"}," - + "{\"schemaId\":\"healthEndpoint\",\"summary\":\"96a0aaaaa454cfa0c716e70c0017fe27\"}]}", - GetSchemasResponse.class); - holder.statusCode = 200; - holder.value = schemasResp; - } - }; - Holder> schemasHolder = oClient.getSchemas(microserviceId); - List schemaResponses = schemasHolder.getValue(); - Assert.assertEquals(200, schemasHolder.getStatusCode()); - Assert.assertEquals(3, schemaResponses.size()); - Assert.assertEquals("bfa81d625cfbd3a57f38745323e16824", schemaResponses.get(1).getSummary()); - } - - @Test - public void getSchemasForNew() { - String microserviceId = "msId"; - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetSchemasResponse schemasResp = Json.decodeValue( - "{\"schemas\":[{\"schemaId\":\"metricsEndpoint\",\"summary\":\"c1188d709631a9038874f9efc6eb894f\"},{\"schemaId\":\"comment\",\"summary\":\"bfa81d625cfbd3a57f38745323e16824\"}," - + "{\"schemaId\":\"healthEndpoint\",\"summary\":\"96a0aaaaa454cfa0c716e70c0017fe27\"}]}", - GetSchemasResponse.class); - holder.statusCode = 200; - holder.value = schemasResp; - } - }; - Holder> schemasHolder = oClient.getSchemas(microserviceId); - List schemas = schemasHolder.getValue(); - Assert.assertEquals(200, schemasHolder.getStatusCode()); - Assert.assertEquals(3, schemas.size()); - Assert.assertEquals("bfa81d625cfbd3a57f38745323e16824", schemas.get(1).getSummary()); - } - - @Test - public void getSchemasFailed() { - String microserviceId = "msId"; - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - holder.setStatusCode(Status.NOT_FOUND.getStatusCode()); - } - }; - Holder> schemasHolder = oClient.getSchemas(microserviceId); - List schemaResponses = schemasHolder.getValue(); - Assert.assertEquals(404, schemasHolder.getStatusCode()); - Assert.assertNull(schemaResponses); - } - - @Test - public void testFindServiceInstance() { - new MockUp() { - @Mock - void get(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - Assert.assertEquals("global=true", requestParam.getQueryParams()); - } - }; - Assert.assertNull(oClient.findServiceInstance("aaa", "bbb")); - } - - @Test - public void findServiceInstance_consumerId_null() { - new MockUp(ipPortManager) { - @Mock - IpPort getAvailableAddress() { - throw new Error("must not invoke this."); - } - }; - new MockUp() { - @Mock - void get(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - Assert.assertEquals("global=true", requestParam.getQueryParams()); - } - }; - Assert.assertNull(oClient.findServiceInstance(null, "appId", "serviceName", "1.0.0+")); - } - - @Test - public void findServiceInstances_microserviceNotExist(@Mocked RequestContext requestContext) { - HttpClientResponse response = new MockUp() { - @Mock - int statusCode() { - return 400; - } - - @Mock - HttpClientResponse bodyHandler(Handler bodyHandler) { - Buffer bodyBuffer = Buffer.buffer("{\"errorCode\":\"400012\"}"); - bodyHandler.handle(bodyBuffer); - return null; - } - }.getMockInstance(); - RestResponse restResponse = new RestResponse(requestContext, response); - new MockUp() { - @Mock - void get(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - Assert.assertEquals("appId=appId&global=true&serviceName=serviceName&version=0.0.0%2B", - requestParam.getQueryParams()); - httpDo(RestUtils.createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler); - } - - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - responseHandler.handle(restResponse); - } - }; - MicroserviceInstances microserviceInstances = oClient - .findServiceInstances("consumerId", "appId", "serviceName", DefinitionConst.VERSION_RULE_ALL, null); - - Assert.assertTrue(microserviceInstances.isMicroserviceNotExist()); - Assert.assertFalse(microserviceInstances.isNeedRefresh()); - } - - @Test - public void testGetServiceCenterInfoSuccess() { - ServiceCenterInfo serviceCenterInfo = new ServiceCenterInfo(); - serviceCenterInfo.setVersion("x.x.x"); - serviceCenterInfo.setBuildTag("xxx"); - serviceCenterInfo.setRunMode("dev"); - serviceCenterInfo.setApiVersion("x.x.x"); - serviceCenterInfo.setConfig(new ServiceCenterConfig()); - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - holder.value = serviceCenterInfo; - } - }; - ServiceCenterInfo info = oClient.getServiceCenterInfo(); - Assert.assertEquals("x.x.x", info.getVersion()); - Assert.assertEquals("xxx", info.getBuildTag()); - Assert.assertEquals("dev", info.getRunMode()); - Assert.assertNotNull(info.getConfig()); - } - - @Test - public void testGetServiceCenterInfoException() { - InterruptedException e = new InterruptedException(); - new MockUp() { - @Mock - public void await() throws InterruptedException { - throw e; - } - }; - - new RegisterSchemaTester() { - void doRun(java.util.List events) { - oClient.getServiceCenterInfo(); - Assert.assertEquals( - "query servicecenter version info failed.", - events.get(0).getMessage()); - Assert.assertEquals(e, events.get(0).getThrowableInformation().getThrowable()); - } - }.run(); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java deleted file mode 100644 index 1badce34f6b..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.client.http; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpVersion; - -public class TestWebsocketClientPool { - @Before - public void setup() { - ArchaiusUtils.resetConfig(); - } - - @After - public void teardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void createHttpClientOptions_http2() { - ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name()); - - HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion()); - Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade()); - } - - @Test - public void createHttpClientOptions_notHttp2() { - HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions(); - - Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion()); - Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java deleted file mode 100644 index a1778ee423a..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestConfigurePropertyUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.registry.BasePath; -import org.junit.Assert; -import org.junit.Test; - -public class TestConfigurePropertyUtils { - @Test - public void testGetPropertiesWithPrefix() { - Configuration configuration = ConfigUtil.createLocalConfig(); - - String prefix = "service_description.properties"; - Map expectedMap = new HashMap<>(); - expectedMap.put("key1", "value1"); - expectedMap.put("key2", "value2"); - Assert.assertEquals(expectedMap, ConfigurePropertyUtils.getPropertiesWithPrefix(configuration, prefix)); - - List paths = ConfigurePropertyUtils.getMicroservicePaths(configuration); - Assert.assertEquals(2, paths.size()); - Assert.assertEquals(paths.get(0).getPath(), "/test1/testpath"); - Assert.assertEquals(paths.get(0).getProperty().get("checksession"), false); - - System.setProperty(Const.URL_PREFIX, "/webroot"); - paths = ConfigurePropertyUtils.getMicroservicePaths(configuration); - Assert.assertEquals(2, paths.size()); - Assert.assertEquals(paths.get(0).getPath(), "/webroot/test1/testpath"); - Assert.assertEquals(paths.get(0).getProperty().get("checksession"), false); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java deleted file mode 100644 index fdb9b6c2f99..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_SERVICE_DESCRIPTION_KEY; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.archaius.sources.ConfigModel; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.junit.Assert; -import org.junit.Test; - -import com.netflix.config.DynamicConfiguration; - -public class TestPropertiesLoader { - private static MicroserviceFactory microserviceFactory = new MicroserviceFactory(); - - @Test - public void testMergeStrings() { - Assert.assertEquals("abc123efg", AbstractPropertiesLoader.mergeStrings("abc", "123", "efg")); - } - - @Test - public void testEmptyExtendedClass() { - Microservice microservice = microserviceFactory.create("default", "emptyExtendedClass"); - Assert.assertEquals(0, microservice.getProperties().size()); - } - - @Test - public void testInvalidExtendedClass() { - ConfigModel configModel = MicroserviceDefinition.createConfigModel("default", "invalidExtendedClass"); - @SuppressWarnings("unchecked") - Map desc = - (Map) configModel.getConfig().get(CONFIG_SERVICE_DESCRIPTION_KEY); - desc.put("propertyExtentedClass", "invalidClass"); - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(Arrays.asList(configModel)); - try { - microserviceFactory.create(microserviceDefinition); - Assert.fail("Must throw exception"); - } catch (Error e) { - Assert.assertEquals(ClassNotFoundException.class, e.getCause().getClass()); - Assert.assertEquals("invalidClass", e.getCause().getMessage()); - } - } - - @Test - public void testCanNotAssignExtendedClass() { - ConfigModel configModel = MicroserviceDefinition.createConfigModel("default", "invalidExtendedClass"); - @SuppressWarnings("unchecked") - Map desc = - (Map) configModel.getConfig().get(CONFIG_SERVICE_DESCRIPTION_KEY); - desc.put("propertyExtentedClass", "java.lang.String"); - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(Arrays.asList(configModel)); - try { - microserviceFactory.create(microserviceDefinition); - Assert.fail("Must throw exception"); - } catch (Error e) { - Assert.assertEquals( - "Define propertyExtendedClass java.lang.String in yaml, but not implement the interface PropertyExtended.", - e.getMessage()); - } - } - - @Test - public void testMicroservicePropertiesLoader() throws Exception { - Microservice microservice = ServiceRegistryFactory.createLocal().getMicroservice(); - Map expectedMap = new HashMap<>(); - expectedMap.put("key1", "value1"); - expectedMap.put("key2", "value2"); - expectedMap.put("ek0", "ev0"); - Assert.assertEquals(expectedMap, microservice.getProperties()); - } - - @Test - public void testInstancePropertiesLoader() { - Microservice microservice = ServiceRegistryFactory.createLocal().getMicroservice(); - MicroserviceInstance instance = microservice.getInstance(); - Map expectedMap = new HashMap<>(); - expectedMap.put("key0", "value0"); - expectedMap.put("ek0", "ev0"); - Assert.assertEquals(expectedMap, instance.getProperties()); - } - - @Test - public void testExtendedClassCompatible() { - Configuration configuration = new DynamicConfiguration(); - configuration.setProperty(CONFIG_SERVICE_DESCRIPTION_KEY + AbstractPropertiesLoader.EXTENDED_CLASS, "invalidClass"); - - AbstractPropertiesLoader loader = MicroservicePropertiesLoader.INSTANCE; - try { - loader.loadProperties(configuration); - Assert.fail("Must throw exception"); - } catch (Error e) { - Assert.assertEquals(ClassNotFoundException.class, e.getCause().getClass()); - Assert.assertEquals("invalidClass", e.getCause().getMessage()); - } - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java deleted file mode 100644 index c6211636f34..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.config; - -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.deployment.DefaultDeploymentProvider; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.netflix.config.DynamicPropertyFactory; - -public class TestServiceRegistryConfig { - @BeforeClass - public static void initClass() { - ArchaiusUtils.resetConfig(); - System.setProperty("servicecomb.service.registry.address", "http://127.0.0.1, https://127.0.0.1"); - DefaultDeploymentProvider.setConfiguration(ConfigUtil.createLocalConfig()); - } - - @AfterClass - public static void teardownClass() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testServiceRegistryConfig() { - ServiceRegistryConfig oConfig = ServiceRegistryConfig.INSTANCE; - Assert.assertEquals(null, oConfig.getAccessKey()); - Assert.assertEquals(30000, oConfig.getConnectionTimeout()); - Assert.assertNotEquals(null, oConfig.getHeartbeatInterval()); - Assert.assertEquals("HTTP_1_1", oConfig.getHttpVersion().name()); - Assert.assertEquals("rest", oConfig.getTransport()); - Assert.assertEquals(1, oConfig.getWorkerPoolSize()); - Assert.assertEquals(true, oConfig.isSsl()); - Assert.assertEquals(30000, oConfig.getRequestTimeout()); - Assert.assertEquals(3000, oConfig.getHeartBeatRequestTimeout()); - Assert.assertNotEquals(null, oConfig.getResendHeartBeatTimes()); - Assert.assertEquals(false, oConfig.isPreferIpAddress()); - Assert.assertEquals(true, oConfig.isWatch()); - Assert.assertEquals(false, oConfig.isClientAuthEnabled()); - Assert.assertEquals(ServiceRegistryConfig.NO_TENANT, oConfig.getTenantName()); - Assert.assertEquals(null, oConfig.getSecretKey()); - Assert.assertNull(ServiceRegistryConfig.INSTANCE.getMicroserviceVersionFactory()); - List ipPorts = oConfig.getIpPort(); - Assert.assertEquals("127.0.0.1:80", ipPorts.get(0).toString()); - Assert.assertEquals("127.0.0.1:443", ipPorts.get(1).toString()); - } - - @Test - public void getMicroserviceVersionFactory() { - DynamicPropertyFactory.getInstance(); - Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - config.addProperty(ServiceRegistryConfig.MICROSERVICE_VERSION_FACTORY, "test"); - - Assert.assertEquals("test", ServiceRegistryConfig.INSTANCE.getMicroserviceVersionFactory()); - - config.clearProperty(ServiceRegistryConfig.MICROSERVICE_VERSION_FACTORY); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionTestUtils.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionTestUtils.java deleted file mode 100644 index 5a9db91896a..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersionTestUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; - -import mockit.Expectations; -import mockit.Mocked; - -public interface MicroserviceVersionTestUtils { - - - public static MicroserviceVersion createMicroserviceVersion(String microserviceId, String version, - @Mocked ServiceRegistry serviceRegistry) { - - Microservice microservice = new Microservice(); - microservice.setServiceId(microserviceId); - microservice.setVersion(version); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAggregatedRemoteMicroservice(microserviceId); - result = microservice; - } - }; - return new MicroserviceVersion(microserviceId); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionsTest.java deleted file mode 100644 index a3317490f3c..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersionsTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Collections; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry; -import org.apache.servicecomb.serviceregistry.version.Version; -import org.apache.servicecomb.serviceregistry.version.VersionUtils; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Mock; -import mockit.MockUp; - -public class StaticMicroserviceVersionsTest { - - private static final String APP_ID = "testAppId"; - - private static final String THIS_SERVICE = "thisService"; - - private static final String MICROSERVICE_NAME = "3rdPartyService"; - - private static final String ENVIRONMENT = "production"; - - private static final String SERVICE_ID_PREFIX = APP_ID + "-" + ENVIRONMENT + "-" + MICROSERVICE_NAME + "-"; - - @BeforeClass - public static void beforeClass() { - RegistryUtils.setServiceRegistry(new AbstractServiceRegistry(null, null, - MicroserviceDefinition.create(APP_ID, THIS_SERVICE)) { - @Override - protected ServiceRegistryClient createServiceRegistryClient() { - return null; - } - }); - RegistryUtils.getMicroservice().setEnvironment(ENVIRONMENT); - } - - @Test - public void addInstanceBasic() { - StaticMicroserviceVersions staticMicroserviceVersions = createStaticMicroserviceVersions(); - - MicroserviceInstance instance = new MicroserviceInstance(); - String serviceVersion = "1.2.1.0"; - staticMicroserviceVersions.addInstances(serviceVersion, Collections.singletonList(instance)); - - MicroserviceVersionRule versionRule = staticMicroserviceVersions.getOrCreateMicroserviceVersionRule(serviceVersion); - MicroserviceVersion latestMicroserviceVersion = versionRule.getLatestMicroserviceVersion(); - Assert.assertEquals(new Version(serviceVersion), latestMicroserviceVersion.getVersion()); - Microservice latestMicroservice = latestMicroserviceVersion.getMicroservice(); - Assert.assertEquals(APP_ID, latestMicroservice.getAppId()); - Assert.assertEquals(SERVICE_ID_PREFIX + serviceVersion, latestMicroservice.getServiceId()); - Assert.assertEquals(MICROSERVICE_NAME, latestMicroservice.getServiceName()); - Assert.assertEquals(serviceVersion, latestMicroservice.getVersion()); - Assert.assertEquals(ENVIRONMENT, latestMicroservice.getEnvironment()); - Assert.assertEquals(TestServiceIntf.class, ((StaticMicroservice) latestMicroservice).getSchemaIntfCls()); - Assert.assertEquals(1, versionRule.getInstances().size()); - Assert.assertSame(instance, versionRule.getInstances().get(instance.getInstanceId())); - Assert.assertEquals(SERVICE_ID_PREFIX + serviceVersion, instance.getServiceId()); - Assert.assertTrue(instance.getInstanceId().startsWith(SERVICE_ID_PREFIX + serviceVersion + "-")); - } - - @Test - public void addInstancesAndGetVersionRuleMultiTimes() { - StaticMicroserviceVersions staticMicroserviceVersions = createStaticMicroserviceVersions(); - - // add instance1 with version 1.1.0 - MicroserviceInstance instance1 = new MicroserviceInstance(); - staticMicroserviceVersions.addInstances("1.1.0", Collections.singletonList(instance1)); - - MicroserviceVersionRule versionRule = staticMicroserviceVersions.getOrCreateMicroserviceVersionRule("0.0.0+"); - MicroserviceVersion latestMicroserviceVersion = versionRule.getLatestMicroserviceVersion(); - Assert.assertEquals(new Version("1.1.0"), latestMicroserviceVersion.getVersion()); - Assert.assertEquals(1, versionRule.getInstances().size()); - Assert.assertSame(instance1, versionRule.getInstances().get(instance1.getInstanceId())); - - // add instance2 with version 1.1.1 - MicroserviceInstance instance2 = new MicroserviceInstance(); - staticMicroserviceVersions.addInstances("1.1.1", Collections.singletonList(instance2)); - - versionRule = staticMicroserviceVersions.getOrCreateMicroserviceVersionRule("0.0.0+"); - latestMicroserviceVersion = versionRule.getLatestMicroserviceVersion(); - Assert.assertEquals(new Version("1.1.1"), latestMicroserviceVersion.getVersion()); - Assert.assertEquals(2, versionRule.getInstances().size()); - Assert.assertSame(instance1, versionRule.getInstances().get(instance1.getInstanceId())); - Assert.assertSame(instance2, versionRule.getInstances().get(instance2.getInstanceId())); - - // add instance3 with version 0.1.0 - MicroserviceInstance instance3 = new MicroserviceInstance(); - staticMicroserviceVersions.addInstances("0.1.0", Collections.singletonList(instance3)); - - versionRule = staticMicroserviceVersions.getOrCreateMicroserviceVersionRule("0.0.0+"); - latestMicroserviceVersion = versionRule.getLatestMicroserviceVersion(); - Assert.assertEquals(new Version("1.1.1"), latestMicroserviceVersion.getVersion()); - Assert.assertEquals(3, versionRule.getInstances().size()); - Assert.assertSame(instance1, versionRule.getInstances().get(instance1.getInstanceId())); - Assert.assertSame(instance2, versionRule.getInstances().get(instance2.getInstanceId())); - Assert.assertSame(instance3, versionRule.getInstances().get(instance3.getInstanceId())); - - // instance3 should be filtered out - versionRule = staticMicroserviceVersions.getOrCreateMicroserviceVersionRule("1.0.0+"); - latestMicroserviceVersion = versionRule.getLatestMicroserviceVersion(); - Assert.assertEquals(new Version("1.1.1"), latestMicroserviceVersion.getVersion()); - Assert.assertEquals(2, versionRule.getInstances().size()); - Assert.assertSame(instance1, versionRule.getInstances().get(instance1.getInstanceId())); - Assert.assertSame(instance2, versionRule.getInstances().get(instance2.getInstanceId())); - Assert.assertNull(versionRule.getInstances().get(instance3.getInstanceId())); - } - - private StaticMicroserviceVersions createStaticMicroserviceVersions() { - EventBus eventBus = new EventBus(); - AppManager appManager = new AppManager(eventBus); - appManager.setStaticMicroserviceVersionFactory(microservice -> new MockUp() { - @Mock - public Version getVersion() { - return VersionUtils.getOrCreate(microservice.getVersion()); - } - - @Mock - public Microservice getMicroservice() { - return microservice; - } - }.getMockInstance()); - return new StaticMicroserviceVersions( - appManager, APP_ID, MICROSERVICE_NAME, TestServiceIntf.class); - } - - private interface TestServiceIntf { - } -} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestAppManager.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestAppManager.java deleted file mode 100644 index 17b5da97615..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestAppManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Collections; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.StaticMicroservice; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestAppManager { - EventBus eventBus = new EventBus(); - - AppManager appManager = new AppManager(eventBus); - - String appId = "appId"; - - String serviceName = "msName"; - - String versionRule = "0+"; - - MicroserviceInstances microserviceInstances = null; - - FindInstancesResponse findInstancesResponse = null; - - @Before - public void setUp() throws Exception { - microserviceInstances = new MicroserviceInstances(); - findInstancesResponse = new FindInstancesResponse(); - findInstancesResponse.setInstances(Collections.emptyList()); - microserviceInstances.setInstancesResponse(findInstancesResponse); - } - - @After - public void tearDown() throws Exception { - findInstancesResponse = null; - microserviceInstances = null; - } - - @Test - public void getOrCreateMicroserviceVersionRule() { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(appId, serviceName, DefinitionConst.VERSION_RULE_ALL, null); - result = microserviceInstances; - } - }; - - MicroserviceVersionRule microserviceVersionRule = - appManager.getOrCreateMicroserviceVersionRule(appId, serviceName, versionRule); - Assert.assertEquals("0.0.0.0+", microserviceVersionRule.getVersionRule().getVersionRule()); - Assert.assertNull(microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void getOrCreateMicroserviceVersions() { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(appId, serviceName, DefinitionConst.VERSION_RULE_ALL, null); - result = microserviceInstances; - } - }; - - MicroserviceVersions microserviceVersions = appManager.getOrCreateMicroserviceVersions(appId, serviceName); - Assert.assertEquals(appId, microserviceVersions.getAppId()); - Assert.assertEquals(serviceName, microserviceVersions.getMicroserviceName()); - } - - @Test - public void setMicroserviceVersionFactory(@Mocked MicroserviceVersionFactory microserviceVersionFactory) { - appManager.setMicroserviceVersionFactory(microserviceVersionFactory); - - Assert.assertSame(microserviceVersionFactory, appManager.getMicroserviceVersionFactory()); - } - - @Test - public void getStaticMicroserviceVersionFactory() { - new MockUp() { - @Mock - String getStaticMicroserviceVersionFactory() { - return TestStaticMicroserviceVersionFactory.class.getName(); - } - }; - - Assert.assertNull(Deencapsulation.getField(appManager, "staticMicroserviceVersionFactory")); - - Assert.assertEquals(TestStaticMicroserviceVersionFactory.class, - appManager.getStaticMicroserviceVersionFactory().getClass()); - } - - static class TestStaticMicroserviceVersionFactory implements StaticMicroserviceVersionFactory { - @Override - public MicroserviceVersion create(StaticMicroservice microservice) { - return null; - } - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestDefaultMicroserviceVersionFactory.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestDefaultMicroserviceVersionFactory.java deleted file mode 100644 index 5dfe428fc2c..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestDefaultMicroserviceVersionFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestDefaultMicroserviceVersionFactory { - @Test - public void create(@Mocked Microservice microservice, @Mocked ServiceRegistry serviceRegistry) { - String microserviceId = "id"; - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAggregatedRemoteMicroservice(microserviceId); - result = microservice; - microservice.getVersion(); - result = "1.0.0"; - } - }; - - MicroserviceVersion microserviceVersion = new DefaultMicroserviceVersionFactory().create("", microserviceId); - Assert.assertSame(microservice, microserviceVersion.getMicroservice()); - Assert.assertEquals("1.0.0.0", microserviceVersion.getVersion().getVersion()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceManager.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceManager.java deleted file mode 100644 index 9fbdf0f4d38..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceManager.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.task.event.MicroserviceNotExistEvent; -import org.apache.servicecomb.serviceregistry.task.event.PeriodicPullEvent; -import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; - -public class TestMicroserviceManager { - String appId = "appId"; - - String serviceName = "msName"; - - String versionRule = "0+"; - - EventBus eventBus = new EventBus(); - - AppManager appManager = new AppManager(eventBus); - - MicroserviceManager microserviceManager = new MicroserviceManager(appManager, appId); - - Map cachedVersions = Deencapsulation.getField(microserviceManager, "versionsByName"); - - MicroserviceInstances microserviceInstances = null; - - FindInstancesResponse findInstancesResponse = null; - - @Before - public void setUp() throws Exception { - microserviceInstances = new MicroserviceInstances(); - findInstancesResponse = new FindInstancesResponse(); - findInstancesResponse.setInstances(Collections.emptyList()); - microserviceInstances.setInstancesResponse(findInstancesResponse); - } - - @After - public void tearDown() throws Exception { - findInstancesResponse = null; - microserviceInstances = null; - } - - @Test - public void getOrCreateMicroserviceVersionRule() { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(appId, serviceName, DefinitionConst.VERSION_RULE_ALL, null); - result = microserviceInstances; - } - }; - - MicroserviceVersionRule microserviceVersionRule = - microserviceManager.getOrCreateMicroserviceVersionRule(serviceName, versionRule); - Assert.assertEquals("0.0.0.0+", microserviceVersionRule.getVersionRule().getVersionRule()); - Assert.assertNull(microserviceVersionRule.getLatestMicroserviceVersion()); - Assert.assertEquals(1, cachedVersions.size()); - } - - @Test - public void testCreateRuleServiceNotExists() { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.findServiceInstances(appId, serviceName, DefinitionConst.VERSION_RULE_ALL, null); - result = null; - } - }; - - AtomicInteger triggerCount = new AtomicInteger(); - new MockUp() { - @Mock - void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) { - triggerCount.incrementAndGet(); - } - }; - - MicroserviceVersionRule microserviceVersionRule = - microserviceManager.getOrCreateMicroserviceVersionRule(serviceName, versionRule); - Assert.assertEquals("0.0.0.0+", microserviceVersionRule.getVersionRule().getVersionRule()); - Assert.assertNull(microserviceVersionRule.getLatestMicroserviceVersion()); - Assert.assertEquals(0, cachedVersions.size()); - - MicroserviceInstanceChangedEvent changedEvent = new MicroserviceInstanceChangedEvent(); - eventBus.post(changedEvent); - Assert.assertEquals(0, triggerCount.get()); - } - - @Test - public void onMicroserviceNotExistEvent_otherApp() { - MicroserviceVersions microserviceVersions = new MicroserviceVersions(appManager, appId, serviceName); - cachedVersions.put(serviceName, microserviceVersions); - - MicroserviceNotExistEvent microserviceNotExistEvent = new MicroserviceNotExistEvent("otherAppId", serviceName); - - Assert.assertEquals(1, cachedVersions.size()); - eventBus.post(microserviceNotExistEvent); - // nothing happened - Assert.assertEquals(1, cachedVersions.size()); - } - - @Test - public void onMicroserviceNotExistEvent_normal() { - MicroserviceVersions microserviceVersions = new MicroserviceVersions(appManager, appId, serviceName); - cachedVersions.put(serviceName, microserviceVersions); - - MicroserviceNotExistEvent microserviceNotExistEvent = new MicroserviceNotExistEvent(appId, serviceName); - - Assert.assertEquals(1, cachedVersions.size()); - eventBus.post(microserviceNotExistEvent); - Assert.assertEquals(0, cachedVersions.size()); - } - - @Test - public void periodicPull() { - testPullEvent(new PeriodicPullEvent()); - } - - @Test - public void serviceRegistryRecovery() { - testPullEvent(new RecoveryEvent()); - } - - private void testPullEvent(Object event) { - Map versionsByName = Deencapsulation.getField(microserviceManager, "versionsByName"); - - Holder count = new Holder<>(); - count.value = 0; - MicroserviceVersions versions = new MockUp() { - @Mock - void submitPull() { - count.value++; - } - }.getMockInstance(); - versionsByName.put("ms", versions); - - eventBus.post(event); - Assert.assertEquals(1, (int) count.value); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersion.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersion.java deleted file mode 100644 index 279743a9c1d..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersion.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.version.Version; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceVersion { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void constructInvalid(@Mocked ServiceRegistry serviceRegistry) { - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid microserviceId invalid.")); - - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getAggregatedRemoteMicroservice("invalid"); - result = null; - } - }; - new MicroserviceVersion("invalid"); - } - - @Test - public void constructNormal(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion microserviceVersion = MicroserviceVersionTestUtils - .createMicroserviceVersion("1", "1.0.0", serviceRegistry); - Assert.assertEquals("1", microserviceVersion.getMicroservice().getServiceId()); - Assert.assertEquals("1.0.0.0", microserviceVersion.getVersion().getVersion()); - } - - @Test - public void constructByMicroservice() { - Microservice microservice = new Microservice(); - String version = "1.2.1"; - microservice.setVersion(version); - MicroserviceVersion microserviceVersion = new MicroserviceVersion(microservice); - - Assert.assertSame(microservice, microserviceVersion.getMicroservice()); - Assert.assertEquals(new Version(version), microserviceVersion.getVersion()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersionRule.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersionRule.java deleted file mode 100644 index 996a865a8c0..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersionRule.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.Arrays; - -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCache; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mocked; - -public class TestMicroserviceVersionRule { - MicroserviceVersionRule microserviceVersionRule = new MicroserviceVersionRule("appId", "msName", "1+"); - - @Test - public void getVersionRule() { - Assert.assertEquals("1.0.0.0+", microserviceVersionRule.getVersionRule().getVersionRule()); - } - - @Test - public void addMicroserviceVersionNotMatch(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion microserviceVersion = MicroserviceVersionTestUtils - .createMicroserviceVersion("1", "0.0.1", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(microserviceVersion); - - Assert.assertNull(microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void addMicroserviceVersionMatch(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion v2 = MicroserviceVersionTestUtils.createMicroserviceVersion("2", "2.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v2); - Assert.assertSame(v2, microserviceVersionRule.getLatestMicroserviceVersion()); - - MicroserviceVersion v1 = MicroserviceVersionTestUtils.createMicroserviceVersion("1", "1.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v1); - Assert.assertSame(v2, microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void deleteMicroserviceVersionNotMatch(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion v2 = MicroserviceVersionTestUtils.createMicroserviceVersion("2", "2.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v2); - - MicroserviceVersion v1 = MicroserviceVersionTestUtils.createMicroserviceVersion("1", "0.0.1", serviceRegistry); - microserviceVersionRule.deleteMicroserviceVersion(v1); - Assert.assertSame(v2, microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void deleteMicroserviceVersionMatchNotExist(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion v2 = MicroserviceVersionTestUtils.createMicroserviceVersion("2", "2.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v2); - - MicroserviceVersion v1 = MicroserviceVersionTestUtils.createMicroserviceVersion("1", "1.0.0", serviceRegistry); - microserviceVersionRule.deleteMicroserviceVersion(v1); - Assert.assertSame(v2, microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void deleteMicroserviceVersionMatchAndExist(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion v2 = MicroserviceVersionTestUtils.createMicroserviceVersion("2", "2.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v2); - - microserviceVersionRule.deleteMicroserviceVersion(v2); - // keep a latest version always, event no versions. - Assert.assertEquals(microserviceVersionRule.getLatestMicroserviceVersion(), v2); - } - - @Test - public void setInstances(@Mocked ServiceRegistry serviceRegistry) { - MicroserviceVersion v1 = MicroserviceVersionTestUtils.createMicroserviceVersion("1", "0.0.1", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v1); - - MicroserviceVersion v2 = MicroserviceVersionTestUtils.createMicroserviceVersion("2", "2.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v2); - - MicroserviceInstance instance1 = new MicroserviceInstance(); - instance1.setServiceId("1"); - instance1.setInstanceId("i1"); - - MicroserviceInstance instance2 = new MicroserviceInstance(); - instance2.setServiceId("2"); - instance2.setInstanceId("i2"); - - MicroserviceInstance instance3 = new MicroserviceInstance(); - instance3.setServiceId("3"); - instance3.setInstanceId("i3"); - - InstanceCache orgCache = microserviceVersionRule.getInstanceCache(); - microserviceVersionRule.setInstances(Arrays.asList(instance1, instance2, instance3)); - - Assert.assertThat(microserviceVersionRule.getInstances().values(), Matchers.contains(instance2)); - Assert.assertNotSame(orgCache, microserviceVersionRule.getInstanceCache()); - Assert.assertSame(microserviceVersionRule.getInstances(), - microserviceVersionRule.getInstanceCache().getInstanceMap()); - Assert.assertSame(microserviceVersionRule.getInstances(), - microserviceVersionRule.getVersionedCache().data()); - Assert.assertEquals(microserviceVersionRule.getLatestMicroserviceVersion(), v2); - microserviceVersionRule.setInstances(Arrays.asList(instance2)); - Assert.assertEquals(microserviceVersionRule.getLatestMicroserviceVersion(), v2); - - MicroserviceVersion v3 = MicroserviceVersionTestUtils.createMicroserviceVersion("3", "3.0.0", serviceRegistry); - microserviceVersionRule.addMicroserviceVersion(v3); - Assert.assertEquals(microserviceVersionRule.getLatestMicroserviceVersion(), v2); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java deleted file mode 100644 index 1382bf9e2cf..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestMicroserviceVersions.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.serviceregistry.api.MicroserviceKey; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.task.event.MicroserviceNotExistEvent; -import org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent; -import org.apache.servicecomb.serviceregistry.version.Version; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestMicroserviceVersions { - EventBus eventBus = new EventBus(); - - @Mocked - ServiceRegistry serviceRegistry; - - AppManager appManager = new AppManager(eventBus); - - String appId = "appId"; - - String microserviceName = "msName"; - - Map microservices = new HashMap<>(); - - List instances = new ArrayList<>(); - - MicroserviceVersions microserviceVersions; - - AtomicInteger pendingPullCount; - - MicroserviceInstances microserviceInstances = null; - - FindInstancesResponse findInstancesResponse = null; - - @Before - public void setUp() throws Exception { - ArchaiusUtils.resetConfig(); - microserviceInstances = new MicroserviceInstances(); - findInstancesResponse = new FindInstancesResponse(); - } - - @After - public void tearDown() throws Exception { - ArchaiusUtils.resetConfig(); - findInstancesResponse = null; - microserviceInstances = null; - } - - public TestMicroserviceVersions() { - microserviceVersions = new MicroserviceVersions(appManager, appId, microserviceName); - pendingPullCount = Deencapsulation.getField(microserviceVersions, "pendingPullCount"); - } - - private void createMicroservice(String microserviceId) { - Microservice microservice = new Microservice(); - microservice.setServiceId(microserviceId); - microservice.setVersion(microserviceId + ".0.0"); - - microservices.put(microserviceId, microservice); - } - - private void createInstance(String microserviceId) { - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId("i" + microserviceId); - instance.setServiceId(microserviceId); - - instances.add(instance); - } - - private void createMicroserviceInstances() { - findInstancesResponse.setInstances(instances); - microserviceInstances.setInstancesResponse(findInstancesResponse); - microserviceInstances.setRevision("1"); - microserviceInstances.setNeedRefresh(true); - } - - private void setup(String microserviceId) { - createMicroservice(microserviceId); - createInstance(microserviceId); - createMicroserviceInstances(); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return microserviceInstances; - } - - @Mock - Microservice getMicroservice(String microserviceId) { - return microservices.get(microserviceId); - } - - @Mock - ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - }; - - new Expectations() { - { - serviceRegistry.getAggregatedRemoteMicroservice(microserviceId); - result = microservices.get(microserviceId); - } - }; - } - - @Test - public void construct() { - microserviceVersions = new MicroserviceVersions(appManager, appId, microserviceName); - - Assert.assertEquals(appId, microserviceVersions.getAppId()); - Assert.assertEquals(microserviceName, microserviceVersions.getMicroserviceName()); - } - - @Test - public void submitPull() { - String microserviceId = "1"; - setup(microserviceId); - microserviceVersions.submitPull(); - - Assert.assertSame(microservices.get(microserviceId), - microserviceVersions.getVersions().get(microserviceId).getMicroservice()); - Assert.assertSame(microservices.get(microserviceId), - microserviceVersions.getVersion(microserviceId).getMicroservice()); - } - - @Test - public void submitPullProtection() { - ArchaiusUtils.setProperty("servicecomb.service.registry.instance.remove.protection", true); - String microserviceId = "1"; - setup(microserviceId); - microserviceVersions.submitPull(); - microserviceVersions.submitPull(); - MicroserviceVersionRule versionRule = microserviceVersions.getOrCreateMicroserviceVersionRule("0+"); - Assert.assertSame(versionRule.getInstances().entrySet().size(), 1); - } - - @Test - public void pullInstancesCancel() { - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - throw new Error("must not pull"); - } - }; - - pendingPullCount.set(2); - - microserviceVersions.pullInstances(); - Assert.assertEquals(1, pendingPullCount.get()); - } - - @Test - public void pullInstancesNull() { - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return null; - } - }; - - pendingPullCount.set(1); - - // not throw exception - microserviceVersions.pullInstances(); - } - - @Test - public void pullInstances_notExists() { - MicroserviceInstances microserviceInstances = new MicroserviceInstances(); - microserviceInstances.setMicroserviceNotExist(true); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return microserviceInstances; - } - }; - - MicroserviceNotExistEvent microserviceNotExistEvent = new MicroserviceNotExistEvent(null, null); - eventBus.register(new Object() { - @Subscribe - public void onMicroserviceNotExistEvent(MicroserviceNotExistEvent event) { - microserviceNotExistEvent.setAppId(event.getAppId()); - microserviceNotExistEvent.setMicroserviceName(event.getMicroserviceName()); - } - }); - - pendingPullCount.set(1); - - // not throw exception - microserviceVersions.pullInstances(); - - Assert.assertEquals(appId, microserviceNotExistEvent.getAppId()); - Assert.assertEquals(microserviceName, microserviceNotExistEvent.getMicroserviceName()); - } - - @Test - public void setInstancesMatch() { - String microserviceId = "1"; - setup(microserviceId); - pendingPullCount.set(1); - - MicroserviceVersionRule microserviceVersionRule = microserviceVersions.getOrCreateMicroserviceVersionRule("1.0.0"); - microserviceVersions.pullInstances(); - - Assert.assertSame(instances.get(0), microserviceVersionRule.getInstances().get("i1")); - } - - @Test - public void setInstances_selectUp() { - String microserviceId = "1"; - - createMicroservice(microserviceId); - createInstance(microserviceId); - createMicroserviceInstances(); - - instances.get(0).setStatus(MicroserviceInstanceStatus.DOWN); - Deencapsulation.invoke(microserviceVersions, "setInstances", instances, "0"); - - List resultInstances = Deencapsulation.getField(microserviceVersions, "instances"); - Assert.assertTrue(resultInstances.isEmpty()); - } - - @Test - public void getOrCreateMicroserviceVersionRule() { - MicroserviceVersionRule microserviceVersionRule = microserviceVersions.getOrCreateMicroserviceVersionRule("1.0.0"); - Assert.assertSame(microserviceVersionRule, microserviceVersions.getOrCreateMicroserviceVersionRule("1.0.0")); - } - - @Test - public void createAndInitMicroserviceVersionRule(@Mocked MicroserviceVersion microserviceVersion) { - String microserviceId = "1"; - createMicroservice(microserviceId); - - Version version = new Version("1.0.0"); - - new Expectations() { - { - microserviceVersion.getVersion(); - result = version; - microserviceVersion.getMicroservice(); - result = microservices.get(microserviceId); - } - }; - - microserviceVersions.getVersions().put(microserviceId, microserviceVersion); - - MicroserviceVersionRule microserviceVersionRule = - microserviceVersions.createAndInitMicroserviceVersionRule("1.0.0"); - Assert.assertSame(microserviceVersion, microserviceVersionRule.getLatestMicroserviceVersion()); - } - - @Test - public void onMicroserviceInstanceChangedAppNotMatch() { - MicroserviceKey key = new MicroserviceKey(); - key.setAppId("otherAppId"); - - MicroserviceInstanceChangedEvent event = new MicroserviceInstanceChangedEvent(); - event.setKey(key); - - microserviceVersions.onMicroserviceInstanceChanged(event); - - Assert.assertEquals(0, pendingPullCount.get()); - } - - @Test - public void onMicroserviceInstanceChangedNameNotMatch() { - MicroserviceKey key = new MicroserviceKey(); - key.setAppId(appId); - key.setServiceName("otherName"); - - MicroserviceInstanceChangedEvent event = new MicroserviceInstanceChangedEvent(); - event.setKey(key); - - eventBus.post(event); - - Assert.assertEquals(0, pendingPullCount.get()); - } - - @Test - public void onMicroserviceInstanceChangedMatch() { - MicroserviceKey key = new MicroserviceKey(); - key.setAppId(appId); - key.setServiceName(microserviceName); - - MicroserviceInstanceChangedEvent event = new MicroserviceInstanceChangedEvent(); - event.setKey(key); - - eventBus.register(new Object() { - @Subscribe - public void onEvent(PullMicroserviceVersionsInstancesEvent pullEvent) { - pendingPullCount.incrementAndGet(); - } - }); - eventBus.post(event); - - Assert.assertEquals(2, pendingPullCount.get()); - } - - @Test - public void safeSetInstances() { - new MockUp(microserviceVersions) { - @Mock - void setInstances(List pulledInstances, String rev) { - throw new Error("failed to set instances"); - } - }; - - microserviceVersions.safeSetInstances(null, null); - - Assert.assertEquals(0, pendingPullCount.get()); - Assert.assertEquals(microserviceVersions.isValidated(), false); - } - - public void checkIsEventAccept(MicroserviceKey key, boolean expected) { - - MicroserviceInstanceChangedEvent changeEvent = new MicroserviceInstanceChangedEvent(); - changeEvent.setKey(key); - boolean isEventAccept = microserviceVersions.isEventAccept(changeEvent); - Assert.assertEquals(expected, isEventAccept); - } - - @Test - public void testIsEventAccept() { - MicroserviceKey key = new MicroserviceKey(); - - key.setAppId(appId); - key.setServiceName(microserviceName); - checkIsEventAccept(key, true); - - key.setServiceName("falseMicroserviceName"); - checkIsEventAccept(key, false); - - key.setAppId("falseAppId"); - checkIsEventAccept(key, false); - - key.setServiceName(microserviceName); - checkIsEventAccept(key, false); - - key.setAppId(appId); - key.setServiceName(appId + Const.APP_SERVICE_SEPARATOR + microserviceName); - - microserviceVersions = - new MicroserviceVersions(appManager, appId, appId + Const.APP_SERVICE_SEPARATOR + microserviceName); - checkIsEventAccept(key, true); - - microserviceVersions = - new MicroserviceVersions(appManager, "falseAppId", appId + Const.APP_SERVICE_SEPARATOR + microserviceName); - checkIsEventAccept(key, false); - - microserviceVersions = new MicroserviceVersions(appManager, "falseAppId", - "false" + appId + Const.APP_SERVICE_SEPARATOR + microserviceName); - checkIsEventAccept(key, false); - - microserviceVersions = - new MicroserviceVersions(appManager, appId, "false" + appId + Const.APP_SERVICE_SEPARATOR + microserviceName); - checkIsEventAccept(key, false); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java deleted file mode 100644 index f4403d83dad..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/consumer/TestSimpleMicroserviceInstancePing.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.consumer; - -import java.io.IOException; -import java.net.ServerSocket; -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.junit.Assert; -import org.junit.Test; - -public class TestSimpleMicroserviceInstancePing { - @Test - public void testPing() throws IOException { - SimpleMicroserviceInstancePing ping = new SimpleMicroserviceInstancePing(); - Assert.assertEquals(ping.getOrder(), 100); - MicroserviceInstance instance = new MicroserviceInstance(); - List endpoints = new ArrayList<>(); - ServerSocket ss = new ServerSocket(35677); - - endpoints.add("http://localhost:35677"); - instance.setEndpoints(endpoints); - Assert.assertTrue(ping.ping(instance)); - MicroserviceInstance instance2 = new MicroserviceInstance(); - Assert.assertFalse(ping.ping(instance2)); - ss.close(); - Assert.assertFalse(ping.ping(instance)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckTask.java deleted file mode 100644 index bed55da34b4..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheCheckTask.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import io.vertx.core.json.Json; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestInstanceCacheCheckTask { - @Mocked - AppManager appManager; - - ScheduledThreadPoolExecutor taskPool = new ScheduledThreadPoolExecutor(2, - task -> new Thread(task, "Service Center Task test thread"), - (task, executor) -> System.out.println("Too many pending tasks, reject " + task.getClass().getName())); - - EventBus eventBus = new EventBus(); - - InstanceCacheCheckTask task = new InstanceCacheCheckTask(); - - InstanceCacheSummary result; - - @Before - public void setUp() { - task.setAppManager(appManager); - task.setTaskPool(taskPool); - task.setEventBus(eventBus); - task.setTimeUnit(TimeUnit.MILLISECONDS); - - new MockUp() { - @Mock - InstanceCacheSummary check() { - return new InstanceCacheSummary(); - } - }; - } - - @After - public void tearDown() throws Exception { - ArchaiusUtils.resetConfig(); - taskPool.shutdownNow(); - } - - @Test - public void manualTask() throws InterruptedException { - - ArchaiusUtils.setProperty(InstanceCacheCheckTask.AUTO_INTERVAL, 0); - CountDownLatch latch = new CountDownLatch(1); - eventBus.register(new Object() { - @Subscribe - public void onChecked(InstanceCacheSummary instanceCacheSummary) { - result = instanceCacheSummary; - latch.countDown(); - } - }); - task.init(); - - ArchaiusUtils.setProperty(InstanceCacheCheckTask.MANUAL, UUID.randomUUID().toString()); - latch.await(); - - Assert.assertEquals("{\"status\":null,\"producers\":[],\"timestamp\":0}", Json.encode(result)); - } - - @Test - public void autoTask_normal() throws InterruptedException { - ArchaiusUtils.setProperty(InstanceCacheCheckTask.AUTO_INTERVAL, 1); - CountDownLatch latch = new CountDownLatch(1); - eventBus.register(new Object() { - @Subscribe - public void onChecked(InstanceCacheSummary instanceCacheSummary) { - result = instanceCacheSummary; - ((ScheduledFuture) Deencapsulation.getField(task, "scheduledFuture")).cancel(false); - latch.countDown(); - } - }); - task.init(); - - latch.await(); - Assert.assertNotNull(Deencapsulation.getField(task, "scheduledFuture")); - Assert.assertEquals("{\"status\":null,\"producers\":[],\"timestamp\":0}", Json.encode(result)); - } - - @Test - public void autoTask_clearOldTask() { - Holder cancelResult = new Holder<>(); - ScheduledFuture scheduledFuture = new MockUp>() { - @Mock - boolean cancel(boolean mayInterruptIfRunning) { - cancelResult.value = true; - return true; - } - }.getMockInstance(); - - ArchaiusUtils.setProperty(InstanceCacheCheckTask.AUTO_INTERVAL, 0); - Deencapsulation.setField(task, "scheduledFuture", scheduledFuture); - task.init(); - - Assert.assertNull(Deencapsulation.getField(task, "scheduledFuture")); - Assert.assertTrue(cancelResult.value); - } - - @Test - public void autoTask_invalidIntervalZero() { - ArchaiusUtils.setProperty(InstanceCacheCheckTask.AUTO_INTERVAL, 0); - task.init(); - - Assert.assertNull(Deencapsulation.getField(task, "scheduledFuture")); - } - - @Test - public void autoTask_invalidIntervalLessThanZero() { - ArchaiusUtils.setProperty(InstanceCacheCheckTask.AUTO_INTERVAL, -1); - task.init(); - - Assert.assertNull(Deencapsulation.getField(task, "scheduledFuture")); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java deleted file mode 100644 index c84cc3e6b98..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.diagnosis.instance; - -import java.util.ArrayList; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; -import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.diagnosis.Status; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.vertx.core.json.Json; -import mockit.Mock; -import mockit.MockUp; - -public class TestInstanceCacheChecker { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - - InstanceCacheChecker checker; - - InstanceCacheSummary expectedSummary = new InstanceCacheSummary(); - - String appId = "appId"; - - String microserviceName = "msName"; - - @Before - public void setUp() throws Exception { - serviceRegistry.init(); - RegistryUtils.setServiceRegistry(serviceRegistry); - - checker = new InstanceCacheChecker(serviceRegistry.getAppManager()); - expectedSummary.setStatus(Status.NORMAL); - expectedSummary.setTimestamp(1); - - new MockUp() { - @Mock - long currentTimeMillis() { - return 1L; - } - }; - } - - @After - public void tearDown() throws Exception { - RegistryUtils.setServiceRegistry(null); - } - - @Test - public void check_appManager_empty() { - InstanceCacheSummary instanceCacheSummary = checker.check(); - - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - } - - @Test - public void check_microserviceManager_empty() { - appId = "notExist"; - serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); - InstanceCacheSummary instanceCacheSummary = checker.check(); - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - } - - protected Holder createFindServiceInstancesResult() { - MicroserviceInstances microserviceInstances = new MicroserviceInstances(); - microserviceInstances.setNeedRefresh(true); - microserviceInstances.setRevision("first"); - FindInstancesResponse findInstancesResponse = new FindInstancesResponse(); - findInstancesResponse.setInstances(new ArrayList<>()); - microserviceInstances.setInstancesResponse(findInstancesResponse); - - Holder findHolder = new Holder<>(); - findHolder.value = microserviceInstances; - return findHolder; - } - - protected void registerMicroservice(String appId, String microserviceName) { - Microservice microservice = new Microservice(); - microservice.setAppId(appId); - microservice.setServiceName(microserviceName); - microservice.setVersion("1.0.0"); - - serviceRegistry.getServiceRegistryClient().registerMicroservice(microservice); - } - - @Test - public void check_findInstances_failed() { - Holder findHolder = createFindServiceInstancesResult(); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return findHolder.value; - } - }; - - registerMicroservice(appId, microserviceName); - - serviceRegistry.getAppManager() - .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); - - findHolder.value = null; - InstanceCacheSummary instanceCacheSummary = checker.check(); - - InstanceCacheResult instanceCacheResult = new InstanceCacheResult(); - instanceCacheResult.setAppId(appId); - instanceCacheResult.setMicroserviceName(microserviceName); - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail("failed to find instances from service center"); - expectedSummary.getProducers().add(instanceCacheResult); - expectedSummary.setStatus(Status.UNKNOWN); - - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - } - - @Test - public void check_findInstances_serviceNotExist() { - Holder findHolder = createFindServiceInstancesResult(); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return findHolder.value; - } - }; - - registerMicroservice(appId, microserviceName); - - serviceRegistry.getAppManager() - .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); - - findHolder.value.setMicroserviceNotExist(true); - InstanceCacheSummary instanceCacheSummary = checker.check(); - - InstanceCacheResult instanceCacheResult = new InstanceCacheResult(); - instanceCacheResult.setAppId(appId); - instanceCacheResult.setMicroserviceName(microserviceName); - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail("microservice is not exist anymore, will be deleted from memory in next pull"); - expectedSummary.getProducers().add(instanceCacheResult); - expectedSummary.setStatus(Status.UNKNOWN); - - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - } - - @Test - public void check_findInstances_revisionNotMatch() { - Holder findHolder = createFindServiceInstancesResult(); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return findHolder.value; - } - }; - - registerMicroservice(appId, microserviceName); - - serviceRegistry.getAppManager() - .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); - - findHolder.value.setRevision("second"); - InstanceCacheSummary instanceCacheSummary = checker.check(); - - InstanceCacheResult instanceCacheResult = new InstanceCacheResult(); - instanceCacheResult.setAppId(appId); - instanceCacheResult.setMicroserviceName(microserviceName); - instanceCacheResult.setStatus(Status.UNKNOWN); - instanceCacheResult.setDetail( - "revision is different, will be synchronized in next pull. local revision=first, remote revision=second"); - expectedSummary.getProducers().add(instanceCacheResult); - expectedSummary.setStatus(Status.UNKNOWN); - - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - } - - @Test - public void check_findInstances_cacheNotMatch() { - Holder findHolder = createFindServiceInstancesResult(); - - new MockUp() { - @Mock - MicroserviceInstances findServiceInstances(String appId, String serviceName, - String versionRule, String revision) { - return findHolder.value; - } - }; - - registerMicroservice(appId, microserviceName); - - MicroserviceVersions microserviceVersions = serviceRegistry.getAppManager() - .getOrCreateMicroserviceVersions(appId, microserviceName); - microserviceVersions.setRevision("first"); - microserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL); - - Holder newFindHolder = createFindServiceInstancesResult(); - newFindHolder.value.getInstancesResponse().getInstances().add(new MicroserviceInstance()); - findHolder.value = newFindHolder.value; - InstanceCacheSummary instanceCacheSummary = checker.check(); - - InstanceCacheResult instanceCacheResult = new InstanceCacheResult(); - instanceCacheResult.setAppId(appId); - instanceCacheResult.setMicroserviceName(microserviceName); - instanceCacheResult.setStatus(Status.ABNORMAL); - instanceCacheResult.setDetail( - "instance cache not match"); - expectedSummary.getProducers().add(instanceCacheResult); - expectedSummary.setStatus(Status.ABNORMAL); - - Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); - Assert.assertNull(microserviceVersions.getRevision()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractTransportDiscoveryFilter.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractTransportDiscoveryFilter.java deleted file mode 100644 index df3292c10d1..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestAbstractTransportDiscoveryFilter.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestAbstractTransportDiscoveryFilter { - class AbstractEndpointDiscoveryFilterForTest extends AbstractEndpointDiscoveryFilter { - @Override - public int getOrder() { - return 0; - } - - @Override - protected String findTransportName(DiscoveryContext context, DiscoveryTreeNode parent) { - return transportName; - } - - @Override - protected Object createEndpoint(String transportName, String endpoint, MicroserviceInstance instance) { - if (disableCreate) { - return null; - } - - return endpoint; - } - } - - boolean disableCreate; - - String transportName; - - AbstractEndpointDiscoveryFilterForTest filter = new AbstractEndpointDiscoveryFilterForTest(); - - DiscoveryContext context = new DiscoveryContext(); - - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent"); - - DiscoveryTreeNode result; - - @Test - public void isGroupingFilter() { - Assert.assertTrue(filter.isGroupingFilter()); - } - - @Test - public void isTransportNameMatch_expectAll() { - Assert.assertTrue(filter.isTransportNameMatch("any", "")); - } - - @Test - public void isTransportNameMatch_equals() { - Assert.assertTrue(filter.isTransportNameMatch("rest", "rest")); - } - - @Test - public void isTransportNameMatch_notEquals() { - Assert.assertFalse(filter.isTransportNameMatch("rest", "highway")); - } - - @Test - public void discoveryNotExist() { - transportName = "notExist"; - parent.data(Collections.emptyMap()); - result = filter.discovery(context, parent); - - Assert.assertTrue(result.isEmpty()); - } - - @Test - public void discoveryExist() { - transportName = "rest"; - DiscoveryTreeNode child = new DiscoveryTreeNode(); - parent.child(transportName, child); - result = filter.discovery(context, parent); - - Assert.assertSame(child, result); - } - - private MicroserviceInstance createInstance(String... schemas) { - String id = UUID.randomUUID().toString(); - MicroserviceInstance instance = new MicroserviceInstance(); - instance.setInstanceId(id); - for (int idx = 0; idx < schemas.length; idx++) { - String schema = schemas[idx]; - instance.getEndpoints().add(String.format("%s://%s:%d", schema, id, 8080 + idx)); - } - return instance; - } - - private Map createMicroserviceInstances(String name, - MicroserviceInstance... instances) { - Map map = new LinkedHashMap<>(); - for (MicroserviceInstance instance : instances) { - map.put(instance.getInstanceId(), instance); - } - return map; - } - - @Test - public void createDiscoveryTree_oneTransport() { - MicroserviceInstance instance1 = createInstance("a", "b"); - MicroserviceInstance instance2 = createInstance("b"); - Map instances = createMicroserviceInstances("name", instance1, instance2); - parent.data(instances); - - result = filter.createDiscoveryTreeNode("a", context, parent); - - Assert.assertEquals("parent/a", result.name()); - Assert.assertThat(result.collectionData(), Matchers.contains(instance1.getEndpoints().get(0))); - } - - @Test - public void createDiscoveryTree_allTransport() { - MicroserviceInstance instance1 = createInstance("a", "b"); - MicroserviceInstance instance2 = createInstance("b"); - Map instances = createMicroserviceInstances("name", instance1, instance2); - parent.data(instances); - - result = filter.createDiscoveryTreeNode("", context, parent); - - Assert.assertEquals("parent/", result.name()); - - List expect = new ArrayList<>(); - expect.addAll(instance1.getEndpoints()); - expect.addAll(instance2.getEndpoints()); - Assert.assertThat(result.collectionData(), Matchers.contains(expect.toArray())); - } - - @Test - public void createDiscoveryTree_ignoreInvalid() { - MicroserviceInstance instance1 = createInstance("a", "b"); - MicroserviceInstance instance2 = createInstance(""); - Map instances = createMicroserviceInstances("name", instance1, instance2); - parent.data(instances); - - result = filter.createDiscoveryTreeNode("", context, parent); - - Assert.assertEquals("parent/", result.name()); - Assert.assertThat(result.collectionData(), Matchers.contains(instance1.getEndpoints().toArray())); - } - - @Test - public void createEndpointNull() { - disableCreate = true; - MicroserviceInstance instance1 = createInstance("a", "b"); - Map instances = createMicroserviceInstances("name", instance1); - parent.data(instances); - - result = filter.createDiscoveryTreeNode("", context, parent); - - Assert.assertEquals("parent/", result.name()); - Assert.assertThat(result.collectionData(), Matchers.empty()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryContext.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryContext.java deleted file mode 100644 index e2b65532a98..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryContext.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import org.junit.Assert; -import org.junit.Test; - -public class TestDiscoveryContext { - DiscoveryContext context = new DiscoveryContext(); - - @Test - public void inputParameters() { - Object inputParameters = new Object(); - context.setInputParameters(inputParameters); - - Assert.assertSame(inputParameters, context.getInputParameters()); - } - - @Test - public void contextParameters() { - String name = "name"; - Object value = new Object(); - context.putContextParameter(name, value); - - Assert.assertSame(value, context.getContextParameter(name)); - Assert.assertNull(context.getContextParameter("notExist")); - } - - @Test - public void rerun() { - Assert.assertNull(context.popRerunFilter()); - - DiscoveryTreeNode node = new DiscoveryTreeNode(); - context.setCurrentNode(node); - context.pushRerunFilter(); - - Assert.assertSame(node, context.popRerunFilter()); - Assert.assertNull(context.popRerunFilter()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java deleted file mode 100644 index 8ab3b003305..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestDiscoveryTree { - DiscoveryTree discoveryTree = new DiscoveryTree(); - - List filters = Deencapsulation.getField(discoveryTree, "filters"); - - DiscoveryContext context = new DiscoveryContext(); - - DiscoveryTreeNode parent = new DiscoveryTreeNode().name("parent"); - - DiscoveryTreeNode result; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void loadFromSPI(@Mocked DiscoveryFilter f1, @Mocked DiscoveryFilter f2) { - Class cls = DiscoveryFilter.class; - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(cls); - result = Arrays.asList(f1, f2); - } - }; - - discoveryTree.loadFromSPI(cls); - - Assert.assertThat(filters, Matchers.contains(f1, f2)); - } - - @Test - public void sort(@Mocked DiscoveryFilter f1, @Mocked DiscoveryFilter f2, @Mocked DiscoveryFilter f3) { - new Expectations() { - { - f1.getOrder(); - result = -1; - f1.enabled(); - result = true; - f2.getOrder(); - result = 0; - f2.enabled(); - result = true; - f3.getOrder(); - result = 0; - f3.enabled(); - result = false; - } - }; - discoveryTree.addFilter(f3); - discoveryTree.addFilter(f2); - discoveryTree.addFilter(f1); - discoveryTree.sort(); - - Assert.assertThat(filters, Matchers.contains(f1, f2)); - } - - @Test - public void isMatch_existingNull() { - Assert.assertFalse(discoveryTree.isMatch(null, null)); - } - - @Test - public void isMatch_yes() { - parent.cacheVersion(1); - Assert.assertTrue(discoveryTree.isMatch(new DiscoveryTreeNode().cacheVersion(1), parent)); - } - - @Test - public void isMatch_no() { - parent.cacheVersion(0); - Assert.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(1), parent)); - } - - @Test - public void isExpired_existingNull() { - Assert.assertTrue(discoveryTree.isExpired(null, null)); - } - - @Test - public void isExpired_yes() { - parent.cacheVersion(1); - Assert.assertTrue(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent)); - } - - @Test - public void isExpired_no() { - parent.cacheVersion(0); - Assert.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent)); - } - - class DiscoveryFilterForTest implements DiscoveryFilter { - protected String groupName; - - public DiscoveryFilterForTest(String groupName) { - this.groupName = groupName; - } - - @Override - public int getOrder() { - return 0; - } - - @Override - public boolean isGroupingFilter() { - return groupName != null; - } - - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - DiscoveryTreeNode child = new DiscoveryTreeNode(); - if (groupName != null) { - child.subName(parent, groupName); - } - return child; - } - } - - @Test - public void filterNormal() { - parent.name("1.0.0-2.0.0"); - - discoveryTree.addFilter(new DiscoveryFilterForTest("g1")); - discoveryTree.addFilter(new DiscoveryFilterForTest(null)); - discoveryTree.addFilter(new DiscoveryFilterForTest("g2")); - discoveryTree.addFilter(new DiscoveryFilterForTest(null)); - - result = discoveryTree.discovery(context, parent); - - Assert.assertEquals("1.0.0-2.0.0/g1/g2", result.name()); - } - - @Test - public void easyDiscovery(@Mocked ServiceRegistry serviceRegistry, - @Mocked InstanceCacheManager instanceCacheManager) { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getInstanceCacheManager(); - result = instanceCacheManager; - instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); - result = parent; - } - }; - - result = discoveryTree.discovery(context, null, null, null); - Assert.assertEquals(parent.name(), result.name()); - Assert.assertEquals(parent.cacheVersion(), result.cacheVersion()); - } - - @Test - public void discovery_filterReturnNull(@Mocked ServiceRegistry serviceRegistry, - @Mocked InstanceCacheManager instanceCacheManager) { - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getInstanceCacheManager(); - result = instanceCacheManager; - instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); - result = parent; - } - }; - - DiscoveryFilter filter = new DiscoveryFilter() { - @Override - public int getOrder() { - return 0; - } - - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - return null; - } - }; - discoveryTree.addFilter(filter); - - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage(Matchers.is(filter.getClass().getName() + " discovery return null.")); - - result = discoveryTree.discovery(context, null, null, null); - } - - @Test - public void filterRerun() { - parent.name("1.0.0-2.0.0"); - - discoveryTree.addFilter(new DiscoveryFilterForTest("g1") { - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - if (context.getContextParameter("step") == null) { - context.pushRerunFilter(); - context.putContextParameter("step", 1); - return new DiscoveryTreeNode().name(groupName).data("first"); - } - - return new DiscoveryTreeNode().name(groupName).data("second"); - } - }); - discoveryTree.addFilter(new DiscoveryFilterForTest(null) { - @Override - public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) { - if ("first".equals(parent.data())) { - return new DiscoveryTreeNode(); - } - - return new DiscoveryTreeNode().data(parent.data()); - } - }); - - result = discoveryTree.discovery(context, parent); - - Assert.assertEquals("second", result.data()); - } - - @Test - public void avoidConcurrentProblem() { - Deencapsulation.setField(discoveryTree, "root", parent.cacheVersion(1)); - Assert.assertTrue(parent.children().isEmpty()); - - discoveryTree.discovery(context, new VersionedCache().cacheVersion(0).name("input")); - Assert.assertTrue(parent.children().isEmpty()); - } - - @Test - public void getOrCreateRoot_match() { - Deencapsulation.setField(discoveryTree, "root", parent); - - DiscoveryTreeNode root = discoveryTree.getOrCreateRoot(parent); - - Assert.assertSame(parent, root); - } - - @Test - public void getOrCreateRoot_expired() { - Deencapsulation.setField(discoveryTree, "root", parent); - - VersionedCache inputCache = new VersionedCache().cacheVersion(parent.cacheVersion() + 1); - DiscoveryTreeNode root = discoveryTree.getOrCreateRoot(inputCache); - - Assert.assertEquals(inputCache.cacheVersion(), root.cacheVersion()); - Assert.assertSame(Deencapsulation.getField(discoveryTree, "root"), root); - } - - - @Test - public void getOrCreateRoot_tempRoot() { - Deencapsulation.setField(discoveryTree, "root", parent); - - VersionedCache inputCache = new VersionedCache().cacheVersion(parent.cacheVersion() - 1); - DiscoveryTreeNode root = discoveryTree.getOrCreateRoot(inputCache); - - Assert.assertEquals(inputCache.cacheVersion(), root.cacheVersion()); - Assert.assertNotSame(Deencapsulation.getField(discoveryTree, "root"), root); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTreeNode.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTreeNode.java deleted file mode 100644 index b7ebb3bcd6c..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTreeNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.discovery; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.cache.VersionedCache; -import org.junit.Assert; -import org.junit.Test; - -public class TestDiscoveryTreeNode { - DiscoveryTreeNode node = new DiscoveryTreeNode(); - - @Test - public void childrenInited() { - Assert.assertFalse(node.childrenInited()); - - node.childrenInited(true); - Assert.assertTrue(node.childrenInited()); - } - - @Test - public void level() { - node.level(1); - - Assert.assertEquals(1, node.level()); - } - - @Test - public void attribute() { - node.attribute("k1", "v1"); - - Assert.assertEquals("v1", node.attribute("k1")); - } - - @Test - public void children() { - Map children = new HashMap<>(); - node.children(children); - - Assert.assertSame(children, node.children()); - } - - @Test - public void child() { - DiscoveryTreeNode child = new DiscoveryTreeNode().name("child"); - node.child(child.name(), child); - - Assert.assertSame(child, node.child(child.name())); - } - - @Test - public void fromCache() { - Object data = new Object(); - VersionedCache other = new VersionedCache().cacheVersion(1).name("cache").data(data); - node.fromCache(other); - - Assert.assertEquals(1, node.cacheVersion()); - Assert.assertEquals("cache", node.name()); - Assert.assertSame(data, node.data()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestAbstractServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestAbstractServiceRegistry.java deleted file mode 100644 index e11a0580830..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestAbstractServiceRegistry.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.registry; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.consumer.DefaultMicroserviceVersionFactory; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersionFactory; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestAbstractServiceRegistry { - class AbstractServiceRegistryForTest extends AbstractServiceRegistry { - public AbstractServiceRegistryForTest(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - super(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - @Override - protected ServiceRegistryClient createServiceRegistryClient() { - return null; - } - } - - static class DefaultMicroserviceVersionFactoryForTest extends DefaultMicroserviceVersionFactory { - - } - - EventBus eventBus = new EventBus(); - - String appId = "app"; - - String microserviceName = "ms"; - - @Mocked - ServiceRegistryConfig serviceRegistryConfig; - - MicroserviceDefinition microserviceDefinition = MicroserviceDefinition.create(appId, microserviceName); - - AbstractServiceRegistryForTest registry; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setup() { - registry = - new AbstractServiceRegistryForTest(eventBus, serviceRegistryConfig, microserviceDefinition); - RegistryUtils.setServiceRegistry(registry); - } - - @After - public void tearDown() { - registry.appManager = null; - } - - @AfterClass - public static void afterClass() { - RegistryUtils.setServiceRegistry(null); - } - - @Test - public void initAppManagerDefault() throws InstantiationException, IllegalAccessException, ClassNotFoundException { - registry.initAppManager(); - - Assert.assertThat(registry.appManager.getMicroserviceVersionFactory(), - Matchers.instanceOf(DefaultMicroserviceVersionFactory.class)); - } - - @Test - public void initAppManagerSpecialMicroserviceVersionFactoryNormal() - throws InstantiationException, IllegalAccessException, ClassNotFoundException { - new Expectations() { - { - serviceRegistryConfig.getMicroserviceVersionFactory(); - result = DefaultMicroserviceVersionFactoryForTest.class.getName(); - } - }; - registry.initAppManager(); - - Assert.assertThat(registry.appManager.getMicroserviceVersionFactory(), - Matchers.instanceOf(DefaultMicroserviceVersionFactoryForTest.class)); - } - - @Test - public void initAppManagerSpecialMicroserviceVersionFactoryFailed() { - new Expectations() { - { - serviceRegistryConfig.getMicroserviceVersionFactory(); - result = "invalid"; - } - }; - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Failed to init appManager.")); - - registry.init(); - } - - @Test - public void registryMicroserviceMapping() { - String testServiceName = "testService"; - final String testVersion = "1.0.1"; - - HashMap versionsByName = prepareForMicroserviceMappingRegistry(); - - ArrayList instancesParam = new ArrayList<>(); - instancesParam.add(new MicroserviceInstance()); - registry.registerMicroserviceMapping(testServiceName, testVersion, instancesParam, Test3rdPartyServiceIntf.class); - - MicroserviceVersions microserviceVersions = versionsByName.get(testServiceName); - List instances = Deencapsulation.getField(microserviceVersions, "instances"); - Assert.assertEquals(1, instances.size()); - Assert.assertSame(instancesParam.get(0), instances.get(0)); - - // nothing will happen if register repeatedly - List newInstancesParam = new ArrayList<>(); - newInstancesParam.add(new MicroserviceInstance()); - registry.registerMicroserviceMapping( - testServiceName, testVersion, newInstancesParam, Test3rdPartyServiceIntf.class); - - microserviceVersions = versionsByName.get(testServiceName); - instances = Deencapsulation.getField(microserviceVersions, "instances"); - Assert.assertEquals(1, instances.size()); - Assert.assertSame(instancesParam.get(0), instances.get(0)); - } - - @Test - public void registryMicroserviceMappingByEndpoints() { - String testServiceName = "testService"; - final String testVersion = "1.0.1"; - - HashMap versionByName = prepareForMicroserviceMappingRegistry(); - - registry.registerMicroserviceMappingByEndpoints(testServiceName, testVersion, - Arrays.asList("cse://127.0.0.1:8080", "cse://127.0.0.1:8081"), Test3rdPartyServiceIntf.class); - - MicroserviceVersions microserviceVersions = versionByName.get(testServiceName); - List instances = Deencapsulation.getField(microserviceVersions, "instances"); - Assert.assertEquals(2, instances.size()); - Assert.assertEquals("cse://127.0.0.1:8080", instances.get(0).getEndpoints().get(0)); - Assert.assertEquals("cse://127.0.0.1:8081", instances.get(1).getEndpoints().get(0)); - } - - private HashMap prepareForMicroserviceMappingRegistry() { - registry.appManager = Mockito.mock(AppManager.class); - MicroserviceManager microserviceManager = Mockito.mock(MicroserviceManager.class); - StaticMicroserviceVersionFactory staticMicroserviceVersionFactory = - Mockito.mock(StaticMicroserviceVersionFactory.class); - HashMap versionsByName = new HashMap<>(); - - Mockito.when(registry.appManager.getOrCreateMicroserviceManager(this.appId)).thenReturn(microserviceManager); - Mockito.when(registry.appManager.getEventBus()).thenReturn(Mockito.mock(EventBus.class)); - Mockito.when(registry.appManager.getStaticMicroserviceVersionFactory()) - .thenReturn(staticMicroserviceVersionFactory); - Mockito.when(staticMicroserviceVersionFactory.create(Mockito.any())) - .thenReturn(Mockito.mock(MicroserviceVersion.class)); - - Mockito.when(microserviceManager.getVersionsByName()).thenReturn(versionsByName); - return versionsByName; - } - - private interface Test3rdPartyServiceIntf { - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestLocalServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestLocalServiceRegistry.java deleted file mode 100644 index 3b01fe885b8..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestLocalServiceRegistry.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.registry; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.junit.Assert; -import org.junit.Test; - -public class TestLocalServiceRegistry { - - @Test - public void testLifeCycle() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - - Assert.assertNull(serviceRegistry.getMicroserviceInstance().getInstanceId()); - serviceRegistry.run(); - Assert.assertNotNull(serviceRegistry.getMicroserviceInstance().getInstanceId()); - - serviceRegistry.destroy(); - Assert.assertTrue(serviceRegistry.getServiceRegistryClient() - .getMicroserviceInstance("", serviceRegistry.getMicroservice().getServiceId()) - .isEmpty()); - } - - @Test - public void testUpdateProperties() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - serviceRegistry.run(); - - Microservice microservice = serviceRegistry.getMicroservice(); - Map properties = new HashMap<>(); - properties.put("k", "v"); - - try { - serviceRegistry.getServiceRegistryClient().updateInstanceProperties(microservice.getServiceId(), - "notExist", - properties); - Assert.fail("must throw exception"); - } catch (IllegalArgumentException e) { - Assert.assertEquals("Invalid argument. microserviceId=" + microservice.getServiceId() - + ", microserviceInstanceId=notExist.", - e.getMessage()); - } - - serviceRegistry.updateMicroserviceProperties(properties); - Assert.assertEquals(properties, microservice.getProperties()); - serviceRegistry.updateInstanceProperties(properties); - Assert.assertEquals(properties, microservice.getInstance().getProperties()); - - properties.put("k1", "v1"); - serviceRegistry.updateMicroserviceProperties(properties); - Assert.assertEquals(properties, microservice.getProperties()); - serviceRegistry.updateInstanceProperties(properties); - Assert.assertEquals(properties, microservice.getInstance().getProperties()); - } - - @Test - public void testSchema() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - Microservice microservice = serviceRegistry.getMicroservice(); - microservice.addSchema("s1", "s1-content"); - serviceRegistry.init(); - serviceRegistry.run(); - - try { - serviceRegistry.getServiceRegistryClient().isSchemaExist("notExist", "s1"); - Assert.fail("must throw exception"); - } catch (IllegalArgumentException e) { - Assert.assertEquals("Invalid serviceId, serviceId=notExist", e.getMessage()); - } - try { - serviceRegistry.getServiceRegistryClient().getSchema("notExist", "s1"); - Assert.fail("must throw exception"); - } catch (IllegalArgumentException e) { - Assert.assertEquals("Invalid serviceId, serviceId=notExist", e.getMessage()); - } - - Assert.assertEquals(true, - serviceRegistry.getServiceRegistryClient().isSchemaExist(microservice.getServiceId(), "s1")); - String content = serviceRegistry.getServiceRegistryClient().getSchema(microservice.getServiceId(), "s1"); - Assert.assertEquals("s1-content", content); - } - - @Test - public void registerMicroservice() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - serviceRegistry.run(); - - Microservice microservice = new Microservice(); - microservice.setAppId("appId"); - microservice.setServiceName("msName"); - - String serviceId = serviceRegistry.getServiceRegistryClient().registerMicroservice(microservice); - Microservice remoteMicroservice = serviceRegistry.getRemoteMicroservice(serviceId); - - Assert.assertEquals(serviceId, remoteMicroservice.getServiceId()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java deleted file mode 100644 index 718e6491782..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.registry; - -import static org.apache.servicecomb.foundation.common.base.ServiceCombConstants.CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY; -import static org.apache.servicecomb.serviceregistry.definition.DefinitionConst.DEFAULT_MICROSERVICE_VERSION; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.task.event.PullMicroserviceVersionsInstancesEvent; -import org.apache.servicecomb.serviceregistry.task.event.ShutdownEvent; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRemoteServiceRegistry { - class TestingRemoteServiceRegistry extends RemoteServiceRegistry { - public TestingRemoteServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - super(eventBus, serviceRegistryConfig, microserviceDefinition); - } - - @Override - protected ServiceRegistryClient createServiceRegistryClient() { - return new LocalServiceRegistryClientImpl(); - } - } - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void testLifeCycle(@Injectable ServiceRegistryConfig config, @Injectable MicroserviceDefinition definition, - @Injectable ServiceRegistry registry) throws InterruptedException { - ArrayList ipPortList = new ArrayList<>(); - ipPortList.add(new IpPort("127.0.0.1", 9980)); - ipPortList.add(new IpPort("127.0.0.1", 9981)); - - CountDownLatch latch = new CountDownLatch(1); - ServiceRegistryTaskInitializer initializer = new MockUp() { - @Mock - void init(RemoteServiceRegistry remoteServiceRegistry) { - latch.countDown(); - } - }.getMockInstance(); - - new Expectations(SPIServiceUtils.class) { - { - definition.getConfiguration(); - result = ConfigUtil.createLocalConfig(); - config.getIpPort(); - result = ipPortList; - config.getTransport(); - result = "rest"; - config.isRegistryAutoDiscovery(); - result = true; - config.getHeartbeatInterval(); - result = 30; - config.getInstancePullInterval(); - result = 30; - config.isWatch(); - result = false; - SPIServiceUtils.getOrLoadSortedService(ServiceRegistryTaskInitializer.class); - result = Arrays.asList(initializer); - } - }; - - ServiceRegistry oldRegistry = RegistryUtils.getServiceRegistry(); - RegistryUtils.setServiceRegistry(registry); - EventBus bus = new EventBus(); - RemoteServiceRegistry remote = new TestingRemoteServiceRegistry(bus, config, definition); - remote.init(); - remote.run(); - - // should not block - latch.await(); - - Assert.assertTrue(2 <= remote.getTaskPool().getTaskCount()); // includes complete tasks - - bus.post(new ShutdownEvent()); - - remote.getTaskPool().schedule(new Runnable() { - @Override - public void run() { - - } - }, 0, TimeUnit.SECONDS); - Assert.assertTrue(remote.getTaskPool().isShutdown()); - RegistryUtils.setServiceRegistry(oldRegistry); - } - - @Test - public void onPullMicroserviceVersionsInstancesEvent(@Injectable ServiceRegistryConfig config, - @Injectable MicroserviceDefinition definition, @Mocked MicroserviceVersions microserviceVersions, - @Mocked Configuration configuration) { - PullMicroserviceVersionsInstancesEvent event = new PullMicroserviceVersionsInstancesEvent(microserviceVersions, 1); - - ScheduledThreadPoolExecutor taskPool = new MockUp() { - @Mock - ScheduledFuture schedule(Runnable command, - long delay, - TimeUnit unit) { - Assert.assertEquals(1, delay); - throw new Error("ok"); - } - }.getMockInstance(); - - new Expectations() { - { - definition.getConfiguration(); - result = configuration; - configuration.getString(CONFIG_QUALIFIED_MICROSERVICE_VERSION_KEY, - DEFAULT_MICROSERVICE_VERSION); - result = "1.0.0"; - } - }; - - expectedException.expect(Error.class); - expectedException.expectMessage(Matchers.is("ok")); - - EventBus bus = new EventBus(); - RemoteServiceRegistry remote = new TestingRemoteServiceRegistry(bus, config, definition); - bus.register(remote); - Deencapsulation.setField(remote, "taskPool", taskPool); - bus.post(event); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java deleted file mode 100644 index 07f7e08f2ab..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.registry; - -import java.util.Collections; - -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.client.LocalServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Mocked; - -/** - * Created by on 2017/3/31. - */ -public class TestServiceRegistryFactory { - @Test - // mock ServiceRegistryClientImpl to avoid send request to remote SC - // even there is no any reference to registryClient, DO NOT delete it. - // because what changed is class ServiceRegistryClientImpl - public void testGetRemoteRegistryClient(@Mocked ServiceRegistryClientImpl registryClient) { - EventBus eventBus = new EventBus(); - ServiceRegistryConfig serviceRegistryConfig = ServiceRegistryConfig.INSTANCE; - MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(Collections.emptyList()); - - ServiceRegistry serviceRegistry = - ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition); - serviceRegistry.init(); - ServiceRegistryClient client = serviceRegistry.getServiceRegistryClient(); - Assert.assertTrue(client instanceof ServiceRegistryClientImpl); - - serviceRegistry = ServiceRegistryFactory.getOrCreate(eventBus, - serviceRegistryConfig, - microserviceDefinition); - Assert.assertTrue(serviceRegistry instanceof RemoteServiceRegistry); - Assert.assertEquals(serviceRegistry, ServiceRegistryFactory.getServiceRegistry()); - - Deencapsulation.setField(ServiceRegistryFactory.class, "serviceRegistry", null); - - System.setProperty("local.registry.file", "/tmp/test.yaml"); - serviceRegistry = ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition); - serviceRegistry.init(); - client = serviceRegistry.getServiceRegistryClient(); - Assert.assertTrue(client instanceof LocalServiceRegistryClientImpl); - Assert.assertTrue(ServiceRegistryFactory.getOrCreate(eventBus, - serviceRegistryConfig, - microserviceDefinition) instanceof LocalServiceRegistry); - System.clearProperty("local.registry.file"); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestAbstractRegisterTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestAbstractRegisterTask.java deleted file mode 100644 index cc5b4b25b6a..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestAbstractRegisterTask.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Mocked; - -public class TestAbstractRegisterTask { - private EventBus eventBus; - - private Microservice microservice; - - @Before - public void setup() { - eventBus = new EventBus(); - - microservice = new Microservice(); - microservice.setAppId("app"); - microservice.setServiceName("ms"); - - microservice.setInstance(new MicroserviceInstance()); - } - - @Test - public void testHeartbeatSuccess(@Mocked ServiceRegistryClient srClient) { - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - ReflectUtils.setField(registerTask, "registered", true); - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - ReflectUtils.setField(heartbeatTask, "heartbeatResult", HeartbeatResult.SUCCESS); - - Assert.assertEquals(true, registerTask.isRegistered()); - eventBus.post(heartbeatTask); - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(eventBus, registerTask.getEventBus()); - } - - @Test - public void testHeartbeatFailed(@Mocked ServiceRegistryClient srClient) { - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - ReflectUtils.setField(registerTask, "registered", true); - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - ReflectUtils.setField(heartbeatTask, "heartbeatResult", HeartbeatResult.INSTANCE_NOT_REGISTERED); - - Assert.assertEquals(true, registerTask.isRegistered()); - eventBus.post(heartbeatTask); - Assert.assertEquals(false, registerTask.isRegistered()); - } - - @Test - public void testHeartbeatOtherFailed(@Mocked ServiceRegistryClient srClient) { - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - ReflectUtils.setField(registerTask, "registered", true); - - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, otherMicroservice); - ReflectUtils.setField(heartbeatTask, "heartbeatResult", HeartbeatResult.INSTANCE_NOT_REGISTERED); - - Assert.assertEquals(true, registerTask.isRegistered()); - eventBus.post(heartbeatTask); - Assert.assertEquals(true, registerTask.isRegistered()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestCompositeTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestCompositeTask.java deleted file mode 100644 index d63e98607f2..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestCompositeTask.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.junit.Assert; -import org.junit.Test; - -public class TestCompositeTask { - private int count; - - @Test - public void testRun() { - CompositeTask task = new CompositeTask(); - for (int idx = 0; idx < 3; idx++) { - task.addTask(() -> { - count++; - }); - } - - task.run(); - - Assert.assertEquals(3, count); - Assert.assertEquals(3, task.getTaskCount()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceHeartbeatTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceHeartbeatTask.java deleted file mode 100644 index 97e1e397897..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceHeartbeatTask.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.response.HeartbeatResponse; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceInstanceHeartbeatTask { - private EventBus eventBus; - - private Microservice microservice; - - private List heartbeatTaskList; - - @Before - public void setup() { - eventBus = new EventBus(); - - heartbeatTaskList = new ArrayList<>(); - eventBus.register(new Object() { - @Subscribe - public void onEvent(MicroserviceInstanceHeartbeatTask task) { - heartbeatTaskList.add(task); - } - }); - - microservice = new Microservice(); - microservice.setAppId("app"); - microservice.setServiceName("ms"); - microservice.setServiceId("serviceId"); - - microservice.setInstance(new MicroserviceInstance()); - microservice.getInstance().setInstanceId("instanceId"); - } - - @Test - public void testNotRegistered(@Mocked ServiceRegistryClient srClient, - @Mocked MicroserviceInstanceRegisterTask registerTask) { - new Expectations() { - { - } - }; - - MicroserviceInstanceHeartbeatTask task = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - registerTask.taskStatus = TaskStatus.INIT; - eventBus.post(registerTask); - - task.run(); - Assert.assertNull(task.getHeartbeatResult()); - Assert.assertEquals(false, task.isNeedRegisterInstance()); - Assert.assertEquals(0, heartbeatTaskList.size()); - } - - @Test - public void testOtherMicroservice(@Mocked ServiceRegistryClient srClient, - @Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked MicroserviceWatchTask watchTask) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setServiceName("ms1"); - - new Expectations() { - { - watchTask.getMicroservice(); - result = otherMicroservice; - } - }; - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - watchTask.taskStatus = TaskStatus.READY; - eventBus.post(watchTask); - - heartbeatTask.run(); - Assert.assertNull(heartbeatTask.getHeartbeatResult()); - Assert.assertEquals(false, heartbeatTask.isNeedRegisterInstance()); - Assert.assertEquals(0, heartbeatTaskList.size()); - } - - @Test - public void testHeartbeatDisconnect(@Mocked ServiceRegistryClient srClient, - @Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked MicroserviceWatchTask watchTask) { - new Expectations() { - { - srClient.heartbeat(anyString, anyString); - result = null; - watchTask.getMicroservice(); - result = microservice; - } - }; - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - watchTask.taskStatus = TaskStatus.READY; - eventBus.post(watchTask); - - heartbeatTask.run(); - Assert.assertEquals(HeartbeatResult.DISCONNECTED, heartbeatTask.getHeartbeatResult()); - Assert.assertEquals(false, heartbeatTask.isNeedRegisterInstance()); - Assert.assertEquals(1, heartbeatTaskList.size()); - } - - @Test - public void testHeartbeatNotRegistered(@Mocked ServiceRegistryClient srClient, - @Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked MicroserviceWatchTask watchTask) { - HeartbeatResponse response = new HeartbeatResponse(); - response.setOk(false); - response.setMessage("FAIL"); - - new Expectations() { - { - srClient.heartbeat(anyString, anyString); - result = response; - watchTask.getMicroservice(); - result = microservice; - } - }; - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - watchTask.taskStatus = TaskStatus.READY; - eventBus.post(watchTask); - - heartbeatTask.run(); - Assert.assertEquals(HeartbeatResult.INSTANCE_NOT_REGISTERED, heartbeatTask.getHeartbeatResult()); - Assert.assertEquals(true, heartbeatTask.isNeedRegisterInstance()); - Assert.assertEquals(1, heartbeatTaskList.size()); - } - - @Test - public void testHeartbeatSuccess(@Mocked ServiceRegistryClient srClient, - @Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked MicroserviceWatchTask watchTask) { - HeartbeatResponse response = new HeartbeatResponse(); - response.setOk(true); - response.setMessage("OK"); - - new Expectations() { - { - srClient.heartbeat(anyString, anyString); - result = response; - watchTask.getMicroservice(); - result = microservice; - } - }; - - MicroserviceInstanceHeartbeatTask heartbeatTask = - new MicroserviceInstanceHeartbeatTask(eventBus, srClient, microservice); - watchTask.taskStatus = TaskStatus.READY; - eventBus.post(watchTask); - - heartbeatTask.run(); - Assert.assertEquals(HeartbeatResult.SUCCESS, heartbeatTask.getHeartbeatResult()); - Assert.assertEquals(false, heartbeatTask.isNeedRegisterInstance()); - Assert.assertEquals(1, heartbeatTaskList.size()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceRegisterTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceRegisterTask.java deleted file mode 100644 index 897e409c9ea..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceInstanceRegisterTask.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.api.registry.HealthCheck; -import org.apache.servicecomb.serviceregistry.api.registry.HealthCheckMode; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceInstanceRegisterTask { - private EventBus eventBus; - - private Microservice microservice; - - private List taskList; - - @Mocked - private ServiceRegistryConfig serviceRegistryConfig; - - @Mocked - private ServiceRegistryClient srClient; - - @Before - public void setup() { - eventBus = new EventBus(); - - taskList = new ArrayList<>(); - eventBus.register(new Object() { - @Subscribe - public void onEvent(MicroserviceInstanceRegisterTask task) { - taskList.add(task); - } - }); - - microservice = new Microservice(); - microservice.setAppId("app"); - microservice.setServiceName("ms"); - microservice.setServiceId("serviceId"); - - microservice.setInstance(new MicroserviceInstance()); - - HealthCheck healthCheck = new HealthCheck(); - healthCheck.setMode(HealthCheckMode.HEARTBEAT); - microservice.getInstance().setHealthCheck(healthCheck); - } - - @Test - public void microserviceNotRegistered() { - microservice.setServiceId(null); - - MicroserviceInstanceRegisterTask registerTask = - new MicroserviceInstanceRegisterTask(eventBus, serviceRegistryConfig, null, microservice); - registerTask.run(); - - Assert.assertEquals(false, registerTask.isRegistered()); - Assert.assertEquals(0, taskList.size()); - } - - @Test - public void registerIpSuccess() { - MicroserviceInstance instance = microservice.getInstance(); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getPublishAddress(); - result = "127.0.0.1"; - serviceRegistryConfig.isPreferIpAddress(); - result = true; - serviceRegistryConfig.getHeartbeatInterval(); - result = 10; - serviceRegistryConfig.getResendHeartBeatTimes(); - result = 20; - srClient.registerMicroserviceInstance(instance); - result = "instanceId"; - } - }; - MicroserviceInstanceRegisterTask registerTask = - new MicroserviceInstanceRegisterTask(eventBus, serviceRegistryConfig, srClient, microservice); - registerTask.taskStatus = TaskStatus.READY; - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals("127.0.0.1", instance.getHostName()); - Assert.assertEquals("instanceId", instance.getInstanceId()); - Assert.assertEquals(10, instance.getHealthCheck().getInterval()); - Assert.assertEquals(20, instance.getHealthCheck().getTimes()); - Assert.assertEquals(1, taskList.size()); - } - - @Test - public void registerHostSuccess() { - MicroserviceInstance instance = microservice.getInstance(); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getPublishHostName(); - result = "hostName"; - serviceRegistryConfig.isPreferIpAddress(); - result = false; - serviceRegistryConfig.getHeartbeatInterval(); - result = 10; - serviceRegistryConfig.getResendHeartBeatTimes(); - result = 20; - srClient.registerMicroserviceInstance(instance); - result = "instanceId"; - } - }; - MicroserviceInstanceRegisterTask registerTask = - new MicroserviceInstanceRegisterTask(eventBus, serviceRegistryConfig, srClient, microservice); - registerTask.taskStatus = TaskStatus.READY; - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals("hostName", instance.getHostName()); - Assert.assertEquals("instanceId", instance.getInstanceId()); - Assert.assertEquals(10, instance.getHealthCheck().getInterval()); - Assert.assertEquals(20, instance.getHealthCheck().getTimes()); - Assert.assertEquals(1, taskList.size()); - } - - @Test - public void registerIpFailed() { - MicroserviceInstance instance = microservice.getInstance(); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getPublishAddress(); - result = "127.0.0.1"; - serviceRegistryConfig.isPreferIpAddress(); - result = true; - serviceRegistryConfig.getHeartbeatInterval(); - result = 10; - serviceRegistryConfig.getResendHeartBeatTimes(); - result = 20; - srClient.registerMicroserviceInstance(instance); - result = null; - } - }; - MicroserviceInstanceRegisterTask registerTask = - new MicroserviceInstanceRegisterTask(eventBus, serviceRegistryConfig, srClient, microservice); - registerTask.taskStatus = TaskStatus.READY; - registerTask.run(); - - Assert.assertEquals(false, registerTask.isRegistered()); - Assert.assertEquals("127.0.0.1", instance.getHostName()); - Assert.assertEquals(10, instance.getHealthCheck().getInterval()); - Assert.assertEquals(20, instance.getHealthCheck().getTimes()); - Assert.assertEquals(1, taskList.size()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceRegisterTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceRegisterTask.java deleted file mode 100644 index 5c44312c93c..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceRegisterTask.java +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.log4j.spi.LoggingEvent; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.Holder; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestMicroserviceRegisterTask { - private EventBus eventBus; - - private Microservice microservice; - - private List taskList; - - LogCollector collector; - - @Before - public void setup() { - collector = new LogCollector(); - eventBus = new EventBus(); - - taskList = new ArrayList<>(); - eventBus.register(new Object() { - @Subscribe - public void onEvent(MicroserviceRegisterTask task) { - taskList.add(task); - } - }); - - microservice = new Microservice(); - microservice.setAppId("app"); - microservice.setServiceName("ms"); - - microservice.setInstance(new MicroserviceInstance()); - } - - @After - public void teardown() { - collector.teardown(); - } - - @Test - public void testNewRegisterFailed(@Mocked ServiceRegistryClient srClient) { - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = null; - srClient.registerMicroservice((Microservice) any); - result = null; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(false, registerTask.isRegistered()); - Assert.assertEquals(false, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals(null, microservice.getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - @Test - public void testNewRegisterSuccess(@Mocked ServiceRegistryClient srClient) { - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200); - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = null; - srClient.registerMicroservice((Microservice) any); - result = "serviceId"; - srClient.getSchemas("serviceId"); - this.result = onlineSchemasHolder; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals("serviceId", microservice.getInstance().getServiceId()); - Assert.assertEquals(1, taskList.size()); - - registerTask.run(); - Assert.assertEquals(1, taskList.size()); - } - - /** - * Local schemaId set is consistent with online schemaId set, and schema contents are not registered. - * This service instance try to register schema content but failed. - */ - @Test - public void testRegisterSchemaFailed(@Mocked ServiceRegistryClient srClient) { - microservice.addSchema("s1", ""); - microservice.addSchema("exist", ""); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200); - ArrayList schemaResponses = new ArrayList<>(); - onlineSchemasHolder.setValue(schemaResponses); - GetSchemaResponse schemaResponse = new GetSchemaResponse(); - schemaResponse.setSchemaId("s1"); - schemaResponses.add(schemaResponse); - schemaResponse.setSchemaId("exist"); - schemaResponses.add(schemaResponse); - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = null; - srClient.registerMicroservice((Microservice) any); - result = "serviceId"; - srClient.registerSchema(anyString, anyString, anyString); - result = false; - srClient.getSchemas("serviceId"); - this.result = onlineSchemasHolder; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(false, registerTask.isRegistered()); - Assert.assertEquals(false, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals("serviceId", microservice.getInstance().getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - /** - * There is no microservice information in service center. - */ - @Test - public void testRegisterSchemaSuccess(@Mocked ServiceRegistryClient srClient) { - microservice.addSchema("s1", "s1Content"); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200); - ArrayList schemaResponseList = new ArrayList<>(); - onlineSchemasHolder.setValue(schemaResponseList); - GetSchemaResponse schemaResponse = new GetSchemaResponse(); - schemaResponseList.add(schemaResponse); - schemaResponse.setSchemaId("s1"); - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = null; - srClient.registerMicroservice((Microservice) any); - result = "serviceId"; - srClient.getSchema("serviceId", "s1"); - result = "s1Content"; - srClient.getSchemas("serviceId"); - result = onlineSchemasHolder; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals("serviceId", microservice.getInstance().getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - @Test - public void testAlreadyRegisteredSchemaIdSetMatch(@Mocked ServiceRegistryClient srClient) { - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200); - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = microservice; - srClient.getSchemas("serviceId"); - result = onlineSchemasHolder; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals("serviceId", microservice.getInstance().getServiceId()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals(1, taskList.size()); - } - - @Test(expected = IllegalStateException.class) - public void testAlreadyRegisteredSchemaIdSetNotMatch(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", ""); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200); - ArrayList schemaResponseList = new ArrayList<>(); - onlineSchemasHolder.setValue(schemaResponseList); - GetSchemaResponse schemaResponse = new GetSchemaResponse(); - - schemaResponseList.add(schemaResponse); - schemaResponse.setSchemaId("s1"); - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas("serviceId"); - result = onlineSchemasHolder; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - } - - @Test - public void testAlreadyRegisteredGetSchemaIdSetFailed(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", ""); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = null; - } - }; - - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(false, registerTask.isRegistered()); - Assert.assertEquals(false, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - @Test - public void testReRegisteredSetForDev(@Mocked ServiceRegistryClient srClient) { - ArchaiusUtils.resetConfig(); - ArchaiusUtils.setProperty("service_description.environment", "development"); - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", ""); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - resp.setSummary("c1188d709631a9038874f9efc6eb894f"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setStatusCode(200).setValue(list); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - srClient.registerSchema(microservice.getServiceId(), anyString, anyString); - result = true; - } - }; - - microservice.addSchema("s1", ""); - microservice.setEnvironment("development"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - /** - * There is microservice information but no schema in service center. - */ - @Test - public void testFirstRegisterForProd(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", null); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setValue(list).setStatusCode(200); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - srClient.getSchema("serviceId", "s1"); - result = null; - srClient.registerSchema("serviceId", "s1", "s1Content"); - result = true; - } - }; - - microservice.addSchema("s1", "s1Content"); - microservice.setEnvironment("production"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - /** - * There is schema in service center which is different from local schema. - */ - @Test(expected = IllegalStateException.class) - public void testReRegisteredSetForProd(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", ""); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - resp.setSummary("c1188d709631a9038874f9efc6eb894f"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setValue(list).setStatusCode(200); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - } - }; - - microservice.addSchema("s1", ""); - microservice.setEnvironment("prod"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - } - - /** - * env = production and there are schemas only existing in service center - */ - @Test(expected = IllegalStateException.class) - public void testReRegisterForProductAndLocalSchemasAreLess(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", null); - otherMicroservice.addSchema("s2", null); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - list.add(resp); - resp = new GetSchemaResponse(); - resp.setSchemaId("s2"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setValue(list).setStatusCode(200); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - srClient.getSchema("serviceId", "s1"); - result = null; - srClient.registerSchema("serviceId", "s1", "s1Content"); - result = true; - } - }; - - microservice.addSchema("s1", "s1Content"); - microservice.setEnvironment("production"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - } - - @Test - public void testReRegisterForDevAndLocalSchemasAreLess(@Mocked ServiceRegistryClient srClient) { - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", null); - otherMicroservice.addSchema("s2", null); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - list.add(resp); - resp = new GetSchemaResponse(); - resp.setSchemaId("s2"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setValue(list).setStatusCode(200); - Holder removeSchemaResult = new Holder<>(); - removeSchemaResult.setStatusCode(200); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - srClient.getSchema("serviceId", "s1"); - result = null; - srClient.registerSchema("serviceId", "s1", "s1Content"); - result = true; - } - }; - - microservice.addSchema("s1", "s1Content"); - microservice.setEnvironment("development"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - registerTask.run(); - - Assert.assertEquals(true, registerTask.isRegistered()); - Assert.assertEquals(true, registerTask.isSchemaIdSetMatch()); - Assert.assertEquals("serviceId", microservice.getServiceId()); - Assert.assertEquals(1, taskList.size()); - } - - /** - * There is schema in service center which is different from local schema. - */ - @Test - public void testLocalSchemaAndServiceCenterSchemaDiff(@Mocked ServiceRegistryClient srClient) { - - Microservice otherMicroservice = new Microservice(); - otherMicroservice.setAppId(microservice.getAppId()); - otherMicroservice.setServiceName("ms1"); - otherMicroservice.addSchema("s1", "abcd"); - - List list = new ArrayList<>(); - GetSchemaResponse resp = new GetSchemaResponse(); - resp.setSchemaId("s1"); - resp.setSummary("c1188d709631a9038874f9efc6eb894f"); - list.add(resp); - Holder> onlineSchemasHolder = new Holder<>(); - onlineSchemasHolder.setValue(list).setStatusCode(200); - - new Expectations() { - { - srClient.getMicroserviceId(anyString, anyString, anyString, anyString); - result = "serviceId"; - srClient.getMicroservice(anyString); - result = otherMicroservice; - srClient.getSchemas(anyString); - result = onlineSchemasHolder; - srClient.getSchema(anyString, anyString); - result = "swagger: \"2.0\"\n" + - "info:\n" + - " version: \"1.0.0\"\n" + - " title: \"swagger definition for org.apache.servicecomb.demo.jaxrs.server.RequestClientTimeOut\"\n" + - " x-java-interface: \"cse.gen.jaxrstest.jaxrs.clientreqtimeout.RequestClientTimeOutIntf\"\n" + - "basePath: \"/clientreqtimeout\"\n" + - "consumes:\n" + - "- \"application/json\"\n" + - "produces:\n" + - "- \"application/json\"\n" + - "paths:\n" + - " /sayhello:\n" + - " post:\n" + - " operationId: \"sayHello\"\n" + - " parameters:\n" + - " - in: \"body\"\n" + - " name: \"student\"\n" + - " required: false\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - " responses:\n" + - " 200:\n" + - " description: \"response of 200\"\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - "definitions:\n" + - " Student:\n" + - " type: \"object\"\n" + - " required:\n" + - " - \"name\"\n" + - " properties:\n" + - " name:\n" + - " type: \"string\"\n" + - " age:\n" + - " type: \"integer\"\n" + - " format: \"int32\"\n" + - " maximum: 20\n" + - " x-java-class: \"org.apache.servicecomb.demo.validator.Student\""; - } - }; - - microservice.addSchema("s1", - "swagger: \"2.0\"\n" + - "info:\n" + - " version: \"1.0.0\"\n" + - " title: \"swagger definition for org.apache.servicecomb.demo.jaxrs.server.RequestClientTimeOut\"\n" + - " x-java-interface: \"cse.gen.jaxrstest.jaxrs.clientreqtimeout.RequestClientTimeOutIntf\"\n" + - "basePath: \"/clientreqtimeout\"\n" + - "consumes:\n" + - "- \"application/json\"\n" + - "produces:\n" + - "- \"application/json\"\n" + - "paths:\n" + - " /sayhello:\n" + - " post:\n" + - " operationId: \"sayHello\"\n" + - " parameters:\n" + - " - in: \"body\"\n" + - " name: \"student\"\n" + - " required: false\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - " responses:\n" + - " 200:\n" + - " description: \"response of 200\"\n" + - " schema:\n" + - " type: \"string\"\n" + - "definitions:\n" + - " Student:\n" + - " type: \"object\"\n" + - " required:\n" + - " - \"name\"\n" + - " properties:\n" + - " name:\n" + - " type: \"string\"\n" + - " age:\n" + - " type: \"integer\"\n" + - " format: \"int32\"\n" + - " maximum: 20\n" + - " x-java-class: \"org.apache.servicecomb.demo.validator.Student\""); - microservice.setEnvironment("prod"); - MicroserviceRegisterTask registerTask = new MicroserviceRegisterTask(eventBus, srClient, microservice); - - Boolean isIlleagalException = false; - - try { - registerTask.run(); - } catch (IllegalStateException exception) { - isIlleagalException = true; - List events = collector.getEvents().stream().filter(e -> { - return MicroserviceRegisterTask.class.getName().equals(e.getLoggerName()); - }).collect(Collectors.toList()); - - Assert.assertEquals("service center schema and local schema both are different:\n" + - " service center schema:\n" + - "[swagger: \"2.0\"\n" + - "info:\n" + - " version: \"1.0.0\"\n" + - " title: \"swagger definition for org.apache.servicecomb.demo.jaxrs.server.RequestClientTimeOut\"\n" + - " x-java-interface: \"cse.gen.jaxrstest.jaxrs.clientreqtimeout.RequestClientTimeOutIntf\"\n" + - "basePath: \"/clientreqtimeout\"\n" + - "consumes:\n" + - "- \"application/json\"\n" + - "produces:\n" + - "- \"application/json\"\n" + - "paths:\n" + - " /sayhello:\n" + - " post:\n" + - " operationId: \"sayHello\"\n" + - " parameters:\n" + - " - in: \"body\"\n" + - " name: \"student\"\n" + - " required: false\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - " responses:\n" + - " 200:\n" + - " description: \"response of 200\"\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - "definitions:\n" + - " Student:\n" + - " type: \"object\"\n" + - " required:\n" + - " - \"name\"\n" + - " properties:\n" + - " name:\n" + - " type: \"string\"\n" + - " age:\n" + - " type: \"integer\"\n" + - " format: \"int32\"\n" + - " maximum: 20\n" + - " x-java-class: \"org.apache.servicecomb.demo.validator.Student\"\n" + - " local schema:\n" + - "[swagger: \"2.0\"\n" + - "info:\n" + - " version: \"1.0.0\"\n" + - " title: \"swagger definition for org.apache.servicecomb.demo.jaxrs.server.RequestClientTimeOut\"\n" + - " x-java-interface: \"cse.gen.jaxrstest.jaxrs.clientreqtimeout.RequestClientTimeOutIntf\"\n" + - "basePath: \"/clientreqtimeout\"\n" + - "consumes:\n" + - "- \"application/json\"\n" + - "produces:\n" + - "- \"application/json\"\n" + - "paths:\n" + - " /sayhello:\n" + - " post:\n" + - " operationId: \"sayHello\"\n" + - " parameters:\n" + - " - in: \"body\"\n" + - " name: \"student\"\n" + - " required: false\n" + - " schema:\n" + - " $ref: \"#/definitions/Student\"\n" + - " responses:\n" + - " 200:\n" + - " description: \"response of 200\"\n" + - " schema:\n" + - " type: \"string\"\n" + - "definitions:\n" + - " Student:\n" + - " type: \"object\"\n" + - " required:\n" + - " - \"name\"\n" + - " properties:\n" + - " name:\n" + - " type: \"string\"\n" + - " age:\n" + - " type: \"integer\"\n" + - " format: \"int32\"\n" + - " maximum: 20\n" + - " x-java-class: \"org.apache.servicecomb.demo.validator.Student\"]", events.get(4).getMessage()); - - Assert.assertEquals("The difference in local schema:\n" + - "[type: \"string\"\n" + - "definitions:\n" + - " Student:\n" + - " type: \"object\"\n" + - " required:\n" + - " - \"name\"\n" + - " properties:\n" + - " name:\n" + - " type: \"string\"\n" + - " age:\n" + - " type: \"integer\"\n" + - " format: \"int32\"\n" + - " maximum: 20\n" + - " x-java-class: \"org.apache.servicecomb.demo.validator.Student\"]", events.get(5).getMessage()); - - } - - Assert.assertEquals(true, isIlleagalException); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceWatchTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceWatchTask.java deleted file mode 100644 index 52053cf542a..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestMicroserviceWatchTask.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.foundation.vertx.AsyncResultCallback; -import org.apache.servicecomb.serviceregistry.api.MicroserviceKey; -import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.api.registry.WatchAction; -import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.task.event.ExceptionEvent; -import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent; -import org.junit.Assert; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestMicroserviceWatchTask { - EventBus eventBus = new EventBus(); - - MicroserviceWatchTask microserviceWatchTask; - - private void initWatch(ServiceRegistryConfig serviceRegistryConfig, - ServiceRegistryClient srClient, Microservice microservice) { - microserviceWatchTask = new MicroserviceWatchTask(eventBus, serviceRegistryConfig, srClient, microservice); - microserviceWatchTask.taskStatus = TaskStatus.READY; - new Expectations() { - { - serviceRegistryConfig.isWatch(); - result = true; - microservice.getServiceId(); - result = "serviceId"; - } - }; - } - - @Test - public void testWatchOpen(@Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked ServiceRegistryClient srClient, - @Mocked Microservice microservice) { - initWatch(serviceRegistryConfig, srClient, microservice); - - new MockUp(srClient) { - @Mock - void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - onOpen.success(null); - } - }; - - Holder openHolder = new Holder<>(); - eventBus.register(new Object() { - @Subscribe - public void onOpen(RecoveryEvent event) { - openHolder.value = true; - } - }); - Assert.assertNull(openHolder.value); - microserviceWatchTask.run(); - Assert.assertTrue(openHolder.value); - } - - @Test - public void testWatchFailed(@Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked ServiceRegistryClient srClient, - @Mocked Microservice microservice) { - initWatch(serviceRegistryConfig, srClient, microservice); - - new MockUp(srClient) { - @Mock - void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - callback.fail(new Error("test failed")); - } - }; - - Holder holder = new Holder<>(); - eventBus.register(new Object() { - @Subscribe - public void onException(ExceptionEvent event) { - holder.value = event.getThrowable(); - } - }); - Assert.assertNull(holder.value); - microserviceWatchTask.run(); - Assert.assertEquals("test failed", holder.value.getMessage()); - } - - @Test - public void testWatchInstanceChanged(@Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked ServiceRegistryClient srClient, - @Mocked Microservice microservice) { - initWatch(serviceRegistryConfig, srClient, microservice); - - MicroserviceInstanceChangedEvent changedEvent = new MicroserviceInstanceChangedEvent(); - MicroserviceKey key = new MicroserviceKey(); - key.setAppId(microservice.getAppId()); - key.setVersion(microservice.getVersion()); - key.setServiceName(microservice.getServiceName()); - changedEvent.setKey(key); - changedEvent.setInstance(microservice.getInstance()); - - new MockUp(srClient) { - @Mock - void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - callback.success(changedEvent); - } - }; - - Holder holder = new Holder<>(); - eventBus.register(new Object() { - @Subscribe - public void onException(MicroserviceInstanceChangedEvent event) { - holder.value = event; - } - }); - - changedEvent.setAction(WatchAction.CREATE); - microserviceWatchTask.run(); - Assert.assertEquals(WatchAction.CREATE, holder.value.getAction()); - - changedEvent.setAction(WatchAction.DELETE); - microserviceWatchTask.run(); - Assert.assertEquals(WatchAction.DELETE, holder.value.getAction()); - - changedEvent.setAction(WatchAction.UPDATE); - microserviceWatchTask.run(); - Assert.assertEquals(WatchAction.UPDATE, holder.value.getAction()); - } - - @Test - public void testNeedToWatch(@Mocked ServiceRegistryConfig serviceRegistryConfig, - @Mocked ServiceRegistryClient srClient, - @Mocked Microservice microservice) { - EventBus eventBus = new EventBus(); - - MicroserviceWatchTask microserviceWatchTask = - new MicroserviceWatchTask(eventBus, serviceRegistryConfig, srClient, microservice); - microserviceWatchTask.taskStatus = TaskStatus.READY; - - new MockUp(srClient) { - @Mock - void watch(String selfMicroserviceId, AsyncResultCallback callback, - AsyncResultCallback onOpen, AsyncResultCallback onClose) { - throw new Error("called watch"); - } - }; - - new Expectations() { - { - serviceRegistryConfig.isWatch(); - result = false; - } - }; - // no watch - try { - microserviceWatchTask.run(); - } catch (Throwable e) { - Assert.fail("must do not watch"); - } - - new Expectations() { - { - serviceRegistryConfig.isWatch(); - result = true; - } - }; - // no watch - try { - microserviceWatchTask.run(); - } catch (Throwable e) { - // ready state, service id can not be null , will always watch - Assert.assertEquals("called watch", e.getMessage()); - } - - new Expectations() { - { - serviceRegistryConfig.isWatch(); - result = false; - } - }; - // no watch - try { - microserviceWatchTask.run(); - } catch (Throwable e) { - // ready state, service id can not be null , will always watch - Assert.assertEquals("called watch", e.getMessage()); - } - - new Expectations() { - { - serviceRegistryConfig.isWatch(); - result = true; - microservice.getServiceId(); - result = "serviceId"; - } - }; - // watch - try { - microserviceWatchTask.run(); - Assert.fail("must watch"); - } catch (Throwable e) { - Assert.assertEquals("called watch", e.getMessage()); - } - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestServiceCenterTask.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestServiceCenterTask.java deleted file mode 100644 index a7913d1fb09..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/task/TestServiceCenterTask.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.serviceregistry.task; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; - -public class TestServiceCenterTask { - private EventBus eventBus = new EventBus(); - - @Mocked - private MicroserviceServiceCenterTask microserviceServiceCenterTask; - - private ServiceCenterTask serviceCenterTask; - - @BeforeClass - public static void initClass() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void teardownClass() { - ArchaiusUtils.resetConfig(); - } - - @Before - public void init() { - serviceCenterTask = - new ServiceCenterTask(eventBus, ServiceRegistryConfig.INSTANCE.getHeartbeatInterval(), - microserviceServiceCenterTask); - } - - @Test - public void testLifeCycleException(@Mocked MicroserviceInstanceRegisterTask instanceEvent, - @Mocked MicroserviceInstanceHeartbeatTask heartBeatEvent) { - new Expectations() { - { - instanceEvent.getTaskStatus(); - result = TaskStatus.FINISHED; - heartBeatEvent.getHeartbeatResult(); - result = HeartbeatResult.DISCONNECTED; - } - }; - serviceCenterTask.init(); - eventBus.post(instanceEvent); - Assert.assertTrue(Deencapsulation.getField(serviceCenterTask, "registerInstanceSuccess")); - - eventBus.post(heartBeatEvent); - Assert.assertFalse(Deencapsulation.getField(serviceCenterTask, "registerInstanceSuccess")); - } - - @Test - public void testLifeCycleSuccess(@Mocked MicroserviceInstanceRegisterTask instanceEvent, - @Mocked MicroserviceInstanceHeartbeatTask heartBeatEvent) { - new Expectations() { - { - instanceEvent.getTaskStatus(); - result = TaskStatus.FINISHED; - heartBeatEvent.getHeartbeatResult(); - result = HeartbeatResult.SUCCESS; - } - }; - serviceCenterTask.init(); - eventBus.post(instanceEvent); - Assert.assertTrue(Deencapsulation.getField(serviceCenterTask, "registerInstanceSuccess")); - - eventBus.post(heartBeatEvent); - Assert.assertTrue(Deencapsulation.getField(serviceCenterTask, "registerInstanceSuccess")); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersion.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersion.java deleted file mode 100644 index 63025de05f0..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersion.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class TestVersion { - Version version; - - short s1 = 1; - - short s2 = 2; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void constructFromStringNormalOnlyMajor() { - version = new Version("1"); - Assert.assertEquals("1.0.0.0", version.getVersion()); - Assert.assertEquals(1, version.getMajor()); - Assert.assertEquals(0, version.getMinor()); - Assert.assertEquals(0, version.getPatch()); - } - - @Test - public void constructFromStringNormalOnlyMajorMinor() { - version = new Version("1.1"); - Assert.assertEquals("1.1.0.0", version.getVersion()); - Assert.assertEquals(1, version.getMajor()); - Assert.assertEquals(1, version.getMinor()); - Assert.assertEquals(0, version.getPatch()); - } - - @Test - public void constructFromStringOnlyMajorMinorPatch() { - version = new Version("1.1.1"); - Assert.assertEquals("1.1.1.0", version.getVersion()); - Assert.assertEquals(1, version.getMajor()); - Assert.assertEquals(1, version.getMinor()); - Assert.assertEquals(1, version.getPatch()); - Assert.assertEquals(0, version.getBuild()); - } - - @Test - public void constructFromStringNormal() { - version = new Version("1.1.1.1"); - Assert.assertEquals("1.1.1.1", version.getVersion()); - Assert.assertEquals(1, version.getMajor()); - Assert.assertEquals(1, version.getMinor()); - Assert.assertEquals(1, version.getPatch()); - Assert.assertEquals(1, version.getBuild()); - } - - - @Test - public void constructFromStringInvalidNull() { - expectedException.expect(NullPointerException.class); - - version = new Version(null); - } - - @Test - public void constructFromStringInvalidEmpty() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid major \"\", version \"\".")); - expectedException.expectCause(Matchers.instanceOf(NumberFormatException.class)); - - version = new Version(""); - } - - @Test - public void constructFromStringInvalidMajorNegative() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("major \"-1\" can not be negative, version \"-1\".")); - - version = new Version("-1"); - } - - @Test - public void constructFromStringInvalidMajorDot() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid minor \"\", version \"1.\".")); - expectedException.expectCause(Matchers.instanceOf(NumberFormatException.class)); - - version = new Version("1."); - } - - @Test - public void constructFromStringInvalidMinorNegative() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("minor \"-1\" can not be negative, version \"1.-1\".")); - - version = new Version("1.-1"); - } - - @Test - public void constructFromStringInvalidMinorDot() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid patch \"\", version \"1.1.\".")); - expectedException.expectCause(Matchers.instanceOf(NumberFormatException.class)); - - version = new Version("1.1."); - } - - @Test - public void constructFromStringInvalidPatchNegative() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("patch \"-1\" can not be negative, version \"1.1.-1\".")); - - version = new Version("1.1.-1"); - } - - @Test - public void constructFromStringInvalidPatchDot() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid build \"\", version \"1.1.1.\".")); - expectedException.expectCause(Matchers.instanceOf(NumberFormatException.class)); - - version = new Version("1.1.1."); - } - - @Test - public void constructFromStringInvalidBuildNegative() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("build \"-1\" can not be negative, version \"1.1.1.-1\".")); - - version = new Version("1.1.1.-1"); - } - - @Test - public void constructFromStringInvalidTooManyPart() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid version \"1.1.1.1.\".")); - version = new Version("1.1.1.1."); - } - - @Test - public void constructFromNumber() { - version = new Version(s1, s1, s1, s1); - Assert.assertEquals("1.1.1.1", version.getVersion()); - Assert.assertEquals(1, version.getMajor()); - Assert.assertEquals(1, version.getMinor()); - Assert.assertEquals(1, version.getPatch()); - Assert.assertEquals(1, version.getPatch()); - } - - @Test - public void testToString() { - version = new Version(s1, s1, s1, s1); - Assert.assertEquals("1.1.1.1", version.toString()); - } - - @Test - public void testHashCode() { - version = new Version(s1, s1, s1, s1); - Assert.assertEquals(version.getVersion().hashCode(), version.hashCode()); - } - - @Test - public void testEquals() { - version = new Version(s1, s1, s1, s1); - - Assert.assertTrue(version.equals(version)); - Assert.assertTrue(version.equals(new Version(s1, s1, s1, s1))); - Assert.assertFalse(version.equals(null)); - } - - @Test - public void compareTo() { - version = new Version(s1, s1, s1, s1); - - Assert.assertEquals(0, version.compareTo(version)); - Assert.assertEquals(0, version.compareTo(new Version(s1, s1, s1, s1))); - - Assert.assertEquals(-1, version.compareTo(new Version(s1, s1, s2, s1))); - Assert.assertEquals(-1, version.compareTo(new Version(s1, s2, s1, s1))); - Assert.assertEquals(-1, version.compareTo(new Version(s2, s1, s1, s1))); - - Assert.assertEquals(1, version.compareTo(new Version((short) 0, - Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE))); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRule.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRule.java deleted file mode 100644 index 5610446d312..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRule.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.junit.Assert; -import org.junit.Test; - -public class TestVersionRule { - class VersionRuleForTest extends VersionRule { - public VersionRuleForTest(String versionRule) { - super(versionRule); - } - - @Override - public boolean isMatch(Version version, Version latestVersion) { - return true; - } - } - - VersionRule versionRule = new VersionRuleForTest("abc"); - - @Test - public void isAccept() { - Assert.assertTrue(versionRule.isAccept(null)); - } - - @Test - public void getVersionRule() { - Assert.assertEquals("abc", versionRule.getVersionRule()); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleFixedParser.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleFixedParser.java deleted file mode 100644 index 37596056fd3..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleFixedParser.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.junit.Assert; -import org.junit.Test; - -public class TestVersionRuleFixedParser { - VersionRule versionRule; - - VersionRuleParser parser = new VersionRuleFixedParser(); - - @Test - public void parseNormal() { - versionRule = parser.parse("1"); - Assert.assertEquals("1.0.0.0", versionRule.getVersionRule()); - } - - @Test - public void isMatch() { - versionRule = parser.parse("1"); - Assert.assertTrue(versionRule.isMatch(VersionConst.v1, null)); - Assert.assertFalse(versionRule.isMatch(VersionConst.v2, null)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleLatestParser.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleLatestParser.java deleted file mode 100644 index fef7a7e1a15..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleLatestParser.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.junit.Assert; -import org.junit.Test; - -public class TestVersionRuleLatestParser { - VersionRuleParser parser = new VersionRuleLatestParser(); - - VersionRule versionRule = parser.parse(DefinitionConst.VERSION_RULE_LATEST); - - @Test - public void parseInvalue() { - Assert.assertNull(parser.parse("")); - } - - @Test - public void parseNormal() { - Assert.assertEquals(DefinitionConst.VERSION_RULE_LATEST, versionRule.getVersionRule()); - } - - @Test - public void isAccept() { - Assert.assertTrue(versionRule.isAccept(null)); - } - - @Test - public void isMatch() { - Assert.assertTrue(versionRule.isMatch(VersionConst.v1, VersionConst.v1)); - Assert.assertFalse(versionRule.isMatch(VersionConst.v2, VersionConst.v1)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleRangeParser.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleRangeParser.java deleted file mode 100644 index a44a23b64ac..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleRangeParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.junit.Assert; -import org.junit.Test; - -public class TestVersionRuleRangeParser { - VersionRuleParser parser = new VersionRuleRangeParser(); - - VersionRule versionRule = parser.parse("1-2"); - - @Test - public void parseInvalid() { - Assert.assertNull(parser.parse("")); - Assert.assertNull(parser.parse("-")); - Assert.assertNull(parser.parse("1-")); - } - - @Test - public void parseNormal() { - Assert.assertEquals("1.0.0.0-2.0.0.0", versionRule.getVersionRule()); - } - - @Test - public void isMatch() { - Assert.assertFalse(versionRule.isMatch(VersionConst.v0, null)); - Assert.assertTrue(versionRule.isMatch(VersionConst.v1, null)); - Assert.assertTrue(versionRule.isMatch(VersionConst.v1Max, null)); - Assert.assertFalse(versionRule.isMatch(VersionConst.v2, null)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleStartFromParser.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleStartFromParser.java deleted file mode 100644 index a99f39f17d2..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleStartFromParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.junit.Assert; -import org.junit.Test; - -public class TestVersionRuleStartFromParser { - VersionRuleParser parser = new VersionRuleStartFromParser(); - - VersionRule versionRule = parser.parse("1+"); - - @Test - public void parseInvalid() { - Assert.assertNull(parser.parse("")); - Assert.assertNull(parser.parse("+")); - Assert.assertNull(parser.parse("1+1")); - } - - @Test - public void parseNormal() { - Assert.assertEquals("1.0.0.0+", versionRule.getVersionRule()); - } - - @Test - public void isMatch() { - Assert.assertFalse(versionRule.isMatch(VersionConst.v0, null)); - Assert.assertTrue(versionRule.isMatch(VersionConst.v1, null)); - Assert.assertTrue(versionRule.isMatch(VersionConst.v1Max, null)); - Assert.assertTrue(versionRule.isMatch(VersionConst.v2, null)); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleUtils.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleUtils.java deleted file mode 100644 index 724a8518809..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionRuleUtils.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; -import org.apache.servicecomb.serviceregistry.version.VersionRuleFixedParser.FixedVersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleLatestParser.LatestVersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleRangeParser.RangeVersionRule; -import org.apache.servicecomb.serviceregistry.version.VersionRuleStartFromParser.StartFromVersionRule; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class TestVersionRuleUtils { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void fixed() { - VersionRule versionRule = VersionRuleUtils.getOrCreate("1"); - Assert.assertThat(versionRule, Matchers.instanceOf(FixedVersionRule.class)); - Assert.assertSame(versionRule, VersionRuleUtils.getOrCreate("1")); - } - - @Test - public void latest() { - VersionRule versionRule = VersionRuleUtils.getOrCreate(DefinitionConst.VERSION_RULE_LATEST); - Assert.assertThat(versionRule, Matchers.instanceOf(LatestVersionRule.class)); - Assert.assertSame(versionRule, VersionRuleUtils.getOrCreate(DefinitionConst.VERSION_RULE_LATEST)); - } - - @Test - public void range() { - VersionRule versionRule = VersionRuleUtils.getOrCreate("1-2"); - Assert.assertThat(versionRule, Matchers.instanceOf(RangeVersionRule.class)); - Assert.assertSame(versionRule, VersionRuleUtils.getOrCreate("1-2")); - } - - @Test - public void startFrom() { - VersionRule versionRule = VersionRuleUtils.getOrCreate("1+"); - Assert.assertThat(versionRule, Matchers.instanceOf(StartFromVersionRule.class)); - Assert.assertSame(versionRule, VersionRuleUtils.getOrCreate("1+")); - } - - @Test - public void invalid() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid major \"\", version \"\".")); - - VersionRuleUtils.getOrCreate(""); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionUtils.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionUtils.java deleted file mode 100644 index cd8a46032fd..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/TestVersionUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -import java.util.concurrent.ConcurrentHashMap; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Deencapsulation; - -public class TestVersionUtils { - @Before - public void setup() { - Deencapsulation.setField(VersionUtils.class, "versionCache", new ConcurrentHashMap<>()); - } - - @After - public void teardown() { - Deencapsulation.setField(VersionUtils.class, "versionCache", new ConcurrentHashMap<>()); - } - - @Test - public void getOrCreate() { - Version v = VersionUtils.getOrCreate("1.0.0"); - - Assert.assertEquals("1.0.0.0", v.getVersion()); - Assert.assertSame(v, VersionUtils.getOrCreate("1.0.0")); - } -} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/VersionConst.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/VersionConst.java deleted file mode 100644 index d92f03ea75e..00000000000 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/version/VersionConst.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.serviceregistry.version; - -public interface VersionConst { - Version v0 = new Version((short) 0, (short) 0, (short) 0, (short) 0); - - Version v1 = new Version("1"); - - Version v1Max = new Version((short) 1, Short.MAX_VALUE, Short.MAX_VALUE, Short.MAX_VALUE); - - Version v2 = new Version("2"); -} diff --git a/service-registry/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider b/service-registry/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider deleted file mode 100644 index 202445dc908..00000000000 --- a/service-registry/src/test/resources/META-INF/services/org.apache.servicecomb.foundation.auth.AuthHeaderProvider +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.serviceregistry.client.http.MockAuthHeaderProvider diff --git a/service-registry/src/test/resources/app1.yaml b/service-registry/src/test/resources/app1.yaml deleted file mode 100644 index 98e523ab57d..00000000000 --- a/service-registry/src/test/resources/app1.yaml +++ /dev/null @@ -1,20 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: app1 -service_description: - name: ms1 diff --git a/service-registry/src/test/resources/app2.yaml b/service-registry/src/test/resources/app2.yaml deleted file mode 100644 index 8aace31c84a..00000000000 --- a/service-registry/src/test/resources/app2.yaml +++ /dev/null @@ -1,20 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -APPLICATION_ID: app2 -service_description: - name: ms2 diff --git a/service-registry/src/test/resources/config/log4j.serviceregistry.client.properties b/service-registry/src/test/resources/config/log4j.serviceregistry.client.properties deleted file mode 100644 index 94f9db4ae37..00000000000 --- a/service-registry/src/test/resources/config/log4j.serviceregistry.client.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/ -paas.logs.file=servicecomb.log -log4j.rootLogger=INFO,paas,stdout diff --git a/service-registry/src/test/resources/log4j.properties b/service-registry/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/service-registry/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/service-registry/src/test/resources/microservice.yaml b/service-registry/src/test/resources/microservice.yaml deleted file mode 100644 index 47883555d9b..00000000000 --- a/service-registry/src/test/resources/microservice.yaml +++ /dev/null @@ -1,60 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -service_description: - name: default - version: 0.0.1 - properties: - key1: value1 - key2: value2 - propertyExtentedClass: org.apache.servicecomb.serviceregistry.MicroServicePropertyExtendedStub - paths: - - path: /test1/testpath - property: - checksession: false - - path: /test2/testpath - property: - checksession: true -instance_description: - properties: - key0: value0 - propertyExtentedClass: org.apache.servicecomb.serviceregistry.MicroServicePropertyExtendedStub - -servicecomb: - service: - registry: - address: http://127.0.0.1:30100 - client: - httpVersion: HTTP_1_1 - workerPoolSize: 1 - timeout: - connection: 30000 - idle: 30000 - instance: - watch: true - preferIpAddress: false - healthCheck: - interval: 1 - times: 5 - datacenter: - name: myDC - region: my-Region - availableZone: my-Zone -#ssl.keystore.path= -#ssl.keystore.pass= -#ssl.truststore.path= -#ssl.truststore.pass= diff --git a/service-registry/src/test/resources/registry.yaml b/service-registry/src/test/resources/registry.yaml deleted file mode 100644 index 8cad52c22d3..00000000000 --- a/service-registry/src/test/resources/registry.yaml +++ /dev/null @@ -1,26 +0,0 @@ -## --------------------------------------------------------------------------- -## Licensed to the Apache Software Foundation (ASF) under one or more -## contributor license agreements. See the NOTICE file distributed with -## this work for additional information regarding copyright ownership. -## The ASF licenses this file to You under the Apache License, Version 2.0 -## (the "License"); you may not use this file except in compliance with -## the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## --------------------------------------------------------------------------- - -springmvctest: - - id: "001" - version: "1.0" - appid: myapp - schemaIds: - - springmvcHello - instances: - - endpoints: - - rest://127.0.0.1:8080 diff --git a/solutions/pom.xml b/solutions/pom.xml new file mode 100644 index 00000000000..4203f65309b --- /dev/null +++ b/solutions/pom.xml @@ -0,0 +1,38 @@ + + + + + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + 4.0.0 + + solutions + Java Chassis::Solutions + pom + + + solution-basic + + + diff --git a/solutions/solution-basic/pom.xml b/solutions/solution-basic/pom.xml new file mode 100644 index 00000000000..1bb51a4b88c --- /dev/null +++ b/solutions/solution-basic/pom.xml @@ -0,0 +1,100 @@ + + + + + + org.apache.servicecomb + solutions + 3.4.0-SNAPSHOT + + 4.0.0 + + solution-basic + Java Chassis::Solutions::BASIC + + + + + org.apache.servicecomb + transport-rest-vertx + + + org.apache.servicecomb + transport-highway + + + org.apache.servicecomb + transport-rest-servlet + + + + + org.apache.servicecomb + provider-springmvc + + + org.apache.servicecomb + provider-pojo + + + org.apache.servicecomb + provider-jaxrs + + + + + org.apache.servicecomb + handler-fault-injection + + + org.apache.servicecomb + handler-flowcontrol-qps + + + org.apache.servicecomb + handler-governance + + + org.apache.servicecomb + handler-loadbalance + + + org.apache.servicecomb + handler-publickey-auth + + + org.apache.servicecomb + handler-router + + + + + org.apache.servicecomb + swagger-invocation-validator + + + + + org.apache.servicecomb + metrics-core + + + + diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpoint.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpoint.java new file mode 100644 index 00000000000..b340b663ad6 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpoint.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import java.util.Map; + +import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +/** + * Java Chassis health check extensions. + */ +@Path("/scb/health") +public interface HealthEndpoint { + String NAME = "scb-health"; + + @Path("/") + @GET + boolean checkHealth(); + + @Path("/details") + @GET + Map checkHealthDetails(); +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpointImpl.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpointImpl.java new file mode 100644 index 00000000000..d8166999068 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthEndpointImpl.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.solution.basic.integration; + +import java.util.Map; + +import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; +import org.apache.servicecomb.foundation.metrics.health.HealthCheckerManager; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +@RestSchema(schemaId = HealthEndpoint.NAME, schemaInterface = HealthEndpoint.class) +public class HealthEndpointImpl implements HealthEndpoint { + @Override + public boolean checkHealth() { + Map results = HealthCheckerManager.getInstance().check(); + for (HealthCheckResult result : results.values()) { + if (!result.isHealthy()) { + return false; + } + } + return true; + } + + @Override + public Map checkHealthDetails() { + return HealthCheckerManager.getInstance().check(); + } +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthInstancePing.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthInstancePing.java new file mode 100644 index 00000000000..79db6818e61 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/HealthInstancePing.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.registry.discovery.InstancePing; +import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance; +import org.apache.servicecomb.registry.discovery.TelnetInstancePing; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +public class HealthInstancePing implements InstancePing { + private static final Logger LOGGER = LoggerFactory.getLogger(HealthInstancePing.class); + + private SCBEngine scbEngine; + + private TelnetInstancePing telnetInstancePing; + + private Environment environment; + + @Autowired + @Lazy + public void setScbEngine(SCBEngine scbEngine) { + this.scbEngine = scbEngine; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + @Lazy + public void setTelnetInstancePing(@Qualifier("scbTelnetInstancePing") TelnetInstancePing telnetInstancePing) { + this.telnetInstancePing = telnetInstancePing; + } + + @Override + public boolean ping(StatefulDiscoveryInstance instance) { + if (CollectionUtils.isEmpty(instance.getEndpoints())) { + return false; + } + + // hard coded here, not very nice + if ("local-registry".equals(instance.getRegistryName())) { + return telnetInstancePing.ping(instance); + } + + Map args = new HashMap<>(2); + args.put("instanceId", instance.getInstanceId()); + args.put("registryName", instance.getRegistryName()); + + for (String endpoint : instance.getEndpoints()) { + URI uri = URI.create(endpoint); + String transportName = uri.getScheme(); + Transport transport = scbEngine.getTransportManager().findTransport(transportName); + if (transport == null) { + continue; + } + // Use myself service name instead of the target. Because can avoid create + // MicroserviceReferenceConfig for the target. + Invocation invocation = InvokerUtils.createInvocation(BootStrapProperties.readServiceName(environment), + transportName, + ManagementEndpoint.NAME, "health", + args, boolean.class); + invocation.setEndpoint(new Endpoint(transport, endpoint, instance)); + boolean result; + try { + result = (boolean) InvokerUtils.syncInvoke(invocation); + } catch (Exception e) { + LOGGER.warn("ping instance {}/{}/{}/{} endpoint {} failed. {}", + instance.getApplication(), + instance.getServiceName(), + instance.getRegistryName(), + instance.getInstanceId(), endpoint, e.getMessage()); + continue; + } + if (result) { + return true; + } + LOGGER.warn("ping instance {}/{}/{}/{} endpoint {} failed", + instance.getApplication(), + instance.getServiceName(), + instance.getRegistryName(), + instance.getInstanceId(), endpoint); + } + + return false; + } + + @Override + public int getOrder() { + return -10000; + } +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/InstanceOpenAPIRegistry.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/InstanceOpenAPIRegistry.java new file mode 100644 index 00000000000..f8314d5afaa --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/InstanceOpenAPIRegistry.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.solution.basic.integration; + +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.provider.OpenAPIRegistry; +import org.apache.servicecomb.core.provider.OpenAPIRegistryManager.OpenAPIChangeListener; +import org.apache.servicecomb.core.provider.consumer.InvokerUtils; +import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.registry.DiscoveryManager; +import org.apache.servicecomb.registry.api.DiscoveryInstance; +import org.apache.servicecomb.router.util.VersionCompareUtil; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.core.type.TypeReference; + +import io.swagger.v3.oas.models.OpenAPI; +import jakarta.ws.rs.core.Response.Status; + +public class InstanceOpenAPIRegistry implements OpenAPIRegistry { + private static final Logger LOGGER = LoggerFactory.getLogger(InstanceOpenAPIRegistry.class); + + private DiscoveryManager discoveryManager; + + private Environment environment; + + private TransportManager transportManager; + + @Autowired + public void setDiscoveryManager(DiscoveryManager discoveryManager) { + this.discoveryManager = discoveryManager; + } + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Autowired + public void setTransportManager(TransportManager transportManager) { + this.transportManager = transportManager; + } + + @Override + public boolean enabled() { + return environment.getProperty(OpenAPIRegistry.CONFIG_PREFIX + ".instance.enabled", boolean.class, true); + } + + @Override + public void registerOpenAPI(String application, String serviceName, String schemaId, OpenAPI api) { + // do nothing + } + + @Override + @SuppressWarnings("unchecked") + public Map loadOpenAPI(String application, String serviceName) { + List discoveryInstances = + discoveryManager.getOrCreateVersionedCache(application, serviceName).data(); + + if (discoveryInstances.isEmpty()) { + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "no instances"); + } + discoveryInstances.sort((a, b) -> VersionCompareUtil.compareVersion(b.getVersion(), a.getVersion())); + + String version = null; + for (DiscoveryInstance instance : discoveryInstances) { + if (version != null && !version.equals(instance.getVersion())) { + break; + } + version = instance.getVersion(); + for (String endpoint : instance.getEndpoints()) { + URI uri = URI.create(endpoint); + String transportName = uri.getScheme(); + Transport transport = transportManager.findTransport(transportName); + if (transport == null) { + continue; + } + // Use myself service name instead of the target. Because can avoid create + // MicroserviceReferenceConfig for the target. + Invocation invocation = InvokerUtils.createInvocation(BootStrapProperties.readServiceName(environment), + transportName, + ManagementEndpoint.NAME, "schemaContents", + new HashMap<>(), new TypeReference>() { + }.getType()); + invocation.setEndpoint(new Endpoint(transport, endpoint, discoveryInstances.get(0))); + try { + Map contents = (Map) InvokerUtils.syncInvoke(invocation); + Map result = new HashMap<>(contents.size()); + contents.forEach((k, v) -> result.put(k, SwaggerUtils.parseSwagger(v))); + return result; + } catch (InvocationException e) { + LOGGER.warn("Get schema contents {}/{}/{} from endpoint {} failed. {}", + instance.getApplication(), + instance.getServiceName(), + instance.getInstanceId(), endpoint, e.getMessage()); + } + } + } + throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "Get schema contents fail from all latest version."); + } + + @Override + public void setOpenAPIChangeListener(OpenAPIChangeListener listener) { + this.discoveryManager.addInstanceChangeListener( + (registryName, application, serviceName, instances) -> { + if (CollectionUtils.isEmpty(instances)) { + return; + } + listener.onOpenAPIChanged(application, serviceName); + }); + } + + @Override + public int getOrder() { + return -9000; + } +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/IntegrationConfiguration.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/IntegrationConfiguration.java new file mode 100644 index 00000000000..dc80439ae81 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/IntegrationConfiguration.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class IntegrationConfiguration { + @Bean + public ManagementEndpointImpl managementEndpoint() { + return new ManagementEndpointImpl(); + } + + @Bean + public HealthEndpointImpl healthEndpoint() { + return new HealthEndpointImpl(); + } + + @Bean + public MetricsEndpointImpl metricsEndpoint() { + return new MetricsEndpointImpl(); + } + + @Bean + public HealthInstancePing healthInstancePing() { + return new HealthInstancePing(); + } + + @Bean + public InstanceOpenAPIRegistry instanceOpenAPIRegistry() { + return new InstanceOpenAPIRegistry(); + } +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpoint.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpoint.java new file mode 100644 index 00000000000..f41aa8a216f --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpoint.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import java.util.Map; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +/** + * Java Chassis internal management apis. + */ +@Path("/scb/management") +public interface ManagementEndpoint { + String NAME = "scb-management"; + + /** + * Health of this instance. If the instanceId match this instance, and this service is ready + * to service return true. Otherwise, return false. + * + * This api is for internal instance status usage. Load balancer will call this api to check if + * the target instance is alive. + */ + @GET + @Path("/health") + boolean health(@QueryParam("instanceId") String instanceId, @QueryParam("registryName") String registryName); + + /** + * Schemas of this instance. + * + * This api is for internal schema loading usage. + */ + @POST + @Path("/schema/contents") + Map schemaContents(); +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpointImpl.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpointImpl.java new file mode 100644 index 00000000000..00852bde863 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/ManagementEndpointImpl.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.provider.LocalOpenAPIRegistry; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.registry.RegistrationManager; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import io.swagger.v3.oas.models.OpenAPI; + +@RestSchema(schemaId = ManagementEndpoint.NAME, schemaInterface = ManagementEndpoint.class) +public class ManagementEndpointImpl implements ManagementEndpoint { + private RegistrationManager registrationManager; + + private LocalOpenAPIRegistry localOpenAPIRegistry; + + @Autowired + public void setRegistrationManager(RegistrationManager registrationManager) { + this.registrationManager = registrationManager; + } + + @Autowired + public void setLocalOpenAPIRegistry(LocalOpenAPIRegistry localOpenAPIRegistry) { + this.localOpenAPIRegistry = localOpenAPIRegistry; + } + + @Override + public boolean health(String instanceId, String registryName) { + if (StringUtils.isEmpty(instanceId) || StringUtils.isEmpty(registryName)) { + return false; + } + String mySelf = registrationManager.getInstanceId(registryName); + if (StringUtils.isEmpty(mySelf)) { + return false; + } + return mySelf.equals(instanceId); + } + + @Override + public Map schemaContents() { + Map apis = localOpenAPIRegistry.loadOpenAPI(); + Map result = new HashMap<>(apis.size()); + apis.forEach((k, v) -> result.put(k, SwaggerUtils.swaggerToString(v))); + return result; + } +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpoint.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpoint.java new file mode 100644 index 00000000000..4bfee7827d5 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpoint.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import java.util.Map; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +/** + * Java Chassis metrics. + */ +@Path("/scb/metrics") +public interface MetricsEndpoint { + String NAME = "scb-metrics"; + + @GET + @Path("/") + Map measure(); +} diff --git a/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpointImpl.java b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpointImpl.java new file mode 100644 index 00000000000..e989a5b8a76 --- /dev/null +++ b/solutions/solution-basic/src/main/java/org/apache/servicecomb/solution/basic/integration/MetricsEndpointImpl.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.solution.basic.integration; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.apache.servicecomb.foundation.metrics.MetricsInitializer; +import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; +import org.apache.servicecomb.provider.rest.common.RestSchema; + +import com.google.common.eventbus.EventBus; + +import io.micrometer.core.instrument.Measurement; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; + +@RestSchema(schemaId = MetricsEndpoint.NAME, schemaInterface = MetricsEndpoint.class) +public class MetricsEndpointImpl implements MetricsInitializer, MetricsEndpoint { + private MeterRegistry meterRegistry; + + @Override + public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) { + this.meterRegistry = meterRegistry; + } + + @Override + public Map measure() { + Map measurements = new LinkedHashMap<>(); + StringBuilder sb = new StringBuilder(); + + for (Meter meter : this.meterRegistry.getMeters()) { + meter.measure().forEach(measurement -> { + String key = idToString(meter.getId(), measurement, sb); + measurements.put(key, measurement.getValue()); + }); + } + + return measurements; + } + + // format id to string: + // idName(tag1=value1,tag2=value2) + protected String idToString(Id id, Measurement measurement, StringBuilder sb) { + sb.setLength(0); + sb.append(id.getName()).append("(").append(EndpointMeter.STATISTIC).append("=") + .append(measurement.getStatistic().name()).append(","); + sb.append(StreamSupport + .stream(id + .getTags() + .spliterator(), false) + .map(this::tagToString) + .collect( + Collectors.joining(","))); + sb.append(')'); + + return sb.toString(); + } + + private String tagToString(Tag tag) { + return tag.getKey() + "=" + tag.getValue(); + } +} diff --git a/solutions/solution-basic/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/solutions/solution-basic/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..351463c398d --- /dev/null +++ b/solutions/solution-basic/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.solution.basic.integration.IntegrationConfiguration diff --git a/solutions/solution-basic/src/main/resources/microservice.yaml b/solutions/solution-basic/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..cead0718220 --- /dev/null +++ b/solutions/solution-basic/src/main/resources/microservice.yaml @@ -0,0 +1,40 @@ +# +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# order of this configure file +servicecomb-config-order: -100 + +servicecomb: +# metrics and access log + accesslog: + enabled: true + pattern: "|%SCB-traceId|%h|%r|%s|%D" + + metrics: + window_time: 300000 + invocation: + latencyDistribution: 0,10,50,100,1000 + Consumer.invocation.slow: + enabled: true + msTime: 1000 + Provider.invocation.slow: + enabled: true + msTime: 1000 + publisher.defaultLog: + enabled: true + endpoints.client.detail.enabled: true diff --git a/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestHealthEndpointImpl.java b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestHealthEndpointImpl.java new file mode 100644 index 00000000000..d0515a73105 --- /dev/null +++ b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestHealthEndpointImpl.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.solution.basic.integration; + +import java.util.Map; + +import org.apache.servicecomb.foundation.metrics.health.HealthCheckResult; +import org.apache.servicecomb.foundation.metrics.health.HealthChecker; +import org.apache.servicecomb.foundation.metrics.health.HealthCheckerManager; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TestHealthEndpointImpl { + private final HealthChecker good = new HealthChecker() { + @Override + public String getName() { + return "test"; + } + + @Override + public HealthCheckResult check() { + return new HealthCheckResult(true, "info", "extra data"); + } + }; + + private final HealthChecker bad = new HealthChecker() { + @Override + public String getName() { + return "test2"; + } + + @Override + public HealthCheckResult check() { + return new HealthCheckResult(false, "info2", "extra data 2"); + } + }; + + + @BeforeEach + public void reset() { + HealthCheckerManager.getInstance().unregister(good.getName()); + HealthCheckerManager.getInstance().unregister(bad.getName()); + } + + @Test + public void checkHealthGood() { + HealthCheckerManager.getInstance().register(good); + HealthEndpointImpl publisher = new HealthEndpointImpl(); + Assertions.assertTrue(publisher.checkHealth()); + } + + @Test + public void checkHealthBad() { + HealthCheckerManager.getInstance().register(good); + HealthCheckerManager.getInstance().register(bad); + HealthEndpointImpl publisher = new HealthEndpointImpl(); + Assertions.assertFalse(publisher.checkHealth()); + } + + @Test + public void checkHealthDetails() { + HealthCheckerManager.getInstance().register(good); + HealthCheckerManager.getInstance().register(bad); + HealthEndpointImpl publisher = new HealthEndpointImpl(); + Map content = publisher.checkHealthDetails(); + Assertions.assertTrue(content.get("test").isHealthy()); + Assertions.assertEquals("info", content.get("test").getInformation()); + Assertions.assertEquals("extra data", content.get("test").getExtraData()); + } +} diff --git a/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestManagementEndpointImpl.java b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestManagementEndpointImpl.java new file mode 100644 index 00000000000..02e06025192 --- /dev/null +++ b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestManagementEndpointImpl.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +public class TestManagementEndpointImpl { + +} diff --git a/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestMetricsEndpointImpl.java b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestMetricsEndpointImpl.java new file mode 100644 index 00000000000..cb175d9b7d8 --- /dev/null +++ b/solutions/solution-basic/src/test/java/org/apache/servicecomb/solution/basic/integration/TestMetricsEndpointImpl.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.solution.basic.integration; + +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.DEFAULT_METRICS_WINDOW_TIME; +import static org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig.METRICS_WINDOW_TIME; + +import java.util.Map; + +import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import com.google.common.eventbus.EventBus; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; + +public class TestMetricsEndpointImpl { + MetricsEndpointImpl publisher = new MetricsEndpointImpl(); + + EventBus eventBus = new EventBus(); + + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setUp() { + Mockito.when(environment.getProperty(METRICS_WINDOW_TIME, int.class, DEFAULT_METRICS_WINDOW_TIME)) + .thenReturn(DEFAULT_METRICS_WINDOW_TIME); + Mockito.when(environment.getProperty( + CONFIG_LATENCY_DISTRIBUTION_MIN_SCOPE_LEN, int.class, 7)) + .thenReturn(7); + } + + @Test + public void measure_globalRegistryNull() { + MeterRegistry registry = new SimpleMeterRegistry(); + publisher.init(registry, eventBus, new MetricsBootstrapConfig(environment)); + + Map result = publisher.measure(); + + Assertions.assertEquals(0, result.size()); + } + + @Test + public void measure_normal() { + MeterRegistry registry = new SimpleMeterRegistry(); + registry.timer("name", "t1", "v1", "t2", "v2"); + + publisher.init(registry, eventBus, new MetricsBootstrapConfig(environment)); + Map result = publisher.measure(); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(0, result.get("name(statistic=COUNT,t1=v1,t2=v2)"), 0); + Assertions.assertEquals(0, result.get("name(statistic=TOTAL_TIME,t1=v1,t2=v2)"), 0); + Assertions.assertEquals(0, result.get("name(statistic=MAX,t1=v1,t2=v2)"), 0); + } +} diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml new file mode 100644 index 00000000000..b96de480b73 --- /dev/null +++ b/spring-boot/pom.xml @@ -0,0 +1,38 @@ + + + + + + org.apache.servicecomb + java-chassis-parent + 3.4.0-SNAPSHOT + ../parents/default + + + 4.0.0 + pom + java-chassis-spring-boot + Java Chassis::Spring Boot + + + spring-boot-starters + + + diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/pom.xml b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/pom.xml new file mode 100644 index 00000000000..c3fa579baee --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/pom.xml @@ -0,0 +1,69 @@ + + + + + + java-chassis-spring-boot-starters + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + java-chassis-spring-boot-starter-servlet + Java Chassis::Spring Boot Starter::Servlet + + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.servicecomb + transport-rest-servlet + + + org.apache.servicecomb + provider-springmvc + + + org.apache.servicecomb + provider-jaxrs + + + org.apache.servicecomb + provider-pojo + + + org.apache.servicecomb + handler-loadbalance + + + jakarta.servlet + jakarta.servlet-api + compile + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + + diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/RestServletInitializer.java b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/RestServletInitializer.java new file mode 100644 index 00000000000..ee247758fd4 --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/RestServletInitializer.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.starter.servlet; + +import java.io.IOException; +import java.net.ServerSocket; + +import org.apache.servicecomb.transport.rest.servlet.ServletUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.core.env.Environment; + +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; + +public class RestServletInitializer + implements WebServerFactoryCustomizer, ServletContextInitializer { + private static final Logger LOGGER = LoggerFactory.getLogger(RestServletInitializer.class); + + private AbstractConfigurableWebServerFactory factory = null; + + private Environment environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void customize(AbstractConfigurableWebServerFactory factory) { + this.factory = factory; + } + + @Override + @SuppressWarnings("try") + public void onStartup(ServletContext servletContext) throws ServletException { + if (this.factory == null) { + // when running in external tomcat, WebServerFactoryCustomizer will not be available, but now tomcat + // is already listening and we can call ServletUtils.init directly. + ServletUtils.init(servletContext, environment); + return; + } + + if (factory.getPort() == 0) { + LOGGER.warn( + "spring boot embedded web container listen port is 0, ServiceComb will not use container's port to handler REST request."); + return; + } + + // when running in embedded tomcat, web container did not listen now. Call ServletUtils.init needs server is ready, + // so mock to listen, and then close. + try (ServerSocket ignored = new ServerSocket(factory.getPort(), 0, factory.getAddress())) { + ServletUtils.init(servletContext, environment); + } catch (IOException e) { + throw new ServletException(e); + } + } +} diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/SpringBootStarterServletConfiguration.java b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/SpringBootStarterServletConfiguration.java new file mode 100644 index 00000000000..5d17aefb60b --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/SpringBootStarterServletConfiguration.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.springboot.starter.servlet; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpringBootStarterServletConfiguration { + @Bean + public RestServletInitializer restServletInitializer() { + return new RestServletInitializer(); + } +} diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/package-info.java b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/package-info.java new file mode 100644 index 00000000000..fbf06e33413 --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/java/org/apache/servicecomb/springboot/starter/servlet/package-info.java @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.springboot.starter.servlet; diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..217c48ac511 --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-servlet/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.springboot.starter.servlet.SpringBootStarterServletConfiguration diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-standalone/pom.xml b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-standalone/pom.xml new file mode 100644 index 00000000000..cd8d007109f --- /dev/null +++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter-standalone/pom.xml @@ -0,0 +1,66 @@ + + + + + + java-chassis-spring-boot-starters + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + java-chassis-spring-boot-starter-standalone + Java Chassis::Spring Boot Starter::Standalone + + + + org.apache.servicecomb + transport-rest-vertx + + + org.apache.servicecomb + provider-springmvc + + + org.apache.servicecomb + provider-jaxrs + + + org.apache.servicecomb + provider-pojo + + + org.apache.servicecomb + handler-loadbalance + + + + org.hibernate.validator + hibernate-validator + + + + org.apache.servicecomb + foundation-test-scaffolding + test + + + + diff --git a/spring-boot/spring-boot-starters/pom.xml b/spring-boot/spring-boot-starters/pom.xml new file mode 100644 index 00000000000..8c3eecd55ed --- /dev/null +++ b/spring-boot/spring-boot-starters/pom.xml @@ -0,0 +1,39 @@ + + + + + + java-chassis-spring-boot + org.apache.servicecomb + 3.4.0-SNAPSHOT + + + 4.0.0 + + java-chassis-spring-boot-starters + Java Chassis::Spring Boot Starter::Parent + pom + + + java-chassis-spring-boot-starter-servlet + java-chassis-spring-boot-starter-standalone + + + diff --git a/swagger/pom.xml b/swagger/pom.xml index d5d30ebf6c4..5009d6dbc8f 100644 --- a/swagger/pom.xml +++ b/swagger/pom.xml @@ -21,8 +21,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default swagger Java Chassis::Swagger diff --git a/swagger/swagger-generator/generator-core/pom.xml b/swagger/swagger-generator/generator-core/pom.xml index fd22a22f4b7..768f6ecd054 100644 --- a/swagger/swagger-generator/generator-core/pom.xml +++ b/swagger/swagger-generator/generator-core/pom.xml @@ -21,53 +21,62 @@ org.apache.servicecomb swagger-generator - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-generator-core Java Chassis::Swagger::Generator::Core - io.swagger - swagger-core + jakarta.validation + jakarta.validation-api - org.apache.servicecomb - foundation-common + io.swagger.core.v3 + swagger-core-jakarta org.apache.servicecomb - common-javassist + foundation-config + + + jakarta.servlet + jakarta.servlet-api - javax.servlet - javax.servlet-api + org.reactivestreams + reactive-streams - org.jmockit - jmockit - provided + org.mockito + mockito-inline + test - junit - junit + org.junit.jupiter + junit-jupiter-api provided - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test org.apache.servicecomb foundation-test-scaffolding + + org.springframework + spring-web + test + diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java index 78f319a551a..c1751b728a8 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java @@ -17,36 +17,83 @@ package org.apache.servicecomb.swagger; +import java.io.File; import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; - -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.Status.Family; +import java.util.Objects; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.base.DynamicEnum; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.springframework.util.StringUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.springframework.util.CollectionUtils; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.util.Yaml; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.core.converter.ResolvedSchema; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import io.swagger.v3.oas.models.servers.Server; +import jakarta.servlet.http.Part; +@SuppressWarnings("rawtypes") public final class SwaggerUtils { private SwaggerUtils() { } - public static String swaggerToString(Swagger swagger) { + /** + * Only ones servers and contains only base path. + */ + public static String getBasePath(OpenAPI swagger) { + if (swagger.getServers() == null || swagger.getServers().size() == 0) { + return null; + } + return swagger.getServers().get(0).getUrl(); + } + + /** + * Only ones servers and contains only base path. + */ + public static void setBasePath(OpenAPI swagger, String basePath) { + if (swagger.getServers() == null) { + swagger.setServers(new ArrayList<>()); + } + if (swagger.getServers().size() == 0) { + swagger.getServers().add(new Server()); + } + swagger.getServers().get(0).setUrl(basePath); + } + + public static String swaggerToString(OpenAPI swagger) { try { return Yaml.mapper().writeValueAsString(swagger); } catch (Throwable e) { @@ -54,16 +101,18 @@ public static String swaggerToString(Swagger swagger) { } } - public static Swagger parseSwagger(URL url) { + public static OpenAPI parseAndValidateSwagger(URL url) { try { - String swaggerContent = IOUtils.toString(url); - return internalParseSwagger(swaggerContent); + String swaggerContent = IOUtils.toString(url, StandardCharsets.UTF_8); + OpenAPI result = internalParseSwagger(swaggerContent); + validateSwagger(result); + return result; } catch (Throwable e) { - throw new ServiceCombException("Parse swagger from url failed, ", e); + throw new ServiceCombException("Parse swagger from url failed, url=" + url, e); } } - public static Swagger parseSwagger(String swaggerContent) { + public static OpenAPI parseSwagger(String swaggerContent) { try { return internalParseSwagger(swaggerContent); } catch (Throwable e) { @@ -71,72 +120,349 @@ public static Swagger parseSwagger(String swaggerContent) { } } - /** - * Provide a method to validate swagger. This method is now implemented to check common errors, and the logic - * will be changed when necessary. For internal use only. - */ - public static void validateSwagger(Swagger swagger) { - Map paths = swagger.getPaths(); - for (Path path : paths.values()) { - Operation operation = path.getPost(); - if (operation != null) { - List parameters = operation.getParameters(); - for (Parameter parameter : parameters) { - if (BodyParameter.class.isInstance(parameter)) { - if (((BodyParameter) parameter).getSchema() == null) { - throw new ServiceCombException("swagger validator: body parameter schema is empty."); - } - } - } + private static void validateSwagger(OpenAPI openAPI) { + if (openAPI.getPaths() == null) { + return; + } + for (PathItem pathItem : openAPI.getPaths().values()) { + if (pathItem.getGet() != null) { + validateOperation(pathItem.getGet()); + } + if (pathItem.getPost() != null) { + validateOperation(pathItem.getPost()); + } + if (pathItem.getDelete() != null) { + validateOperation(pathItem.getDelete()); + } + if (pathItem.getPut() != null) { + validateOperation(pathItem.getPut()); + } + if (pathItem.getPatch() != null) { + validateOperation(pathItem.getPatch()); + } + } + } + + private static void validateOperation(Operation operation) { + if (operation.getRequestBody() != null) { + validateRequestBody(operation.getRequestBody()); + } + if (operation.getParameters() != null) { + validateParameters(operation.getParameters()); + } + } + + private static void validateParameters(List parameters) { + for (Parameter parameter : parameters) { + if (parameter == null) { + throw new ServiceCombException("Parameter can not be null."); + } + if (StringUtils.isEmpty(parameter.getName())) { + throw new ServiceCombException("Parameter name is required."); } } } - private static Swagger internalParseSwagger(String swaggerContent) - throws JsonParseException, JsonMappingException, IOException { - Swagger swagger = Yaml.mapper().readValue(swaggerContent, Swagger.class); - correctResponses(swagger); - return swagger; + private static void validateRequestBody(RequestBody requestBody) { + for (String contentType : requestBody.getContent().keySet()) { + if (SwaggerConst.FILE_MEDIA_TYPE.equals(contentType) || SwaggerConst.FORM_MEDIA_TYPE.equals(contentType)) { + continue; + } + if (requestBody.getExtensions() == null) { + throw new ServiceCombException("Request body x-name extension is required."); + } + if (StringUtils.isEmpty((String) requestBody.getExtensions().get(SwaggerConst.EXT_BODY_NAME))) { + throw new ServiceCombException("Request body x-name extension is required."); + } + break; + } } + private static OpenAPI internalParseSwagger(String swaggerContent) throws IOException { + return Yaml.mapper().readValue(swaggerContent, OpenAPI.class); + } + + // add descriptions to response and add a default response if absent. public static void correctResponses(Operation operation) { - int okCode = Status.OK.getStatusCode(); - String strOkCode = String.valueOf(okCode); - Response okResponse = null; + if (operation.getResponses() == null) { + operation.setResponses(new ApiResponses()); + } + if (operation.getResponses().size() == 0) { + operation.getResponses().addApiResponse(SwaggerConst.SUCCESS_KEY, new ApiResponse()); + } - for (Entry responseEntry : operation.getResponses().entrySet()) { - Response response = responseEntry.getValue(); + for (Entry responseEntry : operation.getResponses().entrySet()) { + ApiResponse response = responseEntry.getValue(); if (StringUtils.isEmpty(response.getDescription())) { response.setDescription("response of " + responseEntry.getKey()); } + } + } - if (operation.getResponses().get(strOkCode) != null) { - continue; + public static void correctResponses(OpenAPI swagger) { + if (swagger.getPaths() == null) { + return; + } + + for (PathItem path : swagger.getPaths().values()) { + for (Operation operation : path.readOperations()) { + correctResponses(operation); } + } + } + + public static Schema resolveTypeSchemas(OpenAPI swagger, Type type) { + ResolvedSchema resolvedSchema = ModelConverters.getInstance().resolveAsResolvedSchema( + new AnnotatedType(type).resolveAsRef(true)); + + if (resolvedSchema == null || resolvedSchema.schema == null) { + throw new IllegalArgumentException("cannot resolve type : " + type); + } + + if (swagger.getComponents() == null) { + swagger.setComponents(new Components()); + } - int statusCode = NumberUtils.toInt(responseEntry.getKey()); - if ("default".equals(responseEntry.getKey())) { - statusCode = okCode; + Map schemaMap = resolvedSchema.referencedSchemas; + if (!CollectionUtils.isEmpty(schemaMap)) { + Map componentSchemas = swagger.getComponents().getSchemas(); + if (componentSchemas == null) { + componentSchemas = new LinkedHashMap<>(schemaMap); + } else { + for (Map.Entry entry : schemaMap.entrySet()) { + if (!componentSchemas.containsKey(entry.getKey())) { + componentSchemas.put(entry.getKey(), entry.getValue()); + } else { + if (!schemaEquals(entry.getValue(), componentSchemas.get(entry.getKey()))) { + throw new IllegalArgumentException("duplicate param model: " + entry.getKey()); + } + } + } } - if (Family.SUCCESSFUL.equals(Family.familyOf(statusCode))) { - okResponse = response; + swagger.getComponents().setSchemas(componentSchemas); + } + return resolvedSchema.schema; + } + + // swagger api equals method will compare Map address(extensions) + // and is not applicable for usage. + public static int schemaHashCode(Schema schema) { + int result = schema.getType() != null ? schema.getType().hashCode() : 0; + result = result ^ (schema.getFormat() != null ? schema.getFormat().hashCode() : 0); + result = result ^ (schema.getName() != null ? schema.getName().hashCode() : 0); + result = result ^ (schema.get$ref() != null ? schema.get$ref().hashCode() : 0); + result = result ^ (schema.getItems() != null ? schemaHashCode(schema.getItems()) : 0); + result = result ^ (schema.getAdditionalProperties() != null ? + schemaHashCode((Schema) schema.getAdditionalProperties()) : 0); + result = result ^ (schema.getProperties() != null ? propertiesHashCode(schema.getProperties()) : 0); + return result; + } + + private static int propertiesHashCode(Map properties) { + int result = 0; + for (Entry entry : properties.entrySet()) { + result = result ^ (entry.getKey().hashCode() ^ schemaHashCode(entry.getValue())); + } + return result; + } + + // swagger api equals method will compare Map address(extensions) + // and is not applicable for usage. + public static boolean schemaEquals(Schema schema1, Schema schema2) { + if (schema1 == null && schema2 == null) { + return true; + } + if (schema1 == null || schema2 == null) { + return false; + } + return StringUtils.equals(schema1.getType(), schema2.getType()) + && StringUtils.equals(schema1.getFormat(), schema2.getFormat()) + && StringUtils.equals(schema1.getName(), schema2.getName()) + && StringUtils.equals(schema1.get$ref(), schema2.get$ref()) + && schemaEquals(schema1.getItems(), schema2.getItems()) + && schemaEquals((Schema) schema1.getAdditionalProperties(), (Schema) schema2.getAdditionalProperties()) + && propertiesEquals(schema1.getProperties(), schema2.getProperties()) + && extensionEquals(schema1.getExtensions(), schema2.getExtensions()); + } + + private static boolean extensionEquals(Map extensions1, Map extensions2) { + if (extensions1 == null && extensions2 == null) { + return true; + } + if (extensions1 == null || extensions2 == null) { + return false; + } + if (extensions1.size() != extensions2.size()) { + return false; + } + boolean result = true; + for (Entry item : extensions1.entrySet()) { + if (!Objects.equals(item.getValue(), extensions2.get(item.getKey()))) { + result = false; + break; } } + return result; + } - if (okResponse != null) { - operation.addResponse(strOkCode, okResponse); + public static boolean propertiesEquals(Map properties1, Map properties2) { + if (properties1 == null && properties2 == null) { + return true; + } + if (properties1 == null || properties2 == null) { + return false; + } + if (properties1.size() != properties2.size()) { + return false; + } + boolean result = true; + for (Entry item : properties1.entrySet()) { + if (!schemaEquals(item.getValue(), properties2.get(item.getKey()))) { + result = false; + break; + } } + return result; } - public static void correctResponses(Swagger swagger) { - if (swagger.getPaths() == null) { - return; + public static Schema getSchema(OpenAPI swagger, String ref) { + return swagger.getComponents().getSchemas().get(ref.substring(Components.COMPONENTS_SCHEMAS_REF.length())); + } + + public static String getSchemaName(String ref) { + return ref.substring(Components.COMPONENTS_SCHEMAS_REF.length()); + } + + public static Schema getSchema(OpenAPI swagger, Schema ref) { + if (ref == null) { + return null; + } + if (ref.get$ref() != null) { + return getSchema(swagger, ref.get$ref()); } + return ref; + } - for (Path path : swagger.getPaths().values()) { - for (Operation operation : path.getOperations()) { - correctResponses(operation); + public static boolean hasAnnotation(Class cls, Class annotation) { + if (cls.getAnnotation(annotation) != null) { + return true; + } + + for (Method method : cls.getMethods()) { + if (method.getAnnotation(annotation) != null) { + return true; } } + + return false; + } + + public static boolean isRawJsonType(RequestBody param) { + if (param.getExtensions() == null) { + return false; + } + Object rawJson = param.getExtensions().get(SwaggerConst.EXT_RAW_JSON_TYPE); + if (rawJson instanceof Boolean) { + return (boolean) rawJson; + } + return false; + } + + public static String getClassName(Map vendorExtensions) { + return getVendorExtension(vendorExtensions, SwaggerConst.EXT_JAVA_CLASS); + } + + public static String getInterfaceName(Map vendorExtensions) { + return getVendorExtension(vendorExtensions, SwaggerConst.EXT_JAVA_INTF); + } + + @SuppressWarnings("unchecked") + public static T getVendorExtension(Map vendorExtensions, String key) { + if (vendorExtensions == null) { + return null; + } + + return (T) vendorExtensions.get(key); + } + + public static boolean isBean(Type type) { + if (type == null) { + return false; + } + + JavaType javaType = TypeFactory.defaultInstance().constructType(type); + if (javaType.isContainerType() || javaType.isEnumType() || javaType.isTypeOrSubTypeOf(DynamicEnum.class)) { + return false; + } + + Class cls = javaType.getRawClass(); + if (ClassUtils.isPrimitiveOrWrapper(cls)) { + return false; + } + + return (cls != String.class + && cls != Date.class + && cls != LocalDate.class + && cls != LocalDateTime.class + && cls != byte[].class + && cls != File.class + && cls != BigInteger.class + && cls != BigDecimal.class + && !cls.getName().equals("org.springframework.web.multipart.MultipartFile") + && !Part.class.isAssignableFrom(cls)); + } + + public static void updateProduces(Operation operation, String[] produces) { + if (produces == null || produces.length == 0) { + return; + } + if (operation.getResponses() == null) { + operation.setResponses(new ApiResponses()); + } + if (operation.getResponses().size() == 0) { + operation.getResponses().addApiResponse(SwaggerConst.SUCCESS_KEY, new ApiResponse()); + } + for (String produce : produces) { + operation.getResponses().forEach((k, v) -> { + if (v.getContent() == null) { + v.setContent(new Content()); + } + if (v.getContent().get(produce) == null) { + v.getContent().addMediaType(produce, new MediaType()); + } + }); + } + } + + public static boolean methodExists(PathItem pathItem, String httpMethod) { + PathItem.HttpMethod method = PathItem.HttpMethod.valueOf(httpMethod); + return switch (method) { + case GET -> pathItem.getGet() != null; + case PUT -> pathItem.getPut() != null; + case POST -> pathItem.getPost() != null; + case PATCH -> pathItem.getPatch() != null; + case DELETE -> pathItem.getDelete() != null; + default -> false; + }; + } + + public static String concatAbsolutePath(OpenAPI swagger, String operationPath) { + String basePath = getBasePath(swagger); + return concatPath(basePath, operationPath); + } + + /** + * Concat the two paths to an absolute path, without end of '/'. + *

+ * e.g. "/" + "/ope" = /ope + * e.g. "/prefix" + "/ope" = /prefix/ope + */ + public static String concatPath(String basePath, String operationPath) { + return ("/" + nonNullify(basePath) + "/" + nonNullify(operationPath)) + .replaceAll("/{2,}", "/"); + } + + private static String nonNullify(String path) { + return path == null ? "" : path; } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java index fa2f0a3b297..31299f128a6 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java @@ -19,28 +19,33 @@ import java.util.Map; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.springframework.util.StringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +@SuppressWarnings("rawtypes") public abstract class AbstractConverter implements Converter { protected abstract Map findVendorExtensions(Object def); - protected abstract JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object def); + protected abstract JavaType doConvert(OpenAPI swagger, Schema def); @Override - public JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { + public JavaType convert(OpenAPI swagger, Schema def) { Map vendorExtensions = findVendorExtensions(def); - String canonical = ClassUtils.getClassName(vendorExtensions); - if (!StringUtils.isEmpty(canonical)) { - try { - return swaggerToClassGenerator.getTypeFactory().constructFromCanonical(canonical); - } catch (Throwable e) { - // ignore this - } + String canonical = SwaggerUtils.getClassName(vendorExtensions); + if (StringUtils.isEmpty(canonical)) { + return doConvert(swagger, def); } - return doConvert(swaggerToClassGenerator, def); + try { + return TypeFactory.defaultInstance().constructFromCanonical(canonical); + } catch (Throwable e) { + return doConvert(swagger, def); + } } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java index 8a07c5648ff..66915d5dffd 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java @@ -18,9 +18,18 @@ package org.apache.servicecomb.swagger.converter; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +@SuppressWarnings("rawtypes") public interface Converter { - // def可能是property或model - // def不可能为null - JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def); + JavaType OBJECT_JAVA_TYPE = TypeFactory.defaultInstance().constructType(Object.class); + + JavaType STRING_JAVA_TYPE = TypeFactory.defaultInstance().constructType(String.class); + + // def can be property or model + // def can not be null + JavaType convert(OpenAPI swagger, Schema def); } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java index 05177dbadc3..5705f2460b9 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java @@ -18,76 +18,43 @@ package org.apache.servicecomb.swagger.converter; import java.math.BigDecimal; +import java.math.BigInteger; import java.time.LocalDate; -import java.util.Date; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import javax.servlet.http.Part; - -import org.apache.servicecomb.swagger.converter.model.ArrayModelConverter; -import org.apache.servicecomb.swagger.converter.model.ModelImplConverter; -import org.apache.servicecomb.swagger.converter.model.RefModelConverter; -import org.apache.servicecomb.swagger.converter.parameter.AbstractSerializableParameterConverter; -import org.apache.servicecomb.swagger.converter.parameter.BodyParameterConverter; import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter; import org.apache.servicecomb.swagger.converter.property.MapPropertyConverter; import org.apache.servicecomb.swagger.converter.property.ObjectPropertyConverter; -import org.apache.servicecomb.swagger.converter.property.RefPropertyConverter; -import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter; -import org.apache.servicecomb.swagger.extend.property.ByteProperty; -import org.apache.servicecomb.swagger.extend.property.ShortProperty; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.ArrayModel; -import io.swagger.models.ModelImpl; -import io.swagger.models.RefModel; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.CookieParameter; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.BaseIntegerProperty; -import io.swagger.models.properties.BooleanProperty; -import io.swagger.models.properties.ByteArrayProperty; -import io.swagger.models.properties.DateProperty; -import io.swagger.models.properties.DateTimeProperty; -import io.swagger.models.properties.DecimalProperty; -import io.swagger.models.properties.DoubleProperty; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.FloatProperty; -import io.swagger.models.properties.IntegerProperty; -import io.swagger.models.properties.LongProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; -import io.swagger.models.properties.StringProperty; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import jakarta.servlet.http.Part; +@SuppressWarnings("rawtypes") public final class ConverterMgr { - private static final JavaType VOID_JAVA_TYPE = TypeFactory.defaultInstance().constructType(void.class); - - private static final Map, JavaType> PROPERTY_MAP = new HashMap<>(); + private static final JavaType VOID_JAVA_TYPE = TypeFactory.defaultInstance().constructType(Void.class); - // key为swagger中标准数据类型的type.format - // value为对应的java class + // key is "type.format" of standard swagger data type + // value is related java class private static final Map TYPE_FORMAT_MAP = new HashMap<>(); - private static Map, Converter> converterMap = new HashMap<>(); + private static final Map, Converter> converterMap = new HashMap<>(); static { - initPropertyMap(); initTypeFormatMap(); initConverters(); } - public static String genTypeFormatKey(String type, String format) { - return type + ":" + String.valueOf(format); + private static String genTypeFormatKey(String type, String format) { + return type + ":" + (format == null ? "" : format); } private ConverterMgr() { @@ -95,79 +62,40 @@ private ConverterMgr() { } private static void initTypeFormatMap() { - try { - for (Entry, JavaType> entry : PROPERTY_MAP.entrySet()) { - Property property = entry.getKey().newInstance(); - String key = genTypeFormatKey(property.getType(), property.getFormat()); - TYPE_FORMAT_MAP.put(key, entry.getValue()); - } - } catch (Throwable e) { - throw new Error(e); - } - } - - private static void initPropertyMap() { - PROPERTY_MAP.put(BooleanProperty.class, TypeFactory.defaultInstance().constructType(Boolean.class)); - - PROPERTY_MAP.put(FloatProperty.class, TypeFactory.defaultInstance().constructType(Float.class)); - PROPERTY_MAP.put(DoubleProperty.class, TypeFactory.defaultInstance().constructType(Double.class)); - PROPERTY_MAP.put(DecimalProperty.class, TypeFactory.defaultInstance().constructType(BigDecimal.class)); - - PROPERTY_MAP.put(ByteProperty.class, TypeFactory.defaultInstance().constructType(Byte.class)); - PROPERTY_MAP.put(ShortProperty.class, TypeFactory.defaultInstance().constructType(Short.class)); - PROPERTY_MAP.put(IntegerProperty.class, TypeFactory.defaultInstance().constructType(Integer.class)); - PROPERTY_MAP.put(BaseIntegerProperty.class, TypeFactory.defaultInstance().constructType(Integer.class)); - PROPERTY_MAP.put(LongProperty.class, TypeFactory.defaultInstance().constructType(Long.class)); - - // stringProperty包含了enum的场景,并不一定是转化为string - // 但是,如果统一走StringPropertyConverter则可以处理enum的场景 - PROPERTY_MAP.put(StringProperty.class, TypeFactory.defaultInstance().constructType(String.class)); - - PROPERTY_MAP.put(DateProperty.class, TypeFactory.defaultInstance().constructType(LocalDate.class)); - PROPERTY_MAP.put(DateTimeProperty.class, TypeFactory.defaultInstance().constructType(Date.class)); - - PROPERTY_MAP.put(ByteArrayProperty.class, TypeFactory.defaultInstance().constructType(byte[].class)); - - PROPERTY_MAP.put(FileProperty.class, TypeFactory.defaultInstance().constructType(Part.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("boolean", ""), + TypeFactory.defaultInstance().constructType(Boolean.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("integer", "int32"), + TypeFactory.defaultInstance().constructType(Integer.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("integer", "int64"), + TypeFactory.defaultInstance().constructType(Long.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("integer", ""), + TypeFactory.defaultInstance().constructType(BigInteger.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("number", "float"), + TypeFactory.defaultInstance().constructType(Float.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("number", "double"), + TypeFactory.defaultInstance().constructType(Double.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("number", ""), + TypeFactory.defaultInstance().constructType(BigDecimal.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", ""), + TypeFactory.defaultInstance().constructType(String.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", "date"), + TypeFactory.defaultInstance().constructType(LocalDate.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", "date-time"), + TypeFactory.defaultInstance().constructType(LocalDateTime.class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", "password"), + TypeFactory.defaultInstance().constructType(String.class)); + + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", "byte"), + TypeFactory.defaultInstance().constructType(Byte[].class)); + TYPE_FORMAT_MAP.put(genTypeFormatKey("string", "binary"), + TypeFactory.defaultInstance().constructType(Part.class)); } private static void initConverters() { - // inner converters - for (Class propertyCls : PROPERTY_MAP.keySet()) { - addInnerConverter(propertyCls); - } - - converterMap.put(RefProperty.class, new RefPropertyConverter()); - converterMap.put(ArrayProperty.class, new ArrayPropertyConverter()); - converterMap.put(MapProperty.class, new MapPropertyConverter()); - converterMap.put(StringProperty.class, new StringPropertyConverter()); - converterMap.put(ObjectProperty.class, new ObjectPropertyConverter()); - - converterMap.put(ModelImpl.class, new ModelImplConverter()); - converterMap.put(RefModel.class, new RefModelConverter()); - converterMap.put(ArrayModel.class, new ArrayModelConverter()); - - converterMap.put(BodyParameter.class, new BodyParameterConverter()); - - AbstractSerializableParameterConverter converter = new AbstractSerializableParameterConverter(); - converterMap.put(QueryParameter.class, converter); - converterMap.put(PathParameter.class, converter); - converterMap.put(HeaderParameter.class, converter); - converterMap.put(FormParameter.class, converter); - converterMap.put(CookieParameter.class, converter); - } - - private static void addInnerConverter(Class propertyCls) { - JavaType javaType = PROPERTY_MAP.get(propertyCls); - if (javaType == null) { - throw new Error("not support inner property class: " + propertyCls.getName()); - } - - converterMap.put(propertyCls, (context, def) -> javaType); - } - - public static void addConverter(Class cls, Converter converter) { - converterMap.put(cls, converter); + converterMap.put(ArraySchema.class, new ArrayPropertyConverter()); + converterMap.put(MapSchema.class, new MapPropertyConverter()); + converterMap.put(ObjectSchema.class, new ObjectPropertyConverter()); + converterMap.put(Schema.class, new ObjectPropertyConverter()); } public static JavaType findJavaType(String type, String format) { @@ -175,17 +103,19 @@ public static JavaType findJavaType(String type, String format) { return TYPE_FORMAT_MAP.get(key); } - // def为null是void的场景 - // def可能是model、property、parameter - public static JavaType findJavaType(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { + // def is null means void + public static JavaType findJavaType(OpenAPI swagger, Schema def) { if (def == null) { return VOID_JAVA_TYPE; } + JavaType javaType = findJavaType(def.getType(), def.getFormat()); + if (javaType != null) { + return javaType; + } Converter converter = converterMap.get(def.getClass()); if (converter == null) { throw new Error("not support def type: " + def.getClass()); } - - return converter.convert(swaggerToClassGenerator, def); + return converter.convert(swagger, def); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java deleted file mode 100644 index e94f8bc5a41..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter; - -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.common.javassist.ClassConfig; -import org.apache.servicecomb.common.javassist.CtTypeJavaType; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.common.javassist.MethodConfig; -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.springframework.util.StringUtils; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.google.common.annotations.VisibleForTesting; - -import io.swagger.models.Model; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.Property; -import javassist.ClassPool; -import javassist.CtClass; - -/** - * generate interface from swagger
- * specially should support: recursive dependency
- *

- * 1.class A {
- *     A a;
- *   }
- * 2.class A {
- *     B b;
- *   }
- *   class B {
- *     A a;
- *   }
- * 
- * javassist can create normal dynamic class to classloader
- * but can not create recursive dependency dynamic class to classloader directly
- * to support recursive dependency, must save all class to byte[], and then convert to class
- * - */ -public class SwaggerToClassGenerator { - private ClassLoader classLoader; - - private Swagger swagger; - - /** - * package for definitions that no x-java-class attribute - */ - private String packageName; - - /** - * if not set, then will get from swagger.info.vendorExtensions.x-java-interface - * if still not set, then will use ${packageName}.SchemaInterface - */ - private String interfaceName; - - private Class interfaceCls; - - private TypeFactory typeFactory; - - private ClassPool classPool; - - // key is swagger model or property - @VisibleForTesting - protected Map swaggerObjectMap = new IdentityHashMap<>(); - - /** - * - * @param classLoader - * @param swagger - * @param packageName package for definitions that no x-java-class attribute - */ - public SwaggerToClassGenerator(ClassLoader classLoader, Swagger swagger, String packageName) { - this.classLoader = classLoader; - this.swagger = swagger; - this.packageName = packageName; - - this.typeFactory = TypeFactory.defaultInstance().withClassLoader(classLoader); - this.classPool = JavassistUtils.getOrCreateClassPool(classLoader); - } - - public ClassPool getClassPool() { - return classPool; - } - - public void setInterfaceName(String interfaceName) { - this.interfaceName = interfaceName; - } - - public ClassLoader getClassLoader() { - return classLoader; - } - - public Swagger getSwagger() { - return swagger; - } - - public String getPackageName() { - return packageName; - } - - public TypeFactory getTypeFactory() { - return typeFactory; - } - - public Class getInterfaceCls() { - return interfaceCls; - } - - /** - * convert definitions/parameters and responses to java class - * convert swagger to interface - */ - public Class convert() { - collectInterfaceName(); - mapDefinitionsToExistingClasses(); - convertDefinitions(); - convertResponses(); - convertPendingCtClasses(); - convertToInterface(); - - return interfaceCls; - } - - protected void collectInterfaceName() { - if (interfaceName != null) { - return; - } - - if (swagger.getInfo() != null) { - interfaceName = ClassUtils.getInterfaceName(swagger.getInfo().getVendorExtensions()); - if (interfaceName != null) { - return; - } - } - - interfaceName = packageName + ".SchemaInterface"; - } - - protected void mapDefinitionsToExistingClasses() { - interfaceCls = ClassUtils.getClassByName(classLoader, interfaceName); - if (interfaceCls == null) { - return; - } - - // TODO: map - } - - protected void convertDefinitions() { - if (swagger.getDefinitions() == null) { - return; - } - - for (Entry entry : swagger.getDefinitions().entrySet()) { - convertModel(entry.getKey(), entry.getValue()); - } - } - - protected void convertResponses() { - if (swagger.getPaths() == null) { - return; - } - - for (Path path : swagger.getPaths().values()) { - for (Operation operation : path.getOperations()) { - for (Response response : operation.getResponses().values()) { - convert(response.getSchema()); - - Map headers = response.getHeaders(); - if (headers == null) { - continue; - } - for (Property header : headers.values()) { - convert(header); - } - } - } - } - } - - protected void convertToInterface() { - if (interfaceCls != null) { - return; - } - - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName(interfaceName); - classConfig.setIntf(true); - - if (swagger.getPaths() != null) { - for (Path path : swagger.getPaths().values()) { - for (Operation operation : path.getOperations()) { - Response result = operation.getResponses().get(SwaggerConst.SUCCESS_KEY); - JavaType resultJavaType = swaggerObjectMap.get(result.getSchema()); - - MethodConfig methodConfig = new MethodConfig(); - methodConfig.setName(operation.getOperationId()); - methodConfig.setResult(resultJavaType); - - for (Parameter parameter : operation.getParameters()) { - String paramName = parameter.getName(); - paramName = ClassUtils.correctMethodParameterName(paramName); - - JavaType paramJavaType = ConverterMgr.findJavaType(this, parameter); - methodConfig.addParameter(paramName, paramJavaType); - } - - classConfig.addMethod(methodConfig); - } - } - } - - interfaceCls = JavassistUtils.createClass(classLoader, classConfig); - } - - protected void convertPendingCtClasses() { - for (Entry entry : swaggerObjectMap.entrySet()) { - JavaType javaType = entry.getValue(); - if (!CtTypeJavaType.class.isInstance(javaType)) { - continue; - } - - CtClass ctClass = ((CtTypeJavaType) javaType).getType().getCtClass(); - Class cls = JavassistUtils.createClass(classLoader, ctClass); - entry.setValue(typeFactory.constructType(cls)); - } - } - - public JavaType convert(Object swaggerObject) { - JavaType javaType = swaggerObjectMap.get(swaggerObject); - if (javaType == null) { - javaType = ConverterMgr.findJavaType(this, swaggerObject); - swaggerObjectMap.put(swaggerObject, javaType); - } - return javaType; - } - - /** - * just only for invoker know that there is no recursive dependency - * - */ - public JavaType forceConvert(Object swaggerObject) { - convert(swaggerObject); - convertPendingCtClasses(); - return swaggerObjectMap.get(swaggerObject); - } - - protected void updateJavaClassInVendor(Map vendorExtensions, String shortClsName) { - String clsName = ClassUtils.getClassName(vendorExtensions); - if (StringUtils.isEmpty(clsName)) { - vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, packageName + "." + shortClsName); - } - } - - protected JavaType convertModel(String name, Model model) { - updateJavaClassInVendor(model.getVendorExtensions(), name); - return convert(model); - } - - public JavaType convertRef(String ref) { - return convertModel(ref, swagger.getDefinitions().get(ref)); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.java deleted file mode 100644 index 336f54f5622..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.model; - -import java.util.Map; - -import org.apache.servicecomb.swagger.converter.AbstractConverter; - -import io.swagger.models.Model; - -public abstract class AbstractModelConverter extends AbstractConverter { - protected Map findVendorExtensions(Object def) { - return ((Model) def).getVendorExtensions(); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java deleted file mode 100644 index dca3ca889bd..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.model; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.ArrayModel; - -public class ArrayModelConverter extends AbstractModelConverter { - @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object model) { - ArrayModel arrayModel = (ArrayModel) model; - - if (arrayModel.getItems() != null) { - return ArrayPropertyConverter.findJavaType(swaggerToClassGenerator, arrayModel.getItems(), false); - } - - // don't know when will this happen. - throw new Error("not support null array model items."); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java deleted file mode 100644 index fa38d743208..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.model; - -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.common.javassist.ClassConfig; -import org.apache.servicecomb.common.javassist.CtType; -import org.apache.servicecomb.common.javassist.CtTypeJavaType; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.converter.property.MapPropertyConverter; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import io.swagger.models.ModelImpl; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import javassist.CtClass; - -public class ModelImplConverter extends AbstractModelConverter { - @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object model) { - ModelImpl modelImpl = (ModelImpl) model; - - JavaType javaType = ConverterMgr.findJavaType(modelImpl.getType(), modelImpl.getFormat()); - if (javaType != null) { - return javaType; - } - - if (modelImpl.getReference() != null) { - return swaggerToClassGenerator.convertRef(modelImpl.getReference()); - } - - if (modelImpl.getAdditionalProperties() != null) { - return MapPropertyConverter.findJavaType(swaggerToClassGenerator, modelImpl.getAdditionalProperties()); - } - - if (ObjectProperty.TYPE.equals(modelImpl.getType()) - && modelImpl.getProperties() == null - && modelImpl.getName() == null) { - return TypeFactory.defaultInstance().constructType(Object.class); - } - - return getOrCreateType(swaggerToClassGenerator, modelImpl); - } - - protected JavaType getOrCreateType(SwaggerToClassGenerator swaggerToClassGenerator, ModelImpl modelImpl) { - String clsName = ClassUtils.getClassName(findVendorExtensions(modelImpl)); - clsName = ClassUtils.correctClassName(clsName); - - return getOrCreateType(swaggerToClassGenerator, modelImpl.getProperties(), clsName); - } - - protected JavaType getOrCreateType(SwaggerToClassGenerator swaggerToClassGenerator, - Map properties, - String clsName) { - Class cls = ClassUtils.getClassByName(swaggerToClassGenerator.getClassLoader(), clsName); - if (cls != null) { - return swaggerToClassGenerator.getTypeFactory().constructType(cls); - } - - CtClass ctClass = getOrCreateCtClass(swaggerToClassGenerator, properties, clsName); - return new CtTypeJavaType(new CtType(ctClass)); - } - - private CtClass getOrCreateCtClass(SwaggerToClassGenerator swaggerToClassGenerator, Map properties, - String clsName) { - CtClass ctClass = swaggerToClassGenerator.getClassPool().getOrNull(clsName); - if (ctClass != null) { - return ctClass; - } - - // must ensure already create CtClass, otherwise recursive dependency class will create failed. - swaggerToClassGenerator.getClassPool().makeClass(clsName); - - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName(clsName); - - if (null != properties) { - for (Entry entry : properties.entrySet()) { - JavaType propertyJavaType = swaggerToClassGenerator.convert(entry.getValue()); - classConfig.addField(entry.getKey(), propertyJavaType); - } - } - - return JavassistUtils.createCtClass(swaggerToClassGenerator.getClassLoader(), classConfig); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.java deleted file mode 100644 index f646cbc36d7..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.model; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.RefModel; - -public class RefModelConverter extends AbstractModelConverter { - @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object refModel) { - return swaggerToClassGenerator.convertRef(((RefModel) refModel).getSimpleRef()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/AbstractSerializableParameterConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/AbstractSerializableParameterConverter.java deleted file mode 100644 index 7573e4ae0de..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/AbstractSerializableParameterConverter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.parameter; - -import org.apache.servicecomb.swagger.converter.Converter; -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter; -import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.StringProperty; - -public class AbstractSerializableParameterConverter implements Converter { - - @Override - public JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { - AbstractSerializableParameter param = (AbstractSerializableParameter) def; - - switch (param.getType()) { - case ArrayProperty.TYPE: - return ArrayPropertyConverter.findJavaType(swaggerToClassGenerator, - param.getItems(), - param.isUniqueItems()); - case StringProperty.TYPE: - return StringPropertyConverter.findJavaType(swaggerToClassGenerator, - param.getType(), - param.getFormat(), - param.getEnum()); - default: - return ConverterMgr.findJavaType(param.getType(), param.getFormat()); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/BodyParameterConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/BodyParameterConverter.java deleted file mode 100644 index 909ead89c29..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/parameter/BodyParameterConverter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.parameter; - -import org.apache.servicecomb.swagger.converter.Converter; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.parameters.BodyParameter; - -public class BodyParameterConverter implements Converter { - - @Override - public JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { - BodyParameter param = (BodyParameter) def; - return swaggerToClassGenerator.convert(param.getSchema()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java index 0998fc318d9..81109f9e02e 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java @@ -21,10 +21,10 @@ import org.apache.servicecomb.swagger.converter.AbstractConverter; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.Schema; public abstract class AbstractPropertyConverter extends AbstractConverter { protected Map findVendorExtensions(Object def) { - return ((Property) def).getVendorExtensions(); + return ((Schema) def).getExtensions(); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java index e7f8d161e63..eaa287065f6 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java @@ -21,31 +21,32 @@ import java.util.List; import java.util.Set; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import org.apache.servicecomb.swagger.converter.ConverterMgr; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +@SuppressWarnings("rawtypes") public class ArrayPropertyConverter extends AbstractPropertyConverter { - public static JavaType findJavaType(SwaggerToClassGenerator swaggerToClassGenerator, - Property itemProperty, - Boolean uniqueItems) { - JavaType itemJavaType = swaggerToClassGenerator.convert(itemProperty); + public static JavaType findJavaType(OpenAPI swagger, Schema itemProperty, Boolean uniqueItems) { + JavaType itemJavaType = ConverterMgr.findJavaType(swagger, itemProperty); @SuppressWarnings("rawtypes") Class collectionClass = List.class; if (Boolean.TRUE.equals(uniqueItems)) { collectionClass = Set.class; } - return swaggerToClassGenerator.getTypeFactory().constructCollectionType(collectionClass, itemJavaType); + return TypeFactory.defaultInstance().constructCollectionType(collectionClass, itemJavaType); } @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object property) { - ArrayProperty arrayProperty = (ArrayProperty) property; + public JavaType doConvert(OpenAPI swagger, Schema property) { + ArraySchema arrayProperty = (ArraySchema) property; - return findJavaType(swaggerToClassGenerator, arrayProperty.getItems(), arrayProperty.getUniqueItems()); + return findJavaType(swagger, arrayProperty.getItems(), arrayProperty.getUniqueItems()); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java index 490fbb60b05..0dc2a221e19 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java @@ -19,26 +19,29 @@ import java.util.Map; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import org.apache.servicecomb.swagger.converter.ConverterMgr; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +@SuppressWarnings("rawtypes") public class MapPropertyConverter extends AbstractPropertyConverter { @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object property) { - MapProperty mapProperty = (MapProperty) property; - Property valueProperty = mapProperty.getAdditionalProperties(); - return findJavaType(swaggerToClassGenerator, valueProperty); + public JavaType doConvert(OpenAPI swagger, Schema property) { + MapSchema mapProperty = (MapSchema) property; + Object valueProperty = mapProperty.getAdditionalProperties(); + if (valueProperty instanceof Boolean) { + return TypeFactory.defaultInstance().constructType(Boolean.class); + } + return findJavaType(swagger, (Schema) valueProperty); } - public static JavaType findJavaType(SwaggerToClassGenerator swaggerToClassGenerator, Property valueProperty) { - JavaType valueJavaType = swaggerToClassGenerator.convert(valueProperty); - - return swaggerToClassGenerator.getTypeFactory().constructMapType(Map.class, - swaggerToClassGenerator.getTypeFactory().constructType(String.class), - valueJavaType); + public static JavaType findJavaType(OpenAPI swagger, Schema valueProperty) { + JavaType valueJavaType = ConverterMgr.findJavaType(swagger, valueProperty); + return TypeFactory.defaultInstance().constructMapType(Map.class, STRING_JAVA_TYPE, valueJavaType); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java index 5de66953879..3564ca4bd55 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java @@ -16,15 +16,25 @@ */ package org.apache.servicecomb.swagger.converter.property; -import org.apache.servicecomb.swagger.converter.Converter; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import java.util.Map; + +import org.apache.servicecomb.swagger.converter.AbstractConverter; import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; -public class ObjectPropertyConverter implements Converter { +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +@SuppressWarnings("rawtypes") +public class ObjectPropertyConverter extends AbstractConverter { + + @Override + protected Map findVendorExtensions(Object def) { + return ((Schema) def).getExtensions(); + } + @Override - public JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { - return TypeFactory.defaultInstance().constructType(Object.class); + protected JavaType doConvert(OpenAPI swagger, Schema def) { + return OBJECT_JAVA_TYPE; } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.java deleted file mode 100644 index 395bc0324a7..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.property; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.properties.RefProperty; - -public class RefPropertyConverter extends AbstractPropertyConverter { - @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object refProperty) { - return swaggerToClassGenerator.convertRef(((RefProperty) refProperty).getSimpleRef()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java deleted file mode 100644 index 895a28e20a6..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.property; - -import java.util.List; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import io.swagger.models.properties.StringProperty; - -public class StringPropertyConverter extends AbstractPropertyConverter { - public static JavaType findJavaType(SwaggerToClassGenerator swaggerToClassGenerator, String type, - String format, List enums) { - if (!isEnum(enums)) { - return ConverterMgr.findJavaType(type, format); - } - - // enum,且需要动态生成class - Class enumCls = JavassistUtils - .getOrCreateEnumWithPackageName(swaggerToClassGenerator.getClassLoader(), - swaggerToClassGenerator.getPackageName(), enums); - return TypeFactory.defaultInstance().constructType(enumCls); - } - - public static boolean isEnum(StringProperty stringProperty) { - return isEnum(stringProperty.getEnum()); - } - - public static boolean isEnum(List enums) { - return enums != null && !enums.isEmpty(); - } - - @Override - public JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object property) { - StringProperty stringProperty = (StringProperty) property; - - List enums = stringProperty.getEnum(); - return findJavaType(swaggerToClassGenerator, - stringProperty.getType(), - stringProperty.getFormat(), - enums); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java deleted file mode 100644 index 3ae7aaac720..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.property; - -import java.util.Collection; - -public enum SwaggerParamCollectionFormat { - CSV("csv", ","), - SSV("ssv", " "), - TSV("tsv", "\t"), - PIPES("pipes", "|") { - @Override - public String[] splitParam(String rawParam) { - if (null == rawParam) { - return new String[0]; - } - return rawParam.split("\\|", -1); - } - }, - MULTI("multi", null) { - /** - * In fact, {@link SwaggerParamCollectionFormat#MULTI#splitParam(String)} of {@link SwaggerParamCollectionFormat#MULTI} - * should never be invoked. We just override this method to ensure it does not throw exception. - */ - @Override - public String[] splitParam(String rawParam) { - if (null == rawParam) { - return new String[0]; - } - return new String[] {rawParam}; - } - }; - - final private String collectionFormat; - - final private String separator; - - SwaggerParamCollectionFormat(String collectionFormat, String separator) { - this.collectionFormat = collectionFormat; - this.separator = separator; - } - - public String getCollectionFormat() { - return collectionFormat; - } - - public String getSeparator() { - return separator; - } - - public String[] splitParam(String rawParam) { - if (null == rawParam) { - return new String[0]; - } - return rawParam.split(separator, -1); - } - - /** - * Join params with {@link #separator}. - * Null element will be ignored since {@code null} cannot be described in query array param. - * - * @return joined params, or return {@code null} if {@code params} is null or all elements of {@code params} are null. - */ - public String joinParam(Collection params) { - if (null == params || params.isEmpty()) { - return null; - } - - StringBuilder paramBuilder = new StringBuilder(); - int nullCount = 0; - for (Object param : params) { - if (param == null) { - nullCount++; - continue; - } - - paramBuilder.append(param).append(separator); - } - if (nullCount == params.size()) { - return null; - } - - paramBuilder.setLength(paramBuilder.length() - 1); - - return paramBuilder.toString(); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ConcreteTypeRegister.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ConcreteTypeRegister.java new file mode 100644 index 00000000000..fe35b2c32c1 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ConcreteTypeRegister.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.extend; + +import java.lang.reflect.Type; +import java.util.Set; + +public interface ConcreteTypeRegister { + void register(Set types); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/DefaultModelResolveObjectMapperProvider.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/DefaultModelResolveObjectMapperProvider.java new file mode 100644 index 00000000000..4b01f22c082 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/DefaultModelResolveObjectMapperProvider.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend; + +import org.apache.servicecomb.swagger.extend.module.EnumModuleExt; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import io.swagger.v3.core.util.Json; + + +public class DefaultModelResolveObjectMapperProvider implements ModelResolveObjectMapperProvider { + @Override + public int getOrder() { + return 100; + } + + @Override + public ObjectMapper getMapper() { + ObjectMapper mapper = Json.mapper(); + mapper.registerModule(new EnumModuleExt()); + mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, false); + return mapper; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ExtendConst.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ExtendConst.java deleted file mode 100644 index a555bca67b1..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ExtendConst.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend; - -public final class ExtendConst { - private ExtendConst() { - - } - - public static final String EXT_JAVA_INTF = "x-java-interface"; - - public static final String EXT_JAVA_CLASS = "x-java-class"; -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolveObjectMapperProvider.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolveObjectMapperProvider.java new file mode 100644 index 00000000000..68e05da4846 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolveObjectMapperProvider.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Implement this interface to create custom {@link ObjectMapper} for Swagger schema generation. + */ +public interface ModelResolveObjectMapperProvider { + /** + * @return order The smaller value it is, the higher priority this provider has. + */ + default int getOrder() { + return 0; + } + + /** + * @return the ObjectMapper, which is used by Swagger to introspect the param types and generate property collections. + */ + ObjectMapper getMapper(); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java index 6b7d876aacf..8caec2dd15e 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java @@ -17,133 +17,131 @@ package org.apache.servicecomb.swagger.extend; -import java.lang.annotation.Annotation; -import java.lang.reflect.Modifier; +import java.lang.reflect.Type; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; -import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.base.DynamicEnum; +import org.apache.servicecomb.foundation.common.base.EnumUtils; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter; +import org.apache.servicecomb.swagger.SwaggerUtils; import org.apache.servicecomb.swagger.extend.property.creator.ByteArrayPropertyCreator; import org.apache.servicecomb.swagger.extend.property.creator.BytePropertyCreator; import org.apache.servicecomb.swagger.extend.property.creator.InputStreamPropertyCreator; import org.apache.servicecomb.swagger.extend.property.creator.PartPropertyCreator; import org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator; -import org.apache.servicecomb.swagger.extend.property.creator.ShortPropertyCreator; -import org.springframework.util.StringUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import com.fasterxml.jackson.databind.JavaType; -import com.google.common.annotations.VisibleForTesting; - -import io.swagger.converter.ModelConverter; -import io.swagger.converter.ModelConverterContext; -import io.swagger.jackson.ModelResolver; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.StringProperty; -import io.swagger.util.Json; - +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.util.PrimitiveType; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; + +/** + * Customize swagger model converters to support: + * + * 1. byte and byte[] related types + * 2. stream related types + * 3. jason mapper customization + * 4. add x-java-class to model + */ +@SuppressWarnings({"unchecked", "rawtypes"}) public class ModelResolverExt extends ModelResolver { - private Map, PropertyCreator> propertyCreatorMap = new HashMap<>(); + private final Map propertyCreatorMap = new HashMap<>(); + + private final Set concreteInterfaces = new HashSet<>(); public ModelResolverExt() { - super(Json.mapper()); + super(findMapper()); addPropertyCreator(new BytePropertyCreator()); - addPropertyCreator(new ShortPropertyCreator()); addPropertyCreator(new ByteArrayPropertyCreator()); + addPropertyCreator(new InputStreamPropertyCreator()); addPropertyCreator(new PartPropertyCreator()); - loadPropertyCreators(); - } - - private void addPropertyCreator(PropertyCreator creator) { - for (Class cls : creator.classes()) { - propertyCreatorMap.put(cls, creator); - } - } - private void loadPropertyCreators() { SPIServiceUtils.getAllService(PropertyCreator.class) .forEach(this::addPropertyCreator); + SPIServiceUtils.getAllService(ConcreteTypeRegister.class) + .forEach(r -> r.register(concreteInterfaces)); } - @VisibleForTesting - protected void setType(JavaType type, Map vendorExtensions) { - vendorExtensions.put(ExtendConst.EXT_JAVA_CLASS, type.toCanonical()); - } - - private void checkType(JavaType type) { - // 原子类型/string在java中是abstract的 - if (type.getRawClass().isPrimitive() - || propertyCreatorMap.containsKey(type.getRawClass()) - || String.class.equals(type.getRawClass())) { - return; - } - - String msg = "Must be a concrete type."; - if (type.isMapLikeType()) { - Class keyTypeClass = type.getKeyType().getRawClass(); - if (!String.class.equals(keyTypeClass)) { - // swagger中map的key只允许为string - throw new Error("Type of key in map must be string, but got " + keyTypeClass.getName()); - } - } - - if (type.isContainerType()) { - checkType(type.getContentType()); - return; - } - - if (type.getRawClass().isInterface()) { - throw new ServiceCombException(type.getTypeName() + " is interface. " + msg); + private static ObjectMapper findMapper() { + ModelResolveObjectMapperProvider objectMapperProvider = SPIServiceUtils + .getPriorityHighestService(ModelResolveObjectMapperProvider.class); + if (null == objectMapperProvider) { + objectMapperProvider = new DefaultModelResolveObjectMapperProvider(); } + return objectMapperProvider.getMapper(); + } - if (Modifier.isAbstract(type.getRawClass().getModifiers())) { - throw new ServiceCombException(type.getTypeName() + " is abstract class. " + msg); + private void addPropertyCreator(PropertyCreator creator) { + for (Class cls : creator.classes()) { + propertyCreatorMap.put(cls, creator); + propertyCreatorMap.put(TypeFactory.defaultInstance().constructType(cls), creator); } } + @Override - public Model resolve(JavaType type, ModelConverterContext context, Iterator next) { - // property is not a model - if (propertyCreatorMap.containsKey(type.getRawClass())) { - return null; + public Schema resolve(AnnotatedType propType, ModelConverterContext context, Iterator next) { + PropertyCreator creator = propertyCreatorMap.get(propType.getType()); + if (creator != null) { + return creator.createProperty(); } - Model model = super.resolve(type, context, next); - if (model == null) { - return null; + if (EnumUtils.isDynamicEnum(propType.getType())) { + return resolveDynamicEnum(TypeFactory.defaultInstance().constructType(propType.getType())); } - checkType(type); - - // 只有声明model的地方才需要标注类型 - if (ModelImpl.class.isInstance(model) && !StringUtils.isEmpty(((ModelImpl) model).getName())) { - setType(type, model.getVendorExtensions()); + Schema result = super.resolve(propType, context, next); + if (!StringUtils.isEmpty(result.get$ref())) { + Schema referencedSchema = context.getDefinedModels() != null + ? context.getDefinedModels().get(SwaggerUtils.getSchemaName(result.get$ref())) : null; + if (referencedSchema != null) { + if (referencedSchema.getExtensions() == null) { + referencedSchema.setExtensions(new HashMap<>()); + } + if (propType.getType() instanceof JavaType) { + referencedSchema.getExtensions().put(SwaggerConst.EXT_JAVA_CLASS, + ((JavaType) propType.getType()).toCanonical()); + } else { + referencedSchema.getExtensions().put(SwaggerConst.EXT_JAVA_CLASS, + TypeFactory.defaultInstance().constructType(propType.getType()).toCanonical()); + } + } } - return model; + return result; } - @Override - public Property resolveProperty(JavaType propType, ModelConverterContext context, Annotation[] annotations, - Iterator next) { - checkType(propType); + private Schema resolveDynamicEnum(JavaType propType) { + Class enumClass = propType.getRawClass(); + Class enumValueClass = propType.findTypeParameters(DynamicEnum.class)[0].getRawClass(); + Schema property = PrimitiveType.createProperty(enumValueClass); - PropertyCreator creator = propertyCreatorMap.get(propType.getRawClass()); - if (creator != null) { - return creator.createProperty(); + if (property instanceof StringSchema) { + List enums = SwaggerEnum.DYNAMIC.readEnumValues(enumClass); + property.setEnum(enums); } - Property property = super.resolveProperty(propType, context, annotations, next); - if (StringProperty.class.isInstance(property)) { - if (StringPropertyConverter.isEnum((StringProperty) property)) { - setType(propType, property.getVendorExtensions()); - } + if (property instanceof NumberSchema) { + List enums = SwaggerEnum.DYNAMIC.readEnumValues(enumClass); + property.setEnum(enums); } + return property; } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/SwaggerEnum.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/SwaggerEnum.java new file mode 100644 index 00000000000..7914fc887eb --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/SwaggerEnum.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.extend; + +import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.base.DynamicEnum; +import org.apache.servicecomb.foundation.common.base.EnumUtils; + +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.annotations.Parameter; + + +public enum SwaggerEnum { + JDK { + @SuppressWarnings({"unchecked", "deprecation"}) + @Override + protected T readEnumValue(Field enumField) { + Enum enumValue = EnumUtils.readEnum(enumField); + return (T) Json.mapper().getSerializationConfig().getAnnotationIntrospector().findEnumValue(enumValue); + } + }, + DYNAMIC { + @Override + protected T readEnumValue(Field enumField) { + DynamicEnum enumValue = EnumUtils.readEnum(enumField); + return enumValue.getValue(); + } + }; + + public String findPropertyDescription(Class enumClass, Annotation[] annotations) { + StringBuilder sb = new StringBuilder(); + + String propertyDescription = readDescription(annotations, null); + if (StringUtils.isNotEmpty(propertyDescription)) { + appendLine(sb, propertyDescription); + } + + EnumUtils.findEnumFields(enumClass).forEach(enumField -> { + Object enumValue = readEnumValue(enumField); + String description = readDescription(enumField.getAnnotations(), ""); + appendLine(sb, "- %s: %s", enumValue, description); + }); + + return sb.toString(); + } + + public List readEnumValues(Class enumClass) { + return EnumUtils.findEnumFields(enumClass) + .map(this::readEnumValue) + .collect(Collectors.toList()); + } + + protected abstract T readEnumValue(Field enumField); + + @SuppressWarnings("unchecked") + private T findAnnotation(Annotation[] annotations, Class cls) { + if (annotations == null) { + return null; + } + + return Arrays.stream(annotations) + .filter(annotation -> cls.isAssignableFrom(annotation.getClass())) + .map(annotation -> (T) annotation) + .findAny() + .orElse(null); + } + + private String readDescription(Annotation[] annotations, String defaultDescription) { + Parameter apiParam = findAnnotation(annotations, Parameter.class); + if (apiParam != null && StringUtils.isNotEmpty(apiParam.description())) { + return apiParam.description(); + } + + return defaultDescription; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/RawJsonRequestBody.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/RawJsonRequestBody.java index 70f981d5459..743bc3f4a0c 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/RawJsonRequestBody.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/RawJsonRequestBody.java @@ -23,16 +23,14 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.core.annotation.AliasFor; - @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RawJsonRequestBody { - @AliasFor("name") + // aliasFor "name" String value() default ""; - @AliasFor("value") + // aliasFor "value" String name() default ""; boolean required() default true; diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/ResponseHeaders.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/ResponseHeaders.java deleted file mode 100644 index 112494b9dc6..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/annotations/ResponseHeaders.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.extend.annotations; - -import static java.lang.annotation.ElementType.METHOD; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import io.swagger.annotations.ResponseHeader; - -@Target({METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface ResponseHeaders { - ResponseHeader[] value(); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospector.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospector.java new file mode 100644 index 00000000000..4e377b81a11 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospector.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend.introspector; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.base.EnumUtils; +import org.apache.servicecomb.swagger.extend.SwaggerEnum; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.introspect.Annotated; + +import io.swagger.v3.core.jackson.SwaggerAnnotationIntrospector; + +import java.util.Objects; + + +public class JsonPropertyIntrospector extends SwaggerAnnotationIntrospector { + private static final long serialVersionUID = 4157263023893695762L; + + @SuppressWarnings("deprecation") + @Override + public String findEnumValue(Enum value) { + try { + JsonProperty annotation = value.getClass().getField(value.name()).getAnnotation(JsonProperty.class); + if (null == annotation || StringUtils.isEmpty(annotation.value())) { + return super.findEnumValue(value); + } + return annotation.value(); + } catch (NoSuchFieldException e) { + return super.findEnumValue(value); + } + } + + @Override + public String findPropertyDescription(Annotated annotated) { + Class enumClass = annotated.getRawType(); + if (enumClass.isEnum() && Objects.nonNull(annotated.getAnnotated())) { + return SwaggerEnum.JDK.findPropertyDescription(enumClass, annotated.getAnnotated().getAnnotations()); + } + if (EnumUtils.isDynamicEnum(enumClass) && Objects.nonNull(annotated.getAnnotated())) { + return SwaggerEnum.DYNAMIC.findPropertyDescription(enumClass, annotated.getAnnotated().getAnnotations()); + } + + return super.findPropertyDescription(annotated); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExt.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExt.java new file mode 100644 index 00000000000..d7bd0f6d918 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExt.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend.module; + +import org.apache.servicecomb.swagger.extend.introspector.JsonPropertyIntrospector; + +import com.fasterxml.jackson.databind.module.SimpleModule; + +public class EnumModuleExt extends SimpleModule { + private static final long serialVersionUID = 2934449381601447264L; + + public EnumModuleExt() { + super("SCB-swagger-enum"); + } + + @Override + public void setupModule(SetupContext context) { + context.insertAnnotationIntrospector(new JsonPropertyIntrospector()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/ContextParameter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/ContextParameter.java deleted file mode 100644 index 956020cc92d..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/ContextParameter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.parameter; - -import io.swagger.models.parameters.Parameter; - -/** - * http request这种不在swagger中体现出来的参数的包装 - */ -public interface ContextParameter extends Parameter { -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/HttpRequestParameter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/HttpRequestParameter.java deleted file mode 100644 index 0e1bff0a823..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/HttpRequestParameter.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.parameter; - -import io.swagger.models.parameters.AbstractParameter; - -public class HttpRequestParameter extends AbstractParameter implements ContextParameter { -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java deleted file mode 100644 index 8fe2690d9e5..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/AbstractBaseIntegerProperty.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2016 SmartBear Software - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Forked from https://github.com/swagger-api/swagger-core/blob/master/modules/swagger-models/src/main/java/io/swagger/models/properties/IntegerProperty.java - */ - -package org.apache.servicecomb.swagger.extend.property; - -import java.util.ArrayList; -import java.util.List; - -import io.swagger.models.Xml; -import io.swagger.models.properties.BaseIntegerProperty; - -public abstract class AbstractBaseIntegerProperty extends BaseIntegerProperty { - protected T defaultValue; - - protected List enumNames; - - public AbstractBaseIntegerProperty(String format) { - super(format); - } - - public AbstractBaseIntegerProperty addEnum(T value) { - if (this.enumNames == null) { - this.enumNames = new ArrayList<>(); - } - if (!enumNames.contains(value)) { - enumNames.add(value); - } - return this; - } - - public AbstractBaseIntegerProperty replaceEnum(List value) { - this.enumNames = value; - return this; - } - - public AbstractBaseIntegerProperty xml(Xml xml) { - this.setXml(xml); - return this; - } - - public AbstractBaseIntegerProperty readOnly() { - this.setReadOnly(Boolean.TRUE); - return this; - } - - protected abstract T parseNumber(String strValue); - - public AbstractBaseIntegerProperty assignDefault(String defaultValue) { - if (defaultValue != null) { - try { - this.defaultValue = parseNumber(defaultValue); - } catch (NumberFormatException e) { - // continue; - } - } - return this; - } - - public AbstractBaseIntegerProperty assignDefault(T defaultValue) { - this.setDefault(defaultValue); - return this; - } - - public AbstractBaseIntegerProperty vendorExtension(String key, Object obj) { - this.setVendorExtension(key, obj); - return this; - } - - public T getDefault() { - return defaultValue; - } - - public void setDefault(String defaultValue) { - this.assignDefault(defaultValue); - } - - public void setDefault(T defaultValue) { - this.defaultValue = defaultValue; - } - - public List getEnum() { - return enumNames; - } - - public void setEnum(List enums) { - this.enumNames = enums; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((defaultValue == null) ? 0 : defaultValue.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof AbstractBaseIntegerProperty)) { - return false; - } - @SuppressWarnings("unchecked") - AbstractBaseIntegerProperty other = (AbstractBaseIntegerProperty) obj; - if (defaultValue == null) { - if (other.defaultValue != null) { - return false; - } - } else if (!defaultValue.equals(other.defaultValue)) { - return false; - } - return true; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ByteProperty.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ByteProperty.java deleted file mode 100644 index 3fe9450e3ec..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ByteProperty.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.property; - -public class ByteProperty extends AbstractBaseIntegerProperty { - public static final String FORMAT = "int8"; - - public ByteProperty() { - super(FORMAT); - } - - public static boolean isType(String type, String format) { - return TYPE.equals(type) && FORMAT.equals(format); - } - - @Override - protected Byte parseNumber(String strValue) { - return Byte.parseByte(strValue); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ShortProperty.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ShortProperty.java deleted file mode 100644 index 05c75ccafe5..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/ShortProperty.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.property; - -public class ShortProperty extends AbstractBaseIntegerProperty { - public static final String FORMAT = "int16"; - - public ShortProperty() { - super(FORMAT); - } - - public static boolean isType(String type, String format) { - return TYPE.equals(type) && FORMAT.equals(format); - } - - @Override - protected Short parseNumber(String strValue) { - return Short.parseShort(strValue); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ByteArrayPropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ByteArrayPropertyCreator.java index 7a65fdcded7..768a07a411f 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ByteArrayPropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ByteArrayPropertyCreator.java @@ -17,16 +17,21 @@ package org.apache.servicecomb.swagger.extend.property.creator; -import io.swagger.models.properties.ByteArrayProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.ByteArraySchema; +import io.swagger.v3.oas.models.media.Schema; +/** + * Swagger core will generate byte array to type=array, this is not correct. + * In Open API, byte array should use type=string,format=byte. + */ +@SuppressWarnings({"rawtypes"}) public class ByteArrayPropertyCreator implements PropertyCreator { private final Class[] classes = {Byte[].class, byte[].class}; @Override - public Property createProperty() { - return new ByteArrayProperty(); + public Schema createProperty() { + return new ByteArraySchema(); } @Override diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/BytePropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/BytePropertyCreator.java index 37011691e92..66e53e67814 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/BytePropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/BytePropertyCreator.java @@ -17,17 +17,22 @@ package org.apache.servicecomb.swagger.extend.property.creator; -import org.apache.servicecomb.swagger.extend.property.ByteProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.Schema; +/** + * Swagger core will generate byte to type=string,format=byte, this is not correct. + * In Open API, type=string,format=byte is for byte array. + */ +@SuppressWarnings({"rawtypes"}) public class BytePropertyCreator implements PropertyCreator { private final Class[] classes = {Byte.class, byte.class}; @Override - public Property createProperty() { - return new ByteProperty(); + public Schema createProperty() { + return new IntegerSchema(); } @Override diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/InputStreamPropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/InputStreamPropertyCreator.java index 37b2b33ce54..8a0556c145a 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/InputStreamPropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/InputStreamPropertyCreator.java @@ -19,16 +19,16 @@ import java.io.InputStream; -import io.swagger.models.properties.ByteArrayProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.ByteArraySchema; +import io.swagger.v3.oas.models.media.Schema; public class InputStreamPropertyCreator implements PropertyCreator { private final Class[] classes = {InputStream.class}; @Override - public Property createProperty() { - return new ByteArrayProperty(); + public Schema createProperty() { + return new ByteArraySchema(); } @Override diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PartPropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PartPropertyCreator.java index 4196ec2a9ad..3a489e5f7ef 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PartPropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PartPropertyCreator.java @@ -17,17 +17,16 @@ package org.apache.servicecomb.swagger.extend.property.creator; -import javax.servlet.http.Part; - -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.FileSchema; +import io.swagger.v3.oas.models.media.Schema; +import jakarta.servlet.http.Part; public class PartPropertyCreator implements PropertyCreator { private final Class[] classes = {Part.class}; @Override - public Property createProperty() { - return new FileProperty(); + public Schema createProperty() { + return new FileSchema(); } @Override diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PropertyCreator.java index b01f4c5f7f0..52629ed7871 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/PropertyCreator.java @@ -17,10 +17,11 @@ package org.apache.servicecomb.swagger.extend.property.creator; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.Schema; +@SuppressWarnings({"rawtypes"}) public interface PropertyCreator { - Property createProperty(); + Schema createProperty(); Class[] classes(); } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ShortPropertyCreator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ShortPropertyCreator.java deleted file mode 100644 index 72bb35f4c46..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/ShortPropertyCreator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.property.creator; - -import org.apache.servicecomb.swagger.extend.property.ShortProperty; - -import io.swagger.models.properties.Property; - -public class ShortPropertyCreator implements PropertyCreator { - - private final Class[] classes = {Short.class, short.class}; - - @Override - public Property createProperty() { - return new ShortProperty(); - } - - @Override - public Class[] classes() { - return classes; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ClassAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ClassAnnotationProcessor.java similarity index 77% rename from swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ClassAnnotationProcessor.java rename to swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ClassAnnotationProcessor.java index 3c4dbe24442..58e5f6c23c4 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ClassAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ClassAnnotationProcessor.java @@ -15,8 +15,12 @@ * limitations under the License. */ -package org.apache.servicecomb.swagger.generator.core; +package org.apache.servicecomb.swagger.generator; -public interface ClassAnnotationProcessor { - void process(Object annotation, SwaggerGenerator swaggerGenerator); +import java.lang.reflect.Type; + +public interface ClassAnnotationProcessor { + Type getProcessType(); + + void process(SwaggerGenerator swaggerGenerator, ANNOTATION annotation); } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/MethodAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/MethodAnnotationProcessor.java new file mode 100644 index 00000000000..4502bbc9719 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/MethodAnnotationProcessor.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator; + +import java.lang.reflect.Type; + +public interface MethodAnnotationProcessor { + Type getProcessType(); + + void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, ANNOTATION annotation); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/OperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/OperationGenerator.java new file mode 100644 index 00000000000..358db852989 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/OperationGenerator.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + + +import org.apache.servicecomb.swagger.generator.core.OperationGeneratorContext; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; + +public interface OperationGenerator { + OpenAPI getSwagger(); + + Operation getOperation(); + + void setHttpMethod(String httpMethod); + + String getHttpMethod(); + + void addOperationToSwagger(); + + void setPath(String value); + + OperationGeneratorContext getOperationGeneratorContext(); + + /** + * Used to check if one of operation has form parameter + */ + boolean isForm(); + + /** + * Used to check if one of operation form parameter is binary + */ + boolean isBinary(); + + /** + * + * Used to check if this operation is websocket + */ + boolean isWebsocket(); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterAnnotationProcessor.java new file mode 100644 index 00000000000..efba1bf571c --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.reflect.Type; + +public interface ParameterAnnotationProcessor { + Type getProcessType(); + + /** + * Get parameter name from annotation. This method is used in both + * swagger generation and invocation. In invocation, need to find the + * swagger parameter name of the method parameter. + */ + String getParameterName(ANNOTATION annotation); + + void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, ANNOTATION annotation); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterGenerator.java new file mode 100644 index 00000000000..2547b5c7f20 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterGenerator.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.swagger.generator.core.ParameterGeneratorContext; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import com.fasterxml.jackson.databind.JavaType; + +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.CookieParameter; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; +import io.swagger.v3.oas.models.parameters.RequestBody; + +public class ParameterGenerator { + private final List annotations; + + private final OperationGenerator operationGenerator; + + private final ParameterGeneratorContext parameterGeneratorContext; + + /** + * Used for pojo wrap parameter, while parameter type is null. + */ + public ParameterGenerator(OperationGenerator operationGenerator, String parameterName, Schema schema) { + this.operationGenerator = operationGenerator; + this.parameterGeneratorContext = new ParameterGeneratorContext(operationGenerator.getOperationGeneratorContext()); + this.parameterGeneratorContext.setParameterName(parameterName); + this.parameterGeneratorContext.setSchema(schema); + this.annotations = Collections.emptyList(); + } + + /** + * Used for @BeanParam like parameters, while extract JavaType of the bean parameter type. + */ + public ParameterGenerator(OperationGenerator operationGenerator, + Map> methodAnnotationMap, + String parameterName, + Annotation[] parameterAnnotations, JavaType genericType) { + this.operationGenerator = operationGenerator; + this.annotations = SwaggerGeneratorUtils.collectParameterAnnotations(parameterAnnotations, + methodAnnotationMap, + parameterName); + this.parameterGeneratorContext = new ParameterGeneratorContext(operationGenerator.getOperationGeneratorContext()); + this.parameterGeneratorContext.setParameterName(parameterName); + this.parameterGeneratorContext.setParameterType(genericType); + } + + /** + * Used for normal method parameter initialization, while extract JavaType from method parameter. + */ + public ParameterGenerator(OperationGenerator operationGenerator, + Map> methodAnnotationMap, + java.lang.reflect.Parameter methodParameter, JavaType genericType) { + this(operationGenerator, + methodAnnotationMap, + methodParameter.isNamePresent() ? methodParameter.getName() : null, + methodParameter.getAnnotations(), + genericType); + } + + /** + * Used for annotation defined parameter, while initial parameter type is null + * and will extract JavaType annotation processors. + */ + public ParameterGenerator(OperationGenerator operationGenerator, String parameterName, List annotations) { + this.operationGenerator = operationGenerator; + this.parameterGeneratorContext = new ParameterGeneratorContext(operationGenerator.getOperationGeneratorContext()); + this.parameterGeneratorContext.setParameterName(parameterName); + this.annotations = annotations; + } + + public ParameterGeneratorContext getParameterGeneratorContext() { + return this.parameterGeneratorContext; + } + + public List getAnnotations() { + return annotations; + } + + public JavaType getGenericType() { + return this.parameterGeneratorContext.getParameterType(); + } + + public HttpParameterType getHttpParameterType() { + return this.parameterGeneratorContext.getHttpParameterType(); + } + + public void setHttpParameterType(HttpParameterType httpParameterType) { + this.parameterGeneratorContext.setHttpParameterType(httpParameterType); + } + + public boolean isForm() { + return parameterGeneratorContext.isForm(); + } + + public boolean isBinary() { + return parameterGeneratorContext.isBinary(); + } + + public void generate() { + this.parameterGeneratorContext.updateConsumes( + this.operationGenerator.isForm(), this.operationGenerator.isBinary(), this.operationGenerator.isWebsocket()); + + if (this.parameterGeneratorContext.getHttpParameterType() == HttpParameterType.BODY) { + if (parameterGeneratorContext.getSupportedConsumes().size() == 0) { + throw new IllegalArgumentException("Consumes not provided for BODY parameter, or is empty " + + "by annotations rule."); + } + RequestBody requestBody = new RequestBody(); + requestBody.setRequired(parameterGeneratorContext.getRequired()); + Map extensions = new HashMap<>(); + extensions.put(SwaggerConst.EXT_BODY_NAME, parameterGeneratorContext.getParameterName()); + if (parameterGeneratorContext.getRawJson() != null) { + extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, parameterGeneratorContext.getRawJson()); + } + requestBody.setExtensions(extensions); + requestBody.setContent(new Content()); + for (String media : parameterGeneratorContext.getSupportedConsumes()) { + MediaType mediaType = new MediaType(); + mediaType.setSchema(parameterGeneratorContext.getSchema()); + requestBody.getContent().addMediaType(media, mediaType); + } + this.operationGenerator.getOperation().setRequestBody(requestBody); + return; + } + if (this.parameterGeneratorContext.getHttpParameterType() == HttpParameterType.FORM) { + if (parameterGeneratorContext.getSupportedConsumes().size() == 0) { + throw new IllegalArgumentException("Consumes not provided for FORM parameter, or is empty " + + "by annotations rule."); + } + RequestBody requestBody = this.operationGenerator.getOperation().getRequestBody(); + if (requestBody == null) { + requestBody = new RequestBody(); + requestBody.setContent(new Content()); + this.operationGenerator.getOperation().setRequestBody(requestBody); + } + for (String media : parameterGeneratorContext.getSupportedConsumes()) { + MediaType mediaType = requestBody.getContent().get(media); + if (mediaType == null) { + mediaType = new MediaType(); + mediaType.setSchema(new ObjectSchema()); + requestBody.getContent().addMediaType(media, mediaType); + } + mediaType.getSchema().addProperty(parameterGeneratorContext.getParameterName(), + parameterGeneratorContext.getSchema()); + } + return; + } + Parameter parameter; + switch (this.parameterGeneratorContext.getHttpParameterType()) { + case PATH -> parameter = new PathParameter(); + case QUERY -> parameter = new QueryParameter(); + case HEADER -> parameter = new HeaderParameter(); + case COOKIE -> parameter = new CookieParameter(); + default -> throw new IllegalStateException("not support httpParameterType " + + this.parameterGeneratorContext.getHttpParameterType()); + } + parameter.setName(parameterGeneratorContext.getParameterName()); + parameter.setSchema(parameterGeneratorContext.getSchema()); + parameter.setRequired(parameterGeneratorContext.getRequired()); + parameter.setExplode(parameterGeneratorContext.getExplode()); + this.operationGenerator.getOperation().addParametersItem(parameter); + + // validations and other annotations supported by swagger default + if (parameterGeneratorContext.getParameterType() != null) { + io.swagger.v3.core.util.ParameterProcessor.applyAnnotations(parameter, + parameterGeneratorContext.getParameterType(), + annotations, operationGenerator.getSwagger().getComponents(), + null, null, null); + } + // spring mvc DefaultValue annotation not processed by swagger api. + if (parameterGeneratorContext.getDefaultValue() != null) { + parameter.getSchema().setDefault(parameterGeneratorContext.getDefaultValue()); + } + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterTypeProcessor.java similarity index 76% rename from swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterTypeProcessor.java rename to swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterTypeProcessor.java index 8154d630d1a..e6af81e0d5e 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterTypeProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ParameterTypeProcessor.java @@ -14,9 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.servicecomb.swagger.generator; -package org.apache.servicecomb.swagger.generator.core; +import com.fasterxml.jackson.databind.JavaType; public interface ParameterTypeProcessor { - void process(OperationGenerator operationGenerator, int paramIdx); + JavaType getProcessType(); + + void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator); } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ResponseTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ResponseTypeProcessor.java new file mode 100644 index 00000000000..a1efa5112ae --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/ResponseTypeProcessor.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.reflect.Type; + +import io.swagger.v3.oas.models.media.Schema; + +public interface ResponseTypeProcessor { + Type getProcessType(); + + /** + * @return if genericResponseType is CompletableFuture<String>, then return String + */ + Type extractResponseType(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType); + + default Type extractResponseType(Type genericResponseType) { + return extractResponseType(null, null, genericResponseType); + } + + Schema process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Type genericResponseType); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerConst.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerConst.java new file mode 100644 index 00000000000..70990922e07 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerConst.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +public final class SwaggerConst { + private SwaggerConst() { + + } + + public static final String SUCCESS_KEY = String.valueOf(Response.Status.OK.getStatusCode()); + + public static final String DEFAULT_MEDIA_TYPE = MediaType.APPLICATION_JSON; + + public static final String FORM_MEDIA_TYPE = MediaType.APPLICATION_FORM_URLENCODED; + + public static final String FILE_MEDIA_TYPE = MediaType.MULTIPART_FORM_DATA; + + public static final String PROTOBUF_TYPE = "application/protobuf"; + + public static final String WEBSOCKET_TYPE = "application/websocket"; + + public static final String TAG_WEBSOCKET = "websocket"; + + public static final String EXT_JAVA_INTF = "x-java-interface"; + + public static final String EXT_JAVA_CLASS = "x-java-class"; + + public static final String EXT_RAW_JSON_TYPE = "x-raw-json"; + + public static final String EXT_JSON_VIEW = "x-json-view"; + + public static final String EXT_BODY_NAME = "x-name"; +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerContextRegister.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerContextRegister.java new file mode 100644 index 00000000000..8095b669802 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerContextRegister.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.reflect.Type; + +public interface SwaggerContextRegister { + Type getContextType(); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGenerator.java new file mode 100644 index 00000000000..cc9bbaaa58b --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGenerator.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.reflect.Method; +import java.util.List; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.swagger.v3.oas.models.OpenAPI; + +public interface SwaggerGenerator { + Logger LOGGER = LoggerFactory.getLogger(SwaggerGenerator.class); + + static OpenAPI generate(Class cls) { + return create(cls).generate(); + } + + static SwaggerGenerator create(Class cls) { + List factories = SPIServiceUtils.getOrLoadSortedService(SwaggerGeneratorFactory.class); + for (SwaggerGeneratorFactory factory : factories) { + if (factory.canProcess(cls)) { + LOGGER.info("select [{}] for [{}] to generate schema.", factory.getClass().getName(), cls.getName()); + return factory.create(cls); + } + } + + throw new IllegalStateException("impossible, must be bug. can not generate swagger for " + cls.getName()); + } + + SwaggerGeneratorContext getSwaggerGeneratorContext(); + + /** + * base path contains application server context-path, and schema base path. + */ + void setBasePath(String basePath); + + void scanClassAnnotation(); + + OpenAPI generate(); + + Class getClazz(); + + OpenAPI getOpenAPI(); + + void setHttpMethod(String httpMethod); + + void replaceMethodWhiteList(String... methodNames); + + T createOperationGenerator(Method method); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorFactory.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorFactory.java new file mode 100644 index 00000000000..3178ff36aff --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorFactory.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import org.apache.servicecomb.foundation.common.utils.SPIOrder; + +public interface SwaggerGeneratorFactory extends SPIOrder { + boolean canProcess(Class cls); + + SwaggerGenerator create(Class cls); +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorUtils.java new file mode 100644 index 00000000000..c8b0498de8b --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerGeneratorUtils.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.generator.core.processor.response.DefaultResponseTypeProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.core.util.Json; + +@SuppressWarnings("rawtypes") +public final class SwaggerGeneratorUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerGeneratorUtils.class); + + // all static fields load from SPI and stateless + private static final Set contextTypes = SPIServiceUtils.getOrLoadSortedService(SwaggerContextRegister.class) + .stream() + .map(swaggerContextRegister -> TypeFactory.defaultInstance() + .constructType(swaggerContextRegister.getContextType())) + .collect(Collectors.toSet()); + + private static final Map> classAnnotationProcessors = new HashMap<>(); + + private static final Map> methodAnnotationProcessors = new HashMap<>(); + + private static final Map responseTypeProcessors = new HashMap<>(); + + private static final DefaultResponseTypeProcessor defaultResponseTypeProcessor = new DefaultResponseTypeProcessor(); + + private static final List parameterAnnotationProcessors = SPIServiceUtils + .getOrLoadSortedService(ParameterAnnotationProcessor.class); + + private static final List parameterTypeProcessors = SPIServiceUtils + .getOrLoadSortedService(ParameterTypeProcessor.class); + + static { + // low order value has high priority + for (ClassAnnotationProcessor processor : SPIServiceUtils + .getOrLoadSortedService(ClassAnnotationProcessor.class)) { + if (classAnnotationProcessors.putIfAbsent(processor.getProcessType(), processor) != null) { + LOGGER.info("ignore duplicated ClassAnnotationProcessor, type={}, processor={}.", + processor.getProcessType().getTypeName(), processor.getClass().getName()); + } + } + + for (MethodAnnotationProcessor processor : SPIServiceUtils + .getOrLoadSortedService(MethodAnnotationProcessor.class)) { + if (methodAnnotationProcessors.putIfAbsent(processor.getProcessType(), processor) != null) { + LOGGER.info("ignore duplicated MethodAnnotationProcessor, type={}, processor={}.", + processor.getProcessType().getTypeName(), processor.getClass().getName()); + } + } + + for (ResponseTypeProcessor processor : SPIServiceUtils.getOrLoadSortedService(ResponseTypeProcessor.class)) { + if (responseTypeProcessors.putIfAbsent(processor.getProcessType(), processor) != null) { + LOGGER.info("ignore duplicated ResponseTypeProcessor, type={}, processor={}.", + processor.getProcessType().getTypeName(), processor.getClass().getName()); + } + } + + List modules = SPIServiceUtils.getOrLoadSortedService(Module.class); + Json.mapper().registerModules(modules.toArray(new Module[0])); + } + + private SwaggerGeneratorUtils() { + } + + @SuppressWarnings("unchecked") + public static ClassAnnotationProcessor findClassAnnotationProcessor(Type type) { + return (ClassAnnotationProcessor) classAnnotationProcessors.get(type); + } + + @SuppressWarnings("unchecked") + public static MethodAnnotationProcessor findMethodAnnotationProcessor(Type type) { + return (MethodAnnotationProcessor) methodAnnotationProcessors.get(type); + } + + @SuppressWarnings("unchecked") + public static ParameterAnnotationProcessor findParameterAnnotationProcessor(Type type) { + for (ParameterAnnotationProcessor processor : parameterAnnotationProcessors) { + if (processor.getProcessType() == type) { + return processor; + } + } + return null; + } + + public static ParameterTypeProcessor findParameterTypeProcessor(Type type) { + for (ParameterTypeProcessor processor : parameterTypeProcessors) { + if (processor.getProcessType() == type) { + return processor; + } + } + return null; + } + + public static ResponseTypeProcessor findResponseTypeProcessor(Type type) { + ResponseTypeProcessor processor = responseTypeProcessors.get(type); + if (processor != null) { + return processor; + } + + if (type instanceof ParameterizedType) { + return responseTypeProcessors.getOrDefault(((ParameterizedType) type).getRawType(), defaultResponseTypeProcessor); + } + + return defaultResponseTypeProcessor; + } + + public static boolean isContextParameter(JavaType type) { + return contextTypes.contains(type); + } + + public static Annotation[] collectAnnotations(BeanPropertyDefinition propertyDefinition) { + List annotations = new ArrayList<>(); + if (propertyDefinition.getField() != null) { + Collections.addAll(annotations, propertyDefinition.getField().getAnnotated().getAnnotations()); + } + if (propertyDefinition.getGetter() != null) { + Collections.addAll(annotations, propertyDefinition.getGetter().getAnnotated().getAnnotations()); + } + if (propertyDefinition.getSetter() != null) { + Collections.addAll(annotations, propertyDefinition.getSetter().getAnnotated().getAnnotations()); + } + return annotations.toArray(new Annotation[0]); + } + + public static String collectParameterName(java.lang.reflect.Parameter methodParameter) { + return collectParameterName(methodParameter.getDeclaringExecutable(), methodParameter.getAnnotations(), + methodParameter.isNamePresent() ? methodParameter.getName() : null); + } + + public static String collectParameterName(Method method, BeanPropertyDefinition propertyDefinition) { + Annotation[] annotations = collectAnnotations(propertyDefinition); + return collectParameterName(method, annotations, propertyDefinition.getName()); + } + + public static String collectParameterName(Executable executable, Annotation[] annotations, String defaultName) { + // 1.annotations + // it's ambiguous to use different name in different annotation + // so we only read the first available name + for (Annotation annotation : annotations) { + ParameterAnnotationProcessor processor = findParameterAnnotationProcessor( + annotation.annotationType()); + if (processor == null) { + continue; + } + + String name = processor.getParameterName(annotation); + if (StringUtils.isNotEmpty(name)) { + return name; + } + } + + // 2.use signature name + // ensure present parameter name + if (StringUtils.isNotEmpty(defaultName)) { + return defaultName; + } + + String msg = String.format(""" + parameter name is not present, method=%s:%s + solution: + change pom.xml, add compiler argument: -parameters, for example: + + org.apache.maven.plugins + maven-compiler-plugin + + -parameters + + """, + executable.getDeclaringClass().getName(), executable.getName()); + throw new IllegalStateException(msg); + } + + public static List collectParameterAnnotations(Annotation[] parameterAnnotations, + Map> methodAnnotationMap, String parameterName) { + List methodAnnotations = methodAnnotationMap.remove(parameterName); + if (methodAnnotations == null) { + methodAnnotations = Collections.emptyList(); + } + + List annotations = new ArrayList<>(); + Collections.addAll(annotations, parameterAnnotations); + annotations.addAll(methodAnnotations); + + return annotations; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerParameterAnnotationProcessor.java new file mode 100644 index 00000000000..72633d01c2f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/SwaggerParameterAnnotationProcessor.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator; + +/** + * A generic class to help classify implementations. Processors of swagger annotations + * will implement this class. + */ +public abstract class SwaggerParameterAnnotationProcessor implements + ParameterAnnotationProcessor { +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractOperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractOperationGenerator.java new file mode 100644 index 00000000000..f3c00478f7b --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractOperationGenerator.java @@ -0,0 +1,444 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.collectAnnotations; +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.findMethodAnnotationProcessor; +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.findResponseTypeProcessor; +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.isContextParameter; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.inject.PlaceholderResolver; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.ParameterTypeProcessor; +import org.apache.servicecomb.swagger.generator.ResponseTypeProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.apache.servicecomb.swagger.generator.core.utils.MethodUtils; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.reflect.TypeToken; + +import io.swagger.v3.core.util.Json; +import io.swagger.v3.core.util.ReflectionUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.headers.Header; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import jakarta.servlet.http.HttpServletResponse; + +@SuppressWarnings("rawtypes") +public abstract class AbstractOperationGenerator implements OperationGenerator { + protected AbstractSwaggerGenerator swaggerGenerator; + + protected OpenAPI swagger; + + protected Class clazz; + + protected Method method; + + protected String httpMethod; + + protected List parameterGenerators = new ArrayList<>(); + + protected String path; + + protected Operation swaggerOperation; + + protected OperationGeneratorContext operationGeneratorContext; + + public AbstractOperationGenerator(AbstractSwaggerGenerator swaggerGenerator, Method method) { + this.swaggerGenerator = swaggerGenerator; + this.swagger = swaggerGenerator.getOpenAPI(); + this.clazz = swaggerGenerator.getClazz(); + this.method = method; + this.httpMethod = swaggerGenerator.getHttpMethod(); + + operationGeneratorContext = new OperationGeneratorContext(swaggerGenerator.getSwaggerGeneratorContext()); + swaggerOperation = new Operation(); + } + + @Override + public OperationGeneratorContext getOperationGeneratorContext() { + return operationGeneratorContext; + } + + @Override + public void setHttpMethod(String httpMethod) { + if (StringUtils.isEmpty(httpMethod)) { + return; + } + + this.httpMethod = httpMethod.toUpperCase(Locale.US); + } + + @Override + public OpenAPI getSwagger() { + return this.swagger; + } + + @Override + public String getHttpMethod() { + return httpMethod; + } + + @Override + public Operation getOperation() { + return swaggerOperation; + } + + public String getOperationId() { + return swaggerOperation.getOperationId(); + } + + @Override + public void setPath(String path) { + path = new PlaceholderResolver().replaceFirst(path); + if (!path.startsWith("/")) { + path = "/" + path; + } + this.path = path; + } + + public void generate() { + scanMethodAnnotation(); + scanMethodParameters(); + scanResponse(); + correctOperation(); + } + + protected void scanMethodAnnotation() { + for (Annotation annotation : Arrays.stream(method.getAnnotations()) + .sorted(Comparator.comparing(a -> a.annotationType().getSimpleName())) + .collect(Collectors.toList())) { + MethodAnnotationProcessor processor = findMethodAnnotationProcessor(annotation.annotationType()); + if (processor == null) { + continue; + } + processor.process(swaggerGenerator, this, annotation); + } + + if (StringUtils.isEmpty(swaggerOperation.getOperationId())) { + swaggerOperation.setOperationId(MethodUtils.findSwaggerMethodName(method)); + } + } + + protected void scanMethodParameters() { + // init generators + initParameterGenerators(); + + // scan annotations and types + Set names = new HashSet<>(); + int bodyCount = 0; + for (ParameterGenerator parameterGenerator : parameterGenerators) { + scanMethodParameter(parameterGenerator); + + if (!names.add(parameterGenerator.getParameterGeneratorContext().getParameterName())) { + throw new IllegalArgumentException( + String.format("not support duplicated parameter, name=%s.", + parameterGenerator.getParameterGeneratorContext().getParameterName())); + } + if (parameterGenerator.getHttpParameterType() == HttpParameterType.BODY) { + if (bodyCount > 0) { + throw new IllegalArgumentException(String.format("Defined %d body parameter.", bodyCount)); + } + bodyCount++; + } + } + + // generate + for (ParameterGenerator parameterGenerator : parameterGenerators) { + parameterGenerator.generate(); + } + } + + protected void initParameterGenerators() { + // 1.group method annotations by parameter name + // key is parameter name + Map> methodAnnotationMap = initMethodAnnotationByParameterName(); + + // 2.create ParameterGenerators by method parameters, merge annotations with method annotations + initMethodParameterGenerators(methodAnnotationMap); + + // 3.create ParameterGenerators remains method annotations + initRemainMethodAnnotationsParameterGenerators(methodAnnotationMap); + } + + protected void initMethodParameterGenerators(Map> methodAnnotationMap) { + for (java.lang.reflect.Parameter methodParameter : method.getParameters()) { + Type genericType = TypeToken.of(clazz) + .resolveType(methodParameter.getParameterizedType()) + .getType(); + ParameterGenerator parameterGenerator = new ParameterGenerator( + this, methodAnnotationMap, methodParameter, + TypeFactory.defaultInstance().constructType(genericType)); + validateParameter(parameterGenerator.getGenericType()); + if (isContextParameter(parameterGenerator.getGenericType())) { + continue; + } + + // jaxrs: @BeanParam + // springmvc: is query, and is bean type + if (isAggregatedParameter(parameterGenerator, methodParameter)) { + extractAggregatedParameterGenerators(methodAnnotationMap, methodParameter); + continue; + } + + parameterGenerators.add(parameterGenerator); + } + } + + protected boolean isAggregatedParameter(ParameterGenerator parameterGenerator, + java.lang.reflect.Parameter methodParameter) { + return false; + } + + protected void extractAggregatedParameterGenerators(Map> methodAnnotationMap, + java.lang.reflect.Parameter methodParameter) { + JavaType javaType = TypeFactory.defaultInstance().constructType(methodParameter.getParameterizedType()); + BeanDescription beanDescription = Json.mapper().getSerializationConfig().introspect(javaType); + for (BeanPropertyDefinition propertyDefinition : beanDescription.findProperties()) { + if (!propertyDefinition.couldSerialize()) { + continue; + } + + Annotation[] annotations = collectAnnotations(propertyDefinition); + ParameterGenerator propertyParameterGenerator = new ParameterGenerator(this, + methodAnnotationMap, + propertyDefinition.getName(), + annotations, + propertyDefinition.getPrimaryType()); + parameterGenerators.add(propertyParameterGenerator); + } + } + + protected void initRemainMethodAnnotationsParameterGenerators(Map> methodAnnotationMap) { + for (Entry> entry : methodAnnotationMap.entrySet()) { + ParameterGenerator parameterGenerator = new ParameterGenerator(this, entry.getKey(), entry.getValue()); + parameterGenerators.add(parameterGenerator); + } + } + + private Map> initMethodAnnotationByParameterName() { + Map> methodAnnotations = new LinkedHashMap<>(); + for (Annotation annotation : method.getAnnotations()) { + if (annotation instanceof io.swagger.v3.oas.annotations.Parameters) { + for (io.swagger.v3.oas.annotations.Parameter apiImplicitParam + : ((io.swagger.v3.oas.annotations.Parameters) annotation).value()) { + addMethodAnnotationByParameterName(methodAnnotations, apiImplicitParam.name(), apiImplicitParam); + } + continue; + } + + if (annotation instanceof io.swagger.v3.oas.annotations.Parameter) { + addMethodAnnotationByParameterName(methodAnnotations, + ((io.swagger.v3.oas.annotations.Parameter) annotation).name(), annotation); + } + } + return methodAnnotations; + } + + private void addMethodAnnotationByParameterName(Map> methodAnnotations, String name, + Annotation annotation) { + if (StringUtils.isEmpty(name)) { + throw new IllegalStateException(String.format("%s.name should not be empty. method=%s:%s", + annotation.annotationType().getSimpleName(), + method.getDeclaringClass().getName(), + method.getName())); + } + + methodAnnotations.computeIfAbsent(name, n -> new ArrayList<>()) + .add(annotation); + } + + protected void validateParameter(JavaType type) { + if (type.isTypeOrSubTypeOf(HttpServletResponse.class)) { + // not support, log the reason + throw new IllegalStateException( + "all input/output of ServiceComb operation are models, not allow to use HttpServletResponse."); + } + } + + protected void scanMethodParameter(ParameterGenerator parameterGenerator) { + for (Annotation annotation : parameterGenerator.getAnnotations()) { + ParameterAnnotationProcessor processor = SwaggerGeneratorUtils + .findParameterAnnotationProcessor(annotation.annotationType()); + if (processor != null) { + processor.process(this.swaggerGenerator, this, parameterGenerator, annotation); + } + } + + Schema schema = parameterGenerator.getParameterGeneratorContext().getSchema(); + if (schema == null) { + JavaType parameterType = parameterGenerator.getGenericType(); + ParameterTypeProcessor processor = SwaggerGeneratorUtils.findParameterTypeProcessor(parameterType); + if (processor != null) { + processor.process(this.swaggerGenerator, this, parameterGenerator); + } else { + parameterGenerator.getParameterGeneratorContext().setSchema(SwaggerUtils.resolveTypeSchemas(this.swagger, + parameterType)); + } + } + } + + @Override + public boolean isForm() { + for (ParameterGenerator parameterGenerator : parameterGenerators) { + if (parameterGenerator.isForm()) { + return true; + } + } + return false; + } + + @Override + public boolean isBinary() { + for (ParameterGenerator parameterGenerator : parameterGenerators) { + if (parameterGenerator.isBinary()) { + return true; + } + } + return false; + } + + @Override + public boolean isWebsocket() { + return this.swaggerOperation.getTags() != null && + this.swaggerOperation.getTags().contains(SwaggerConst.TAG_WEBSOCKET); + } + + @Override + public void addOperationToSwagger() { + if (StringUtils.isEmpty(httpMethod)) { + return; + } + + if (swagger.getPaths() == null) { + swagger.setPaths(new Paths()); + } + + PathItem pathObj = swagger.getPaths().get(path); + if (pathObj == null) { + pathObj = new PathItem(); + swagger.path(path, pathObj); + } else if (SwaggerUtils.methodExists(pathObj, httpMethod)) { + throw new IllegalStateException(String.format("Duplicate operation path detected. method=%s:%s.", + method.getDeclaringClass().getName(), + method.getName())); + } + + pathObj.operation(PathItem.HttpMethod.valueOf(httpMethod), swaggerOperation); + } + + public void correctOperation() { + SwaggerUtils.correctResponses(swaggerOperation); + } + + public void scanResponse() { + operationGeneratorContext.updateProduces(); + swaggerOperation.setResponses(new ApiResponses()); + for (Entry> response : operationGeneratorContext.getResponses().entrySet()) { + ApiResponse apiResponse = new ApiResponse(); + if (StringUtils.isNotEmpty(operationGeneratorContext.getResponseDescriptions().get(response.getKey()))) { + apiResponse.setDescription(operationGeneratorContext.getResponseDescriptions().get(response.getKey())); + } + if (operationGeneratorContext.getResponseHeaders().get(response.getKey()) != null) { + operationGeneratorContext.getResponseHeaders().get(response.getKey()).forEach((k, v) -> { + Header header = new Header(); + header.setSchema(v); + apiResponse.addHeaderObject(k, header); + }); + } + Schema schema = response.getValue() != null ? response.getValue() : + createResponseModel(); + + if (schema == null) { + swaggerOperation.getResponses().addApiResponse(response.getKey(), apiResponse); + continue; + } + + apiResponse.setContent(new Content()); + // file download using WILDCARD content-type + if ("string".equals(schema.getType()) && "binary".equals(schema.getFormat())) { + MediaType mediaType = new MediaType(); + mediaType.setSchema(schema); + apiResponse.getContent().addMediaType(jakarta.ws.rs.core.MediaType.WILDCARD, mediaType); + } else { + for (String produce : operationGeneratorContext.getSupportedProduces()) { + MediaType mediaType = new MediaType(); + mediaType.setSchema(schema); + apiResponse.getContent().addMediaType(produce, mediaType); + } + } + swaggerOperation.getResponses().addApiResponse(response.getKey(), apiResponse); + } + } + + protected Schema createResponseModel() { + Type responseType = + TypeToken.of(clazz) + .resolveType(method.getGenericReturnType()) + .getType(); + if (ReflectionUtils.isVoid(responseType)) { + return null; + } + + ResponseTypeProcessor processor = findResponseTypeProcessor(responseType); + return processor.process(swaggerGenerator, this, responseType); + } + + public Method getMethod() { + return method; + } + + public List getParameterGenerators() { + return parameterGenerators; + } + + public Operation getSwaggerOperation() { + return swaggerOperation; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGenerator.java new file mode 100644 index 00000000000..6549418441d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGenerator.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.findClassAnnotationProcessor; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.config.inject.PlaceholderResolver; +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.utils.MethodUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.servers.Server; + + +/** + *
+ * support:
+ * 1.pojo + swagger annotation
+ *   wrap all input parameter to be fields of body
+ * 2.pojo + swagger annotation + jaxrs annotation
+ * 3.pojo + swagger annotation + springmvc annotation
+ * 
+ */ +public abstract class AbstractSwaggerGenerator implements SwaggerGenerator { + protected SwaggerGeneratorContext swaggerGeneratorContext = new SwaggerGeneratorContext(); + + protected Class cls; + + protected OpenAPI openAPI; + + // allowed to control only process some methods + // empty means all methods are available + protected Set methodWhiteList = new HashSet<>(); + + // key is operationId + // to check if operationId is duplicated + protected Map operationGenerators = new LinkedHashMap<>(); + + protected String httpMethod; + + public AbstractSwaggerGenerator(Class cls) { + this.openAPI = new OpenAPI(); + this.openAPI.components(new Components()) + .paths(new Paths()) + .servers(new ArrayList<>()) + .info(new Info()); + this.cls = cls; + } + + public OpenAPI getOpenAPI() { + return openAPI; + } + + @Override + public Class getClazz() { + return cls; + } + + public String getHttpMethod() { + return httpMethod; + } + + @Override + public void setHttpMethod(String httpMethod) { + this.httpMethod = httpMethod.toUpperCase(Locale.US); + } + + @Override + public SwaggerGeneratorContext getSwaggerGeneratorContext() { + return swaggerGeneratorContext; + } + + public OpenAPI generate() { + LOGGER.info("generate schema from [{}]", cls); + scanClassAnnotation(); + + scanMethods(); + addOperationsToSwagger(); + + correctSwagger(); + + return openAPI; + } + + public void scanClassAnnotation() { + for (Annotation annotation : cls.getAnnotations()) { + ClassAnnotationProcessor processor = findClassAnnotationProcessor(annotation.annotationType()); + if (processor == null) { + continue; + } + processor.process(this, annotation); + } + } + + /** + * fill empty and required field to be default value + * if can not build default value, then throw exceptions + */ + protected void correctSwagger() { + correctBasePath(); + correctInfo(); + } + + private void correctBasePath() { + if (openAPI.getServers() == null) { + openAPI.setServers(new ArrayList<>()); + } + if (openAPI.getServers().size() <= 0) { + Server server = new Server(); + server.setUrl("/" + cls.getSimpleName()); + openAPI.getServers().add(server); + } + } + + private void correctInfo() { + Info info = openAPI.getInfo(); + if (info == null) { + info = new Info(); + openAPI.setInfo(info); + } + + if (StringUtils.isEmpty(info.getTitle())) { + info.setTitle("swagger definition for " + cls.getName()); + } + if (StringUtils.isEmpty(info.getVersion())) { + info.setVersion("1.0.0"); + } + } + + @Override + public void replaceMethodWhiteList(String... methodNames) { + methodWhiteList.clear(); + + if (methodNames == null || methodNames.length == 0) { + return; + } + + methodWhiteList.addAll(Arrays.asList(methodNames)); + } + + /** + * Whether this method should be processed as a swagger operation + * @return true if this isn't a swagger operation; otherwise, false. + */ + protected boolean isSkipMethod(Method method) { + if (method.getDeclaringClass().getName().equals(Object.class.getName())) { + return true; + } + // skip static method + int modifiers = method.getModifiers(); + if (Modifier.isStatic(modifiers)) { + return true; + } + // skip bridge method + if (method.isBridge()) { + return true; + } + + Operation apiOperation = method.getAnnotation(Operation.class); + if (apiOperation != null && apiOperation.hidden()) { + return true; + } + + if (!methodWhiteList.isEmpty()) { + return !methodWhiteList.contains(MethodUtils.findSwaggerMethodName(method)); + } + + return false; + } + + protected void scanMethods() { + List methods = MethodUtils.findSwaggerMethods(cls); + + for (Method method : methods) { + if (isSkipMethod(method)) { + continue; + } + + AbstractOperationGenerator operationGenerator = createOperationGenerator(method); + operationGenerator.setHttpMethod(httpMethod); + try { + operationGenerator.generate(); + } catch (Throwable e) { + String msg = String.format("Generate swagger operation failed, method=%s:%s, cause=%s", + this.cls.getSimpleName(), method.getName(), e.getMessage()); + throw new IllegalStateException(msg, e); + } + + if (StringUtils.isEmpty(operationGenerator.httpMethod)) { + throw new IllegalStateException( + String.format("HttpMethod must not both be empty in class and method, method=%s:%s.", + cls.getName(), method.getName())); + } + + if (operationGenerators.putIfAbsent(operationGenerator.getOperationId(), operationGenerator) != null) { + throw new IllegalStateException( + String.format("OperationId must be unique. method=%s:%s.", cls.getName(), method.getName())); + } + } + } + + protected void addOperationsToSwagger() { + for (OperationGenerator operationGenerator : operationGenerators.values()) { + operationGenerator.addOperationToSwagger(); + } + } + + @Override + public void setBasePath(String basePath) { + basePath = new PlaceholderResolver().replaceFirst(basePath); + if (openAPI.getServers() == null) { + openAPI.setServers(new ArrayList<>()); + } + if (openAPI.getServers().size() == 0) { + openAPI.getServers().add(new Server()); + } + openAPI.getServers().get(0).setUrl(basePath); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGeneratorContext.java deleted file mode 100644 index 83fce365fcb..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AbstractSwaggerGeneratorContext.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -import org.apache.servicecomb.foundation.common.RegisterManager; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.generator.core.AnnotationProcessorManager.AnnotationType; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiImplicitParamClassProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiImplicitParamMethodProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiImplicitParamsClassProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiImplicitParamsMethodProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiOperationProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponseClassProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponseMethodProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponsesClassProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponsesMethodProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ResponseHeaderProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.ResponseHeadersProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.SwaggerDefinitionProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.parametertype.RawJsonRequestBodyProcessor; -import org.apache.servicecomb.swagger.generator.core.processor.response.DefaultResponseTypeProcessor; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ResponseHeader; -import io.swagger.annotations.SwaggerDefinition; - -/** - * 根据class反向生成swagger的上下文对象 - */ -public abstract class AbstractSwaggerGeneratorContext implements SwaggerGeneratorContext, EmbeddedValueResolverAware { - protected StringValueResolver stringValueResolver; - - protected AnnotationProcessorManager classAnnotationMgr = - new AnnotationProcessorManager<>(AnnotationType.CLASS); - - protected AnnotationProcessorManager methodAnnotationMgr = - new AnnotationProcessorManager<>(AnnotationType.METHOD); - - protected AnnotationProcessorManager parameterAnnotationMgr = - new AnnotationProcessorManager<>(AnnotationType.PARAMETER); - - // 管理方法入参的processor,用于支撑httpRequest、Context之类的特殊处理 - // key为class - protected RegisterManager parameterTypeProcessorMgr = - new RegisterManager<>("parameter type processor mgr"); - - protected DefaultParameterProcessor defaultParameterProcessor; - - protected RegisterManager responseTypeProcessorMgr = - new RegisterManager<>("response type processor mgr"); - - protected ResponseTypeProcessor defaultResponseTypeProcessor = new DefaultResponseTypeProcessor(); - - public AbstractSwaggerGeneratorContext() { - initClassAnnotationMgr(); - initMethodAnnotationMgr(); - initParameterAnnotationMgr(); - - initParameterTypeProcessorMgr(); - - initDefaultParameterProcessor(); - - initResponseTypeProcessorMgr(); - } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } - - @Override - public String resolveStringValue(String strVal) { - if (stringValueResolver == null) { - return strVal; - } - - return stringValueResolver.resolveStringValue(strVal); - } - - protected void initClassAnnotationMgr() { - classAnnotationMgr.register(Api.class, new ApiProcessor()); - classAnnotationMgr.register(SwaggerDefinition.class, new SwaggerDefinitionProcessor()); - - classAnnotationMgr.register(ApiImplicitParams.class, new ApiImplicitParamsClassProcessor()); - classAnnotationMgr.register(ApiImplicitParam.class, new ApiImplicitParamClassProcessor()); - - classAnnotationMgr.register(ApiResponses.class, new ApiResponsesClassProcessor()); - classAnnotationMgr.register(ApiResponse.class, new ApiResponseClassProcessor()); - } - - protected void initMethodAnnotationMgr() { - methodAnnotationMgr.register(ApiOperation.class, new ApiOperationProcessor()); - - methodAnnotationMgr.register(ApiImplicitParams.class, new ApiImplicitParamsMethodProcessor()); - methodAnnotationMgr.register(ApiImplicitParam.class, new ApiImplicitParamMethodProcessor()); - - methodAnnotationMgr.register(ApiResponses.class, new ApiResponsesMethodProcessor()); - methodAnnotationMgr.register(ApiResponse.class, new ApiResponseMethodProcessor()); - - methodAnnotationMgr.register(ResponseHeaders.class, new ResponseHeadersProcessor()); - methodAnnotationMgr.register(ResponseHeader.class, new ResponseHeaderProcessor()); - } - - protected void initParameterAnnotationMgr() { - parameterAnnotationMgr.register(RawJsonRequestBody.class, new RawJsonRequestBodyProcessor()); - } - - protected void initParameterTypeProcessorMgr() { - SPIServiceUtils.getAllService(CommonParameterTypeProcessor.class).forEach(p -> { - parameterTypeProcessorMgr.register(p.getParameterType(), p); - }); - } - - protected void initDefaultParameterProcessor() { - } - - protected void initResponseTypeProcessorMgr() { - SPIServiceUtils.getAllService(ResponseTypeProcessor.class).forEach(p -> { - responseTypeProcessorMgr.register(p.getResponseType(), p); - }); - } - - public void setDefaultParamProcessor(DefaultParameterProcessor defaultParamProcessor) { - this.defaultParameterProcessor = defaultParamProcessor; - } - - public ClassAnnotationProcessor findClassAnnotationProcessor(Class annotationType) { - return classAnnotationMgr.findProcessor(annotationType); - } - - public MethodAnnotationProcessor findMethodAnnotationProcessor(Class annotationType) { - return methodAnnotationMgr.findProcessor(annotationType); - } - - public ParameterAnnotationProcessor findParameterAnnotationProcessor(Class annotationType) { - return parameterAnnotationMgr.findProcessor(annotationType); - } - - public ParameterTypeProcessor findParameterTypeProcessor(Type type) { - return parameterTypeProcessorMgr.findValue(type); - } - - public DefaultParameterProcessor getDefaultParamProcessor() { - return defaultParameterProcessor; - } - - @Override - public ResponseTypeProcessor findResponseTypeProcessor(Type responseType) { - ResponseTypeProcessor processor = responseTypeProcessorMgr.findValue(responseType); - if (processor == null) { - processor = defaultResponseTypeProcessor; - } - - return processor; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AnnotationProcessorManager.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AnnotationProcessorManager.java deleted file mode 100644 index 5e01b525b23..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/AnnotationProcessorManager.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.lang.annotation.Annotation; - -import org.apache.servicecomb.foundation.common.RegisterManager; - -public class AnnotationProcessorManager extends RegisterManager { - enum AnnotationType { - CLASS, - METHOD, - PARAMETER - } - - public AnnotationProcessorManager(AnnotationType annotationType) { - super(annotationType + " annotation processor mgr"); - } - - public void register(Class annotationCls, T processor) { - register(annotationCls.getName(), processor); - } - - public T findProcessor(Class annotationCls) { - return this.findValue(annotationCls.getName()); - } - - public T findProcessor(String annotationName) { - return this.findValue(annotationName); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CommonParameterTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CommonParameterTypeProcessor.java deleted file mode 100644 index 789cdcaa51d..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CommonParameterTypeProcessor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -/** - * 通过spi自动注入到所有的GeneratorContext实例中去 - */ -public interface CommonParameterTypeProcessor extends ParameterTypeProcessor { - Class getParameterType(); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CompositeSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CompositeSwaggerGeneratorContext.java deleted file mode 100644 index 70adc13ec42..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/CompositeSwaggerGeneratorContext.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.stereotype.Component; -import org.springframework.util.StringValueResolver; - -@Component -public class CompositeSwaggerGeneratorContext implements EmbeddedValueResolverAware { - - private static final Logger LOGGER = LoggerFactory.getLogger(CompositeSwaggerGeneratorContext.class); - - private List contextList; - - private Map, SwaggerGeneratorContext> producerClassSwaggerContextCacheMap = new ConcurrentHashMapEx<>(); - - public CompositeSwaggerGeneratorContext() { - contextList = SPIServiceUtils.getSortedService(SwaggerGeneratorContext.class); - } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - for (SwaggerGeneratorContext context : contextList) { - if (EmbeddedValueResolverAware.class.isInstance(context)) { - ((EmbeddedValueResolverAware) context).setEmbeddedValueResolver(resolver); - } - } - } - - public List getContextList() { - return contextList; - } - - public SwaggerGeneratorContext selectContext(Class cls) { - return producerClassSwaggerContextCacheMap.computeIfAbsent(cls, producerClass -> { - for (SwaggerGeneratorContext context : contextList) { - if (context.canProcess(cls)) { - LOGGER.info("select [{}] for [{}] to generate schema.", context.getClass().getName(), cls.getName()); - return context; - } - } - throw new Error("impossible, must be bug."); - }); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/DefaultParameterProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/DefaultParameterProcessor.java deleted file mode 100644 index 57cb0b811d9..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/DefaultParameterProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -/** - * method参数没有RESTful相关标注时的处理器 - * jaxrs中,处理为body参数 - * springmvc中处理为requestParam参数 - */ -public interface DefaultParameterProcessor { - void process(OperationGenerator operationGenerator, int paramIndex); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/MethodAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/MethodAnnotationProcessor.java deleted file mode 100644 index f91f5e86e42..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/MethodAnnotationProcessor.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -public interface MethodAnnotationProcessor { - void process(Object annotation, OperationGenerator operationGenerator); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java deleted file mode 100644 index 8c9a834297b..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; - -import javax.ws.rs.DefaultValue; - -import org.apache.servicecomb.swagger.SwaggerUtils; -import org.apache.servicecomb.swagger.extend.parameter.ContextParameter; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.AnnotationUtils; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.Property; -import io.swagger.util.ReflectionUtils; - -public class OperationGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(OperationGenerator.class); - - protected SwaggerGenerator swaggerGenerator; - - protected Swagger swagger; - - protected Operation operation; - - // 根据方法上独立的ResponseHeader(s)标注生成的数据 - // 如果Response中不存在对应的header,则会将这些header补充进去 - protected Map responseHeaderMap = new HashMap<>(); - - // provider的方法 - protected Method providerMethod; - - // 方法annotation所有的参数 - private List methodAnnotationParameters = new ArrayList<>(); - - // provider所有的参数 - // 如果相同的参数名在annotationParameters中已经存在 - // 则从annotationParameters移除,将之转移到providerParameters中来,覆盖在同名位置 - private List providerParameters = new ArrayList<>(); - - // 生成的契约参数 - private List swaggerParameters = new ArrayList<>(); - - protected SwaggerGeneratorContext context; - - protected String path; - - protected String httpMethod; - - public OperationGenerator(SwaggerGenerator swaggerGenerator, Method providerMethod) { - this.swaggerGenerator = swaggerGenerator; - this.swagger = swaggerGenerator.swagger; - this.operation = new Operation(); - this.providerMethod = providerMethod; - this.context = swaggerGenerator.context; - - if (swagger.getParameters() != null) { - methodAnnotationParameters.addAll(swagger.getParameters().values()); - } - } - - public void addResponseHeader(String name, Property header) { - responseHeaderMap.put(name, header); - } - - public List getSwaggerParameters() { - return swaggerParameters; - } - - public SwaggerGeneratorContext getContext() { - return context; - } - - public SwaggerGenerator getSwaggerGenerator() { - return swaggerGenerator; - } - - public Swagger getSwagger() { - return swagger; - } - - public Operation getOperation() { - return operation; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - path = context.resolveStringValue(path); - if (!path.startsWith("/")) { - path = "/" + path; - } - this.path = path; - } - - public String getHttpMethod() { - return httpMethod; - } - - public void setHttpMethod(String httpMethod) { - if (StringUtils.isEmpty(httpMethod)) { - return; - } - - this.httpMethod = httpMethod.toLowerCase(Locale.US); - } - - public void addMethodAnnotationParameter(Parameter parameter) { - methodAnnotationParameters.add(parameter); - } - - /** - * Add a parameter into {@linkplain #providerParameters}, - * duplicated name params will be ignored(excepting for {@linkplain ContextParameter}s) - */ - public void addProviderParameter(Parameter parameter) { - if (ContextParameter.class.isInstance(parameter)) { - // ContextParameter has no name and is not written in schema, - // so just add it without checking - providerParameters.add(parameter); - return; - } - // check duplicated param according to param name - for (Parameter providerParameter : providerParameters) { - if (parameter.getName().equals(providerParameter.getName())) { - LOGGER.warn( - "Param name [{}] is duplicated which may cause ambiguous deserialization result. Please check you schema definition", - parameter.getName()); - return; - } - } - - providerParameters.add(parameter); - } - - public List getProviderParameters() { - return providerParameters; - } - - public void generate() { - scanMethodAnnotation(); - scanMethodParameters(); - scanResponse(); - - checkBodyParameter(); - copyToSwaggerParameters(); - operation.setParameters(swaggerParameters); - - correctOperation(); - } - - protected void copyToSwaggerParameters() { - for (Parameter parameter : providerParameters) { - if (ContextParameter.class.isInstance(parameter)) { - continue; - } - - int annotationIdx = ParamUtils.findParameterByName(parameter.getName(), methodAnnotationParameters); - if (annotationIdx != -1) { - Parameter annotationParameter = methodAnnotationParameters.remove(annotationIdx); - swaggerParameters.add(annotationParameter); - continue; - } - - swaggerParameters.add(parameter); - } - - swaggerParameters.addAll(methodAnnotationParameters); - } - - protected int countRealBodyParameter(List parameters) { - int count = 0; - for (Parameter p : parameters) { - if (ParamUtils.isRealBodyParameter(p)) { - count++; - } - } - - return count; - } - - protected void checkBodyParameter() { - // annotationParameters中不能有多个body - int annotationBodyCount = countRealBodyParameter(methodAnnotationParameters); - if (annotationBodyCount > 1) { - throw new Error(String.format("too many (%d) body parameter in %s:%s annotation", - annotationBodyCount, - providerMethod.getDeclaringClass().getName(), - providerMethod.getName())); - } - - // providerParameters中不能有多个body - int parameterBodyCount = countRealBodyParameter(providerParameters); - if (parameterBodyCount > 1) { - throw new Error(String.format("too many (%d) body parameter in %s:%s parameters", - parameterBodyCount, - providerMethod.getDeclaringClass().getName(), - providerMethod.getName())); - } - - // annotationParameters和providerParameters不能同时出现body - if (annotationBodyCount + parameterBodyCount >= 2) { - throw new Error(String.format("not allow both defined body parameter in %s:%s annotation and parameters", - providerMethod.getDeclaringClass().getName(), - providerMethod.getName())); - } - } - - protected void scanMethodAnnotation() { - for (Annotation annotation : providerMethod.getAnnotations()) { - MethodAnnotationProcessor processor = context.findMethodAnnotationProcessor(annotation.annotationType()); - if (processor == null) { - continue; - } - processor.process(annotation, this); - } - - setDefaultTag(); - } - - private void setDefaultTag() { - // if tag has been defined, do nothing - if (null != operation.getTags()) { - for (String tag : operation.getTags()) { - if (!StringUtils.isEmpty(tag)) { - return; - } - } - } - - // if there is no tag, set default tag - if (!swaggerGenerator.getDefaultTags().isEmpty()) { - operation.setTags(new ArrayList<>(swaggerGenerator.getDefaultTags())); - } - } - - /** - * - * 根据method上的数据,综合生成契约参数 - */ - protected void scanMethodParameters() { - Annotation[][] allAnnotations = providerMethod.getParameterAnnotations(); - Type[] parameterTypes = providerMethod.getGenericParameterTypes(); - for (int paramIdx = 0; paramIdx < parameterTypes.length; paramIdx++) { - int swaggerParamCount = providerParameters.size(); - Type type = parameterTypes[paramIdx]; - - // 根据annotation处理 - Annotation[] paramAnnotations = allAnnotations[paramIdx]; - processByParameterAnnotation(paramAnnotations, paramIdx, type); - - if (isArgumentNotProcessed(swaggerParamCount)) { - // 是否需要根据参数类型处理,目标场景:httpRequest之类 - processByParameterType(type, paramIdx); - } - - if (isArgumentNotProcessed(swaggerParamCount)) { - // 没有用于描述契约的标注,根据函数原型来反射生成 - context.getDefaultParamProcessor().process(this, paramIdx); - } - - if (!isArgumentNotProcessed(swaggerParamCount)) { - Parameter parameter = providerParameters.get(this.providerParameters.size() - 1); - AnnotationUtils.processApiParam(paramAnnotations, parameter); - } - } - } - - private boolean isArgumentNotProcessed(int swaggerParamCount) { - return swaggerParamCount == providerParameters.size(); - } - - @SuppressWarnings({"rawtypes"}) - protected void processByParameterAnnotation(Annotation[] paramAnnotations, int paramIdx, Type parameterType) { - String defaultValue = null; - Parameter parameter = null; - for (Annotation annotation : paramAnnotations) { - //JAX-RS default value cannot be mapped to parameter name directly, stored it to map with the actual parameter - if (annotation instanceof DefaultValue) { - defaultValue = ((DefaultValue) annotation).value(); - } else { - ParameterAnnotationProcessor processor = - context.findParameterAnnotationProcessor(annotation.annotationType()); - if (processor != null) { - processor.process(annotation, this, paramIdx); - parameter = this.providerParameters.get(this.providerParameters.size() - 1); - } - } - } - if (parameter instanceof AbstractSerializableParameter) { - if (defaultValue != null) { - ((AbstractSerializableParameter) parameter).setDefaultValue(defaultValue); - } else if ((((AbstractSerializableParameter) parameter).getDefaultValue() == null) - && (!((AbstractSerializableParameter) parameter) - .getRequired())) { //if required false then only take java primitive values as defaults - if (parameterType instanceof Class && ((Class) parameterType).isPrimitive()) { - switch (parameterType.getTypeName()) { - case "boolean": - defaultValue = "false"; - break; - default: - defaultValue = "0"; - } - } - ((AbstractSerializableParameter) parameter).setDefaultValue(defaultValue); - } - } - } - - protected void processByParameterType(Type parameterType, int paramIdx) { - ParameterTypeProcessor processor = context.findParameterTypeProcessor(parameterType); - if (processor != null) { - processor.process(this, paramIdx); - } - } - - public void correctOperation() { - if (StringUtils.isEmpty(operation.getOperationId())) { - operation.setOperationId(providerMethod.getName()); - } - - context.postProcessOperation(this); - - SwaggerUtils.correctResponses(operation); - addHeaderToResponse(); - } - - private void addHeaderToResponse() { - for (Entry responseEntry : operation.getResponses().entrySet()) { - Response response = responseEntry.getValue(); - - for (Entry entry : responseHeaderMap.entrySet()) { - if (response.getHeaders() != null && response.getHeaders().containsKey(entry.getKey())) { - continue; - } - - response.addHeader(entry.getKey(), entry.getValue()); - } - } - } - - public void scanResponse() { - if (operation.getResponses() != null) { - Response successResponse = operation.getResponses().get(SwaggerConst.SUCCESS_KEY); - if (successResponse != null) { - if (successResponse.getSchema() == null) { - // 标注已经定义了response,但是是void,这可能是在标注上未定义 - // 根据函数原型来处理response - Property property = createResponseProperty(); - successResponse.setSchema(property); - } - return; - } - } - - Property property = createResponseProperty(); - Response response = new Response(); - response.setSchema(property); - operation.addResponse(SwaggerConst.SUCCESS_KEY, response); - } - - protected Property createResponseProperty() { - Type responseType = providerMethod.getReturnType(); - if (ReflectionUtils.isVoid(responseType)) { - return null; - } - - ResponseTypeProcessor processor = context.findResponseTypeProcessor(responseType); - return processor.process(this); - } - - public Method getProviderMethod() { - return providerMethod; - } - - protected void addOperationToSwagger() { - if (StringUtils.isEmpty(httpMethod)) { - return; - } - - Path pathObj = swagger.getPath(path); - if (pathObj == null) { - pathObj = new Path(); - swagger.path(path, pathObj); - } - - HttpMethod hm = HttpMethod.valueOf(httpMethod.toUpperCase(Locale.US)); - if (pathObj.getOperationMap().get(hm) != null) { - throw new Error(String.format("Only allowed one default path. %s:%s", - swaggerGenerator.getCls().getName(), - providerMethod.getName())); - } - pathObj.set(httpMethod, operation); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGeneratorContext.java new file mode 100644 index 00000000000..3cf1105c836 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGeneratorContext.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.swagger.generator.SwaggerConst; + +import com.fasterxml.jackson.databind.JavaType; + +import io.swagger.v3.oas.models.media.Schema; + +public class OperationGeneratorContext extends SwaggerGeneratorContext { + private final Map> responses = new HashMap<>(); + + private JavaType responseType; + + private final Map responseDescriptions = new HashMap<>(); + + // statusCode:headerName:headerSchema + private final Map>> responseHeaders = new HashMap<>(); + + public OperationGeneratorContext(SwaggerGeneratorContext parent) { + super(parent); + updateResponse(SwaggerConst.SUCCESS_KEY, null); + } + + public Map> getResponses() { + return responses; + } + + public void updateResponse(String code, Schema schema) { + this.responses.put(code, schema); + } + + public JavaType getResponseType() { + return responseType; + } + + public void setResponseType(JavaType responseType) { + this.responseType = responseType; + } + + public Map getResponseDescriptions() { + return responseDescriptions; + } + + public void updateResponseDescription(String code, String description) { + this.responseDescriptions.put(code, description); + } + + public Map>> getResponseHeaders() { + return responseHeaders; + } + + public void updateResponseHeader(String code, String header, Schema schema) { + this.responseHeaders.computeIfAbsent(code, key -> new HashMap<>()); + this.responseHeaders.get(code).put(header, schema); + } + + public void updateProduces() { + List removed = new ArrayList<>(); + for (String media : supportedProduces) { + if (SUPPORTED_BODY_CONTENT_TYPE.contains(media)) { + continue; + } + removed.add(media); + } + supportedProduces.removeAll(removed); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterAnnotationProcessor.java deleted file mode 100644 index 465b8678aa5..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterAnnotationProcessor.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -public interface ParameterAnnotationProcessor { - // 在ApiImplicitParam场景中paramIdx为-1 - void process(Object annotation, OperationGenerator operationGenerator, int paramIdx); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterGeneratorContext.java new file mode 100644 index 00000000000..dc9f6c9c0da --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ParameterGeneratorContext.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import com.fasterxml.jackson.databind.JavaType; + +import io.swagger.v3.oas.models.media.Schema; +import jakarta.ws.rs.core.MediaType; + +public class ParameterGeneratorContext extends OperationGeneratorContext { + /** + * Parameter type. Maybe override by annotations. And for pojo wrapped parameter, + * this is null. + */ + private JavaType parameterType; + + private String parameterName; + + private HttpParameterType httpParameterType; + + private Boolean explode; + + private Boolean required; + + private Object defaultValue; + + private Boolean rawJson; + + private Schema schema; + + public ParameterGeneratorContext(OperationGeneratorContext parent) { + super(parent); + } + + public JavaType getParameterType() { + return parameterType; + } + + public void setParameterType(JavaType parameterType) { + this.parameterType = parameterType; + } + + public String getParameterName() { + return parameterName; + } + + public void setParameterName(String parameterName) { + this.parameterName = parameterName; + } + + public Boolean getExplode() { + return explode; + } + + public void setExplode(Boolean explode) { + this.explode = explode; + } + + public Boolean getRequired() { + return required; + } + + public void setRequired(Boolean required) { + this.required = required; + } + + public Boolean getRawJson() { + return rawJson; + } + + public void setRawJson(Boolean rawJson) { + this.rawJson = rawJson; + } + + public Schema getSchema() { + return schema; + } + + public void setSchema(Schema schema) { + this.schema = schema; + } + + public HttpParameterType getHttpParameterType() { + return httpParameterType; + } + + public void setHttpParameterType(HttpParameterType httpParameterType) { + this.httpParameterType = httpParameterType; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + public void updateConsumes(boolean isForm, boolean isBinary, boolean isWebSocket) { + List removed = new ArrayList<>(); + if (isWebSocket) { + supportedConsumes.clear(); + supportedConsumes.add(SwaggerConst.WEBSOCKET_TYPE); + return; + } + + if (httpParameterType == HttpParameterType.BODY) { + if (isForm) { + throw new IllegalArgumentException("Both form and body parameter not allowed."); + } + for (String media : supportedConsumes) { + if (SUPPORTED_BODY_CONTENT_TYPE.contains(media)) { + continue; + } + removed.add(media); + } + supportedConsumes.removeAll(removed); + return; + } + + if (httpParameterType == HttpParameterType.FORM) { + for (String media : supportedConsumes) { + if (!SUPPORTED_FORM_CONTENT_TYPE.contains(media)) { + removed.add(media); + continue; + } + if (isBinary && supportedConsumes.contains(MediaType.APPLICATION_FORM_URLENCODED)) { + removed.add(MediaType.APPLICATION_FORM_URLENCODED); + } + if (!isBinary && supportedConsumes.contains(MediaType.MULTIPART_FORM_DATA)) { + removed.add(MediaType.MULTIPART_FORM_DATA); + } + } + supportedConsumes.removeAll(removed); + return; + } + + supportedConsumes.clear(); + } + + public boolean isForm() { + return httpParameterType == HttpParameterType.FORM; + } + + public boolean isBinary() { + if ("string".equals(this.schema.getType()) && "binary".equals(this.schema.getFormat())) { + return true; + } + + return "array".equals(this.schema.getType()) && + "string".equals(this.schema.getItems().getType()) && + "binary".equals(this.schema.getItems().getFormat()); + } + + public boolean isObject() { + return "object".equals(this.schema.getType()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ResponseTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ResponseTypeProcessor.java deleted file mode 100644 index 9e60e3fe1c2..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/ResponseTypeProcessor.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core; - -import io.swagger.models.properties.Property; - -public interface ResponseTypeProcessor { - Class getResponseType(); - - // void的场景,不会到processor中来处理 - Property process(OperationGenerator operationGenerator); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerConst.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerConst.java deleted file mode 100644 index f97a5ea512d..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerConst.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import javax.ws.rs.core.Response; - -public final class SwaggerConst { - private SwaggerConst() { - - } - - public static final String SUCCESS_KEY = String.valueOf(Response.Status.OK.getStatusCode()); - - public static final String EXT_JAVA_INTF = "x-java-interface"; - - public static final String EXT_JAVA_CLASS = "x-java-class"; - - public static final String EXT_RAW_JSON_TYPE = "x-raw-json"; -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGenerator.java deleted file mode 100644 index 919711ef279..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGenerator.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.springframework.util.StringUtils; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.models.Info; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; -import io.swagger.models.Tag; -import io.swagger.models.parameters.Parameter; - -/** - * 根据class提取swagger信息 - * 支持以下场景的使用: - * 1.pojo + swagger annotation - * 2.pojo + swagger annotation + jaxrs annotation - * 3.pojo + swagger annotation + springmvc annotation - * 场景1,使用默认规则处理rest入参,比如将所有参数包装为一个class,统一放在body中 - * jaxrs/spring mvc的场景,需要配合各自的插件jar包 - * 非场景1,如果标注不完整,仍然会尝试使用场景1的规则产生默认数据 - */ -public class SwaggerGenerator { - protected SwaggerGeneratorContext context; - - // 需要生成class时,使用这个值 - protected String packageName; - - // 动态生成的class,加载在该classLoader中 - // 如果为null,表示加载在线程相关的classLoader中 - protected ClassLoader classLoader; - - protected Class cls; - - protected Swagger swagger; - - /** - * According to the definition of swagger, the {@link Tag} defined in {@link Api#tags()} will be set - * to all of the operations in this swagger. And the {@link Tag} definde in {@link ApiOperation#tags()} will overwrite - * the {@link Api#tags()}. - */ - protected Set defaultTags = new LinkedHashSet<>(); - - private Map operationGeneratorMap = new LinkedHashMap<>(); - - private String httpMethod; - - public SwaggerGenerator(SwaggerGeneratorContext context, Class cls) { - this.swagger = new Swagger(); - this.context = context; - this.cls = cls; - this.classLoader = JvmUtils.findClassLoader(); - this.packageName = "gen.swagger"; - } - - public SwaggerGeneratorContext getContext() { - return context; - } - - public void setPackageName(String packageName) { - this.packageName = packageName; - } - - public String ensureGetPackageName() { - // 不自动指定package,还是事先规划会比较合适 - if (packageName == null) { - throw new Error("package name must not be null."); - } - - return packageName; - } - - public ClassLoader getClassLoader() { - return classLoader; - } - - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - public Swagger getSwagger() { - return swagger; - } - - public Class getCls() { - return cls; - } - - public String getHttpMethod() { - return httpMethod; - } - - public void setHttpMethod(String httpMethod) { - this.httpMethod = httpMethod.toLowerCase(Locale.US); - } - - public Swagger generate() { - for (Annotation annotation : cls.getAnnotations()) { - ClassAnnotationProcessor processor = context.findClassAnnotationProcessor(annotation.annotationType()); - if (processor == null) { - continue; - } - processor.process(annotation, this); - } - - scanMethods(); - addOperationsToSwagger(); - - correctSwagger(); - - return swagger; - } - - /** - * 查找必填但是没值的字段,将之设置为默认值 - * 如果无法构造默认值,则抛出异常 - */ - protected void correctSwagger() { - if (StringUtils.isEmpty(swagger.getSwagger())) { - swagger.setSwagger("2.0"); - } - - correctBasePath(); - correctInfo(); - correctProduces(); - correctConsumes(); - } - - private void correctProduces() { - List produces = swagger.getProduces(); - if (produces == null || produces.isEmpty()) { - produces = Arrays.asList(MediaType.APPLICATION_JSON); - swagger.setProduces(produces); - } - } - - private void correctConsumes() { - List consumes = swagger.getConsumes(); - if (consumes == null || consumes.isEmpty()) { - consumes = Arrays.asList(MediaType.APPLICATION_JSON); - swagger.setConsumes(consumes); - } - } - - protected void correctBasePath() { - String basePath = swagger.getBasePath(); - if (StringUtils.isEmpty(basePath)) { - basePath = "/" + cls.getSimpleName(); - } - if (!basePath.startsWith("/")) { - basePath = "/" + basePath; - } - swagger.setBasePath(basePath); - } - - private void correctInfo() { - Info info = swagger.getInfo(); - if (info == null) { - info = new Info(); - swagger.setInfo(info); - } - - if (StringUtils.isEmpty(info.getTitle())) { - info.setTitle("swagger definition for " + cls.getName()); - } - if (StringUtils.isEmpty(info.getVersion())) { - info.setVersion("1.0.0"); - } - - setJavaInterface(info, cls); - } - - protected void setJavaInterface(Info info, Class cls) { - if (cls.isInterface() && !isInterfaceReactive(cls)) { - info.setVendorExtension(SwaggerConst.EXT_JAVA_INTF, cls.getName()); - return; - } - - // Class[] interfaces = cls.getInterfaces(); - // if (interfaces.length == 1) { - // info.setVendorExtension(SwaggerConst.EXT_JAVA_INTF, interfaces[0].getName()); - // return; - // } - - String intfName = ensureGetPackageName() + "." + cls.getSimpleName() + "Intf"; - info.setVendorExtension(SwaggerConst.EXT_JAVA_INTF, intfName); - } - - /** - * Whether this interface class is reactive. - * This is used for the situation that the {@code interfaceCls} may be used as swagger interface directly - */ - private boolean isInterfaceReactive(Class interfaceCls) { - for (Method method : interfaceCls.getDeclaredMethods()) { - if (isSkipMethod(method)) { - continue; - } - if (CompletableFuture.class.isAssignableFrom(method.getReturnType())) { - return true; - } - } - return false; - } - - /** - * Whether this method should be processed as a swagger operation - * @return true if this isn't a swagger operation; otherwise, false. - */ - protected boolean isSkipMethod(Method method) { - if (method.getDeclaringClass().getName().equals(Object.class.getName())) { - return true; - } - // skip static method - int modifiers = method.getModifiers(); - if (Modifier.isStatic(modifiers)) { - return true; - } - - ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); - if (apiOperation != null && apiOperation.hidden()) { - return apiOperation.hidden(); - } - - return !context.canProcess(method); - } - - protected void scanMethods() { - // 有时方法顺序不同,很不利于测试,所以先排序 - List methods = Arrays.asList(cls.getMethods()); - methods.sort(Comparator.comparing(Method::getName)); - for (Method method : methods) { - if (isSkipMethod(method)) { - continue; - } - OperationGenerator operationGenerator = new OperationGenerator(this, method); - operationGenerator.setHttpMethod(httpMethod); - try { - operationGenerator.generate(); - } catch (Throwable e) { - String msg = - String.format("generate operation swagger failed, %s:%s", this.cls.getName(), method.getName()); - throw new Error(msg, e); - } - - String operationId = operationGenerator.getOperation().getOperationId(); - if (operationGeneratorMap.containsKey(operationId)) { - throw new Error(String.format("OperationId must be unique. %s:%s", cls.getName(), method.getName())); - } - operationGeneratorMap.put(operationId, operationGenerator); - } - } - - protected void addOperationsToSwagger() { - for (OperationGenerator operationGenerator : operationGeneratorMap.values()) { - operationGenerator.addOperationToSwagger(); - } - } - - public void setBasePath(String basePath) { - basePath = context.resolveStringValue(basePath); - swagger.setBasePath(basePath); - } - - public Map getOperationGeneratorMap() { - return operationGeneratorMap; - } - - public List findProviderParameter(String methodName) { - OperationGenerator operationGenerator = operationGeneratorMap.get(methodName); - if (operationGenerator == null) { - throw new Error("method not found, name=" + methodName); - } - - return operationGenerator.getProviderParameters(); - } - - public List findSwaggerParameter(String methodName) { - for (Path path : swagger.getPaths().values()) { - for (Operation operation : path.getOperations()) { - if (methodName.equals(operation.getOperationId())) { - return operation.getParameters(); - } - } - } - - throw new Error("method not found, name=" + methodName); - } - - /** - * Add a tag to {@link #defaultTags} if the corresponding tag not exists. - * @param tagName the name of the added tag - */ - public void addDefaultTag(String tagName) { - if (StringUtils.isEmpty(tagName) || defaultTags.contains(tagName)) { - return; - } - - defaultTags.add(tagName); - } - - public Set getDefaultTags() { - return defaultTags; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGeneratorContext.java index 0feb620e473..7b1eeda13e0 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGeneratorContext.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/SwaggerGeneratorContext.java @@ -14,38 +14,75 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.servicecomb.swagger.generator.core; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.swagger.generator.SwaggerConst; + +import jakarta.ws.rs.core.MediaType; + +/** + * Context information to help generate specific open api parts. + */ +public class SwaggerGeneratorContext { + protected static final List SUPPORTED_CONTENT_TYPE + = Arrays.asList(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, MediaType.TEXT_PLAIN, + MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_FORM_URLENCODED, SwaggerConst.WEBSOCKET_TYPE, + MediaType.SERVER_SENT_EVENTS); -public interface SwaggerGeneratorContext { - // 用于排序,规避cse中定义的restSchema无法识别是jaxrs还是springmvc模式的问题 - // 实际使用时springmvc的context优先级最高 - int getOrder(); + protected static final List SUPPORTED_BODY_CONTENT_TYPE + = Arrays.asList(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, + MediaType.TEXT_PLAIN); - boolean canProcess(Class cls); + protected static final List SUPPORTED_FORM_CONTENT_TYPE + = Arrays.asList(MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_FORM_URLENCODED); - boolean canProcess(Method method); + protected List supportedConsumes; - ClassAnnotationProcessor findClassAnnotationProcessor(Class annotationType); + protected List supportedProduces; - MethodAnnotationProcessor findMethodAnnotationProcessor(Class annotationType); + public SwaggerGeneratorContext() { + supportedConsumes = new ArrayList<>(); + supportedConsumes.addAll(SUPPORTED_CONTENT_TYPE); + supportedProduces = new ArrayList<>(); + supportedProduces.addAll(SUPPORTED_CONTENT_TYPE); + } - ParameterAnnotationProcessor findParameterAnnotationProcessor(Class annotationType); + public SwaggerGeneratorContext(SwaggerGeneratorContext parent) { + supportedConsumes = new ArrayList<>(); + supportedConsumes.addAll(parent.supportedConsumes); + supportedProduces = new ArrayList<>(); + supportedProduces.addAll(parent.supportedProduces); + } - // 管理方法入参的processor,用于支撑httpRequest、Context之类的特殊处理 - // key为class - ParameterTypeProcessor findParameterTypeProcessor(Type parameterType); + public void updateProduces(List produces) { + checkMediaTypeValid(produces); + supportedProduces.clear(); + supportedProduces.addAll(produces); + } - // 经过所有步骤后,仍然无法被处理的参数的默认处理器 - DefaultParameterProcessor getDefaultParamProcessor(); + public void updateConsumes(List consumes) { + checkMediaTypeValid(consumes); + supportedConsumes.clear(); + supportedConsumes.addAll(consumes); + } - ResponseTypeProcessor findResponseTypeProcessor(Type responseType); + public List getSupportedConsumes() { + return supportedConsumes; + } - void postProcessOperation(OperationGenerator operationGenerator); + public List getSupportedProduces() { + return supportedProduces; + } - String resolveStringValue(String strVal); + private void checkMediaTypeValid(List produces) { + for (String produce : produces) { + if (!SUPPORTED_CONTENT_TYPE.contains(produce)) { + throw new IllegalArgumentException("Not support media type " + produce); + } + } + } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/HttpParameterType.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/HttpParameterType.java new file mode 100644 index 00000000000..00254e99b3f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/HttpParameterType.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.model; + +import java.util.Locale; + +import org.apache.commons.lang3.StringUtils; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; + +public enum HttpParameterType { + /** io.swagger.v3.oas.annotations.enums.ParameterIn.PATH */ + PATH, + /** io.swagger.v3.oas.annotations.enums.ParameterIn.QUERY */ + QUERY, + /** io.swagger.v3.oas.annotations.enums.ParameterIn.HEADER */ + HEADER, + /** io.swagger.v3.oas.annotations.enums.ParameterIn.COOKIE */ + COOKIE, + + /** request bodies: application/x-www-form-urlencoded, multipart/form-data */ + FORM, + + /** request bodies: application/json, etc. */ + BODY; + + public static HttpParameterType from(ParameterIn in) { + return switch (in) { + case COOKIE -> HttpParameterType.COOKIE; + case QUERY -> HttpParameterType.QUERY; + case HEADER -> HttpParameterType.HEADER; + case PATH -> HttpParameterType.PATH; + default -> null; + }; + } + + public static HttpParameterType parse(String value) { + if (StringUtils.isEmpty(value)) { + return null; + } + + return HttpParameterType.valueOf(value.toUpperCase(Locale.US)); + } + + public static boolean isBodyParameter(HttpParameterType type) { + return BODY == type || FORM == type; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperation.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperation.java new file mode 100644 index 00000000000..5aedab55f4d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperation.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.model; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem.HttpMethod; + +public class SwaggerOperation { + private final OpenAPI swagger; + + private final String path; + + private final HttpMethod httpMethod; + + private final Operation operation; + + public SwaggerOperation(OpenAPI swagger, String path, HttpMethod httpMethod, Operation operation) { + this.swagger = swagger; + this.path = path; + this.httpMethod = httpMethod; + this.operation = operation; + } + + public int parameterCount() { + int result = 0; + if (operation.getRequestBody() != null) { + result++; + } + if (operation.getParameters() != null) { + result += operation.getParameters().size(); + } + return result; + } + + public OpenAPI getSwagger() { + return swagger; + } + + public String getPath() { + return path; + } + + public HttpMethod getHttpMethod() { + return httpMethod; + } + + public Operation getOperation() { + return operation; + } + + public String getOperationId() { + return operation.getOperationId(); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperations.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperations.java new file mode 100644 index 00000000000..487685b228f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/model/SwaggerOperations.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.PathItem.HttpMethod; +import io.swagger.v3.oas.models.Paths; + +public class SwaggerOperations { + public static SwaggerOperations generate(Class cls) { + OpenAPI swagger = SwaggerGenerator.create(cls).generate(); + return new SwaggerOperations(swagger); + } + + private final OpenAPI swagger; + + // key is operationId + private final Map operations = new HashMap<>(); + + public SwaggerOperations(OpenAPI swagger) { + this.swagger = swagger; + Paths paths = swagger.getPaths(); + if (paths == null || paths.isEmpty()) { + return; + } + + for (Entry pathEntry : paths.entrySet()) { + for (Entry operationEntry : pathEntry.getValue().readOperationsMap().entrySet()) { + if (StringUtils.isEmpty(operationEntry.getValue().getOperationId())) { + throw new IllegalStateException(String + .format("OperationId can not be empty, path=%s, httpMethod=%s.", + pathEntry.getKey(), operationEntry.getKey())); + } + + SwaggerOperation swaggerOperation = new SwaggerOperation(swagger, pathEntry.getKey(), operationEntry.getKey(), + operationEntry.getValue()); + if (operations.putIfAbsent(operationEntry.getValue().getOperationId(), swaggerOperation) != null) { + throw new IllegalStateException( + "please make sure operationId is unique, duplicated operationId is " + operationEntry.getValue() + .getOperationId()); + } + } + } + } + + public OpenAPI getSwagger() { + return swagger; + } + + public SwaggerOperation findOperation(String operationId) { + return operations.get(operationId); + } + + public Map getOperations() { + return operations; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/package-info.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/package-info.java deleted file mode 100644 index 9d14694466b..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * 根据annotation及接口反射,反向生成swagger - * 本package中的功能会被cse依赖,但是不会依赖cse的概念 - */ -package org.apache.servicecomb.swagger.generator.core; diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java index 2193f8e29a5..532c5efdd33 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/AnnotationUtils.java @@ -17,327 +17,319 @@ package org.apache.servicecomb.swagger.generator.core.processor.annotation; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseConfig; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseConfigBase; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseHeaderConfig; -import org.springframework.util.ClassUtils; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; -import io.swagger.annotations.ResponseHeader; -import io.swagger.converter.ModelConverters; -import io.swagger.models.Model; -import io.swagger.models.Operation; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.CookieParameter; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.LongProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; -import io.swagger.util.ParameterProcessor; -import io.swagger.util.ReflectionUtils; - +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.servers.Server; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.MediaType; + +/** + * Utility class to convert from OpenAPI annotations to models. + */ +@SuppressWarnings({"rawtypes", "unchecked"}) public final class AnnotationUtils { private AnnotationUtils() { } - public static void appendDefinition(Swagger swagger, Map newDefinitions) { - if (newDefinitions.isEmpty()) { - return; - } - - Map definitions = swagger.getDefinitions(); - if (definitions == null) { - definitions = new LinkedHashMap<>(); - swagger.setDefinitions(definitions); + public static List serversModel(Server[] servers) { + if (servers == null) { + return null; } - - definitions.putAll(newDefinitions); - } - - private static ResponseConfig convert(ApiOperation apiOperation) { - ResponseConfig responseConfig = new ResponseConfig(); - responseConfig.setCode(apiOperation.code()); - responseConfig.setResponseClass(apiOperation.response()); - responseConfig.setResponseContainer(apiOperation.responseContainer()); - responseConfig.setResponseReference(apiOperation.responseReference()); - responseConfig.setResponseHeaders(apiOperation.responseHeaders()); - return responseConfig; + return Arrays.stream(servers).map(AnnotationUtils::convertServer).collect(Collectors.toList()); } - private static ResponseConfig convert(ApiResponse apiResponse) { - ResponseConfig responseConfig = new ResponseConfig(); - responseConfig.setCode(apiResponse.code()); - responseConfig.setDescription(apiResponse.message()); - responseConfig.setResponseClass(apiResponse.response()); - responseConfig.setResponseContainer(apiResponse.responseContainer()); - responseConfig.setResponseReference(apiResponse.reference()); - responseConfig.setResponseHeaders(apiResponse.responseHeaders()); - return responseConfig; + public static io.swagger.v3.oas.models.servers.Server convertServer(Server server) { + io.swagger.v3.oas.models.servers.Server item = new io.swagger.v3.oas.models.servers.Server(); + item.setUrl(server.url()); + item.setDescription(server.description()); + return item; } - public static ResponseHeaderConfig convert(ResponseHeader responseHeader) { - if (StringUtils.isEmpty(responseHeader.name())) { + public static io.swagger.v3.oas.models.info.Info infoModel(Info infoAnnotation) { + if (infoAnnotation == null) { return null; } - ResponseHeaderConfig config = new ResponseHeaderConfig(); - config.setName(responseHeader.name()); - config.setDescription(responseHeader.description()); - config.setResponseClass(responseHeader.response()); - config.setResponseContainer(responseHeader.responseContainer()); - return config; - } + io.swagger.v3.oas.models.info.Info info = new io.swagger.v3.oas.models.info.Info(); - public static void addResponse(Swagger swagger, Operation operation, ApiOperation apiOperation) { - ResponseConfig responseConfig = convert(apiOperation); - generateResponse(swagger, responseConfig); - mergeResponse(operation, responseConfig); - } + info.setTitle(infoAnnotation.title()); + info.setVersion(infoAnnotation.version()); + if (StringUtils.isNotEmpty(infoAnnotation.description())) { + info.setDescription(infoAnnotation.description()); + } + if (StringUtils.isNotEmpty(infoAnnotation.termsOfService())) { + info.setTermsOfService(infoAnnotation.termsOfService()); + } + info.setContact(contactModel(infoAnnotation.contact())); + info.setLicense(licenseModel(infoAnnotation.license())); + info.setExtensions(extensionsModel(infoAnnotation.extensions())); - public static void addResponse(Swagger swagger, ApiResponse apiResponse) { - ResponseConfig responseConfig = convert(apiResponse); - generateResponse(swagger, responseConfig); - swagger.response(String.valueOf(responseConfig.getCode()), responseConfig.getResponse()); + return info; } - public static void addResponse(Swagger swagger, Operation operation, ApiResponse apiResponse) { - ResponseConfig responseConfig = convert(apiResponse); - generateResponse(swagger, responseConfig); - mergeResponse(operation, responseConfig); - } + public static io.swagger.v3.oas.models.info.License licenseModel(License licenseAnnotation) { + io.swagger.v3.oas.models.info.License license = new io.swagger.v3.oas.models.info.License(); - private static void mergeResponse(Operation operation, ResponseConfig responseConfig) { - if (operation.getResponses() == null) { - operation.response(responseConfig.getCode(), responseConfig.getResponse()); - return; - } - Response response = operation.getResponses().get(String.valueOf(responseConfig.getCode())); - if (response == null) { - operation.response(responseConfig.getCode(), responseConfig.getResponse()); - return; - } - Response sourceResp = responseConfig.getResponse(); - if (StringUtils.isNotEmpty(sourceResp.getDescription()) && StringUtils.isEmpty(response.getDescription())) { - response.setDescription(sourceResp.getDescription()); - } - if (sourceResp.getSchema() != null && response.getSchema() == null) { - response.setSchema(sourceResp.getSchema()); + if (StringUtils.isNotEmpty(licenseAnnotation.name())) { + license.setName(licenseAnnotation.name()); } - if (sourceResp.getExamples() != null && response.getExamples() == null) { - response.setExamples(sourceResp.getExamples()); + if (StringUtils.isNotEmpty(licenseAnnotation.url())) { + license.setUrl(licenseAnnotation.url()); } - if (sourceResp.getHeaders() != null && response.getHeaders() == null) { - response.setHeaders(sourceResp.getHeaders()); - } - if (sourceResp.getVendorExtensions() != null && response.getVendorExtensions() == null) { - response.setVendorExtensions(sourceResp.getVendorExtensions()); + + if (StringUtils.isEmpty(license.getName()) && StringUtils.isEmpty(license.getUrl())) { + return null; } + + return license; } - private static void generateResponse(Swagger swagger, ResponseConfig responseConfig) { - Response response = new Response(); + public static io.swagger.v3.oas.models.info.Contact contactModel(Contact contactAnnotation) { + io.swagger.v3.oas.models.info.Contact contact = new io.swagger.v3.oas.models.info.Contact(); - Property property = generateResponseProperty(swagger, responseConfig); - response.setSchema(property); - response.setDescription(responseConfig.getDescription()); + if (StringUtils.isNotEmpty(contactAnnotation.name())) { + contact.setName(contactAnnotation.name()); + } + if (StringUtils.isNotEmpty(contactAnnotation.url())) { + contact.setUrl(contactAnnotation.url()); + } + if (StringUtils.isNotEmpty(contactAnnotation.email())) { + contact.setEmail(contactAnnotation.email()); + } - if (responseConfig.getResponseHeaders() != null) { - Map headers = generateResponseHeader(swagger, responseConfig.getResponseHeaders()); - response.setHeaders(headers); + if (StringUtils.isEmpty(contact.getName()) && + StringUtils.isEmpty(contact.getUrl()) && + StringUtils.isEmpty(contact.getEmail())) { + return null; } - responseConfig.setResponse(response); + return contact; } - private static Map generateResponseHeader(Swagger swagger, - List responseHeaders) { - Map headers = new HashMap<>(); - for (ResponseHeaderConfig config : responseHeaders) { - Property property = generateResponseHeaderProperty(swagger, config); - headers.put(config.getName(), property); + public static List tagsModel(Tag[] tagArray) { + if (tagArray == null) { + return null; } - return headers; - } - public static Property generateResponseHeaderProperty(Swagger swagger, ResponseHeaderConfig config) throws Error { - Property property = generateResponseProperty(swagger, config); - if (property == null) { - throw new Error("invalid responseHeader, " + config); - } - return property; + List tags = Arrays.stream(tagArray) + .filter(t -> !t.name().isEmpty()) + .map(AnnotationUtils::tagModel) + .collect(Collectors.toList()); + return tags.isEmpty() ? null : tags; } - public static Property generateResponseProperty(Swagger swagger, ResponseConfigBase config) throws Error { - Class responseClass = config.getResponseClass(); - if (responseClass == null || ReflectionUtils.isVoid(responseClass)) { + public static List tagsModel(String[] tagArray) { + if (tagArray == null) { return null; } - if (!ClassUtils.isPrimitiveOrWrapper(responseClass)) { - Map newDefinitions = ModelConverters.getInstance().readAll(responseClass); - appendDefinition(swagger, newDefinitions); - } + List tags = Arrays.stream(tagArray) + .filter(t -> !t.isEmpty()) + .collect(Collectors.toList()); + return tags.isEmpty() ? null : tags; + } - Property property = ModelConverters.getInstance().readAsProperty(responseClass); - // responseContainer只可能是:"List", "Set" or "Map" - // 根据swagger定义这里是区分大小写的, 虽然不明白为何这样做,不过还是不要改标准了 - switch (config.getResponseContainer()) { - case "List": - property = new ArrayProperty(property); - break; - case "Set": - property = new ArrayProperty(property); - ((ArrayProperty) property).setUniqueItems(true); - break; - case "Map": - property = new MapProperty(property); - break; - case "": - // 不必处理 - break; - default: - throw new Error("not support responseContainer " + config.getResponseContainer()); - } - return property; + public static io.swagger.v3.oas.models.tags.Tag tagModel(Tag tagAnnotation) { + io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag(); + tag.setName(tagAnnotation.name()); + tag.setDescription(tagAnnotation.description()); + tag.setExternalDocs(externalDocumentationModel(tagAnnotation.externalDocs())); + tag.setExtensions(extensionsModel(tagAnnotation.extensions())); + return tag; } - public static Parameter createParameter(Swagger swagger, ApiImplicitParam paramAnnotation) { - Parameter parameter = createParameterInstance(paramAnnotation); - Type dataType = ReflectionUtils.typeFromString(paramAnnotation.dataType()); - parameter = ParameterProcessor.applyAnnotations(swagger, - parameter, - dataType, - Arrays.asList(paramAnnotation)); - return parameter; + public static io.swagger.v3.oas.models.ExternalDocumentation externalDocumentationModel( + ExternalDocumentation externalDocs) { + io.swagger.v3.oas.models.ExternalDocumentation doc = new io.swagger.v3.oas.models.ExternalDocumentation(); + doc.setUrl(externalDocs.url()); + doc.setDescription(externalDocs.description()); + return doc; } - private static Parameter createParameterInstance(ApiImplicitParam paramAnnotation) { - switch (paramAnnotation.paramType()) { - case "path": - return new PathParameter(); - case "query": - return new QueryParameter(); - case "body": - return new BodyParameter(); - case "header": - return new HeaderParameter(); - case "form": - return new FormParameter(); - case "cookie": - return new CookieParameter(); - default: - throw new Error("not support paramType " + paramAnnotation.paramType()); - } + public static Map extensionsModel(Extension[] extensions) { + Map result = new HashMap<>(); + Stream.of(extensions).forEach(e -> result.put(e.name(), extensionPropertiesModel(e.properties()))); + return result; } - @SuppressWarnings("unchecked") - public static T findAnnotation(Annotation[] annotations, Class annotationType) { - for (Annotation annotation : annotations) { - if (annotation.annotationType().equals(annotationType)) { - return (T) annotation; - } - } + public static Map extensionPropertiesModel(ExtensionProperty[] properties) { + Map result = new HashMap<>(); + Stream.of(properties).forEach(e -> result.put(e.name(), e.value())); + return result; + } - return null; + public static String responseCodeModel(ApiResponse apiResponse) { + if (StringUtils.isEmpty(apiResponse.responseCode())) { + return "200"; + } + return apiResponse.responseCode(); } - public static void processApiParam(Annotation[] paramAnnotations, Parameter parameter) { - ApiParam param = findAnnotation(paramAnnotations, ApiParam.class); - if (param == null) { - return; + public static io.swagger.v3.oas.models.responses.ApiResponses apiResponsesModel(OpenAPI openAPI, + ApiResponses apiResponses) { + io.swagger.v3.oas.models.responses.ApiResponses result = + new io.swagger.v3.oas.models.responses.ApiResponses(); + result.setExtensions(extensionsModel(apiResponses.extensions())); + for (ApiResponse apiResponse : apiResponses.value()) { + result.addApiResponse(responseCodeModel(apiResponse), apiResponseModel(openAPI, apiResponse)); } + return result; + } - if (parameter instanceof AbstractSerializableParameter) { - processApiParam(param, (AbstractSerializableParameter) parameter); - return; + public static io.swagger.v3.oas.models.responses.ApiResponses apiResponsesModel(OpenAPI openAPI, + ApiResponse[] apiResponses) { + io.swagger.v3.oas.models.responses.ApiResponses result = + new io.swagger.v3.oas.models.responses.ApiResponses(); + for (ApiResponse apiResponse : apiResponses) { + if (result.get(responseCodeModel(apiResponse)) != null) { + throw new IllegalStateException("not support too many ApiResponse with same status code"); + } else { + result.addApiResponse(responseCodeModel(apiResponse), apiResponseModel(openAPI, apiResponse)); + } } + return result; + } - processApiParam(param, (BodyParameter) parameter); + public static io.swagger.v3.oas.models.responses.ApiResponse apiResponseModel(OpenAPI openAPI, + ApiResponse apiResponse) { + io.swagger.v3.oas.models.responses.ApiResponse result = + new io.swagger.v3.oas.models.responses.ApiResponse(); + result.setDescription(apiResponse.description()); + result.setContent(contentModel(openAPI, apiResponse.content())); + result.setHeaders(headersModel(openAPI, apiResponse.headers())); + return result; } - protected static void processApiParam(ApiParam param, BodyParameter p) { - if (param.required()) { - p.setRequired(true); - } - if (StringUtils.isNotEmpty(param.name())) { - p.setName(param.name()); - } - if (StringUtils.isNotEmpty(param.value())) { - p.setDescription(param.value()); - } - if (StringUtils.isNotEmpty(param.access())) { - p.setAccess(param.access()); + public static Map headersModel(OpenAPI openAPI, Header[] headers) { + Map result = new HashMap<>(); + for (Header header : headers) { + io.swagger.v3.oas.models.headers.Header model = + new io.swagger.v3.oas.models.headers.Header(); + model.setDescription(header.description()); + model.setSchema(schemaModel(openAPI, header.schema())); + result.put(header.name(), model); } + return result; + } - Example example = param.examples(); - if (example != null && example.value() != null) { - for (ExampleProperty ex : example.value()) { - String mediaType = ex.mediaType(); - String value = ex.value(); - if (!mediaType.isEmpty() && !value.isEmpty()) { - p.example(mediaType.trim(), value.trim()); + public static io.swagger.v3.oas.models.media.Content contentModel(OpenAPI openAPI, Content[] contents) { + io.swagger.v3.oas.models.media.Content result = new io.swagger.v3.oas.models.media.Content(); + for (io.swagger.v3.oas.annotations.media.Content content : contents) { + String mediaTypeName = mediaTypeModel(content); + MediaType mediaType = result.get(mediaTypeName); + boolean isForm = SwaggerConst.FORM_MEDIA_TYPE.equals(mediaTypeName) || + SwaggerConst.FILE_MEDIA_TYPE.equals(mediaTypeName); + if (mediaType == null) { + mediaType = new MediaType(); + if (isForm) { + io.swagger.v3.oas.models.media.Schema schema = new io.swagger.v3.oas.models.media.Schema(); + schema.setProperties(new HashMap<>()); + schema.addProperty(content.schema().name(), schemaModel(openAPI, content.schema(), content.examples())); + mediaType.setSchema(schema); + } else { + mediaType.setSchema(schemaModel(openAPI, content.schema(), content.examples())); + } + result.addMediaType(mediaTypeName, mediaType); + } else { + if (isForm) { + mediaType.getSchema().addProperty(content.schema().name(), + schemaModel(openAPI, content.schema(), content.examples())); + } else { + throw new IllegalStateException("Not allowed to define duplicated content type for " + mediaTypeName); } } } + return result; } - protected static void processApiParam(ApiParam param, AbstractSerializableParameter p) { - if (param.required()) { - p.setRequired(true); - } - if (param.readOnly()) { - p.setReadOnly(true); - } - if (param.allowEmptyValue()) { - p.setAllowEmptyValue(true); - } - if (StringUtils.isNotEmpty(param.name())) { - p.setName(param.name()); - } - if (StringUtils.isNotEmpty(param.value())) { - p.setDescription(param.value()); - } - if (StringUtils.isNotEmpty(param.example())) { - p.setExample(param.example()); - } - if (StringUtils.isNotEmpty(param.access())) { - p.setAccess(param.access()); + public static io.swagger.v3.oas.models.parameters.RequestBody requestBodyModel(OpenAPI openAPI, + RequestBody requestBody) { + if (requestBody == null || isOperationDefaultRequestBody(requestBody)) { + return null; } - if (StringUtils.isNoneEmpty(param.collectionFormat())) { - p.setCollectionFormat(param.collectionFormat()); + io.swagger.v3.oas.models.parameters.RequestBody result = new io.swagger.v3.oas.models.parameters.RequestBody(); + result.setContent(AnnotationUtils.contentModel(openAPI, requestBody.content())); + return result; + } + + private static boolean isOperationDefaultRequestBody(RequestBody requestBody) { + return "".equals(requestBody.description()) && requestBody.content().length == 0 + && !requestBody.required() && requestBody.extensions().length == 0; + } + + private static String mediaTypeModel(io.swagger.v3.oas.annotations.media.Content content) { + if (StringUtils.isEmpty(content.mediaType())) { + return SwaggerConst.DEFAULT_MEDIA_TYPE; } - if (StringUtils.isNotEmpty(param.type())) { - if ("java.io.File".equalsIgnoreCase(param.type())) { - p.setProperty(new FileProperty()); - } else if ("long".equalsIgnoreCase(param.type())) { - p.setProperty(new LongProperty()); - } else { - p.setType(param.type()); - } + return content.mediaType(); + } + + public static io.swagger.v3.oas.models.media.Schema schemaModel(OpenAPI openAPI, Schema schema) { + if (schema.implementation() != Void.class) { + io.swagger.v3.oas.models.media.Schema result = + SwaggerUtils.resolveTypeSchemas(openAPI, schema.implementation()); + result.setDescription(schema.description()); + result.setExample(schema.example()); + result.setNullable(schema.nullable()); + return result; + } + + io.swagger.v3.oas.models.media.Schema result = + new io.swagger.v3.oas.models.media.Schema(); + result.setType(schema.type()); + result.setFormat(schema.format()); + result.setDescription(schema.description()); + result.setExample(schema.example()); + result.setNullable(schema.nullable()); + return result; + } + + public static io.swagger.v3.oas.models.media.Schema schemaModel(OpenAPI openAPI, Schema schema, + ExampleObject[] exampleObjects) { + io.swagger.v3.oas.models.media.Schema result = schemaModel(openAPI, schema); + List examples = new ArrayList<>(); + for (ExampleObject exampleObject : exampleObjects) { + examples.add(exampleObject.name() + ":" + exampleObject.value()); } + result.setExamples(examples); + return result; + } + + public static io.swagger.v3.oas.models.Operation operationModel(OpenAPI openAPI, Operation apiOperationAnnotation) { + io.swagger.v3.oas.models.Operation result = new io.swagger.v3.oas.models.Operation(); + result.setSummary(apiOperationAnnotation.summary()); + result.setDescription(apiOperationAnnotation.description()); + result.setExtensions(extensionsModel(apiOperationAnnotation.extensions())); + result.setResponses(apiResponsesModel(openAPI, apiOperationAnnotation.responses())); + result.setOperationId(apiOperationAnnotation.operationId()); + result.setTags(tagsModel(apiOperationAnnotation.tags())); + result.setRequestBody(requestBodyModel(openAPI, apiOperationAnnotation.requestBody())); + return result; } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamClassProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamClassProcessor.java deleted file mode 100644 index 7758ca522d6..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamClassProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.models.parameters.Parameter; - -public class ApiImplicitParamClassProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - ApiImplicitParam paramAnnotation = (ApiImplicitParam) annotation; - - Parameter parameter = AnnotationUtils.createParameter(swaggerGenerator.getSwagger(), paramAnnotation); - swaggerGenerator.getSwagger().addParameter(parameter.getName(), parameter); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamMethodProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamMethodProcessor.java deleted file mode 100644 index cbd191d383b..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamMethodProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.models.parameters.Parameter; - -public class ApiImplicitParamMethodProcessor implements MethodAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ApiImplicitParam paramAnnotation = (ApiImplicitParam) annotation; - - Parameter parameter = AnnotationUtils.createParameter(operationGenerator.getSwagger(), paramAnnotation); - operationGenerator.addMethodAnnotationParameter(parameter); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsClassProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsClassProcessor.java deleted file mode 100644 index ad681928191..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsClassProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; - -public class ApiImplicitParamsClassProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - ApiImplicitParams apiImplicitParamsAnnotation = (ApiImplicitParams) annotation; - - ClassAnnotationProcessor processor = - swaggerGenerator.getContext().findClassAnnotationProcessor(ApiImplicitParam.class); - for (ApiImplicitParam paramAnnotation : apiImplicitParamsAnnotation.value()) { - processor.process(paramAnnotation, swaggerGenerator); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsMethodProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsMethodProcessor.java deleted file mode 100644 index bb353bd12c0..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiImplicitParamsMethodProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; - -public class ApiImplicitParamsMethodProcessor implements MethodAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ApiImplicitParams apiImplicitParamsAnnotation = (ApiImplicitParams) annotation; - - MethodAnnotationProcessor processor = - operationGenerator.getContext().findMethodAnnotationProcessor(ApiImplicitParam.class); - for (ApiImplicitParam paramAnnotation : apiImplicitParamsAnnotation.value()) { - processor.process(paramAnnotation, operationGenerator); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessor.java deleted file mode 100644 index 0207727ff75..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessor.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.springframework.util.StringUtils; - -import io.swagger.annotations.ApiOperation; -import io.swagger.models.Operation; -import io.swagger.models.Scheme; -import io.swagger.util.BaseReaderUtils; - -public class ApiOperationProcessor implements MethodAnnotationProcessor { - - private static final String SEPARATOR = ","; - - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ApiOperation apiOperationAnnotation = (ApiOperation) annotation; - Operation operation = operationGenerator.getOperation(); - - operationGenerator.setHttpMethod(apiOperationAnnotation.httpMethod()); - - if (!StringUtils.isEmpty(apiOperationAnnotation.value())) { - operation.setSummary(apiOperationAnnotation.value()); - } - - if (!StringUtils.isEmpty(apiOperationAnnotation.notes())) { - operation.setDescription(apiOperationAnnotation.notes()); - } - - operation.setOperationId(apiOperationAnnotation.nickname()); - operation.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(apiOperationAnnotation.extensions())); - - convertTags(apiOperationAnnotation.tags(), operation); - convertProduces(apiOperationAnnotation.produces(), operation); - convertConsumes(apiOperationAnnotation.consumes(), operation); - convertProtocols(apiOperationAnnotation.protocols(), operation); - AnnotationUtils.addResponse(operationGenerator.getSwagger(), - operation, - apiOperationAnnotation); - - // responseReference未解析 - // hidden未解析 - // authorizations未解析 - } - - // protocols以分号为创建,比如:http, https, ws, wss - private void convertProtocols(String protocols, Operation operation) { - if (protocols == null) { - return; - } - - for (String protocol : protocols.split(SEPARATOR)) { - if (StringUtils.isEmpty(protocol)) { - continue; - } - - operation.addScheme(Scheme.forValue(protocol)); - } - } - - // consumes以分号为创建,比如:application/json, application/xml - private void convertConsumes(String consumes, Operation operation) { - if (StringUtils.isEmpty(consumes)) { - return; - } - - List consumeList = Arrays.stream(consumes.split(SEPARATOR)).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!consumeList.isEmpty()) { - operation.setConsumes(consumeList); - } - } - - // produces以分号为创建,比如:application/json, application/xml - private void convertProduces(String produces, Operation operation) { - if (StringUtils.isEmpty(produces)) { - return; - } - - List produceList = Arrays.stream(produces.split(SEPARATOR)).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!produceList.isEmpty()) { - operation.setProduces(produceList); - } - } - - private void convertTags(String[] tags, Operation operation) { - if (tags == null || tags.length == 0) { - return; - } - - for (String tag : tags) { - if (StringUtils.isEmpty(tag)) { - continue; - } - - operation.addTag(tag); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java deleted file mode 100644 index f882e340a87..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessor.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.springframework.util.StringUtils; - -import io.swagger.annotations.Api; -import io.swagger.models.Swagger; - -public class ApiProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - Api api = (Api) annotation; - - setTags(api, swaggerGenerator); - // except for @Api, @RequestMapping can also set consumes and produces - // @RequestMapping takes HIGHER priority than @Api for legacy reason - processConsumes(api, swaggerGenerator.getSwagger()); - processProduces(api, swaggerGenerator.getSwagger()); - } - - private void processProduces(Api api, Swagger swagger) { - List validProducesList = getValidStringList(api.produces()); - if (isBlank(swagger.getProduces()) && !validProducesList.isEmpty()) { - swagger.setProduces(validProducesList); - } - } - - private void processConsumes(Api api, Swagger swagger) { - List validConsumesList = getValidStringList(api.consumes()); - if (isBlank(swagger.getConsumes()) && !validConsumesList.isEmpty()) { - swagger.setConsumes(validConsumesList); - } - } - - /** - * Split {@link Api#consumes} and {@link Api#produces}, and filter empty items. - */ - private List getValidStringList(String rawString) { - return Stream.of(rawString.split(",")) - .filter(s -> !StringUtils.isEmpty(s)) - .map(String::trim) - .collect(Collectors.toList()); - } - - /** - * @return true if {@code stringList} is empty or each element of {@code stringList} is empty; - * otherwise false. - */ - private boolean isBlank(List stringList) { - boolean isEmpty = null == stringList || stringList.isEmpty(); - if (isEmpty) { - return true; - } - - for (String s : stringList) { - if (StringUtils.isEmpty(s)) { - return true; - } - } - return false; - } - - private void setTags(Api api, SwaggerGenerator swaggerGenerator) { - String[] tags = api.tags(); - for (String tagName : tags) { - if (StringUtils.isEmpty(tagName)) { - continue; - } - swaggerGenerator.addDefaultTag(tagName); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseClassProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseClassProcessor.java deleted file mode 100644 index b0c0d7cfa10..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseClassProcessor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; - -import io.swagger.annotations.ApiResponse; - -public class ApiResponseClassProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - // swagger号称不允许独立使用这个标注,不过支持独立使用,也没什么后果 - ApiResponse apiResponse = (ApiResponse) annotation; - - AnnotationUtils.addResponse(swaggerGenerator.getSwagger(), apiResponse); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseMethodProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseMethodProcessor.java index 2a6c253227e..3f6850a2128 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseMethodProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponseMethodProcessor.java @@ -16,20 +16,63 @@ */ package org.apache.servicecomb.swagger.generator.core.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; -import io.swagger.annotations.ApiResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.springframework.util.CollectionUtils; -public class ApiResponseMethodProcessor implements MethodAnnotationProcessor { +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +public class ApiResponseMethodProcessor implements MethodAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - // swagger号称不允许独立使用这个标注,不过支持独立使用,也没什么后果 - ApiResponse apiResponse = (ApiResponse) annotation; + public Type getProcessType() { + return ApiResponse.class; + } - AnnotationUtils.addResponse(operationGenerator.getSwagger(), - operationGenerator.getOperation(), - apiResponse); + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ApiResponse apiResponse) { + List produces = new ArrayList<>(); + String responseCode = apiResponse.responseCode(); + if (StringUtils.isEmpty(responseCode) || "default".equals(responseCode)) { + responseCode = SwaggerConst.SUCCESS_KEY; + } + Class type = null; + for (Content content : apiResponse.content()) { + if (StringUtils.isNotEmpty(content.mediaType())) { + produces.add(content.mediaType()); + } + if (content.schema() != null && content.schema().implementation() != Void.class) { + type = content.schema().implementation(); + } + } + operationGenerator.getOperationGeneratorContext().updateResponse(responseCode, + type == null ? null : SwaggerUtils.resolveTypeSchemas(swaggerGenerator.getOpenAPI(), type)); + if (StringUtils.isNotEmpty(apiResponse.description())) { + operationGenerator.getOperationGeneratorContext().updateResponseDescription(responseCode, + apiResponse.description()); + } + for (Header header : apiResponse.headers()) { + if (header.schema() == null || header.schema().implementation() == Void.class) { + throw new IllegalArgumentException("@ApiResponse header schema implementation must be defined."); + } + if (StringUtils.isEmpty(header.name())) { + throw new IllegalArgumentException("@ApiResponse header name must be defined."); + } + operationGenerator.getOperationGeneratorContext().updateResponseHeader(responseCode, + header.name(), AnnotationUtils.schemaModel(swaggerGenerator.getOpenAPI(), header.schema())); + } + if (!CollectionUtils.isEmpty(produces)) { + operationGenerator.getOperationGeneratorContext().updateProduces(produces); + } } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesClassProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesClassProcessor.java deleted file mode 100644 index 6101d3c9e43..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesClassProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; - -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -public class ApiResponsesClassProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - ApiResponses apiResponses = (ApiResponses) annotation; - - ClassAnnotationProcessor processor = - swaggerGenerator.getContext().findClassAnnotationProcessor(ApiResponse.class); - for (ApiResponse apiResponse : apiResponses.value()) { - processor.process(apiResponse, swaggerGenerator); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesMethodProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesMethodProcessor.java index c00b78fef28..383598aa1de 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesMethodProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiResponsesMethodProcessor.java @@ -16,22 +16,65 @@ */ package org.apache.servicecomb.swagger.generator.core.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.springframework.util.CollectionUtils; -public class ApiResponsesMethodProcessor implements MethodAnnotationProcessor { +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +public class ApiResponsesMethodProcessor implements MethodAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ApiResponses apiResponses = (ApiResponses) annotation; + public Type getProcessType() { + return ApiResponses.class; + } - MethodAnnotationProcessor processor = - operationGenerator.getContext().findMethodAnnotationProcessor(ApiResponse.class); + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ApiResponses apiResponses) { + List produces = new ArrayList<>(); for (ApiResponse apiResponse : apiResponses.value()) { - processor.process(apiResponse, operationGenerator); + if (StringUtils.isEmpty(apiResponse.responseCode()) || "default".equals(apiResponse.responseCode())) { + throw new IllegalArgumentException("@ApiResponse status code must be defined."); + } + Class type = null; + for (Content content : apiResponse.content()) { + if (StringUtils.isNotEmpty(content.mediaType())) { + produces.add(content.mediaType()); + } + if (content.schema() != null && content.schema().implementation() != Void.class) { + type = content.schema().implementation(); + } + } + operationGenerator.getOperationGeneratorContext().updateResponse(apiResponse.responseCode(), + type == null ? null : SwaggerUtils.resolveTypeSchemas(swaggerGenerator.getOpenAPI(), type)); + if (StringUtils.isNotEmpty(apiResponse.description())) { + operationGenerator.getOperationGeneratorContext().updateResponseDescription(apiResponse.responseCode(), + apiResponse.description()); + } + for (Header header : apiResponse.headers()) { + if (header.schema() == null || header.schema().implementation() == Void.class) { + throw new IllegalArgumentException("@ApiResponse header schema implementation must be defined."); + } + if (StringUtils.isEmpty(header.name())) { + throw new IllegalArgumentException("@ApiResponse header name must be defined."); + } + operationGenerator.getOperationGeneratorContext().updateResponseHeader(apiResponse.responseCode(), + header.name(), AnnotationUtils.schemaModel(swaggerGenerator.getOpenAPI(), header.schema())); + } + } + if (!CollectionUtils.isEmpty(produces)) { + operationGenerator.getOperationGeneratorContext().updateProduces(produces); } } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessor.java new file mode 100644 index 00000000000..67406375f13 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessor.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.models.OpenAPI; + +public class OpenAPIDefinitionProcessor implements ClassAnnotationProcessor { + @Override + public Type getProcessType() { + return OpenAPIDefinition.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OpenAPIDefinition definitionAnnotation) { + OpenAPI swagger = swaggerGenerator.getOpenAPI(); + swagger.setServers(AnnotationUtils.serversModel(definitionAnnotation.servers())); + swagger.setTags(AnnotationUtils.tagsModel(definitionAnnotation.tags())); + swagger.setInfo(AnnotationUtils.infoModel(definitionAnnotation.info())); + swagger.setExternalDocs(AnnotationUtils.externalDocumentationModel(definitionAnnotation.externalDocs())); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessor.java new file mode 100644 index 00000000000..86986a90c6a --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessor.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.annotation; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.springframework.util.CollectionUtils; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +public class OperationMethodAnnotationProcessor implements MethodAnnotationProcessor { + public Type getProcessType() { + return Operation.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, + OperationGenerator operationGenerator, Operation apiOperationAnnotation) { + io.swagger.v3.oas.models.Operation operation = operationGenerator.getOperation(); + + if (!StringUtils.isEmpty(apiOperationAnnotation.method())) { + operationGenerator.setHttpMethod(apiOperationAnnotation.method()); + } + + if (apiOperationAnnotation.responses() != null) { + // This is a bit different from swagger annotation intention. + // Here we assume @Content defines all supported media type and only one implementation class for one status code. + List produces = new ArrayList<>(); + for (ApiResponse apiResponse : apiOperationAnnotation.responses()) { + if (StringUtils.isEmpty(apiResponse.responseCode()) || "default".equals(apiResponse.responseCode())) { + throw new IllegalArgumentException("@ApiResponse status code must be defined."); + } + Class type = null; + for (Content content : apiResponse.content()) { + if (StringUtils.isNotEmpty(content.mediaType())) { + produces.add(content.mediaType()); + } + if (content.schema() != null && content.schema().implementation() != Void.class) { + type = content.schema().implementation(); + } + } + operationGenerator.getOperationGeneratorContext().updateResponse(apiResponse.responseCode(), + type == null ? null : SwaggerUtils.resolveTypeSchemas(swaggerGenerator.getOpenAPI(), type)); + if (StringUtils.isNotEmpty(apiResponse.description())) { + operationGenerator.getOperationGeneratorContext().updateResponseDescription(apiResponse.responseCode(), + apiResponse.description()); + } + for (Header header : apiResponse.headers()) { + if (header.schema() == null || header.schema().implementation() == Void.class) { + throw new IllegalArgumentException("@ApiResponse header schema implementation must be defined."); + } + if (StringUtils.isEmpty(header.name())) { + throw new IllegalArgumentException("@ApiResponse header name must be defined."); + } + operationGenerator.getOperationGeneratorContext().updateResponseHeader(apiResponse.responseCode(), + header.name(), AnnotationUtils.schemaModel(swaggerGenerator.getOpenAPI(), header.schema())); + } + } + if (!CollectionUtils.isEmpty(produces)) { + operationGenerator.getOperationGeneratorContext().updateProduces(produces); + } + } + + io.swagger.v3.oas.models.Operation specificOperation = + AnnotationUtils.operationModel(swaggerGenerator.getOpenAPI(), apiOperationAnnotation); + if (!StringUtils.isEmpty(specificOperation.getSummary())) { + operation.setSummary(specificOperation.getSummary()); + } + + if (!StringUtils.isEmpty(specificOperation.getDescription())) { + operation.setDescription(specificOperation.getDescription()); + } + + if (!StringUtils.isEmpty(specificOperation.getOperationId())) { + operation.setOperationId(specificOperation.getOperationId()); + } + + if (!CollectionUtils.isEmpty(specificOperation.getExtensions())) { + operation.setExtensions(specificOperation.getExtensions()); + } + + if (!CollectionUtils.isEmpty(specificOperation.getTags())) { + operation.setTags(specificOperation.getTags()); + } + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/RequestBodyMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/RequestBodyMethodAnnotationProcessor.java new file mode 100644 index 00000000000..aeace6a5756 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/RequestBodyMethodAnnotationProcessor.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import io.swagger.v3.oas.annotations.parameters.RequestBody; + +public class RequestBodyMethodAnnotationProcessor implements MethodAnnotationProcessor { + @Override + public Type getProcessType() { + return RequestBody.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + RequestBody annotation) { + io.swagger.v3.oas.models.parameters.RequestBody requestBody = + AnnotationUtils.requestBodyModel(swaggerGenerator.getOpenAPI(), annotation); + operationGenerator.getOperation().setRequestBody(requestBody); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeaderProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeaderProcessor.java deleted file mode 100644 index c65dffa1f1a..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeaderProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.annotation.models.ResponseHeaderConfig; - -import io.swagger.annotations.ResponseHeader; -import io.swagger.models.properties.Property; - -public class ResponseHeaderProcessor implements MethodAnnotationProcessor { - - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ResponseHeader responseHeader = (ResponseHeader) annotation; - - ResponseHeaderConfig config = AnnotationUtils.convert(responseHeader); - if (config != null) { - Property property = - AnnotationUtils.generateResponseHeaderProperty(operationGenerator.getSwagger(), config); - operationGenerator.addResponseHeader(config.getName(), property); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeadersProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeadersProcessor.java deleted file mode 100644 index cb6cfe2ea41..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ResponseHeadersProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -import io.swagger.annotations.ResponseHeader; - -public class ResponseHeadersProcessor implements MethodAnnotationProcessor { - - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - ResponseHeaders responseHeaders = (ResponseHeaders) annotation; - - MethodAnnotationProcessor processor = - operationGenerator.getContext().findMethodAnnotationProcessor(ResponseHeader.class); - for (ResponseHeader responseHeader : responseHeaders.value()) { - processor.process(responseHeader, operationGenerator); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessor.java deleted file mode 100644 index 3763b5ed579..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessor.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.springframework.util.StringUtils; - -import io.swagger.annotations.SwaggerDefinition; -import io.swagger.models.Contact; -import io.swagger.models.ExternalDocs; -import io.swagger.models.Info; -import io.swagger.models.License; -import io.swagger.models.Scheme; -import io.swagger.models.Swagger; -import io.swagger.models.Tag; -import io.swagger.util.BaseReaderUtils; - -public class SwaggerDefinitionProcessor implements ClassAnnotationProcessor { - @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - SwaggerDefinition definitionAnnotation = (SwaggerDefinition) annotation; - Swagger swagger = swaggerGenerator.getSwagger(); - - swaggerGenerator.setBasePath(definitionAnnotation.basePath()); - swagger.setHost(definitionAnnotation.host()); - - convertConsumes(definitionAnnotation, swagger); - convertProduces(definitionAnnotation, swagger); - convertSchemes(definitionAnnotation, swagger); - convertTags(definitionAnnotation, swagger); - convertInfo(definitionAnnotation.info(), swagger); - swagger.setExternalDocs(convertExternalDocs(definitionAnnotation.externalDocs())); - } - - private void convertInfo(io.swagger.annotations.Info infoAnnotation, Swagger swagger) { - if (infoAnnotation == null) { - return; - } - - Info info = new Info(); - - info.setTitle(infoAnnotation.title()); - info.setVersion(infoAnnotation.version()); - info.setDescription(infoAnnotation.description()); - info.setTermsOfService(infoAnnotation.termsOfService()); - info.setContact(convertContact(infoAnnotation.contact())); - info.setLicense(convertLicense(infoAnnotation.license())); - info.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(infoAnnotation.extensions())); - - swagger.setInfo(info); - } - - private License convertLicense(io.swagger.annotations.License licenseAnnotation) { - License license = new License(); - - license.setName(licenseAnnotation.name()); - license.setUrl(licenseAnnotation.url()); - - return license; - } - - private Contact convertContact(io.swagger.annotations.Contact contactAnnotation) { - Contact contact = new Contact(); - - contact.setName(contactAnnotation.name()); - contact.setUrl(contactAnnotation.url()); - contact.setEmail(contactAnnotation.email()); - - return contact; - } - - private void convertTags(SwaggerDefinition definitionAnnotation, Swagger swagger) { - if (definitionAnnotation.tags() == null) { - return; - } - - Stream stream = - Arrays.asList(definitionAnnotation.tags()).stream(); - List tags = stream.map(this::convertTag).collect(Collectors.toList()); - swagger.setTags(tags); - } - - private Tag convertTag(io.swagger.annotations.Tag tagAnnotation) { - Tag tag = new Tag(); - tag.setName(tagAnnotation.name()); - tag.setDescription(tagAnnotation.description()); - tag.setExternalDocs(convertExternalDocs(tagAnnotation.externalDocs())); - tag.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(tagAnnotation.extensions())); - return tag; - } - - private ExternalDocs convertExternalDocs(io.swagger.annotations.ExternalDocs annotationExternalDocs) { - ExternalDocs externalDocs = new ExternalDocs(); - externalDocs.setUrl(annotationExternalDocs.url()); - externalDocs.setDescription(annotationExternalDocs.value()); - - return externalDocs; - } - - private void convertSchemes(SwaggerDefinition definitionAnnotation, Swagger swagger) { - if (definitionAnnotation.schemes() == null) { - return; - } - - Stream stream = - Arrays.asList(definitionAnnotation.schemes()).stream(); - List schemes = stream.map(this::convertScheme).collect(Collectors.toList()); - swagger.setSchemes(schemes); - } - - private Scheme convertScheme(io.swagger.annotations.SwaggerDefinition.Scheme annotationScheme) { - return Scheme.forValue(annotationScheme.name()); - } - - private void convertProduces(SwaggerDefinition definitionAnnotation, Swagger swagger) { - String[] produces = definitionAnnotation.produces(); - if (produces == null) { - return; - } - List produceList = Arrays.stream(produces).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!produceList.isEmpty()) { - swagger.setProduces(produceList); - } - } - - private void convertConsumes(SwaggerDefinition definitionAnnotation, Swagger swagger) { - String[] consumes = definitionAnnotation.consumes(); - if (consumes == null) { - return; - } - List consumeList = Arrays.stream(consumes).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!consumeList.isEmpty()) { - swagger.setConsumes(consumeList); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfig.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfig.java deleted file mode 100644 index bcd72fcdc21..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation.models; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.swagger.generator.core.processor.annotation.AnnotationUtils; - -import io.swagger.annotations.ResponseHeader; -import io.swagger.models.Response; - -/** - * Response的数据源太多,单单是标注都有N个 - * 所以将数据提取出来,统一处理 - */ -public class ResponseConfig extends ResponseConfigBase { - private int code; - - private List responseHeaders; - - // 根据本config生成的response - private Response response; - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public List getResponseHeaders() { - return responseHeaders; - } - - public void setResponseHeaders(List responseHeaders) { - this.responseHeaders = responseHeaders; - } - - public void setResponseHeaders(ResponseHeader[] responseHeaders) { - this.responseHeaders = new ArrayList<>(); - for (ResponseHeader header : responseHeaders) { - ResponseHeaderConfig config = AnnotationUtils.convert(header); - if (config != null) { - this.responseHeaders.add(config); - } - } - - if (this.responseHeaders.isEmpty()) { - this.responseHeaders = null; - } - } - - public Response getResponse() { - return response; - } - - public void setResponse(Response response) { - this.response = response; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfigBase.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfigBase.java deleted file mode 100644 index a82de0d3e3a..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseConfigBase.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation.models; - -public class ResponseConfigBase { - private String description; - - private String responseReference; - - private Class responseClass; - - private String responseContainer; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getResponseReference() { - return responseReference; - } - - public void setResponseReference(String responseReference) { - this.responseReference = responseReference; - } - - public Class getResponseClass() { - return responseClass; - } - - public void setResponseClass(Class responseClass) { - this.responseClass = responseClass; - } - - public String getResponseContainer() { - return responseContainer; - } - - public void setResponseContainer(String responseContainer) { - this.responseContainer = responseContainer; - } - - @Override - public String toString() { - return "ResponseConfigBase [description=" + description + ", responseReference=" + responseReference - + ", responseClass=" + responseClass + ", responseContainer=" + responseContainer + "]"; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseHeaderConfig.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseHeaderConfig.java deleted file mode 100644 index a6ec8320251..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/models/ResponseHeaderConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.annotation.models; - -public class ResponseHeaderConfig extends ResponseConfigBase { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "ResponseHeaderConfig [name=" + name + ", " + super.toString() + "]"; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java deleted file mode 100644 index 54ec775a15c..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.parameter; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ParameterAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.models.parameters.AbstractSerializableParameter; - -public abstract class AbstractParameterProcessor> - implements ParameterAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator, int paramIdx) { - T parameter = createParameter(); - - fillParameter(annotation, operationGenerator, paramIdx, parameter); - - operationGenerator.addProviderParameter(parameter); - } - - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - T parameter) { - setParameterName(annotation, operationGenerator, paramIdx, parameter); - setParameterType(operationGenerator, paramIdx, parameter); - setParameterDefaultValue(annotation, parameter); - } - - protected void setParameterType(OperationGenerator operationGenerator, int paramIdx, - T parameter) { - ParamUtils.setParameterType(operationGenerator.getSwagger(), - operationGenerator.getProviderMethod(), - paramIdx, - parameter); - } - - protected void setParameterName(Object annotation, OperationGenerator operationGenerator, int paramIdx, - T parameter) { - String paramName = getAnnotationParameterName(annotation); - paramName = ParamUtils.getParameterName(paramName, operationGenerator.getProviderMethod(), paramIdx); - parameter.setName(paramName); - } - - protected void setParameterDefaultValue(Object annotation, T parameter) { - String defaultValue = getAnnotationParameterDefaultValue(annotation); - if (StringUtils.isNotEmpty(defaultValue)) { - parameter.setDefaultValue(defaultValue); - } - } - - protected String getAnnotationParameterDefaultValue(Object annotation) { - return ""; - } - - public abstract T createParameter(); - - public abstract String getAnnotationParameterName(Object annotation); -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/HttpServletRequestContextRegister.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/HttpServletRequestContextRegister.java new file mode 100644 index 00000000000..8e9f7199685 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/HttpServletRequestContextRegister.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import java.lang.reflect.Type; + +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.servicecomb.swagger.generator.SwaggerContextRegister; + +public class HttpServletRequestContextRegister implements SwaggerContextRegister { + @Override + public Type getContextType() { + return HttpServletRequest.class; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ParameterParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ParameterParameterAnnotationProcessor.java new file mode 100644 index 00000000000..12849da4e63 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ParameterParameterAnnotationProcessor.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerParameterAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; + +public class ParameterParameterAnnotationProcessor + extends SwaggerParameterAnnotationProcessor { + @Override + public Class getProcessType() { + return io.swagger.v3.oas.annotations.Parameter.class; + } + + @Override + public String getParameterName(Parameter annotation) { + if (StringUtils.isNotEmpty(annotation.name())) { + return annotation.name(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, io.swagger.v3.oas.annotations.Parameter annotation) { + if (annotation.schema() != null + && annotation.schema().implementation() != null + && annotation.schema().implementation() != Void.class) { + parameterGenerator.getParameterGeneratorContext() + .setParameterType(TypeFactory.defaultInstance().constructType(annotation.schema().implementation())); + } + + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + + if (annotation.in() != null && annotation.in() != ParameterIn.DEFAULT) { + parameterGenerator.setHttpParameterType(HttpParameterType.from(annotation.in())); + } + + if (Explode.TRUE.equals(annotation.explode())) { + parameterGenerator.getParameterGeneratorContext().setExplode(true); + } + if (Explode.FALSE.equals(annotation.explode())) { + parameterGenerator.getParameterGeneratorContext().setExplode(false); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartArrayParameterTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartArrayParameterTypeProcessor.java new file mode 100644 index 00000000000..daf9f584558 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartArrayParameterTypeProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import org.apache.servicecomb.swagger.generator.ParameterGenerator; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.FileSchema; +import jakarta.servlet.http.Part; + +public class PartArrayParameterTypeProcessor extends PartParameterTypeProcessor { + @Override + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType(Part[].class); + } + + @Override + protected void formParameterSchema(ParameterGenerator parameterGenerator) { + parameterGenerator.getParameterGeneratorContext().setSchema(new ArraySchema().items(new FileSchema())); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartListParameterTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartListParameterTypeProcessor.java new file mode 100644 index 00000000000..8d47dfdc359 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartListParameterTypeProcessor.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import jakarta.servlet.http.Part; + +public class PartListParameterTypeProcessor extends PartArrayParameterTypeProcessor { + @Override + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType(ParameterizedTypeUtil.make(List.class, Part.class)); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartParameterTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartParameterTypeProcessor.java new file mode 100644 index 00000000000..d35db0df987 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/PartParameterTypeProcessor.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.ParameterTypeProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.models.media.FileSchema; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.MediaType; + +public class PartParameterTypeProcessor implements ParameterTypeProcessor { + @Override + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType(Part.class); + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator) { + if (!parameterGenerator.getParameterGeneratorContext().getSupportedConsumes() + .contains(MediaType.MULTIPART_FORM_DATA)) { + throw new IllegalArgumentException("Part type must declare consumes " + MediaType.MULTIPART_FORM_DATA); + } + if (parameterGenerator.getHttpParameterType() != HttpParameterType.FORM) { + throw new IllegalArgumentException( + getProcessType().getRawClass().getSimpleName() + " type must declare as form parameter."); + } + if (StringUtils.isEmpty(parameterGenerator.getParameterGeneratorContext().getParameterName())) { + throw new IllegalArgumentException( + "Name is required for parameter " + getProcessType().getRawClass().getSimpleName()); + } + parameterGenerator.getParameterGeneratorContext().updateConsumes(List.of(MediaType.MULTIPART_FORM_DATA)); + + formParameterSchema(parameterGenerator); + } + + protected void formParameterSchema(ParameterGenerator parameterGenerator) { + parameterGenerator.getParameterGeneratorContext().setSchema(new FileSchema()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java new file mode 100644 index 00000000000..1d64144365f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerParameterAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.core.MediaType; + +public class RawJsonRequestBodyProcessor extends + SwaggerParameterAnnotationProcessor { + @Override + public Class getProcessType() { + return RawJsonRequestBody.class; + } + + @Override + public String getParameterName(RawJsonRequestBody annotation) { + if (StringUtils.isNotEmpty(annotation.value())) { + return annotation.value(); + } else if (StringUtils.isNotEmpty(annotation.name())) { + return annotation.name(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RawJsonRequestBody annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.BODY); + + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); + parameterGenerator.getParameterGeneratorContext().setRawJson(true); + parameterGenerator.getParameterGeneratorContext().updateConsumes(Arrays.asList(MediaType.APPLICATION_JSON, + MediaType.TEXT_PLAIN)); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RequestBodyParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RequestBodyParameterAnnotationProcessor.java new file mode 100644 index 00000000000..06ab22cae34 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RequestBodyParameterAnnotationProcessor.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerParameterAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import io.swagger.v3.oas.annotations.parameters.RequestBody; + +public class RequestBodyParameterAnnotationProcessor extends + SwaggerParameterAnnotationProcessor { + @Override + public Class getProcessType() { + return io.swagger.v3.oas.annotations.parameters.RequestBody.class; + } + + @Override + public String getParameterName(RequestBody requestBody) { + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, io.swagger.v3.oas.annotations.parameters.RequestBody annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.BODY); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ServerWebSocketContextRegister.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ServerWebSocketContextRegister.java new file mode 100644 index 00000000000..70bb4255096 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/ServerWebSocketContextRegister.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.parameter; + +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.SwaggerContextRegister; + +import io.vertx.core.http.ServerWebSocket; + +public class ServerWebSocketContextRegister implements SwaggerContextRegister { + @Override + public Type getContextType() { + return ServerWebSocket.class; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/HttpServletRequestProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/HttpServletRequestProcessor.java deleted file mode 100644 index 3b5bb0dc19d..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/HttpServletRequestProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.parametertype; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.swagger.extend.parameter.HttpRequestParameter; -import org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -public class HttpServletRequestProcessor implements CommonParameterTypeProcessor { - @Override - public Class getParameterType() { - return HttpServletRequest.class; - } - - @Override - public void process(OperationGenerator operationGenerator, int paramIdx) { - HttpRequestParameter parameter = new HttpRequestParameter(); - operationGenerator.addProviderParameter(parameter); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/RawJsonRequestBodyProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/RawJsonRequestBodyProcessor.java deleted file mode 100644 index f31e1080e2c..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parametertype/RawJsonRequestBodyProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.parametertype; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ParameterAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.models.parameters.BodyParameter; - -public class RawJsonRequestBodyProcessor implements ParameterAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator, int paramIdx) { - BodyParameter bodyParameter = ParamUtils.createBodyParameter(operationGenerator, paramIdx); - bodyParameter.setVendorExtension("x-raw-json", true); - bodyParameter.setRequired(true); - operationGenerator.addProviderParameter(bodyParameter); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/AbstractOneGenericResponseProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/AbstractOneGenericResponseProcessor.java deleted file mode 100644 index ec4b275de77..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/AbstractOneGenericResponseProcessor.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.response; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.Property; - -// eg: -// ResponseEntiry -// CompletableFurture -public abstract class AbstractOneGenericResponseProcessor implements ResponseTypeProcessor { - @Override - public Property process(OperationGenerator operationGenerator) { - ParameterizedType type = - (ParameterizedType) operationGenerator.getProviderMethod().getGenericReturnType(); - - Type responseType = type.getActualTypeArguments()[0]; - ParamUtils.addDefinitions(operationGenerator.getSwagger(), responseType); - return ModelConverters.getInstance().readAsProperty(responseType); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/CompletableFutureProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/CompletableFutureProcessor.java index 30faa105520..09fc57537a3 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/CompletableFutureProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/CompletableFutureProcessor.java @@ -19,9 +19,13 @@ import java.util.concurrent.CompletableFuture; -public class CompletableFutureProcessor extends AbstractOneGenericResponseProcessor { +public class CompletableFutureProcessor extends DefaultResponseTypeProcessor { + public CompletableFutureProcessor() { + extractActualType = true; + } + @Override - public Class getResponseType() { + public Class getProcessType() { return CompletableFuture.class; } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/DefaultResponseTypeProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/DefaultResponseTypeProcessor.java index b7426c71cb7..46788ae8ecc 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/DefaultResponseTypeProcessor.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/DefaultResponseTypeProcessor.java @@ -16,27 +16,73 @@ */ package org.apache.servicecomb.swagger.generator.core.processor.response; +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.findResponseTypeProcessor; + +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ResponseTypeProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.Property; +import io.swagger.v3.core.util.ReflectionUtils; +import io.swagger.v3.oas.models.media.Schema; +import jakarta.servlet.http.Part; public class DefaultResponseTypeProcessor implements ResponseTypeProcessor { + protected boolean extractActualType; + @Override - public Class getResponseType() { + public Type getProcessType() { // not care for this. return null; } @Override - public Property process(OperationGenerator operationGenerator) { - Type responseType = operationGenerator.getProviderMethod().getGenericReturnType(); + public Type extractResponseType(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType) { + if (extractActualType) { + genericResponseType = ((ParameterizedType) genericResponseType).getActualTypeArguments()[0]; + } + + return doExtractResponseType(genericResponseType); + } + + private Type doExtractResponseType(Type genericResponseType) { + if (!(genericResponseType instanceof ParameterizedType)) { + return genericResponseType; + } + + // eg: + // genericResponseType is CompletableFuture> + // responseType is ResponseEntity + // responseRawType is ResponseEntity + Type responseRawType = genericResponseType; + if (genericResponseType instanceof ParameterizedType) { + responseRawType = ((ParameterizedType) genericResponseType).getRawType(); + } + + ResponseTypeProcessor processor = findResponseTypeProcessor(responseRawType); + if (responseRawType.equals(processor.getProcessType())) { + return processor.extractResponseType(genericResponseType); + } + + return genericResponseType; + } + + @Override + public Schema process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType) { + Type responseType = extractResponseType(swaggerGenerator, operationGenerator, genericResponseType); + if (responseType == null || ReflectionUtils.isVoid(responseType)) { + return null; + } + + if (responseType instanceof Class && Part.class.isAssignableFrom((Class) responseType)) { + responseType = Part.class; + } - ParamUtils.addDefinitions(operationGenerator.getSwagger(), responseType); - return ModelConverters.getInstance().readAsProperty(responseType); + return SwaggerUtils.resolveTypeSchemas(swaggerGenerator.getOpenAPI(), responseType); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/OptionalProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/OptionalProcessor.java new file mode 100644 index 00000000000..6d8b6047c97 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/OptionalProcessor.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.response; + +import java.lang.reflect.Type; +import java.util.Optional; + +public class OptionalProcessor extends DefaultResponseTypeProcessor { + public OptionalProcessor() { + extractActualType = true; + } + + @Override + public Type getProcessType() { + return Optional.class; + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/PublisherProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/PublisherProcessor.java new file mode 100644 index 00000000000..8388477dca5 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/response/PublisherProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.processor.response; + +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.reactivestreams.Publisher; + +import io.swagger.v3.oas.models.media.Schema; +import jakarta.ws.rs.core.MediaType; + +public class PublisherProcessor extends DefaultResponseTypeProcessor { + public PublisherProcessor() { + extractActualType = true; + } + + @Override + public Type getProcessType() { + return Publisher.class; + } + + @Override + public Schema process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType) { + operationGenerator.getOperationGeneratorContext() + .updateProduces(List.of(MediaType.SERVER_SENT_EVENTS)); + return super.process(swaggerGenerator, operationGenerator, genericResponseType); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/SwaggerGeneratorForTest.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/SwaggerGeneratorForTest.java deleted file mode 100644 index 139a747f11a..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/SwaggerGeneratorForTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.unittest; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; - -public class SwaggerGeneratorForTest extends SwaggerGenerator { - // 可用于控制一次扫描中有哪些method需要处理 - // 如果methodNameSet为null,表示全部处理 - private Set methodNameSet; - - public SwaggerGeneratorForTest(SwaggerGeneratorContext context, Class cls) { - super(context, cls); - setPackageName("gen.cse.ms.ut"); - } - - public boolean containsMethod(String methodName) { - if (methodNameSet == null) { - // 无约束 - return true; - } - - return methodNameSet.contains(methodName); - } - - protected void clearMethod() { - if (methodNameSet != null) { - methodNameSet.clear(); - } - methodNameSet = null; - } - - public void replaceMethods(String... methodNames) { - clearMethod(); - - if (methodNames == null || methodNames.length == 0) { - return; - } - - if (methodNameSet == null) { - methodNameSet = new HashSet<>(); - } - - methodNameSet.addAll(Arrays.asList(methodNames)); - } - - @Override - protected boolean isSkipMethod(Method method) { - boolean skip = super.isSkipMethod(method); - if (skip) { - return true; - } - - return !containsMethod(method.getName()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/UnitTestSwaggerUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/UnitTestSwaggerUtils.java index 346f8294d92..c3d6270424e 100644 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/UnitTestSwaggerUtils.java +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/unittest/UnitTestSwaggerUtils.java @@ -19,40 +19,27 @@ import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.junit.Assert; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.junit.jupiter.api.Assertions; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import io.swagger.models.Swagger; -import io.swagger.util.Yaml; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; public final class UnitTestSwaggerUtils { - private static ObjectWriter writer = Yaml.pretty(); - - private static CompositeSwaggerGeneratorContext compositeContext = new CompositeSwaggerGeneratorContext(); + private static final ObjectWriter writer = Yaml.pretty(); private UnitTestSwaggerUtils() { } - public static SwaggerGenerator generateSwagger(Class cls) { - return generateSwagger(Thread.currentThread().getContextClassLoader(), cls); - } - - public static SwaggerGenerator generateSwagger(ClassLoader classLoader, Class cls) { - SwaggerGeneratorContext context = compositeContext.selectContext(cls); - SwaggerGenerator generator = new SwaggerGenerator(context, cls); - generator.setClassLoader(classLoader); - generator.generate(); - - return generator; - } - public static String loadExpect(String resPath) { URL url = Thread.currentThread().getContextClassLoader().getResource(resPath); if (url == null) { @@ -60,13 +47,13 @@ public static String loadExpect(String resPath) { } try { - return IOUtils.toString(url); + return IOUtils.toString(url, StandardCharsets.UTF_8); } catch (IOException e) { return e.getMessage(); } } - public static String pretty(Swagger swagger) { + public static String pretty(OpenAPI swagger) { try { return writer.writeValueAsString(swagger); } catch (JsonProcessingException e) { @@ -74,42 +61,50 @@ public static String pretty(Swagger swagger) { } } - public static Swagger parse(String content) { + public static OpenAPI parse(String content) { try { - return Yaml.mapper().readValue(content, Swagger.class); + return Yaml.mapper().readValue(content, OpenAPI.class); } catch (Exception e) { - return new Swagger(); + return new OpenAPI(); // throw new Error(e); } } - public static SwaggerGenerator testSwagger(ClassLoader classLoader, String resPath, SwaggerGeneratorContext context, - Class cls, - String... methods) { - SwaggerGeneratorForTest generator = new SwaggerGeneratorForTest(context, cls); - generator.setClassLoader(classLoader); - generator.replaceMethods(methods); - - Swagger swagger = generator.generate(); + public static SwaggerGenerator testSwagger(String resPath, Class cls, String... methods) { + SwaggerGenerator generator = SwaggerGenerator.create(cls); + generator.replaceMethodWhiteList(methods); - String expectSchema = loadExpect(resPath); - Swagger expectSwagger = parse(expectSchema); + OpenAPI swagger = generator.generate(); + String schema = pretty(swagger).trim(); - String schema = pretty(swagger); - swagger = parse(schema); + String expectSchema = loadExpect(resPath).replace("\r\n", "\n").trim(); + int offset = expectSchema.indexOf("---\nopenapi: 3.0.1"); + if (offset > 0) { + expectSchema = expectSchema.substring(offset + 4); + } - if (swagger != null && !swagger.equals(expectSwagger)) { - Assert.assertEquals(expectSchema, schema); + try { + ObjectMapper yaml = new ObjectMapper(new YAMLFactory()); + JsonNode expected = yaml.readTree(expectSchema); + JsonNode actual = yaml.readTree(schema); + + if (!actual.equals(expected)) { + ObjectMapper json = new ObjectMapper(); + String expectedPretty = json.writerWithDefaultPrettyPrinter().writeValueAsString(expected); + String actualPretty = json.writerWithDefaultPrettyPrinter().writeValueAsString(actual); + Assertions.fail("OpenAPI mismatch.\n=== EXPECTED ===\n" + expectedPretty + "\n=== ACTUAL ===\n" + actualPretty); + } + } catch (Exception e) { + Assertions.fail("Failed to parse/compare OpenAPI YAML: " + e.getMessage(), e); } return generator; } - public static Throwable getException(SwaggerGeneratorContext context, Class cls, - String... methods) { + public static Throwable getException(Class cls, String... methods) { try { - SwaggerGeneratorForTest generator = new SwaggerGeneratorForTest(context, cls); - generator.replaceMethods(methods); + SwaggerGenerator generator = SwaggerGenerator.create(cls); + generator.replaceMethodWhiteList(methods); generator.generate(); } catch (Throwable e) { @@ -117,21 +112,26 @@ public static Throwable getException(SwaggerGeneratorContext context, Class c } // 不允许成功 - Assert.assertEquals("not allowed run to here", "run to here"); + Assertions.assertEquals("not allowed run to here", "run to here"); return null; } - public static void testException(String expectMsgLevel1, String expectMsgLevel2, SwaggerGeneratorContext context, - Class cls, + public static void testException(String expectMsgLevel1, String expectMsgLevel2, String expectMsgLevel3, Class cls, String... methods) { - Throwable exception = getException(context, cls, methods); - Assert.assertEquals(expectMsgLevel1, exception.getMessage()); - Assert.assertEquals(expectMsgLevel2, exception.getCause().getMessage()); + Throwable exception = getException(cls, methods); + Assertions.assertEquals(expectMsgLevel1, exception.getMessage()); + Assertions.assertEquals(expectMsgLevel2, exception.getCause().getMessage()); + Assertions.assertEquals(expectMsgLevel3, exception.getCause().getCause().getMessage()); } - public static void testException(String expectMsg, SwaggerGeneratorContext context, Class cls, - String... methods) { - Throwable exception = getException(context, cls, methods); - Assert.assertEquals(expectMsg, exception.getMessage()); + public static void testException(String expectMsgLevel1, String expectMsgLevel2, Class cls, String... methods) { + Throwable exception = getException(cls, methods); + Assertions.assertEquals(expectMsgLevel1, exception.getMessage()); + Assertions.assertEquals(expectMsgLevel2, exception.getCause().getMessage()); + } + + public static void testException(String expectMsg, Class cls, String... methods) { + Throwable exception = getException(cls, methods); + Assertions.assertEquals(expectMsg, exception.getMessage()); } } diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ClassUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ClassUtils.java deleted file mode 100644 index 1e43c7e17ae..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ClassUtils.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.utils; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -import javax.lang.model.SourceVersion; - -import org.apache.servicecomb.common.javassist.ClassConfig; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.foundation.common.utils.JvmUtils; -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.springframework.util.StringUtils; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; - -public final class ClassUtils { - private ClassUtils() { - } - - public static Class getClassByName(ClassLoader classLoader, String clsName) { - classLoader = JvmUtils.correctClassLoader(classLoader); - try { - return classLoader.loadClass(clsName); - } catch (ClassNotFoundException e) { - return null; - } - } - - // 将一系列body parameter包装成一个class - public static Class getOrCreateBodyClass(OperationGenerator operationGenerator, - List bodyParameters) { - SwaggerGenerator swaggerGenerator = operationGenerator.getSwaggerGenerator(); - Method method = operationGenerator.getProviderMethod(); - String clsName = swaggerGenerator.ensureGetPackageName() + "." + method.getName() + "Body"; - Class cls = getClassByName(swaggerGenerator.getClassLoader(), clsName); - if (cls != null) { - return cls; - } - - ClassConfig classConfig = new ClassConfig(); - classConfig.setClassName(clsName); - - // 1.全是预备body - // 2.预备body与明确body混合 - SwaggerToClassGenerator classGenerator = new SwaggerToClassGenerator(swaggerGenerator.getClassLoader(), - swaggerGenerator.getSwagger(), swaggerGenerator.ensureGetPackageName()); - for (BodyParameter bp : bodyParameters) { - JavaType javaType = ConverterMgr.findJavaType(classGenerator, bp); - classConfig.addField(bp.getName(), javaType); - } - - return JavassistUtils.createClass(swaggerGenerator.getClassLoader(), classConfig); - } - - public static boolean hasAnnotation(Class cls, Class annotation) { - if (cls.getAnnotation(annotation) != null) { - return true; - } - - for (Method method : cls.getMethods()) { - if (method.getAnnotation(annotation) != null) { - return true; - } - } - - return false; - } - - public static boolean isRawJsonType(Parameter param) { - Object rawJson = param.getVendorExtensions().get(SwaggerConst.EXT_RAW_JSON_TYPE); - if (Boolean.class.isInstance(rawJson)) { - return (boolean) rawJson; - } - return false; - } - - public static String getClassName(Map vendorExtensions) { - return getVendorExtension(vendorExtensions, SwaggerConst.EXT_JAVA_CLASS); - } - - public static String getInterfaceName(Map vendorExtensions) { - return getVendorExtension(vendorExtensions, SwaggerConst.EXT_JAVA_INTF); - } - - public static String getRawClassName(String canonical) { - if (StringUtils.isEmpty(canonical)) { - return null; - } - - int idx = canonical.indexOf("<"); - if (idx == 0) { - throw new IllegalStateException("Invalid class canonical: " + canonical); - } - - if (idx < 0) { - return canonical; - } - - return canonical.substring(0, idx); - } - - @SuppressWarnings("unchecked") - public static T getVendorExtension(Map vendorExtensions, String key) { - if (vendorExtensions == null) { - return null; - } - - return (T) vendorExtensions.get(key); - } - - public static String correctMethodParameterName(String paramName) { - if (SourceVersion.isName(paramName)) { - return paramName; - } - - StringBuilder newParam = new StringBuilder(); - for (int index = 0; index < paramName.length(); index++) { - char tempChar = paramName.charAt(index); - if (Character.isJavaIdentifierPart(tempChar)) { - newParam.append(paramName.charAt(index)); - continue; - } - - if (tempChar == '.' || tempChar == '-') { - newParam.append('_'); - } - } - return newParam.toString(); - } - - public static String correctClassName(String name) { - if (SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name)) { - return name; - } - String parts[] = name.split("\\.", -1); - for (int idx = 0; idx < parts.length; idx++) { - String part = parts[idx]; - if (part.isEmpty()) { - parts[idx] = "_"; - continue; - } - - part = part.replaceAll("[,;<>-]", "_").replace("[", "array_"); - if (Character.isDigit(part.charAt(0)) || SourceVersion.isKeyword(part)) { - part = "_" + part; - } - parts[idx] = part; - } - return String.join(".", parts); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java new file mode 100644 index 00000000000..bf2d012cf9d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/MethodUtils.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import io.swagger.v3.oas.annotations.Operation; + + +public class MethodUtils { + /** + * Get the methods of cls which are valid for generating Swagger schema. + * @param cls The REST interface class, or so called "controller" class, to be analysed. + * @return the valid methods to be used to generate Swagger schema, sorted by their Swagger operation name. + */ + public static List findSwaggerMethods(Class cls) { + Method[] methods = cls.getMethods(); + List result = new ArrayList<>(methods.length); + + for (Method m : methods) { + if (!isSkipMethod(cls, m)) { + result.add(m); + } + } + + // order of cls.getMethods() is undefined and not stable + // so we must sort them first to make generation is stable + result.sort(Comparator.comparing(MethodUtils::findSwaggerMethodName)); + return result; + } + + public static Map findSwaggerMethodsMapOfOperationId(Class cls) { + List methods = findSwaggerMethods(cls); + Map result = new HashMap<>(); + methods.forEach((item) -> result.put(findSwaggerMethodName(item), item)); + return result; + } + + /** + * Pick out those methods not proper to be added into the Swagger schema. + * + * @param cls the owner class of the method + * @param method the method to be validate + * @return true if this method should be abandoned; + * false if this method should be added in to Swagger schema + */ + public static boolean isSkipMethod(Class cls, Method method) { + if (method.isDefault()) { + return true; + } + if (method.getDeclaringClass() == Object.class) { + return true; + } + if (method.getDeclaringClass().isInterface() + && !cls.isInterface()) { + // inherited template methods + return true; + } + // skip static method + int modifiers = method.getModifiers(); + if (Modifier.isStatic(modifiers)) { + return true; + } + // skip bridge method + if (method.isBridge()) { + return true; + } + + Operation apiOperation = method.getAnnotation(Operation.class); + return apiOperation != null && apiOperation.hidden(); + } + + /** + * Get the operationId in schema of this method, + * no matter whether it should be hidden. + * @return If the operation name is specified via {@link Operation}, use that one. + * Otherwise the method name is returned. + */ + public static String findSwaggerMethodName(Method method) { + Operation apiOperationAnnotation = method.getAnnotation(Operation.class); + if (apiOperationAnnotation == null || StringUtils.isEmpty(apiOperationAnnotation.operationId())) { + return method.getName(); + } + + return apiOperationAnnotation.operationId(); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java deleted file mode 100644 index 6f9354b91b6..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.utils; - -import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.springframework.core.DefaultParameterNameDiscoverer; -import org.springframework.core.MethodParameter; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.PropertyBuilder; -import io.swagger.models.properties.RefProperty; -import io.swagger.models.properties.StringProperty; - -public final class ParamUtils { - private static DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); - - private ParamUtils() { - - } - - // 如果existName为empty,则通过原型查找 - public static String getParameterName(String existName, Method method, int paramIdx) { - if (StringUtils.isEmpty(existName)) { - existName = getParameterName(method, paramIdx); - } - - return existName; - } - - public static String getParameterName(Executable methodOrConstructor, int parameterIndex) { - MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(methodOrConstructor, parameterIndex); - return getParameterName(methodParameter, parameterIndex); - } - - public static String getParameterName(Method method, int paramIdx) { - MethodParameter methodParameter = new MethodParameter(method, paramIdx); - return getParameterName(methodParameter, paramIdx); - } - - public static String getParameterName(MethodParameter methodParameter, int paramIdx) { - methodParameter.initParameterNameDiscovery(parameterNameDiscoverer); - - String paramName = methodParameter.getParameterName(); - if (paramName == null) { - // 小于jdk8的场景中,即使有debug参数,也无法对着interface获取参数名,此时直接使用arg + paramIndex来表示 - paramName = "arg" + paramIdx; - } - return paramName; - } - - public static Type getGenericParameterType(Method method, int paramIdx) { - return method.getGenericParameterTypes()[paramIdx]; - } - - public static String generateBodyParameterName(Method method) { - return method.getName() + "Body"; - } - - public static BodyParameter createBodyParameter(OperationGenerator operationGenerator, - int paramIdx) { - Method method = operationGenerator.getProviderMethod(); - String paramName = getParameterName(method, paramIdx); - Type paramType = getGenericParameterType(method, paramIdx); - return createBodyParameter(operationGenerator.getSwagger(), paramName, paramType); - } - - public static BodyParameter createBodyParameter(Swagger swagger, String paramName, Type paramType) { - addDefinitions(swagger, paramType); - - Property property = ModelConverters.getInstance().readAsProperty(paramType); - Model model = PropertyBuilder.toModel(property); - if (model instanceof ModelImpl && property instanceof StringProperty) { - ((ModelImpl) model).setEnum(((StringProperty) property).getEnum()); - } - - BodyParameter bodyParameter = new BodyParameter(); - bodyParameter.setName(paramName); - bodyParameter.setSchema(model); - - return bodyParameter; - } - - public static void addDefinitions(Swagger swagger, Type paramType) { - Map models = ModelConverters.getInstance().readAll(paramType); - for (Map.Entry entry : models.entrySet()) { - swagger.addDefinition(entry.getKey(), entry.getValue()); - } - } - - public static void setParameterType(Swagger swagger, Method method, int paramIdx, - AbstractSerializableParameter parameter) { - Type paramType = ParamUtils.getGenericParameterType(method, paramIdx); - - ParamUtils.addDefinitions(swagger, paramType); - - Property property = ModelConverters.getInstance().readAsProperty(paramType); - - if (isComplexProperty(property)) { - // cannot set a simple parameter(header, query, etc.) as complex type - String msg = String.format("not allow complex type for %s parameter, method=%s:%s, paramIdx=%d, type=%s", - parameter.getIn(), - method.getDeclaringClass().getName(), - method.getName(), - paramIdx, - paramType.getTypeName()); - throw new Error(msg); - } - parameter.setProperty(property); - } - - /** - * Set param type info. For {@linkplain javax.ws.rs.BeanParam BeanParam} scenario. - * - * @param paramType type of the swagger parameter - * @param parameter swagger parameter - */ - public static void setParameterType(Type paramType, AbstractSerializableParameter parameter) { - Property property = ModelConverters.getInstance().readAsProperty(paramType); - - if (isComplexProperty(property)) { - // cannot set a simple parameter(header, query, etc.) as complex type - throw new IllegalArgumentException( - String.format( - "not allow such type of param:[%s], param name is [%s]", - property.getClass(), - parameter.getName())); - } - parameter.setProperty(property); - } - - public static boolean isComplexProperty(Property property) { - if (RefProperty.class.isInstance(property) || ObjectProperty.class.isInstance(property) - || MapProperty.class.isInstance(property)) { - return true; - } - - if (ArrayProperty.class.isInstance(property)) { - return isComplexProperty(((ArrayProperty) property).getItems()); - } - - return false; - } - - public static int findParameterByName(String name, List parameterList) { - for (int idx = 0; idx < parameterList.size(); idx++) { - Parameter parameter = parameterList.get(idx); - if (name.equals(parameter.getName())) { - return idx; - } - } - - return -1; - } - - public static boolean isRealBodyParameter(Parameter parameter) { - return BodyParameter.class.getName().equals(parameter.getClass().getName()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoOperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoOperationGenerator.java new file mode 100644 index 00000000000..ffc7e540a88 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoOperationGenerator.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.pojo; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.isContextParameter; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.core.AbstractOperationGenerator; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.apache.servicecomb.swagger.generator.core.utils.MethodUtils; + +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.reflect.TypeToken; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import jakarta.ws.rs.HttpMethod; + +public class PojoOperationGenerator extends AbstractOperationGenerator { + public PojoOperationGenerator(AbstractSwaggerGenerator swaggerGenerator, Method method) { + super(swaggerGenerator, method); + } + + @Override + protected void initParameterGenerators() { + List bodyParameters = new ArrayList<>(); + for (java.lang.reflect.Parameter methodParameter : method.getParameters()) { + Type type = TypeToken.of(clazz) + .resolveType(methodParameter.getParameterizedType()) + .getType(); + ParameterGenerator parameterGenerator = new ParameterGenerator( + this, Collections.emptyMap(), methodParameter, + TypeFactory.defaultInstance().constructType(type)); + validateParameter(parameterGenerator.getGenericType()); + if (isContextParameter(parameterGenerator.getGenericType())) { + continue; + } + + bodyParameters.add(parameterGenerator); + } + + tryWrapParametersToBody(bodyParameters); + } + + private void tryWrapParametersToBody(List bodyParameters) { + if (bodyParameters.size() == 0) { + return; + } + + if (bodyParameters.size() == 1 && SwaggerUtils.isBean(bodyParameters.get(0).getGenericType())) { + ParameterGenerator parameterGenerator = bodyParameters.get(0); + parameterGenerator.setHttpParameterType(HttpParameterType.BODY); + parameterGenerators.add(parameterGenerator); + return; + } + + wrapParametersToBody(bodyParameters); + } + + private void wrapParametersToBody(List bodyFields) { + // process annotations like parameter name + for (ParameterGenerator parameterGenerator : bodyFields) { + scanMethodParameter(parameterGenerator); + } + + String simpleRef = MethodUtils.findSwaggerMethodName(method) + "Body"; + + Schema bodyModel = new ObjectSchema(); + for (ParameterGenerator parameterGenerator : bodyFields) { + bodyModel.addProperty(parameterGenerator.getParameterGeneratorContext().getParameterName(), + parameterGenerator.getParameterGeneratorContext().getSchema()); + } + + swagger.getComponents().addSchemas(simpleRef, bodyModel); + Schema bodyModelNew = new Schema<>(); + bodyModelNew.set$ref(Components.COMPONENTS_SCHEMAS_REF + simpleRef); + ParameterGenerator newParameterGenerator = new ParameterGenerator(this, simpleRef, bodyModelNew); + newParameterGenerator.setHttpParameterType(HttpParameterType.BODY); + parameterGenerators.add(newParameterGenerator); + } + + @Override + public void correctOperation() { + correctPath(); + correctHttpMethod(); + super.correctOperation(); + } + + protected void correctPath() { + if (StringUtils.isEmpty(path)) { + path = "/" + getOperationId(); + } + } + + protected void correctHttpMethod() { + if (StringUtils.isEmpty(httpMethod)) { + setHttpMethod(HttpMethod.POST); + } + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGenerator.java new file mode 100644 index 00000000000..0a2e6985aeb --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGenerator.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.pojo; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; + +import jakarta.ws.rs.core.MediaType; + +public class PojoSwaggerGenerator extends AbstractSwaggerGenerator { + protected static final List SUPPORTED_CONTENT_TYPE + = Arrays.asList(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, MediaType.TEXT_PLAIN); + + public PojoSwaggerGenerator(Class cls) { + super(cls); + swaggerGeneratorContext.updateConsumes(SUPPORTED_CONTENT_TYPE); + swaggerGeneratorContext.updateProduces(SUPPORTED_CONTENT_TYPE); + } + + @SuppressWarnings("unchecked") + @Override + public T createOperationGenerator(Method method) { + return (T) new PojoOperationGenerator(this, method); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorContext.java deleted file mode 100644 index eb8ecc8a924..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorContext.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.pojo; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import javax.ws.rs.HttpMethod; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.apache.servicecomb.swagger.generator.pojo.converter.parameter.PendingBodyParameterConverter; -import org.apache.servicecomb.swagger.generator.pojo.extend.parameter.PendingBodyParameter; -import org.apache.servicecomb.swagger.generator.pojo.processor.parameter.PojoDefaultParameterProcessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; - -public class PojoSwaggerGeneratorContext extends AbstractSwaggerGeneratorContext { - - private static final Logger LOGGER = LoggerFactory.getLogger(PojoSwaggerGeneratorContext.class); - - static { - ConverterMgr.addConverter(PendingBodyParameter.class, new PendingBodyParameterConverter()); - } - - @Override - public int getOrder() { - return Integer.MAX_VALUE; - } - - @Override - public boolean canProcess(Class cls) { - for (Annotation annotation : cls.getAnnotations()) { - // we check the annotations by class name to avoid importing extra dependencies in this module - if ("javax.ws.rs.Path".equals(annotation.annotationType().getCanonicalName()) - || "org.springframework.web.bind.annotation.RequestMapping" - .equals(annotation.annotationType().getCanonicalName())) { - LOGGER.info( - "There is @RequestMapping or @Path annotation on the REST interface class, but POJO swagger context is chosen. " - + "If this is unexpected, maybe you should check your dependency jar files."); - } - } - return true; - } - - @Override - public boolean canProcess(Method method) { - return true; - } - - @Override - protected void initDefaultParameterProcessor() { - defaultParameterProcessor = new PojoDefaultParameterProcessor(); - } - - protected void correctPath(OperationGenerator operationGenerator) { - String path = operationGenerator.getPath(); - if (StringUtils.isEmpty(path)) { - path = "/" + operationGenerator.getOperation().getOperationId(); - } - operationGenerator.setPath(path); - } - - // 必须全是body,或全是pending,如果是混合的,直接报错 - protected void handlePendingBody(OperationGenerator operationGenerator) { - List bodyParameters = collectBodyBasedParameters(operationGenerator); - if (bodyParameters.isEmpty()) { - return; - } - - if (bodyParameters.size() == 1) { - Parameter bodyParameter = bodyParameters.get(0); - replaceBodyBasedParameter(operationGenerator, bodyParameter); - return; - } - - // 将多个pending合并成一个body - mergeBodyBasedParameters(operationGenerator, bodyParameters); - } - - protected List collectBodyBasedParameters(OperationGenerator operationGenerator) { - List bodyParameters = new ArrayList<>(); - for (Parameter parameter : operationGenerator.getSwaggerParameters()) { - if (BodyParameter.class.isInstance(parameter)) { - bodyParameters.add((BodyParameter) parameter); - } - } - return bodyParameters; - } - - protected void replaceBodyBasedParameter(OperationGenerator operationGenerator, Parameter bodyBasedParameter) { - if (ParamUtils.isRealBodyParameter(bodyBasedParameter)) { - return; - } - - List swaggerParameters = operationGenerator.getSwaggerParameters(); - int idx = swaggerParameters.indexOf(bodyBasedParameter); - String bodyParamName = bodyBasedParameter.getName(); - BodyParameter bodyParameter = ((PendingBodyParameter) bodyBasedParameter).createBodyParameter(bodyParamName); - swaggerParameters.set(idx, bodyParameter); - } - - protected void mergeBodyBasedParameters(OperationGenerator operationGenerator, - List bodyParameters) { - List swaggerParameters = operationGenerator.getSwaggerParameters(); - swaggerParameters.removeAll(bodyParameters); - - // 将这些body包装为一个class,整体做为一个body参数 - String bodyParamName = ParamUtils.generateBodyParameterName(operationGenerator.getProviderMethod()); - Class cls = ClassUtils.getOrCreateBodyClass(operationGenerator, bodyParameters); - BodyParameter bodyParameter = - ParamUtils.createBodyParameter(operationGenerator.getSwagger(), bodyParamName, cls); - swaggerParameters.add(bodyParameter); - } - - protected void correctHttpMethod(OperationGenerator operationGenerator) { - if (StringUtils.isEmpty(operationGenerator.getHttpMethod())) { - operationGenerator.setHttpMethod(HttpMethod.POST); - } - } - - @Override - public void postProcessOperation(OperationGenerator operationGenerator) { - correctPath(operationGenerator); - correctHttpMethod(operationGenerator); - handlePendingBody(operationGenerator); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorFactory.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorFactory.java new file mode 100644 index 00000000000..05053f8609d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/PojoSwaggerGeneratorFactory.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.pojo; + +import java.lang.annotation.Annotation; + +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PojoSwaggerGeneratorFactory implements SwaggerGeneratorFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(PojoSwaggerGeneratorFactory.class); + + @Override + public int getOrder() { + return Integer.MAX_VALUE; + } + + @Override + public boolean canProcess(Class cls) { + for (Annotation annotation : cls.getAnnotations()) { + // we check the annotations by class name to avoid importing extra dependencies in this module + if (annotation instanceof Path + || "org.springframework.web.bind.annotation.RequestMapping" + .equals(annotation.annotationType().getCanonicalName())) { + LOGGER.info( + "There is @RequestMapping or @Path annotation on the REST interface class, but POJO swagger generator is chosen. " + + "If this is unexpected, maybe you should check your dependency jar files."); + } + } + return true; + } + + @Override + public SwaggerGenerator create(Class cls) { + return new PojoSwaggerGenerator(cls); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/converter/parameter/PendingBodyParameterConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/converter/parameter/PendingBodyParameterConverter.java deleted file mode 100644 index 6a594f8e1b3..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/converter/parameter/PendingBodyParameterConverter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.pojo.converter.parameter; - -import org.apache.servicecomb.swagger.converter.Converter; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.pojo.extend.parameter.PendingBodyParameter; - -import com.fasterxml.jackson.databind.JavaType; - -public class PendingBodyParameterConverter implements Converter { - - @Override - public JavaType convert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { - PendingBodyParameter param = (PendingBodyParameter) def; - return swaggerToClassGenerator.convert(param.getProperty()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java deleted file mode 100644 index 065b6122d78..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/extend/parameter/PendingBodyParameter.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.pojo.extend.parameter; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.swagger.models.ModelImpl; -import io.swagger.models.RefModel; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.PropertyBuilder; -import io.swagger.models.properties.RefProperty; -import io.swagger.util.Json; - -// -// 备选body -// int test(int x, Set y) -// 反向生成契约时,x、y都是备选body,最终再合并成body -// 如果直接使用BodyParamter,会导致y有信息丢失 -// 只在透明rpc模式中使用 -// jaxrs、springmvc这种模式,要求符合模式本身的定义场景,不允许随意组合 -// -public class PendingBodyParameter extends BodyParameter { - @JsonIgnore - private OperationGenerator operationGenerator; - - @JsonIgnore - private Property property; - - @JsonIgnore - private Type type; - - public void setOperationGenerator(OperationGenerator operationGenerator) { - this.operationGenerator = operationGenerator; - } - - public Property getProperty() { - return property; - } - - public void setProperty(Property property) { - this.property = property; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - @JsonIgnore - public Method getMethod() { - return operationGenerator.getProviderMethod(); - } - - public BodyParameter createBodyParameter(String paramName) { - String modelType = ParamUtils.generateBodyParameterName(operationGenerator.getProviderMethod()); - RefModel model = toRefModel(modelType); - - setName(paramName); - setSchema(model); - - try { - return Json.mapper().readValue(Json.mapper().writeValueAsString(this), BodyParameter.class); - } catch (IOException e) { - throw new IllegalStateException("failed to createBodyParameter.", e); - } - } - - // swagger中的body只能是ref,不能是简单类型 - private RefModel toRefModel(String modelType) { - if (RefProperty.class.isInstance(property)) { - return (RefModel) PropertyBuilder.toModel(property); - } - - ModelImpl modelImpl = new ModelImpl(); - modelImpl.setType("object"); - modelImpl.setName(name); - modelImpl.addProperty(name, property); - - operationGenerator.getSwagger().addDefinition(modelType, modelImpl); - - RefModel refModel = new RefModel(); - refModel.setReference("#/definitions/" + modelType); - - return refModel; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/package-info.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/package-info.java deleted file mode 100644 index aae80216843..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * 透明rpc相关功能独立project比较合适,可是core的ut就太麻烦了 - */ -package org.apache.servicecomb.swagger.generator.pojo; diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/processor/parameter/PojoDefaultParameterProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/processor/parameter/PojoDefaultParameterProcessor.java deleted file mode 100644 index 750aa743a01..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/processor/parameter/PojoDefaultParameterProcessor.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.pojo.processor.parameter; - -import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.pojo.extend.parameter.PendingBodyParameter; -import org.apache.servicecomb.swagger.generator.pojo.utils.PojoParamUtils; - -public class PojoDefaultParameterProcessor implements DefaultParameterProcessor { - - @Override - public void process(OperationGenerator operationGenerator, int paramIndex) { - PendingBodyParameter pendingBodyParameter = - PojoParamUtils.createPendingBodyParameter(operationGenerator, paramIndex); - operationGenerator.addProviderParameter(pendingBodyParameter); - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/utils/PojoParamUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/utils/PojoParamUtils.java deleted file mode 100644 index 33492f5f297..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/pojo/utils/PojoParamUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.pojo.utils; - -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.apache.servicecomb.swagger.generator.pojo.extend.parameter.PendingBodyParameter; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.Property; - -public final class PojoParamUtils { - private PojoParamUtils() { - } - - public static PendingBodyParameter createPendingBodyParameter(OperationGenerator operationGenerator, - int paramIdx) { - Method method = operationGenerator.getProviderMethod(); - String paramName = ParamUtils.getParameterName(method, paramIdx); - Type paramType = ParamUtils.getGenericParameterType(method, paramIdx); - return createPendingBodyParameter(operationGenerator, paramName, paramType); - } - - public static PendingBodyParameter createPendingBodyParameter(OperationGenerator operationGenerator, - String paramName, Type paramType) { - ParamUtils.addDefinitions(operationGenerator.getSwagger(), paramType); - Property property = ModelConverters.getInstance().readAsProperty(paramType); - - PendingBodyParameter pendingBodyParameter = new PendingBodyParameter(); - pendingBodyParameter.setName(paramName); - pendingBodyParameter.setProperty(property); - pendingBodyParameter.setType(paramType); - pendingBodyParameter.setOperationGenerator(operationGenerator); - - return pendingBodyParameter; - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestOperationGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestOperationGenerator.java new file mode 100644 index 00000000000..9ce1c1ac9e6 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestOperationGenerator.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.rest; + +import java.lang.reflect.Method; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.core.AbstractOperationGenerator; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; + +public abstract class RestOperationGenerator extends AbstractOperationGenerator { + public RestOperationGenerator(AbstractSwaggerGenerator swaggerGenerator, Method method) { + super(swaggerGenerator, method); + } + + @Override + public void correctOperation() { + checkPath(); + correctPath(); + super.correctOperation(); + } + + protected void checkPath() { + if (StringUtils.isEmpty(path) + && StringUtils.isEmpty(SwaggerUtils.getBasePath(swagger))) { + throw new IllegalStateException("Path must not both be empty in class and method"); + } + } + + protected void correctPath() { + if (StringUtils.isEmpty(path)) { + path = "/"; + } + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGenerator.java new file mode 100644 index 00000000000..a6811f684ab --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGenerator.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.rest; + +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; + +public abstract class RestSwaggerGenerator extends AbstractSwaggerGenerator { + public RestSwaggerGenerator(Class cls) { + super(cls); + } +} diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGeneratorContext.java deleted file mode 100644 index 1d77cca257c..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/rest/RestSwaggerGeneratorContext.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.rest; - -import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.springframework.util.StringUtils; - -public abstract class RestSwaggerGeneratorContext extends AbstractSwaggerGeneratorContext { - protected void correctPath(OperationGenerator operationGenerator) { - String path = operationGenerator.getPath(); - if (StringUtils.isEmpty(path)) { - path = "/"; - } - operationGenerator.setPath(path); - } - - @Override - public void postProcessOperation(OperationGenerator operationGenerator) { - checkPath(operationGenerator); - correctPath(operationGenerator); - } - - protected void checkPath(OperationGenerator operationGenerator) { - if (StringUtils.isEmpty(operationGenerator.getPath()) - && StringUtils.isEmpty(operationGenerator.getSwagger().getBasePath())) { - throw new Error("Path must not both be empty in class and method"); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/io.swagger.converter.ModelConverter b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/io.swagger.v3.core.converter.ModelConverter similarity index 100% rename from swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/io.swagger.converter.ModelConverter rename to swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/io.swagger.v3.core.converter.ModelConverter diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor new file mode 100644 index 00000000000..3b9c9f84002 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.annotation.OpenAPIDefinitionProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor new file mode 100644 index 00000000000..249784556de --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.annotation.OperationMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponsesMethodProcessor +org.apache.servicecomb.swagger.generator.core.processor.annotation.ApiResponseMethodProcessor +org.apache.servicecomb.swagger.generator.core.processor.annotation.RequestBodyMethodAnnotationProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor new file mode 100644 index 00000000000..eba9ece3fd7 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.parameter.RequestBodyParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.core.processor.parameter.ParameterParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.core.processor.parameter.RawJsonRequestBodyProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor new file mode 100644 index 00000000000..130af5d2a49 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.parameter.PartParameterTypeProcessor +org.apache.servicecomb.swagger.generator.core.processor.parameter.PartArrayParameterTypeProcessor +org.apache.servicecomb.swagger.generator.core.processor.parameter.PartListParameterTypeProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor new file mode 100644 index 00000000000..9abf37e8c9d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.response.CompletableFutureProcessor +org.apache.servicecomb.swagger.generator.core.processor.response.OptionalProcessor +org.apache.servicecomb.swagger.generator.core.processor.response.PublisherProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister new file mode 100644 index 00000000000..db52891e086 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.core.processor.parameter.HttpServletRequestContextRegister +org.apache.servicecomb.swagger.generator.core.processor.parameter.ServerWebSocketContextRegister diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGenerator b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGenerator new file mode 100644 index 00000000000..35c874ef2a2 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGenerator @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGenerator diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory new file mode 100644 index 00000000000..ba83d84d0d5 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorFactory diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor deleted file mode 100644 index c9d2951b87e..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.core.processor.parametertype.HttpServletRequestProcessor diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor deleted file mode 100644 index 22a219349f5..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.core.processor.response.CompletableFutureProcessor \ No newline at end of file diff --git a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext b/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext deleted file mode 100644 index ff8527acaa1..00000000000 --- a/swagger/swagger-generator/generator-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/TestSwaggerUtils.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/TestSwaggerUtils.java index d0d7c81c4b6..8cf0fa503f5 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/TestSwaggerUtils.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/TestSwaggerUtils.java @@ -19,174 +19,108 @@ import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.fasterxml.jackson.core.JsonProcessingException; - -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.util.Yaml; -import mockit.Expectations; -import mockit.Mocked; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; public class TestSwaggerUtils { - @Rule - public ExpectedException expectedException = ExpectedException.none(); @Test public void swaggerToStringNormal() { - Swagger swagger = new Swagger(); + OpenAPI swagger = new OpenAPI(); String content = SwaggerUtils.swaggerToString(swagger); - Swagger newSwagger = SwaggerUtils.parseSwagger(content); - Assert.assertEquals(swagger, newSwagger); + OpenAPI newSwagger = SwaggerUtils.parseSwagger(content); + Assertions.assertEquals(swagger, newSwagger); } - @Test - public void swaggerToStringException(@Mocked Swagger swagger) throws JsonProcessingException { - new Expectations() { - { - swagger.getBasePath(); - result = new Error("failed"); - } - }; - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage("Convert swagger to string failed, "); - - SwaggerUtils.swaggerToString(swagger); - } @Test - public void parseSwaggerUrlNormal(@Mocked URL url) throws IOException { - String content = "swagger: \"2.0\""; - new Expectations(IOUtils.class) { - { - IOUtils.toString(url); - result = content; - } - }; - - Swagger swagger = Yaml.mapper().readValue(content, Swagger.class); - Swagger result = SwaggerUtils.parseSwagger(url); - Assert.assertEquals(swagger, result); + public void parseSwaggerUrlNormal() throws IOException { + String content = "openapi: 3.0.1"; + URL url = Mockito.mock(URL.class); + try (MockedStatic ioUtilsMockedStatic = Mockito.mockStatic(IOUtils.class)) { + ioUtilsMockedStatic.when(() -> IOUtils.toString(url, StandardCharsets.UTF_8)).thenReturn(content); + OpenAPI swagger = Yaml.mapper().readValue(content, OpenAPI.class); + OpenAPI result = SwaggerUtils.parseAndValidateSwagger(url); + Assertions.assertEquals(swagger, result); + Assertions.assertEquals("3.0.1", result.getOpenapi()); + } } @Test - public void parseSwaggerUrlException(@Mocked URL url) throws IOException { - new Expectations(IOUtils.class) { - { - IOUtils.toString(url); - result = new Error("failed"); - } - }; - - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage("Parse swagger from url failed, "); - - SwaggerUtils.parseSwagger(url); + public void parseSwaggerUrlException() throws IOException { + URL url = Mockito.mock(URL.class); + try (MockedStatic ioUtilsMockedStatic = Mockito.mockStatic(IOUtils.class)) { + ioUtilsMockedStatic.when(() -> IOUtils.toString(url, StandardCharsets.UTF_8)) + .thenThrow(new RuntimeExceptionWithoutStackTrace("failed")); + ServiceCombException exception = Assertions.assertThrows(ServiceCombException.class, + () -> SwaggerUtils.parseAndValidateSwagger(url)); + Assertions.assertTrue(exception.getMessage().contains("Parse swagger from url failed, ")); + } } @Test - public void parseSwaggerContentException() throws IOException { - expectedException.expect(ServiceCombException.class); - expectedException.expectMessage("Parse swagger from content failed, "); - - SwaggerUtils.parseSwagger(""); + public void parseSwaggerContentException() { + ServiceCombException exception = Assertions.assertThrows(ServiceCombException.class, + () -> SwaggerUtils.parseSwagger("")); + Assertions.assertEquals("Parse swagger from content failed, ", exception.getMessage()); } @Test public void correctResponsesOperationFixEmptyDescription() { - Response response = new Response(); + ApiResponse response = new ApiResponse(); Operation operation = new Operation(); - operation.addResponse("200", response); + operation.setResponses(new ApiResponses()); + operation.getResponses().addApiResponse("200", response); SwaggerUtils.correctResponses(operation); - Assert.assertEquals("response of 200", response.getDescription()); + Assertions.assertEquals("response of 200", response.getDescription()); } @Test public void correctResponsesOperationNotChangeExistDescription() { - Response response = new Response(); + ApiResponse response = new ApiResponse(); response.setDescription("description"); Operation operation = new Operation(); - operation.addResponse("200", response); - - SwaggerUtils.correctResponses(operation); - Assert.assertEquals("description", response.getDescription()); - } - - @Test - public void correctResponsesOperationDefaultTo200() { - Response response = new Response(); - - Operation operation = new Operation(); - operation.addResponse("default", response); - - SwaggerUtils.correctResponses(operation); - Assert.assertSame(response, operation.getResponses().get("200")); - } - - @Test - public void correctResponsesOperation2xxTo200() { - Response response = new Response(); - - Operation operation = new Operation(); - operation.addResponse("default", new Response()); - operation.addResponse("201", response); - operation.addResponse("301", new Response()); + operation.setResponses(new ApiResponses()); + operation.getResponses().addApiResponse("200", response); SwaggerUtils.correctResponses(operation); - Assert.assertSame(response, operation.getResponses().get("200")); - } - - @Test - public void correctResponsesNoPaths() { - Swagger swagger = new Swagger(); - - // not throw exception - SwaggerUtils.correctResponses(swagger); + Assertions.assertEquals("description", response.getDescription()); } @Test public void correctResponsesHavePaths() { - Response response = new Response(); + ApiResponse response = new ApiResponse(); Operation operation = new Operation(); - operation.addResponse("200", response); + operation.setResponses(new ApiResponses()); + operation.getResponses().addApiResponse("200", response); - Path path = new Path(); - path.set("get", operation); + PathItem path = new PathItem(); + path.get(operation); - Swagger swagger = new Swagger(); + OpenAPI swagger = new OpenAPI(); swagger.path("/base", path); SwaggerUtils.correctResponses(swagger); - Assert.assertEquals("response of 200", response.getDescription()); - } - - - @Test(expected = ServiceCombException.class) - public void testInvalidate() throws Exception { - URL resource = TestSwaggerUtils.class.getResource("/swagger1.yaml"); - Swagger swagger = SwaggerUtils.parseSwagger(resource); - SwaggerUtils.validateSwagger(swagger); - } - - @Test - public void testInvalidateValid() throws Exception { - URL resource = TestSwaggerUtils.class.getResource("/swagger2.yaml"); - Swagger swagger = SwaggerUtils.parseSwagger(resource); - SwaggerUtils.validateSwagger(swagger); + Assertions.assertEquals("response of 200", response.getDescription()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestAbstractConverter.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestAbstractConverter.java deleted file mode 100644 index bd363937a3f..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestAbstractConverter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import mockit.Mocked; - -public class TestAbstractConverter { - Map vendorExtensions = new HashMap<>(); - - JavaType doConvertResult; - - ClassLoader classLoader = new ClassLoader() { - }; - - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(classLoader, null, null); - - AbstractConverter converter = new AbstractConverter() { - @Override - protected Map findVendorExtensions(Object def) { - return vendorExtensions; - } - - @Override - protected JavaType doConvert(SwaggerToClassGenerator swaggerToClassGenerator, Object def) { - return doConvertResult; - } - }; - - @Test - public void convert_canonical_normal() { - doConvertResult = TypeFactory.defaultInstance().constructType(String.class); - vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, "java.lang.String"); - - Assert.assertSame(doConvertResult, converter.convert(swaggerToClassGenerator, null)); - } - - @Test - public void convert_noCanonical(@Mocked JavaType type) { - doConvertResult = type; - - Assert.assertSame(type, converter.convert(swaggerToClassGenerator, null)); - } - - @Test - public void convert_canonical_generic() { - doConvertResult = TypeFactory.defaultInstance().constructParametricType(Optional.class, String.class); - vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, "java.util.Optional"); - - Assert.assertSame(doConvertResult, converter.convert(swaggerToClassGenerator, null)); - } - - @Test - public void convert_canonical_rawNotExist() { - doConvertResult = TypeFactory.defaultInstance().constructType(String.class); - vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, "xxx"); - - Assert.assertSame(doConvertResult, converter.convert(swaggerToClassGenerator, null)); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestConverterMgr.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestConverterMgr.java deleted file mode 100644 index d3b793c5379..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/TestConverterMgr.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter; - -import java.util.Map; - -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.servicecomb.swagger.extend.property.ByteProperty; -import org.apache.servicecomb.swagger.extend.property.ShortProperty; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.properties.BaseIntegerProperty; -import io.swagger.models.properties.BooleanProperty; -import io.swagger.models.properties.ByteArrayProperty; -import io.swagger.models.properties.DateProperty; -import io.swagger.models.properties.DateTimeProperty; -import io.swagger.models.properties.DecimalProperty; -import io.swagger.models.properties.DoubleProperty; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.FloatProperty; -import io.swagger.models.properties.IntegerProperty; -import io.swagger.models.properties.LongProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.StringProperty; - -public class TestConverterMgr { - @Test - public void propertyMapGenericSignature() throws IllegalAccessException { - @SuppressWarnings("unchecked") - Map, JavaType> propertyMap = (Map, JavaType>) FieldUtils - .readStaticField(ConverterMgr.class, "PROPERTY_MAP", true); - - Assert.assertEquals("Ljava/lang/Boolean;", propertyMap.get(BooleanProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Float;", propertyMap.get(FloatProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Double;", propertyMap.get(DoubleProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/math/BigDecimal;", propertyMap.get(DecimalProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Byte;", propertyMap.get(ByteProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Short;", propertyMap.get(ShortProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Integer;", propertyMap.get(IntegerProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Integer;", propertyMap.get(BaseIntegerProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/Long;", propertyMap.get(LongProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/lang/String;", propertyMap.get(StringProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/time/LocalDate;", propertyMap.get(DateProperty.class).getGenericSignature()); - Assert.assertEquals("Ljava/util/Date;", propertyMap.get(DateTimeProperty.class).getGenericSignature()); - Assert.assertEquals("[B;", propertyMap.get(ByteArrayProperty.class).getGenericSignature()); - Assert.assertEquals("Ljavax/servlet/http/Part;", propertyMap.get(FileProperty.class).getGenericSignature()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/model/TestModelImplConverter.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/model/TestModelImplConverter.java deleted file mode 100644 index be5dbdcf453..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/model/TestModelImplConverter.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.model; - -import java.util.Map; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.Model; -import io.swagger.models.ModelImpl; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.properties.IntegerProperty; -import io.swagger.models.properties.StringProperty; - -public class TestModelImplConverter { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - Swagger swagger = new Swagger(); - - ClassLoader classLoader = new ClassLoader() { - }; - - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(classLoader, swagger, "pkg"); - - @After - public void teardown() { - JavassistUtils.clearByClassLoader(classLoader); - } - - @Test - public void convert_simple() { - ModelImpl model = new ModelImpl(); - model.setType(StringProperty.TYPE); - swagger.addDefinition("string", model); - - swaggerToClassGenerator.convert(); - - Assert.assertSame(String.class, swaggerToClassGenerator.convert(model).getRawClass()); - } - - @Test - public void convert_ref() { - ModelImpl model = new ModelImpl(); - model.setType(StringProperty.TYPE); - swagger.addDefinition("string", model); - - ModelImpl refModel = new ModelImpl(); - refModel.setReference("string"); - swagger.addDefinition("ref", refModel); - - swaggerToClassGenerator.convert(); - - Assert.assertSame(String.class, swaggerToClassGenerator.convert(refModel).getRawClass()); - } - - @Test - public void convert_map() { - ModelImpl mapModel = new ModelImpl(); - mapModel.setAdditionalProperties(new IntegerProperty()); - swagger.addDefinition("map", mapModel); - - swaggerToClassGenerator.convert(); - - JavaType javaType = swaggerToClassGenerator.convert(mapModel); - Assert.assertSame(Map.class, javaType.getRawClass()); - Assert.assertSame(String.class, javaType.getKeyType().getRawClass()); - Assert.assertSame(Integer.class, javaType.getContentType().getRawClass()); - } - - static class Empty { - } - - @Test - public void convert_empty() { - ParamUtils.createBodyParameter(swagger, "body", Empty.class); - Model model = swagger.getDefinitions().get(Empty.class.getSimpleName()); - model.getVendorExtensions().put(SwaggerConst.EXT_JAVA_CLASS, "pkg.Empty"); - - JavaType javaType = swaggerToClassGenerator.forceConvert(model); - - Assert.assertEquals("pkg.Empty", javaType.getRawClass().getName()); - } - - @Test - public void convert_object() { - BodyParameter bodyParameter = ParamUtils.createBodyParameter(swagger, "body", Object.class); - Model model = bodyParameter.getSchema(); - - JavaType javaType = swaggerToClassGenerator.convert(model); - - Assert.assertSame(Object.class, javaType.getRawClass()); - } - - @Test - public void convert_createClass() throws NoSuchFieldException { - ModelImpl model = new ModelImpl(); - model.addProperty("f1", new StringProperty()); - model.setVendorExtension(SwaggerConst.EXT_JAVA_CLASS, "pkg.Model"); - - swagger.addDefinition("cls", model); - - JavaType javaType = swaggerToClassGenerator.forceConvert(model); - - Class cls = javaType.getRawClass(); - Assert.assertEquals("pkg.Model", cls.getName()); - Assert.assertSame(String.class, cls.getField("f1").getType()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java deleted file mode 100644 index 5b42cd50616..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.converter.property; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class SwaggerParamCollectionFormatTest { - @Test - public void splitParamNormal() { - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,b,c"), - Matchers.arrayContaining("a", "b", "c")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("10 11 12"), - Matchers.arrayContaining("10", "11", "12")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\tb\tc"), - Matchers.arrayContaining("a", "b", "c")); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a|b|c"), - Matchers.arrayContaining("a", "b", "c")); - } - - @Test - public void splitParamMulti() { - Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam("a,b,c"), - Matchers.arrayContaining("a,b,c")); - } - - @Test - public void splitParam_SingleElement() { - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a"), - Matchers.arrayContaining("a")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a"), - Matchers.arrayContaining("a")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a"), - Matchers.arrayContaining("a")); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a"), - Matchers.arrayContaining("a")); - Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam("a"), - Matchers.arrayContaining("a")); - } - - @Test - public void splitParam_NullElement() { - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(null), - Matchers.emptyArray()); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam(null), - Matchers.emptyArray()); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam(null), - Matchers.emptyArray()); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam(null), - Matchers.emptyArray()); - Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam(null), - Matchers.emptyArray()); - } - - @Test - public void splitParam_BlankElement() { - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(""), - Matchers.arrayContaining("")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam(""), - Matchers.arrayContaining("")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam(""), - Matchers.arrayContaining("")); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam(""), - Matchers.arrayContaining("")); - Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam(""), - Matchers.arrayContaining("")); - - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,,b"), - Matchers.arrayContaining("a", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a b"), - Matchers.arrayContaining("a", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\t\tb"), - Matchers.arrayContaining("a", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a||b"), - Matchers.arrayContaining("a", "", "b")); - - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,,"), - Matchers.arrayContaining("a", "", "")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a "), - Matchers.arrayContaining("a", "", "")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\t\t"), - Matchers.arrayContaining("a", "", "")); - String[] actual = SwaggerParamCollectionFormat.PIPES.splitParam("a||"); - Assert.assertThat(Arrays.toString(actual), actual, - Matchers.arrayContaining("a", "", "")); - - Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(",,b"), - Matchers.arrayContaining("", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam(" b"), - Matchers.arrayContaining("", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("\t\tb"), - Matchers.arrayContaining("", "", "b")); - Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("||b"), - Matchers.arrayContaining("", "", "b")); - } - - @Test - public void joinNormal() { - List params = Arrays.asList("a", "b", "c"); - assertEquals("a,b,c", SwaggerParamCollectionFormat.CSV.joinParam(params)); - assertEquals("a b c", SwaggerParamCollectionFormat.SSV.joinParam(params)); - assertEquals("a\tb\tc", SwaggerParamCollectionFormat.TSV.joinParam(params)); - assertEquals("a|b|c", SwaggerParamCollectionFormat.PIPES.joinParam(params)); - } - - @Test - public void join_SingleElement() { - List params = Collections.singletonList("a"); - assertEquals("a", SwaggerParamCollectionFormat.CSV.joinParam(params)); - assertEquals("a", SwaggerParamCollectionFormat.SSV.joinParam(params)); - assertEquals("a", SwaggerParamCollectionFormat.TSV.joinParam(params)); - assertEquals("a", SwaggerParamCollectionFormat.PIPES.joinParam(params)); - } - - @Test - public void join_EmptyArray() { - Assert.assertNull(SwaggerParamCollectionFormat.CSV.joinParam(Collections.EMPTY_LIST)); - } - - @Test - public void join_NullAndBlankElement() { - Assert.assertNull(SwaggerParamCollectionFormat.CSV.joinParam(Collections.singletonList(null))); - - assertEquals("", SwaggerParamCollectionFormat.CSV.joinParam(Collections.singleton(""))); - assertEquals("a,,b,c", SwaggerParamCollectionFormat.CSV.joinParam(Arrays.asList("a", "", "b", "c"))); - assertEquals("a b c", SwaggerParamCollectionFormat.SSV.joinParam(Arrays.asList("a", "", "b", "c"))); - assertEquals("a\t\tb\tc", SwaggerParamCollectionFormat.TSV.joinParam(Arrays.asList("a", "", "b", "c"))); - assertEquals("a||b|c", SwaggerParamCollectionFormat.PIPES.joinParam(Arrays.asList("a", "", "b", "c"))); - - assertEquals("a,b,,c", - SwaggerParamCollectionFormat.CSV - .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null))); - assertEquals("a b c", - SwaggerParamCollectionFormat.SSV - .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null))); - assertEquals("a\tb\t\tc", - SwaggerParamCollectionFormat.TSV - .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null))); - assertEquals("a|b||c", - SwaggerParamCollectionFormat.PIPES - .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null))); - - assertEquals("a,b,,c", - SwaggerParamCollectionFormat.CSV - .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null))); - assertEquals("a b c", - SwaggerParamCollectionFormat.SSV - .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null))); - assertEquals("a\tb\t\tc", - SwaggerParamCollectionFormat.TSV - .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null))); - assertEquals("a|b||c", - SwaggerParamCollectionFormat.PIPES - .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null))); - } - - @Test - public void join_NullArray() { - assertNull(SwaggerParamCollectionFormat.CSV.joinParam(null)); - } - - /** - * In fact, the {@link SwaggerParamCollectionFormat#joinParam(Collection)} of {@link SwaggerParamCollectionFormat#MULTI} - * should never be invoked. - * This test is just for ensuring the method does not throw exception. - */ - @Test - public void joinMulti() { - SwaggerParamCollectionFormat.MULTI.joinParam(Arrays.asList("a", "b", "c")); - SwaggerParamCollectionFormat.MULTI.joinParam(Collections.singletonList("a")); - assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(new ArrayList())); - assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(Collections.singleton(null))); - assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(null)); - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/TestModelResolverExt.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/TestModelResolverExt.java deleted file mode 100644 index 9cc4abba15b..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/TestModelResolverExt.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.extend; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -public class TestModelResolverExt { - static ModelResolverExt resolver = new ModelResolverExt(); - - Map vendorExtensions = new HashMap<>(); - - @Test - public void setType() { - JavaType type = TypeFactory.defaultInstance().constructCollectionType(List.class, String.class); - resolver.setType(type, vendorExtensions); - - Assert.assertEquals("java.util.List", vendorExtensions.get(SwaggerConst.EXT_JAVA_CLASS)); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospectorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospectorTest.java new file mode 100644 index 00000000000..6ab24facd76 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/introspector/JsonPropertyIntrospectorTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend.introspector; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class JsonPropertyIntrospectorTest { + + @Test + public void findEnumValue() { + JsonPropertyIntrospector introspector = new JsonPropertyIntrospector(); + + Assertions.assertEquals("AB", introspector.findEnumValue(TestEnum.AB)); + Assertions.assertEquals("C-D", introspector.findEnumValue(TestEnum.C_D)); + Assertions.assertEquals("E.F", introspector.findEnumValue(TestEnum.E_F)); + Assertions.assertEquals("HI", introspector.findEnumValue(TestEnum.HI)); + } + + public enum TestEnum { + AB, + @JsonProperty(value = "C-D") + C_D, + @JsonProperty(value = "E.F") + E_F, + @JsonProperty + HI + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExtTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExtTest.java new file mode 100644 index 00000000000..309f84f4b4a --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/module/EnumModuleExtTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.extend.module; + +import static org.hamcrest.Matchers.contains; + +import java.util.List; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class EnumModuleExtTest { + public enum TestEnum { + AB, + @JsonProperty(value = "C-D") + C_D, + @JsonProperty(value = "E.F") + E_F, + @JsonProperty + HI + } + + @Test + public void testEnumModule() throws JsonProcessingException { + ObjectMapper mapper = Json.mapper(); + String serializeValue = mapper.writeValueAsString(TestEnum.AB); + Assertions.assertEquals("\"AB\"", serializeValue); + serializeValue = mapper.writeValueAsString(TestEnum.C_D); + Assertions.assertEquals("\"C-D\"", serializeValue); + serializeValue = mapper.writeValueAsString(TestEnum.E_F); + Assertions.assertEquals("\"E.F\"", serializeValue); + serializeValue = mapper.writeValueAsString(TestEnum.HI); + Assertions.assertEquals("\"\"", serializeValue); + } + + @Test + public void testEnumModuleModel() { + OpenAPI openAPI = new OpenAPI(); + Schema schema = SwaggerUtils.resolveTypeSchemas(openAPI, TestEnum.class); + Assertions.assertEquals(schema.getType(), "string"); + MatcherAssert.assertThat((List) schema.getEnum(), contains("AB", "C-D", "E.F", "")); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/property/creator/TestPartPropertyCreator.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/property/creator/TestPartPropertyCreator.java index 8d2bea314f3..677e3772ebb 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/property/creator/TestPartPropertyCreator.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/extend/property/creator/TestPartPropertyCreator.java @@ -17,13 +17,13 @@ package org.apache.servicecomb.swagger.extend.property.creator; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import io.swagger.models.properties.FileProperty; +import io.swagger.v3.oas.models.media.FileSchema; public class TestPartPropertyCreator { @@ -32,11 +32,11 @@ public class TestPartPropertyCreator { @SuppressWarnings("unchecked") @Test public void classes() { - Assert.assertThat(creator.classes(), Matchers.arrayContaining(Part.class)); + MatcherAssert.assertThat(creator.classes(), Matchers.arrayContaining(Part.class)); } @Test public void createProperty() { - Assert.assertThat(creator.createProperty(), Matchers.instanceOf(FileProperty.class)); + MatcherAssert.assertThat(creator.createProperty(), Matchers.instanceOf(FileSchema.class)); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/ClassUtilsForTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/ClassUtilsForTest.java deleted file mode 100644 index f2330a90abd..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/ClassUtilsForTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core; - -import java.util.Map; - -import org.apache.servicecomb.swagger.converter.ConverterMgr; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.springframework.util.StringUtils; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.Swagger; - -public class ClassUtilsForTest { - public static Class getOrCreateInterface(SwaggerGenerator generator) { - return getOrCreateInterface(generator.getSwagger(), - generator.getClassLoader(), - generator.ensureGetPackageName()); - } - - public static Class getOrCreateInterface(Swagger swagger, ClassLoader classLoader, - String packageName) { - String intfName = ClassUtils.getInterfaceName(swagger.getInfo().getVendorExtensions()); - Class intf = ClassUtils.getClassByName(classLoader, intfName); - if (intf != null) { - return intf; - } - - if (packageName == null) { - int idx = intfName.lastIndexOf("."); - if (idx == -1) { - packageName = ""; - } else { - packageName = intfName.substring(0, idx); - } - } - - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(classLoader, swagger, packageName); - swaggerToClassGenerator.setInterfaceName(intfName); - return swaggerToClassGenerator.convert(); - } - - public static Class getClassByVendorExtensions(ClassLoader classLoader, Map vendorExtensions, - String clsKey) { - String clsName = ClassUtils.getVendorExtension(vendorExtensions, clsKey); - if (StringUtils.isEmpty(clsName)) { - return null; - } - - return ClassUtils.getClassByName(classLoader, clsName); - } - - public static JavaType findJavaType(SwaggerGenerator generator, Object def) { - return ConverterMgr.findJavaType(new SwaggerToClassGenerator(generator.getClassLoader(), generator.getSwagger(), - generator.ensureGetPackageName()), def); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiImplicitParams.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiImplicitParams.java deleted file mode 100644 index 0bb4f28dfe8..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiImplicitParams.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import org.apache.servicecomb.foundation.test.scaffolding.model.User; -import org.apache.servicecomb.swagger.generator.core.unittest.SwaggerGeneratorForTest; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; -import io.swagger.models.parameters.Parameter; - -public class TestApiImplicitParams { - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - - interface ApiImplicitParamsAnnotation { - @ApiImplicitParams( - value = {@ApiImplicitParam( - paramType = "body", - name = "body", - dataType = "org.apache.servicecomb.foundation.test.scaffolding.model.User")}) - void testBody(); - } - - @Test - public void testBody() { - SwaggerGenerator swaggerGenerator = - new SwaggerGeneratorForTest(context, ApiImplicitParamsAnnotation.class); - swaggerGenerator.generate(); - - Swagger swagger = swaggerGenerator.getSwagger(); - Path path = swagger.getPaths().get("/testBody"); - Operation operation = path.getOperations().get(0); - Parameter parameter = operation.getParameters().get(0); - - JavaType javaType = ClassUtilsForTest.findJavaType(swaggerGenerator, parameter); - Assert.assertEquals(User.class, javaType.getRawClass()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiOperation.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiOperation.java index 134a4d3cf2f..73f63e71425 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiOperation.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiOperation.java @@ -19,153 +19,101 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; import java.util.Arrays; -import java.util.Map; - -import org.apache.servicecomb.swagger.generator.core.unittest.SwaggerGeneratorForTest; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.Extension; -import io.swagger.annotations.ExtensionProperty; -import io.swagger.annotations.ResponseHeader; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Scheme; -import io.swagger.models.Swagger; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; + +@SuppressWarnings({"rawtypes", "unused"}) public class TestApiOperation { - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); + static SwaggerOperations swaggerOperations = SwaggerOperations.generate(ApiOperationAnnotation.class); + + @AfterAll + public static void teardown() { + swaggerOperations = null; + } interface ApiOperationAnnotation { - @ApiOperation( - value = "summary", - notes = "notes", + @Operation( + summary = "summary", + description = "notes", tags = {"tag1", "tag2"}, - httpMethod = "GET", - nickname = "test", - produces = "application/json", - consumes = "application/json", - protocols = "http,https", - code = 202, - responseHeaders = {@ResponseHeader(name = "h1", response = int.class)}, + method = "GET", + operationId = "test", + responses = @ApiResponse(responseCode = "202", + content = @Content(mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = String.class)), + headers = @Header(name = "h1", schema = @Schema(implementation = Integer.class))), extensions = {@Extension( name = "x-tagA", properties = {@ExtensionProperty(name = "x-tagAExt", value = "value of tagAExt")})}) void testBase(); - @ApiOperation(value = "aaa", code = 202, response = String.class) + @Operation(summary = "aaa") + @ApiResponse(responseCode = "202", content = @Content(schema = @Schema(implementation = String.class))) int testPrimitive(); - @ApiOperation(value = "aaa", response = Integer.class, responseContainer = "Map") - int testMap(); - - @ApiOperation(value = "aaa", response = Integer.class, responseContainer = "List") - int testList(); - - @ApiOperation(value = "aaa", response = Integer.class, responseContainer = "Set") - int testSet(); - - @ApiOperation(value = "aaa", hidden = true) + @Operation(summary = "aaa", hidden = true) int testHidden(); } - interface UnknownResponseContainer { - @ApiOperation(value = "aaa", response = Integer.class, responseContainer = "xxx") - int testUnknown(); - } @Test public void testApiOperation() { - SwaggerGenerator swaggerGenerator = - new SwaggerGeneratorForTest(context, ApiOperationAnnotation.class); - swaggerGenerator.generate(); - - Swagger swagger = swaggerGenerator.getSwagger(); - testBase(swagger.getPath("/test")); - testPrimitive(swagger.getPath("/testPrimitive")); - testMap(swagger.getPath("/testMap")); - testList(swagger.getPath("/testList")); - testSet(swagger.getPath("/testSet")); - assertThat(swagger.getPath("/testHidden"), is(nullValue())); - } - - @Test - public void testUnknown() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.TestApiOperation$UnknownResponseContainer:testUnknown", - "not support responseContainer xxx", - context, - UnknownResponseContainer.class); - } - - private void testSet(Path path) { - Operation operation = path.getPost(); - Property result200 = operation.getResponses().get("200").getSchema(); - Assert.assertEquals(ArrayProperty.class, result200.getClass()); - Assert.assertEquals(true, ((ArrayProperty) result200).getUniqueItems()); - } - - private void testList(Path path) { - Operation operation = path.getPost(); - Property result200 = operation.getResponses().get("200").getSchema(); - Assert.assertEquals(ArrayProperty.class, result200.getClass()); - Assert.assertEquals(null, ((ArrayProperty) result200).getUniqueItems()); - } - - private void testMap(Path path) { - Operation operation = path.getPost(); - Property result200 = operation.getResponses().get("200").getSchema(); - Assert.assertEquals(MapProperty.class, result200.getClass()); + OpenAPI swagger = swaggerOperations.getSwagger(); + testBase(swagger.getPaths().get("/test")); + testPrimitive(swagger.getPaths().get("/testPrimitive")); + MatcherAssert.assertThat(swagger.getPaths().get("/testHidden"), is(nullValue())); } - private void testPrimitive(Path path) { - Operation operation = path.getPost(); + private void testPrimitive(PathItem path) { + io.swagger.v3.oas.models.Operation operation = path.getPost(); - Assert.assertEquals(2, operation.getResponses().size()); + Assertions.assertEquals(2, operation.getResponses().size()); - Property result200 = operation.getResponses().get("200").getSchema(); - Assert.assertEquals("integer", result200.getType()); - Assert.assertEquals("int32", result200.getFormat()); + io.swagger.v3.oas.models.media.Schema result200 = + operation.getResponses().get("200").getContent().get(MediaType.APPLICATION_JSON).getSchema(); + Assertions.assertEquals("integer", result200.getType()); + Assertions.assertEquals("int32", result200.getFormat()); - Property result202 = operation.getResponses().get("202").getSchema(); - Assert.assertEquals("string", result202.getType()); - Assert.assertEquals(null, result202.getFormat()); + io.swagger.v3.oas.models.media.Schema result202 = + operation.getResponses().get("202").getContent().get(MediaType.APPLICATION_JSON).getSchema(); + Assertions.assertEquals("string", result202.getType()); } - private void testBase(Path path) { - Assert.assertEquals(1, path.getOperations().size()); - - Operation operation = path.getGet(); + private void testBase(PathItem path) { + Assertions.assertEquals(1, path.readOperations().size()); - Assert.assertEquals("summary", operation.getSummary()); - Assert.assertEquals("notes", operation.getDescription()); - Assert.assertEquals(Arrays.asList("tag1", "tag2"), operation.getTags()); - Assert.assertEquals(Arrays.asList("application/json"), operation.getProduces()); - Assert.assertEquals(Arrays.asList("application/json"), operation.getConsumes()); - Assert.assertEquals(Arrays.asList(Scheme.HTTP, Scheme.HTTPS), operation.getSchemes()); + io.swagger.v3.oas.models.Operation operation = path.getGet(); - Map responseMap = operation.getResponses(); - Assert.assertEquals(2, responseMap.size()); + Assertions.assertEquals("summary", operation.getSummary()); + Assertions.assertEquals("notes", operation.getDescription()); + Assertions.assertEquals(Arrays.asList("tag1", "tag2"), operation.getTags()); - Response response = responseMap.get(SwaggerConst.SUCCESS_KEY); - Assert.assertNotNull(response); - Assert.assertEquals(null, response.getSchema()); + ApiResponses responseMap = operation.getResponses(); + Assertions.assertEquals(2, responseMap.size()); - response = responseMap.get("202"); - Assert.assertNotNull(response); - Assert.assertEquals(null, response.getSchema()); + io.swagger.v3.oas.models.responses.ApiResponse response = responseMap.get("202"); + Assertions.assertNotNull(response); + Assertions.assertEquals("string", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getType()); - Assert.assertEquals(1, response.getHeaders().size()); - Assert.assertEquals("integer", response.getHeaders().get("h1").getType()); + Assertions.assertEquals(1, response.getHeaders().size()); + Assertions.assertEquals("integer", response.getHeaders().get("h1").getSchema().getType()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiResponse.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiResponse.java index 8f60345f903..e39b3bbf858 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiResponse.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestApiResponse.java @@ -17,120 +17,120 @@ package org.apache.servicecomb.swagger.generator.core; -import org.apache.servicecomb.swagger.generator.core.unittest.SwaggerGeneratorForTest; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ResponseHeader; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Response; -import io.swagger.models.Swagger; -import io.swagger.models.properties.Property; - +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestApiResponse { - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); + + SwaggerOperations swaggerOperations; + + @BeforeAll + public void setUp() { + swaggerOperations = SwaggerOperations.generate(ApiResponseAnnotation.class); + } + + @AfterAll + public void tearDown() { + swaggerOperations = null; + } interface ApiResponseAnnotation { @ApiResponse( - responseHeaders = {@ResponseHeader(name = "k1", response = int.class), - @ResponseHeader(name = "k2", response = String.class)}, - code = 200, - message = "") + headers = {@Header(name = "k1", schema = @Schema(implementation = Integer.class)), + @Header(name = "k2", schema = @Schema(implementation = String.class))}, + responseCode = "200", + description = "") void testApiResponseHeader(); - @ResponseHeader(name = "k1", response = int.class) + @ApiResponse(responseCode = "200", + headers = {@Header(name = "k1", schema = @Schema(implementation = Integer.class))}) void testResponseHeader(); @ApiResponse( - code = 200, - response = int.class, - message = "msg") + content = @Content(schema = @Schema(implementation = Integer.class)), + responseCode = "200", + description = "msg") void testSingle(); - @ApiResponses({@ApiResponse(code = 200, response = int.class, message = "msg1"), - @ApiResponse(code = 301, response = String.class, message = "msg2")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Integer.class)), description = "msg1"), + @ApiResponse(responseCode = "301", content = @Content(schema = @Schema(implementation = String.class)), description = "msg2")}) void testMulti(); } @Test - public void testBody() { - SwaggerGenerator swaggerGenerator = - new SwaggerGeneratorForTest(context, ApiResponseAnnotation.class); - swaggerGenerator.generate(); - - checkResponseDesc(swaggerGenerator); - checkApiResponseHeader(swaggerGenerator); - checkResponseHeader(swaggerGenerator); - checkSingle(swaggerGenerator); - checkMulti(swaggerGenerator); - } - - private void checkResponseHeader(SwaggerGenerator generator) { - Swagger swagger = generator.getSwagger(); - - Path path = swagger.getPaths().get("/testResponseHeader"); - Operation operation = path.getOperations().get(0); - Assert.assertEquals("testResponseHeader", operation.getOperationId()); - - Response response = operation.getResponses().get("200"); - Property property = response.getHeaders().get("k1"); - Assert.assertEquals(Integer.class, ClassUtilsForTest.findJavaType(generator, property).getRawClass()); + public void checkResponseHeader() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testResponseHeader"); + Assertions.assertEquals("/testResponseHeader", swaggerOperation.getPath()); + + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + io.swagger.v3.oas.models.headers.Header property = response.getHeaders().get("k1"); + Assertions.assertEquals("integer", property.getSchema().getType()); + Assertions.assertEquals("int32", property.getSchema().getFormat()); } - private void checkResponseDesc(SwaggerGenerator generator) { - Swagger swagger = generator.getSwagger(); - - Path path = swagger.getPaths().get("/testMulti"); - Operation operation = path.getOperations().get(0); - - Response response1 = operation.getResponses().get("200"); - Response response2 = operation.getResponses().get("301"); - Assert.assertEquals("msg1", response1.getDescription()); - Assert.assertEquals("msg2", response2.getDescription()); + @Test + public void checkResponseDesc() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testMulti"); + Assertions.assertEquals("/testMulti", swaggerOperation.getPath()); + + io.swagger.v3.oas.models.responses.ApiResponse response1 = swaggerOperation.getOperation().getResponses() + .get("200"); + io.swagger.v3.oas.models.responses.ApiResponse response2 = swaggerOperation.getOperation().getResponses() + .get("301"); + Assertions.assertEquals("msg1", response1.getDescription()); + Assertions.assertEquals("msg2", response2.getDescription()); } - private void checkApiResponseHeader(SwaggerGenerator generator) { - Swagger swagger = generator.getSwagger(); - - Path path = swagger.getPaths().get("/testApiResponseHeader"); - Operation operation = path.getOperations().get(0); - Assert.assertEquals("testApiResponseHeader", operation.getOperationId()); + @Test + public void checkApiResponseHeader() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testApiResponseHeader"); + Assertions.assertEquals("/testApiResponseHeader", swaggerOperation.getPath()); - Response response = operation.getResponses().get("200"); - Property property = response.getHeaders().get("k1"); - Assert.assertEquals(Integer.class, ClassUtilsForTest.findJavaType(generator, property).getRawClass()); + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + io.swagger.v3.oas.models.headers.Header property = response.getHeaders().get("k1"); + Assertions.assertEquals("integer", property.getSchema().getType()); + Assertions.assertEquals("int32", property.getSchema().getFormat()); property = response.getHeaders().get("k2"); - Assert.assertEquals(String.class, ClassUtilsForTest.findJavaType(generator, property).getRawClass()); + Assertions.assertEquals("string", property.getSchema().getType()); + Assertions.assertEquals(null, property.getSchema().getFormat()); } - public void checkSingle(SwaggerGenerator generator) { - Swagger swagger = generator.getSwagger(); - - Path path = swagger.getPaths().get("/testSingle"); - Operation operation = path.getOperations().get(0); - Assert.assertEquals("testSingle", operation.getOperationId()); + @Test + public void checkSingle() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testSingle"); + Assertions.assertEquals("/testSingle", swaggerOperation.getPath()); - Response response = operation.getResponses().get("200"); - Assert.assertEquals(Integer.class, ClassUtilsForTest.findJavaType(generator, response.getSchema()).getRawClass()); + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + Assertions.assertEquals("integer", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getType()); + Assertions.assertEquals("int32", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getFormat()); } - public void checkMulti(SwaggerGenerator generator) { - Swagger swagger = generator.getSwagger(); - - Path path = swagger.getPaths().get("/testMulti"); - - Operation operation = path.getOperations().get(0); - Assert.assertEquals("testMulti", operation.getOperationId()); + @Test + public void checkMulti() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testMulti"); + Assertions.assertEquals("/testMulti", swaggerOperation.getPath()); - Response response = operation.getResponses().get("200"); - Assert.assertEquals(Integer.class, ClassUtilsForTest.findJavaType(generator, response.getSchema()).getRawClass()); + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + Assertions.assertEquals("integer", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getType()); + Assertions.assertEquals("int32", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getFormat()); - response = operation.getResponses().get("301"); - Assert.assertEquals(String.class, ClassUtilsForTest.findJavaType(generator, response.getSchema()).getRawClass()); + response = swaggerOperation.getOperation().getResponses().get("301"); + Assertions.assertEquals("string", response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getType()); + Assertions.assertEquals(null, response.getContent().get(MediaType.APPLICATION_JSON).getSchema().getFormat()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestArrayType.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestArrayType.java index 695bf3c88eb..931fe3da9e0 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestArrayType.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestArrayType.java @@ -16,46 +16,34 @@ */ package org.apache.servicecomb.swagger.generator.core; -import java.lang.reflect.Method; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; import org.apache.servicecomb.swagger.generator.core.schema.ArrayType; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import javassist.CtClass; -import javassist.CtMethod; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ByteArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import jakarta.ws.rs.core.MediaType; public class TestArrayType { - ClassLoader classLoader = new ClassLoader() { - }; - - @After - public void tearDown() { - JavassistUtils.clearByClassLoader(classLoader); - } - @Test - public void test() throws Exception { - SwaggerGenerator generator = UnitTestSwaggerUtils.generateSwagger(classLoader, ArrayType.class); - Class cls = ClassUtilsForTest.getOrCreateInterface(generator); - Method method = ReflectUtils.findMethod(cls, "testBytes"); - - Class param = (Class) method.getParameters()[0].getParameterizedType(); - Assert.assertEquals(byte[].class, param.getField("value").getType()); - Assert.assertEquals(byte[].class, method.getReturnType()); - } - - public CtMethod findMethod(CtClass cc, String methodName) { - for (CtMethod method : cc.getMethods()) { - if (methodName.equals(method.getName())) { - return method; - } - } - - return null; + public void test() { + SwaggerOperations swaggerOperations = SwaggerOperations.generate(ArrayType.class); + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testBytes"); + RequestBody bodyParameter = swaggerOperation.getOperation().getRequestBody(); + Schema model = bodyParameter.getContent().get(MediaType.APPLICATION_JSON).getSchema(); + + Assertions.assertEquals(Components.COMPONENTS_SCHEMAS_REF + "testBytesBody", model.get$ref()); + OpenAPI openAPI = swaggerOperation.getSwagger(); + Schema schema = openAPI.getComponents().getSchemas().get("testBytesBody"); + Assertions.assertEquals(1, schema.getProperties().size()); + + ByteArraySchema arrayProperty = (ByteArraySchema) schema.getProperties().get("value"); + Assertions.assertEquals("string", arrayProperty.getType()); + Assertions.assertEquals("byte", arrayProperty.getFormat()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java index a1c0ea216c1..646ab449b0e 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java @@ -17,163 +17,47 @@ package org.apache.servicecomb.swagger.generator.core; -import static org.hamcrest.core.Is.is; - import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; - -import javax.lang.model.SourceVersion; -import javax.ws.rs.Path; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.servicecomb.foundation.test.scaffolding.model.User; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import io.swagger.annotations.SwaggerDefinition; -import io.swagger.models.parameters.PathParameter; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.models.parameters.RequestBody; +import jakarta.ws.rs.Path; -@SwaggerDefinition +@OpenAPIDefinition public class TestClassUtils { - ClassLoader classLoader = new ClassLoader() { - }; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void getClassByName_exist() { - String clsName = String.class.getName(); - - Assert.assertSame(String.class, ClassUtils.getClassByName(null, clsName)); - Assert.assertSame(String.class, ClassUtils.getClassByName(classLoader, clsName)); - } - - @Test - public void getClassByName_notExist() { - String clsName = "notExist"; - - Assert.assertNull(ClassUtils.getClassByName(null, clsName)); - Assert.assertNull(ClassUtils.getClassByName(classLoader, clsName)); - } - - public static class Impl { - public List getUser(List p1, List p2) { - return null; - } - } - - @Test - public void getOrCreateBodyClass() throws NoSuchFieldException { - SwaggerGenerator generator = UnitTestSwaggerUtils.generateSwagger(Impl.class); - OperationGenerator operationGenerator = generator.getOperationGeneratorMap().get("getUser"); - - Class cls = ClassUtils.getOrCreateBodyClass(operationGenerator, null); - Assert.assertEquals("gen.swagger.getUserBody", cls.getName()); - Assert.assertEquals("java.util.List", cls.getField("p1").getGenericType().getTypeName()); - Assert.assertEquals("java.util.List", - cls.getField("p2").getGenericType().getTypeName()); - } - @Test public void testHasAnnotation() { - Assert.assertTrue(ClassUtils.hasAnnotation(TestClassUtils.class, SwaggerDefinition.class)); - Assert.assertTrue(ClassUtils.hasAnnotation(TestClassUtils.class, Test.class)); + Assertions.assertTrue(SwaggerUtils.hasAnnotation(TestClassUtils.class, OpenAPIDefinition.class)); + Assertions.assertTrue(SwaggerUtils.hasAnnotation(TestClassUtils.class, Test.class)); - Assert.assertFalse(ClassUtils.hasAnnotation(TestClassUtils.class, Path.class)); + Assertions.assertFalse(SwaggerUtils.hasAnnotation(TestClassUtils.class, Path.class)); } @Test public void isRawJsonType() { - PathParameter param = new PathParameter(); - - Assert.assertFalse(ClassUtils.isRawJsonType(param)); - - param.setVendorExtension(SwaggerConst.EXT_RAW_JSON_TYPE, Boolean.FALSE); - Assert.assertFalse(ClassUtils.isRawJsonType(param)); + RequestBody param = new RequestBody(); - param.setVendorExtension(SwaggerConst.EXT_RAW_JSON_TYPE, Boolean.TRUE); - Assert.assertTrue(ClassUtils.isRawJsonType(param)); - } + Assertions.assertFalse(SwaggerUtils.isRawJsonType(param)); - @Test - public void correctMethodParameterName_normal() { - String name = "name"; - Assert.assertSame(name, ClassUtils.correctMethodParameterName(name)); - } + param.addExtension(SwaggerConst.EXT_RAW_JSON_TYPE, Boolean.FALSE); + Assertions.assertFalse(SwaggerUtils.isRawJsonType(param)); - @Test - public void correctMethodParameterName_update() { - String name = "name.-"; - Assert.assertEquals("name__", ClassUtils.correctMethodParameterName(name)); - } - - @Test - public void testCorrectClassNameInTheCrossed() { - String result = ClassUtils.correctClassName("a-b"); - Assert.assertThat(result, is("a_b")); - - result = ClassUtils.correctClassName("a.a-b"); - Assert.assertThat(result, is("a.a_b")); - } - - @Test - public void testCorrectClassNameStartWithNumber() { - String result = ClassUtils.correctClassName("100"); - Assert.assertThat(result, is("_100")); - - result = ClassUtils.correctClassName("a.100"); - Assert.assertThat(result, is("a._100")); - } - - @Test - public void testCorrectClassNameReservedWords() throws IllegalAccessException { - @SuppressWarnings("unchecked") - Set JAVA_RESERVED_WORDS = (Set) FieldUtils.readStaticField(SourceVersion.class, "keywords", true); - String name = String.join(".", JAVA_RESERVED_WORDS); - String expectResult = "_" + String.join("._", JAVA_RESERVED_WORDS); - - String result = ClassUtils.correctClassName(name); - Assert.assertThat(result, is(expectResult)); - } - - @Test - public void testCorrectClassNameEmptyPart() { - String result = ClassUtils.correctClassName("..a..a.."); - Assert.assertThat(result, is("_._.a._.a._._")); - } - - @Test - public void testCorrectClassNameCanonical() { - String result = ClassUtils.correctClassName("java.util.List["); - Assert.assertThat(result, is("java.util.List_java.lang.String_array_")); - } - - @Test - public void testCorrectClassNameStringArray() { - String result = ClassUtils.correctClassName("[Ljava/lang/String;"); - Assert.assertThat(result, is("array_Ljava/lang/String_")); - } - - @Test - public void testCorrectClassNameNormal() { - String result = ClassUtils.correctClassName("String"); - Assert.assertThat(result, is("String")); + param.addExtension(SwaggerConst.EXT_RAW_JSON_TYPE, Boolean.TRUE); + Assertions.assertTrue(SwaggerUtils.isRawJsonType(param)); } @Test public void getClassName_noName() { - Assert.assertNull(ClassUtils.getClassName(null)); + Assertions.assertNull(SwaggerUtils.getClassName(null)); Map vendorExtensions = new HashMap<>(); - Assert.assertNull(ClassUtils.getClassName(vendorExtensions)); + Assertions.assertNull(SwaggerUtils.getClassName(vendorExtensions)); } @Test @@ -181,14 +65,14 @@ public void getClassName_normal() { Map vendorExtensions = new HashMap<>(); vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, String.class.getName()); - Assert.assertSame(String.class.getName(), ClassUtils.getClassName(vendorExtensions)); + Assertions.assertSame(String.class.getName(), SwaggerUtils.getClassName(vendorExtensions)); } @Test public void getInterfaceName_noName() { Map vendorExtensions = new HashMap<>(); - Assert.assertNull(ClassUtils.getInterfaceName(vendorExtensions)); + Assertions.assertNull(SwaggerUtils.getInterfaceName(vendorExtensions)); } @Test @@ -196,30 +80,6 @@ public void getInterfaceName_normal() { Map vendorExtensions = new HashMap<>(); vendorExtensions.put(SwaggerConst.EXT_JAVA_INTF, String.class.getName()); - Assert.assertSame(String.class.getName(), ClassUtils.getInterfaceName(vendorExtensions)); - } - - @Test - public void getRawClassName_empty() { - Assert.assertNull(ClassUtils.getRawClassName(null)); - Assert.assertNull(ClassUtils.getRawClassName("")); - } - - @Test - public void getRawClassName_normal() { - Assert.assertEquals(String.class.getName(), ClassUtils.getRawClassName(String.class.getName())); - } - - @Test - public void getRawClassName_generic() { - Assert.assertEquals("abc", ClassUtils.getRawClassName("abc")); - } - - @Test - public void getRawClassName_invalid() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage(Matchers.is("Invalid class canonical: ")); - - ClassUtils.getRawClassName(""); + Assertions.assertSame(String.class.getName(), SwaggerUtils.getInterfaceName(vendorExtensions)); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestInvalidType.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestInvalidType.java deleted file mode 100644 index c23843bd6e0..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestInvalidType.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core; - -import org.apache.servicecomb.swagger.generator.core.schema.InvalidType; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Ignore; -import org.junit.Test; - -public class TestInvalidType { - static SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - - @Test - public void testIntf() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testIntf", - "[simple type, class org.apache.servicecomb.swagger.generator.core.schema.InvalidType$InvalidIntf] is interface. Must be a concrete type.", - context, - InvalidType.class, - "testIntf"); - } - - @Test - public void testAbstractClass() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testAbstractClass", - "[simple type, class org.apache.servicecomb.swagger.generator.core.schema.InvalidType$InvalidClass] is abstract class. Must be a concrete type.", - context, - InvalidType.class, - "testAbstractClass"); - } - - @Ignore("need to discuss in JVA-422") - @Test - public void testObject() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testObject", - "java.lang.Object not support. Must be a concrete type.", - context, - InvalidType.class, - "testObject"); - } - - @Ignore("need to discuss in JVA-422") - @Test - public void testNotClearList() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testNotClearList", - "java.lang.Object not support. Must be a concrete type.", - context, - InvalidType.class, - "testNotClearList"); - } - - @Ignore("need to discuss in JVA-422") - @Test - public void testNotClearSet() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testNotClearSet", - "java.lang.Object not support. Must be a concrete type.", - context, - InvalidType.class, - "testNotClearSet"); - } - - @Ignore("need to discuss in JVA-422") - @Test - public void testNotClearMap() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testNotClearMap", - "java.lang.Object not support. Must be a concrete type.", - context, - InvalidType.class, - "testNotClearMap"); - } - - @Ignore("need to discuss in JVA-422") - @Test - public void testInvalidFieldClass() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidType:testInvalidFieldClass", - "java.lang.Object not support. Must be a concrete type.", - context, - InvalidType.class, - "testInvalidFieldClass"); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java index 9fe126fdda4..b46b9bb8327 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java @@ -18,160 +18,119 @@ package org.apache.servicecomb.swagger.generator.core; import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.equalTo; -import java.lang.reflect.Method; -import java.util.Collections; import java.util.List; -import io.swagger.annotations.*; -import io.swagger.models.Response; -import org.apache.servicecomb.foundation.test.scaffolding.spring.SpringUtils; -import org.apache.servicecomb.swagger.extend.parameter.HttpRequestParameter; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.util.StringValueResolver; - -import io.swagger.models.parameters.BodyParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; - +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestOperationGenerator { - @Test - public void testPathPlaceHolder() { - StringValueResolver stringValueResolver = - SpringUtils.createStringValueResolver(Collections.singletonMap("var", "varValue")); - - PojoSwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - context.setEmbeddedValueResolver(stringValueResolver); + SwaggerOperations swaggerOperations; - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(context, null); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, null); - operationGenerator.setPath("/a/${var}/b"); - - assertEquals("/a/varValue/b", operationGenerator.getPath()); + @BeforeAll + public void setUp() { + swaggerOperations = SwaggerOperations.generate(TestClass.class); } - @Test - public void testConvertTags() throws NoSuchMethodException { - Method function = TestClass.class.getMethod("function"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - - operationGenerator.generate(); - - List tagList = operationGenerator.getOperation().getTags(); - assertThat(tagList, contains("tag1", "tag2")); + @AfterAll + public void tearDown() { + swaggerOperations = null; } - @Test - public void testConvertTagsOnMethodWithNoTag() throws NoSuchMethodException { - Method function = TestClass.class.getMethod("functionWithNoTag"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - swaggerGenerator.addDefaultTag("default0"); - swaggerGenerator.addDefaultTag("default1"); + @OpenAPIDefinition(tags = {@Tag(name = "default0"), @Tag(name = "default1")}) + private static class TestClass { + @ApiResponse(responseCode = "200", description = "200 is ok............", + content = @Content(mediaType = "application/json", schema = @Schema(name = "String")), + headers = @Header(name = "x-user-domain", schema = @Schema(implementation = String.class))) + @Operation(summary = "value1", tags = {"tag1", "tag2"}, + responses = { + @ApiResponse(responseCode = "200", headers = + {@Header(name = "x-user-name", schema = @Schema(implementation = String.class)), + @Header(name = "x-user-id", schema = @Schema(implementation = String.class))})}, + extensions = { + @Extension(name = "x-class-name", properties = @ExtensionProperty(value = "value", name = "key"))}) + public void responseThenApiOperation() { + } - operationGenerator.generate(); + @Operation(summary = "value1", tags = {"tag1", "tag2"}, + responses = {@ApiResponse(responseCode = "200", headers = { + @Header(name = "x-user-name", schema = @Schema(implementation = String.class)), + @Header(name = "x-user-id", schema = @Schema(implementation = String.class))})}, + extensions = { + @Extension(name = "x-class-name", properties = { + @ExtensionProperty(value = "value", name = "key")})}) + @ApiResponse(responseCode = "200", description = "200 is ok............", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = String.class)), + headers = @Header(name = "x-user-domain", schema = @Schema(implementation = String.class))) + public void apiOperationThenResponse() { + } + + @Operation(summary = "value2") + public void apiOperationNoTag() { + } - List tagList = operationGenerator.getOperation().getTags(); - assertThat(tagList, contains("default0", "default1")); + public void noApiOperation() { + } } @Test - public void testConvertTagsOnMethodWithNoAnnotation() throws NoSuchMethodException { - Method function = TestClass.class.getMethod("functionWithNoAnnotation"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - swaggerGenerator.addDefaultTag("default0"); - swaggerGenerator.addDefaultTag("default1"); - - operationGenerator.generate(); - - List tagList = operationGenerator.getOperation().getTags(); - assertThat(tagList, contains("default0", "default1")); + public void apiOperationNoTag() { + SwaggerOperation operation = swaggerOperations.findOperation("apiOperationNoTag"); + List tags = operation.getOperation().getTags(); + MatcherAssert.assertThat(tags, equalTo(null)); + Assertions.assertEquals("value2", operation.getOperation().getSummary()); } @Test - public void addProviderParameter() throws NoSuchMethodException { - Method function = TestClass.class.getMethod("functionWithNoAnnotation"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - - Parameter parameter = new BodyParameter(); - parameter.setName("param0"); - operationGenerator.addProviderParameter(parameter); - Assert.assertEquals(1, operationGenerator.getProviderParameters().size()); - Assert.assertSame(parameter, operationGenerator.getProviderParameters().get(0)); - - parameter = new HttpRequestParameter(); - operationGenerator.addProviderParameter(parameter); - Assert.assertSame(parameter, operationGenerator.getProviderParameters().get(1)); - - parameter = new QueryParameter(); - parameter.setName("param1"); - operationGenerator.addProviderParameter(parameter); - Assert.assertSame(parameter, operationGenerator.getProviderParameters().get(2)); - - parameter = new QueryParameter(); - parameter.setName("param0"); - operationGenerator.addProviderParameter(parameter); - Assert.assertEquals(3, operationGenerator.getProviderParameters().size()); - Assert.assertNotSame(parameter, operationGenerator.getProviderParameters().get(2)); + public void noApiOperation() { + SwaggerOperation operation = swaggerOperations.findOperation("noApiOperation"); + List tags = operation.getOperation().getTags(); + MatcherAssert.assertThat(tags, equalTo(null)); + Assertions.assertNull(operation.getOperation().getSummary()); } @Test - public void testApiOperationAndResponse() throws NoSuchMethodException { - Method function = TestClass.class.getMethod("function"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - operationGenerator.generate(); - Response response = operationGenerator.getOperation().getResponses().get("200"); - Assert.assertEquals("200 is ok............", response.getDescription()); - Assert.assertNotNull(response.getHeaders().get("x-user-domain")); - Assert.assertNull(response.getHeaders().get("x-user-name")); - Assert.assertNotNull(operationGenerator.getOperation().getVendorExtensions().get("x-class-name")); - - Method function1 = TestClass.class.getMethod("function1"); - SwaggerGenerator swaggerGenerator1 = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator1 = new OperationGenerator(swaggerGenerator1, function1); - operationGenerator1.generate(); - Response response1 = operationGenerator1.getOperation().getResponses().get("200"); - Assert.assertEquals("200 is ok............", response1.getDescription()); - Assert.assertNull(response1.getHeaders().get("x-user-domain")); - Assert.assertNotNull(response1.getHeaders().get("x-user-name")); - Assert.assertNotNull(operationGenerator1.getOperation().getVendorExtensions().get("x-class-name")); + public void responseThenApiOperation() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("responseThenApiOperation"); + List tags = swaggerOperation.getOperation().getTags(); + MatcherAssert.assertThat(tags, contains("tag1", "tag2")); + + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + Assertions.assertEquals("200 is ok............", response.getDescription()); + Assertions.assertNotNull(response.getHeaders().get("x-user-domain")); + Assertions.assertNotNull(response.getHeaders().get("x-user-name")); + Assertions.assertNotNull(swaggerOperation.getOperation().getExtensions().get("x-class-name")); + Assertions.assertNull(swaggerOperation.getOperation().getExtensions().get("x-not-exists")); } - private static class TestClass { - - @ApiResponse(code = 200, message = "200 is ok............", response = String.class, - responseHeaders = @ResponseHeader(name = "x-user-domain", response = String.class)) - @ApiOperation(value = "value1", tags = {"tag1", "tag2"}, - responseHeaders = {@ResponseHeader(name = "x-user-name", response = String.class), - @ResponseHeader(name = "x-user-id", response = String.class)}, - extensions= {@Extension(name="x-class-name", properties= {@ExtensionProperty(value="value", name = "key")})}) - public void function() { - } - - - @ApiOperation(value = "value1", tags = {"tag1", "tag2"}, - responseHeaders = {@ResponseHeader(name = "x-user-name", response = String.class), - @ResponseHeader(name = "x-user-id", response = String.class)}, - extensions= {@Extension(name="x-class-name", properties= {@ExtensionProperty(value="value", name = "key")})}) - @ApiResponse(code = 200, message = "200 is ok............", response = String.class, - responseHeaders = @ResponseHeader(name = "x-user-domain", response = String.class)) - public void function1() { - } - - @ApiOperation(value = "value2") - public void functionWithNoTag() { - } - - @SuppressWarnings("unused") - public void functionWithNoAnnotation() { - } + @Test + public void apiOperationThenResponse() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("apiOperationThenResponse"); + List tags = swaggerOperation.getOperation().getTags(); + MatcherAssert.assertThat(tags, contains("tag1", "tag2")); + + io.swagger.v3.oas.models.responses.ApiResponse response = swaggerOperation.getOperation().getResponses().get("200"); + Assertions.assertEquals("200 is ok............", response.getDescription()); + Assertions.assertNotNull(response.getHeaders().get("x-user-domain")); + Assertions.assertNotNull(response.getHeaders().get("x-user-name")); + Assertions.assertNotNull(swaggerOperation.getOperation().getExtensions().get("x-class-name")); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java deleted file mode 100644 index b1161748e69..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; -import io.swagger.models.properties.StringProperty; - -public class TestParamUtils { - @Test - public void testGetRawJsonType() { - Parameter param = Mockito.mock(Parameter.class); - Map extensions = new HashMap<>(); - when(param.getVendorExtensions()).thenReturn(extensions); - - extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, true); - Assert.assertTrue(ClassUtils.isRawJsonType(param)); - - extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, "test"); - Assert.assertFalse(ClassUtils.isRawJsonType(param)); - } - - @Test - public void isComplexProperty() { - Property property = new RefProperty("ref"); - Assert.assertTrue(ParamUtils.isComplexProperty(property)); - property = new ObjectProperty(); - Assert.assertTrue(ParamUtils.isComplexProperty(property)); - property = new MapProperty(); - Assert.assertTrue(ParamUtils.isComplexProperty(property)); - property = new ArrayProperty(new ObjectProperty()); - Assert.assertTrue(ParamUtils.isComplexProperty(property)); - - property = new ArrayProperty(new StringProperty()); - Assert.assertFalse(ParamUtils.isComplexProperty(property)); - property = new StringProperty(); - Assert.assertFalse(ParamUtils.isComplexProperty(property)); - } - - @Test - public void setParameterTypeByTypeNormal() { - AbstractSerializableParameter parameter = new QueryParameter(); - ParamUtils.setParameterType(String.class, parameter); - Assert.assertEquals("string", parameter.getType()); - - parameter = new HeaderParameter(); - ParamUtils.setParameterType(long.class, parameter); - Assert.assertEquals("integer", parameter.getType()); - Assert.assertEquals("int64", parameter.getFormat()); - } - - @Test - public void setParameterTypeByTypeOnComplexType() { - AbstractSerializableParameter parameter = new QueryParameter(); - parameter.setName("testName"); - try { - ParamUtils.setParameterType(ArrayList.class, parameter); - Assert.fail("an exception is expected!"); - } catch (IllegalArgumentException e) { - Assert.assertEquals("not allow such type of param:[class io.swagger.models.properties.ArrayProperty], " - + "param name is [testName]", e.getMessage()); - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojo.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojo.java new file mode 100644 index 00000000000..d733d025080 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojo.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core; + +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; + +public class TestPojo { + @SuppressWarnings("unused") + public static class ParameterAnnotation { + @Operation(summary = "differentName", operationId = "differentName") + public int operationIdAndParameter(@Parameter(name = "x") int a, @Parameter(name = "y") int b) { + return a * 2 + b; + } + } + + @Test + public void testResponseEntity() { + UnitTestSwaggerUtils.testSwagger("schemas/ParameterAnnotation.yaml", ParameterAnnotation.class); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojoExample.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojoExample.java new file mode 100644 index 00000000000..e9ad9c7ea20 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestPojoExample.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core; + +import org.apache.servicecomb.swagger.generator.core.pojo.PojoExample1; +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.junit.jupiter.api.Test; + +public class TestPojoExample { + @Test + public void testPojoExample1() { + UnitTestSwaggerUtils.testSwagger("schemas/pojoExample1.yaml", PojoExample1.class); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestProperty.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestProperty.java deleted file mode 100644 index 492167618db..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestProperty.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter; -import org.apache.servicecomb.swagger.generator.core.unittest.SwaggerGeneratorForTest; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.StringProperty; - -public class TestProperty { - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - - @Test - public void testStringProperty() { - SwaggerGenerator generator = new SwaggerGeneratorForTest(context, null); - - List enums = Arrays.asList("testStringProperty_a", "testStringProperty_b"); - - StringProperty sp = new StringProperty(); - sp._enum(enums); - - StringPropertyConverter spc = new StringPropertyConverter(); - JavaType jt = spc.convert( - new SwaggerToClassGenerator(generator.getClassLoader(), generator.getSwagger(), - generator.ensureGetPackageName()), - sp); - - StringProperty spNew = (StringProperty) ModelConverters.getInstance().readAsProperty(jt); - Assert.assertEquals(enums, spNew.getEnum()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerDefinition.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerDefinition.java index e23c0e059a2..c7b2166889f 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerDefinition.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerDefinition.java @@ -17,36 +17,31 @@ package org.apache.servicecomb.swagger.generator.core; -import java.util.Arrays; import java.util.Map; -import org.apache.servicecomb.swagger.generator.core.unittest.SwaggerGeneratorForTest; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.annotations.Contact; -import io.swagger.annotations.Extension; -import io.swagger.annotations.ExtensionProperty; -import io.swagger.annotations.ExternalDocs; -import io.swagger.annotations.Info; -import io.swagger.annotations.License; -import io.swagger.annotations.SwaggerDefinition; -import io.swagger.annotations.Tag; -import io.swagger.models.Swagger; - +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.servers.Server; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") public class TestSwaggerDefinition { - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - - @SwaggerDefinition( - basePath = "base", - host = "host", - consumes = {"json", "xml"}, - produces = {"abc", "123"}, + @OpenAPIDefinition( + servers = @Server(url = "host/base"), tags = {@Tag( name = "tagA", description = "desc of tagA", - externalDocs = @ExternalDocs(value = "tagA ext docs", url = "url of tagA ext docs"), + externalDocs = @ExternalDocumentation(description = "tagA ext docs", url = "url of tagA ext docs"), extensions = {@Extension( name = "x-tagA", properties = {@ExtensionProperty(name = "x-tagAExt", value = "value of tagAExt")})})}, @@ -60,8 +55,8 @@ public class TestSwaggerDefinition { extensions = {@Extension( name = "x-info", properties = {@ExtensionProperty(name = "x-infoExt", value = "value of infoExt")})}), - externalDocs = @ExternalDocs( - value = "SwaggerAnnotation ext docs", + externalDocs = @ExternalDocumentation( + description = "SwaggerAnnotation ext docs", url = "url of SwaggerAnnotation ext docs")) interface SwaggerAnnotation { } @@ -69,68 +64,49 @@ interface SwaggerAnnotation { interface SwaggerNoAnnotation { } - @SuppressWarnings("unchecked") @Test public void testSwaggerDefinition() { - SwaggerGenerator swaggerGenerator = - new SwaggerGeneratorForTest(context, SwaggerAnnotation.class); - swaggerGenerator.generate(); - - Swagger swagger = swaggerGenerator.getSwagger(); - - Assert.assertEquals(SwaggerAnnotation.class.getName(), - swagger.getInfo().getVendorExtensions().get(SwaggerConst.EXT_JAVA_INTF)); - Assert.assertEquals("2.0", swagger.getSwagger()); - Assert.assertEquals("/base", swagger.getBasePath()); - Assert.assertEquals("host", swagger.getHost()); - Assert.assertEquals(Arrays.asList("json", "xml"), swagger.getConsumes()); - Assert.assertEquals(Arrays.asList("abc", "123"), swagger.getProduces()); - - Assert.assertEquals(1, swagger.getTags().size()); - io.swagger.models.Tag tagA = swagger.getTags().get(0); - Assert.assertEquals("tagA", tagA.getName()); - Assert.assertEquals("desc of tagA", tagA.getDescription()); - Assert.assertEquals("tagA ext docs", tagA.getExternalDocs().getDescription()); - Assert.assertEquals("url of tagA ext docs", tagA.getExternalDocs().getUrl()); - Assert.assertEquals(1, tagA.getVendorExtensions().size()); - - Map tagValue = (Map) tagA.getVendorExtensions().get("x-tagA"); - Assert.assertEquals("value of tagAExt", tagValue.get("x-tagAExt")); - - io.swagger.models.Info info = swagger.getInfo(); - Assert.assertEquals("title of SwaggerAnnotation", info.getTitle()); - Assert.assertEquals("0.1", info.getVersion()); - Assert.assertEquals("termsOfService", info.getTermsOfService()); - Assert.assertEquals("description of info for SwaggerAnnotation", info.getDescription()); - - Assert.assertEquals("contact", info.getContact().getName()); - Assert.assertEquals("contact@email.com", info.getContact().getEmail()); - Assert.assertEquals("http://contact", info.getContact().getUrl()); - - Assert.assertEquals("license ", info.getLicense().getName()); - Assert.assertEquals("http://license", info.getLicense().getUrl()); - - Assert.assertEquals(2, info.getVendorExtensions().size()); - - Map infoValue = (Map) info.getVendorExtensions().get("x-info"); - Assert.assertEquals("value of infoExt", infoValue.get("x-infoExt")); - - Assert.assertEquals("SwaggerAnnotation ext docs", swagger.getExternalDocs().getDescription()); - Assert.assertEquals("url of SwaggerAnnotation ext docs", swagger.getExternalDocs().getUrl()); + OpenAPI swagger = SwaggerGenerator.generate(SwaggerAnnotation.class); + + Assertions.assertEquals("value of infoExt", + ((Map) swagger.getInfo().getExtensions().get("x-info")).get("x-infoExt")); + Assertions.assertEquals("3.0.1", swagger.getOpenapi()); + Assertions.assertEquals("host/base", swagger.getServers().get(0).getUrl()); + + Assertions.assertEquals(1, swagger.getTags().size()); + io.swagger.v3.oas.models.tags.Tag tagA = swagger.getTags().get(0); + Assertions.assertEquals("tagA", tagA.getName()); + Assertions.assertEquals("desc of tagA", tagA.getDescription()); + Assertions.assertEquals("tagA ext docs", tagA.getExternalDocs().getDescription()); + Assertions.assertEquals("url of tagA ext docs", tagA.getExternalDocs().getUrl()); + Assertions.assertEquals(1, tagA.getExtensions().size()); + + Map tagValue = (Map) tagA.getExtensions().get("x-tagA"); + Assertions.assertEquals("value of tagAExt", tagValue.get("x-tagAExt")); + + io.swagger.v3.oas.models.info.Info info = swagger.getInfo(); + Assertions.assertEquals("title of SwaggerAnnotation", info.getTitle()); + Assertions.assertEquals("0.1", info.getVersion()); + Assertions.assertEquals("termsOfService", info.getTermsOfService()); + Assertions.assertEquals("description of info for SwaggerAnnotation", info.getDescription()); + + Assertions.assertEquals("contact", info.getContact().getName()); + Assertions.assertEquals("contact@email.com", info.getContact().getEmail()); + Assertions.assertEquals("http://contact", info.getContact().getUrl()); + + Assertions.assertEquals("license ", info.getLicense().getName()); + Assertions.assertEquals("http://license", info.getLicense().getUrl()); + + Assertions.assertEquals("SwaggerAnnotation ext docs", swagger.getExternalDocs().getDescription()); + Assertions.assertEquals("url of SwaggerAnnotation ext docs", swagger.getExternalDocs().getUrl()); } @Test public void testFillDefault() { - SwaggerGenerator swaggerGenerator = - new SwaggerGeneratorForTest(context, SwaggerNoAnnotation.class); - swaggerGenerator.generate(); - swaggerGenerator.correctSwagger(); - - Swagger swagger = swaggerGenerator.getSwagger(); - - Assert.assertEquals("2.0", swagger.getSwagger()); - Assert.assertEquals("/SwaggerNoAnnotation", swagger.getBasePath()); - Assert.assertEquals("swagger definition for " + SwaggerNoAnnotation.class.getName(), + OpenAPI swagger = SwaggerGenerator.generate(SwaggerNoAnnotation.class); + Assertions.assertEquals("3.0.1", swagger.getOpenapi()); + Assertions.assertEquals("/SwaggerNoAnnotation", swagger.getServers().get(0).getUrl()); + Assertions.assertEquals("swagger definition for " + SwaggerNoAnnotation.class.getName(), swagger.getInfo().getTitle()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerGenerator.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerGenerator.java index eb9e8274968..a05bbce200c 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerGenerator.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerGenerator.java @@ -17,41 +17,30 @@ package org.apache.servicecomb.swagger.generator.core; -import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertThat; - -import java.util.Collections; - -import org.apache.servicecomb.foundation.test.scaffolding.spring.SpringUtils; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.util.StringValueResolver; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGenerator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; public class TestSwaggerGenerator { - @Test - public void testBasePathPlaceHolder() { - StringValueResolver stringValueResolver = - SpringUtils.createStringValueResolver(Collections.singletonMap("var", "varValue")); - - PojoSwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); - context.setEmbeddedValueResolver(stringValueResolver); + Environment environment = Mockito.mock(Environment.class); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(context, null); - swaggerGenerator.setBasePath("/a/${var}/b"); - - Assert.assertEquals("/a/varValue/b", swaggerGenerator.getSwagger().getBasePath()); + @BeforeEach + public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); } @Test - public void testAddDefaultTag() { - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), null); + public void testBasePathPlaceHolder() { + Mockito.when(environment.getProperty("var")).thenReturn("varValue"); - swaggerGenerator.addDefaultTag("test1"); - swaggerGenerator.addDefaultTag(""); - swaggerGenerator.addDefaultTag(null); - swaggerGenerator.addDefaultTag("test2"); + PojoSwaggerGenerator swaggerGenerator = new PojoSwaggerGenerator(null); + swaggerGenerator.setBasePath("/a/${var}/b"); - assertThat(swaggerGenerator.getDefaultTags(), contains("test1", "test2")); + Assertions.assertEquals("/a/varValue/b", SwaggerUtils.getBasePath(swaggerGenerator.getOpenAPI())); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerUtils.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerUtils.java index 5e640e0f4fa..7611a3f80a7 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerUtils.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestSwaggerUtils.java @@ -17,200 +17,179 @@ package org.apache.servicecomb.swagger.generator.core; +import static junit.framework.TestCase.fail; +import static org.hamcrest.Matchers.containsString; +import static org.mockito.Mockito.when; + import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.Date; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; -import org.apache.servicecomb.common.javassist.JavassistUtils; import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; -import org.apache.servicecomb.swagger.generator.core.schema.InvalidResponseHeader; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils; +import org.apache.servicecomb.swagger.generator.core.pojo.TestTypeClass; +import org.apache.servicecomb.swagger.generator.core.pojo.TestTypeRecord; +import org.apache.servicecomb.swagger.generator.core.pojo.TestType1; +import org.apache.servicecomb.swagger.generator.core.pojo.TestType2; import org.apache.servicecomb.swagger.generator.core.schema.RepeatOperation; import org.apache.servicecomb.swagger.generator.core.schema.Schema; import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -public class TestSwaggerUtils { - ClassLoader classLoader = new ClassLoader() { - }; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; - SwaggerGeneratorContext context = new PojoSwaggerGeneratorContext(); +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.RequestBody; - private SwaggerGenerator testSchemaMethod(String resultName, String... methodNames) { - return UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/" + resultName + ".yaml", - context, - Schema.class, - methodNames); - } - - @After - public void tearDown() { - JavassistUtils.clearByClassLoader(classLoader); - } +@SuppressWarnings("rawtypes") +public class TestSwaggerUtils { + Logger LOGGER = Logger.getLogger(TestSwaggerUtils.class.getName()); @Test - public void testBoolean() { - testSchemaMethod("boolean", "testboolean"); - testSchemaMethod("booleanObject", "testBoolean"); + public void testSchemaMethod() { + UnitTestSwaggerUtils.testSwagger("schemas/Schema.yaml", + Schema.class); } @Test - public void testByte() { - testSchemaMethod("byte", "testbyte"); - testSchemaMethod("byteObject", "testByte"); + public void testRepeatOperation() { + UnitTestSwaggerUtils.testException( + "OperationId must be unique. method=org.apache.servicecomb.swagger.generator.core.schema.RepeatOperation:add.", + RepeatOperation.class); } @Test - public void testShort() { - testSchemaMethod("short", "testshort"); - testSchemaMethod("shortObject", "testShort"); - } + public void noParameterName() { + Method method = ReflectUtils.findMethod(Schema.class, "testint"); + Parameter parameter = Mockito.spy(method.getParameters()[0]); + Mockito.when(parameter.isNamePresent()).thenReturn(false); - @Test - public void testInt() { - testSchemaMethod("int", "testint"); - testSchemaMethod("intObject", "testInteger"); + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, + () -> SwaggerGeneratorUtils.collectParameterName(parameter)); + String expectedMsg = + "parameter name is not present, method=org.apache.servicecomb.swagger.generator.core.schema.Schema:testint\n" + + "solution:\n" + + " change pom.xml, add compiler argument: -parameters, for example:\n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " -parameters\n" + + " \n" + + " "; + Assertions.assertEquals(expectedMsg, exception.getMessage()); } @Test - public void testLong() { - testSchemaMethod("long", "testlong"); - testSchemaMethod("longObject", "testLong"); - } + public void testGetRawJsonType() { + RequestBody param = Mockito.mock(RequestBody.class); + Map extensions = new HashMap<>(); + when(param.getExtensions()).thenReturn(extensions); - @Test - public void testFloat() { - testSchemaMethod("float", "testfloat"); - testSchemaMethod("floatObject", "testFloat"); - } + extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, true); + Assertions.assertTrue(SwaggerUtils.isRawJsonType(param)); - @Test - public void testDouble() { - testSchemaMethod("double", "testdouble"); - testSchemaMethod("doubleObject", "testDouble"); + extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, "test"); + Assertions.assertFalse(SwaggerUtils.isRawJsonType(param)); } - @Test - public void testEnum() { - SwaggerGenerator generator = testSchemaMethod("enum", "testEnum"); - Class intf = ClassUtilsForTest.getOrCreateInterface(generator); - - Method method = ReflectUtils.findMethod(intf, "testEnum"); - Class bodyCls = method.getParameterTypes()[0]; - Field[] fields = bodyCls.getFields(); - Assert.assertEquals(Color.class, fields[0].getType()); - Assert.assertEquals(fields[0].getType(), fields[1].getType()); - } + private static class AllTypeTest1 { + TestType1 t1; - @Test - public void testChar() { - testSchemaMethod("char", "testchar"); - testSchemaMethod("charObject", "testChar"); - } + List t2; - @Test - public void testBytes() { - testSchemaMethod("bytes", "testbytes"); - testSchemaMethod("bytesObject", "testBytes"); - } + Map t3; - @Test - public void testString() { - testSchemaMethod("string", "testString"); + TestType1[] t4; } - @Test - public void testObject() { - testSchemaMethod("object", "testObject"); - } + private static class AllTypeTest2 { + TestType2 t1; - @Test - public void testArray() { - testSchemaMethod("array", "testArray"); - } + List t2; - @Test - public void testSet() { - testSchemaMethod("set", "testSet"); - } + Map t3; - @Test - public void testList() { - testSchemaMethod("list", "testList"); - } + TestType2[] t4; - @Test - public void testMap() { - testSchemaMethod("map", "testMap"); } - @Test - public void testMapList() { - testSchemaMethod("mapList", "testMapList"); + private static class AllTypeTest3{ + TestTypeRecord t5; } - - @Test - public void testAllType() { - testSchemaMethod("allType", "testAllType"); + private static class AllTypeTest4{ + TestTypeClass t5; } @Test - public void testMultiParam() { - testSchemaMethod("multiParam", "testMultiParam"); + public void testAddDefinitions() { + testAllType(AllTypeTest1.class, AllTypeTest2.class); } - @Test - public void testAllMethod() { - testSchemaMethod("allMethod"); + private void testAllType(Class clazz1, Class clazz2) { + Field[] fields1 = clazz1.getDeclaredFields(); + Field[] fields2 = clazz2.getDeclaredFields(); + for (Field value : fields1) { + for (Field field : fields2) { + if (value.isSynthetic() || field.isSynthetic()) { + continue; + } + try { + testExcep(value.getGenericType(), field.getGenericType()); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + LOGGER.warning(value.getGenericType() + " " + field.getGenericType() + " " + e.getMessage()); + MatcherAssert.assertThat(e.getMessage(), containsString("duplicate param model:")); + } + } + } } @Test - public void testResponseHeader() { - testSchemaMethod("responseHeader", "testResponseHeader"); + public void testAddDefinitionsWithRecord() { + testAllType(AllTypeTest3.class, AllTypeTest4.class); } - @Test - public void testApiResponse() { - testSchemaMethod("apiResponse", "testApiResponse"); + private void testExcep(Type f1, Type f2) { + OpenAPI swagger = new OpenAPI(); + SwaggerUtils.resolveTypeSchemas(swagger, f1); + SwaggerUtils.resolveTypeSchemas(swagger, f2); } @Test - public void testApiOperation() { - testSchemaMethod("apiOperation", "testApiOperation"); - } + public void test_resolve_type_schemas_correct() { + OpenAPI openAPI = new OpenAPI(); - @Test - public void testCompletableFuture() { - testSchemaMethod("completableFuture", "testCompletableFuture"); - } + io.swagger.v3.oas.models.media.Schema schema = SwaggerUtils.resolveTypeSchemas(openAPI, String.class); + Assertions.assertTrue(schema instanceof StringSchema); - @Test - public void testDate() { - SwaggerGenerator generator = testSchemaMethod("date", "testDate"); - Class intf = ClassUtilsForTest.getOrCreateInterface(generator); + openAPI = new OpenAPI(); + schema = SwaggerUtils.resolveTypeSchemas(openAPI, Integer.class); + Assertions.assertTrue(schema instanceof IntegerSchema); - Method method = ReflectUtils.findMethod(intf, "testDate"); - Assert.assertEquals(Date.class, method.getReturnType()); - } + openAPI = new OpenAPI(); + schema = SwaggerUtils.resolveTypeSchemas(openAPI, TestType1.class); + schema = SwaggerUtils.getSchema(openAPI, schema); // resolve reference + // should be ObjectSchema but swagger is not. + //
 Assertions.assertTrue(schema instanceof ObjectSchema) 
+ Assertions.assertEquals("object", schema.getType()); - @Test - public void testRepeatOperation() { - UnitTestSwaggerUtils.testException( - "OperationId must be unique. org.apache.servicecomb.swagger.generator.core.schema.RepeatOperation:add", - context, - RepeatOperation.class); - } + openAPI = new OpenAPI(); + schema = SwaggerUtils.getSchema(openAPI, SwaggerUtils.resolveTypeSchemas(openAPI, TestTypeClass.class)); // resolve reference + Assertions.assertEquals("object", schema.getType()); - @Test - public void testInvalidResponseHeader() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.core.schema.InvalidResponseHeader:test", - "invalid responseHeader, ResponseHeaderConfig [name=h, ResponseConfigBase [description=, responseReference=null, responseClass=class java.lang.Void, responseContainer=]]", - context, - InvalidResponseHeader.class, - "test"); + openAPI = new OpenAPI(); + schema = SwaggerUtils.getSchema(openAPI, SwaggerUtils.resolveTypeSchemas(openAPI, TestTypeRecord.class)); // resolve reference + Assertions.assertEquals("object", schema.getType()); } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/model/TestSwaggerOperations.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/model/TestSwaggerOperations.java new file mode 100644 index 00000000000..ac05836b2a0 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/model/TestSwaggerOperations.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.model; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.pojo.PojoExample1; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.parameters.RequestBody; + +public class TestSwaggerOperations { + + @Test + public void emptyOperationId() { + OpenAPI swagger = SwaggerUtils.parseAndValidateSwagger(this.getClass().getResource("/schemas/boolean.yaml")); + swagger.getPaths().values().stream() + .findFirst().get() + .getPost().setOperationId(""); + + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, + () -> new SwaggerOperations(swagger)); + Assertions.assertEquals("OperationId can not be empty, path=/testboolean, httpMethod=POST.", + exception.getMessage()); + } + + @Test + public void testPojoExample1() { + SwaggerOperations swaggerOperations = SwaggerOperations.generate(PojoExample1.class); + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testMultiParameter"); + Assertions.assertEquals(null, swaggerOperation.getOperation().getParameters()); + RequestBody requestBody = swaggerOperation.getOperation().getRequestBody(); + Assertions.assertEquals(2, + SwaggerUtils.getSchema(swaggerOperation.getSwagger(), + requestBody.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE).getSchema()).getProperties().size()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/PojoExample1.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/PojoExample1.java new file mode 100644 index 00000000000..d93beb010ca --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/PojoExample1.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.pojo; + +public class PojoExample1 { + public TestType1 testOneParameter(TestType1 testType1) { + return null; + } + + public TestType1 testMultiParameter(TestType1 testType1, String testString) { + return null; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType1.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType1.java new file mode 100644 index 00000000000..16120da045f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType1.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "XXX") +public class TestType1 { + public Integer val1; +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType2.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType2.java new file mode 100644 index 00000000000..e21e9c31eaa --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestType2.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "XXX") +public class TestType2 { + public String val2; +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeClass.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeClass.java new file mode 100644 index 00000000000..b00a4433480 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeClass.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "YYY") +public class TestTypeClass { + @Schema(description = "language") + private TestTypeEnumLang testTypeEnumLang; + + public TestTypeEnumLang getTestTypeEnumLang() { + return testTypeEnumLang; + } + + public void setTestTypeEnumLang(TestTypeEnumLang testTypeEnumLang) { + this.testTypeEnumLang = testTypeEnumLang; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeEnumLang.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeEnumLang.java new file mode 100644 index 00000000000..515f45c7bb1 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeEnumLang.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.pojo; + +public enum TestTypeEnumLang { + JAVA, CHINESE, UNKNOWN; +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeRecord.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeRecord.java new file mode 100644 index 00000000000..c61cc0913eb --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/pojo/TestTypeRecord.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "YYY") +public record TestTypeRecord( + @Schema(description = "language") TestTypeEnumLang testTypeEnumLang) { +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessorTest.java deleted file mode 100644 index 27f285e967f..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiOperationProcessorTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; - -import java.lang.reflect.Method; -import java.util.List; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.hamcrest.Matchers; -import org.junit.Test; - -import io.swagger.annotations.ApiOperation; - -public class ApiOperationProcessorTest { - - @Test - public void testConvertTags() throws NoSuchMethodException { - ApiOperationProcessor apiOperationProcessor = new ApiOperationProcessor(); - - Method function = TestClass.class.getMethod("function"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - - apiOperationProcessor.process(function.getAnnotation(ApiOperation.class), - operationGenerator); - - assertThat(operationGenerator.getOperation().getTags(), containsInAnyOrder("tag1", "tag2")); - } - - @Test - public void testConvertTagsOnMethodWithNoTag() throws NoSuchMethodException { - ApiOperationProcessor apiOperationProcessor = new ApiOperationProcessor(); - - Method function = TestClass.class.getMethod("functionWithNoTag"); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, function); - - apiOperationProcessor.process(function.getAnnotation(ApiOperation.class), - operationGenerator); - - List tagList = operationGenerator.getOperation().getTags(); - assertNull(tagList); - } - - @Test - public void testMediaType() throws NoSuchMethodException { - ApiOperationProcessor apiOperationProcessor = new ApiOperationProcessor(); - - Method method = TestClass.class.getMethod("testSingleMediaType", String.class); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new PojoSwaggerGeneratorContext(), TestClass.class); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, method); - - apiOperationProcessor.process(method.getAnnotation(ApiOperation.class), operationGenerator); - - assertThat(operationGenerator.getOperation().getConsumes(), Matchers.contains(MediaType.TEXT_PLAIN)); - assertThat(operationGenerator.getOperation().getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - - method = TestClass.class.getMethod("testMultiMediaType", String.class); - apiOperationProcessor.process(method.getAnnotation(ApiOperation.class), operationGenerator); - - assertThat(operationGenerator.getOperation().getConsumes(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - assertThat(operationGenerator.getOperation().getProduces(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - - method = TestClass.class.getMethod("testBlankMediaType", String.class); - apiOperationProcessor.process(method.getAnnotation(ApiOperation.class), operationGenerator); - - assertThat(operationGenerator.getOperation().getConsumes(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - assertThat(operationGenerator.getOperation().getProduces(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - - operationGenerator.getOperation().addConsumes(MediaType.TEXT_HTML); - operationGenerator.getOperation().addProduces(MediaType.TEXT_HTML); - assertThat(operationGenerator.getOperation().getConsumes(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN, MediaType.TEXT_HTML)); - assertThat(operationGenerator.getOperation().getProduces(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_HTML)); - } - - private static class TestClass { - @ApiOperation(value = "value1", tags = {"tag1", "tag2"}) - public void function() { - } - - @ApiOperation(value = "value2") - public void functionWithNoTag() { - } - - @ApiOperation(value = "testSingleMediaType", consumes = MediaType.TEXT_PLAIN, produces = MediaType.APPLICATION_XML) - public String testSingleMediaType(String input) { - return input; - } - - @ApiOperation(value = "testMultiMediaType", - consumes = MediaType.APPLICATION_JSON + "," + MediaType.TEXT_PLAIN, - produces = MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML) - public String testMultiMediaType(String input) { - return input; - } - - @ApiOperation(value = "testBlankMediaType", consumes = "", produces = "") - public String testBlankMediaType(String input) { - return input; - } - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java deleted file mode 100644 index 047daac0d56..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/ApiProcessorTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.hamcrest.Matchers; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.annotations.Api; - -public class ApiProcessorTest { - private ApiProcessor apiProcessor = new ApiProcessor(); - - @Test - public void process() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - apiProcessor.process(SwaggerTestTarget.class.getAnnotation(Api.class), - swaggerGenerator); - - assertThat(swaggerGenerator.getDefaultTags(), contains("tag1", "tag2")); - assertNull(swaggerGenerator.getSwagger().getConsumes()); - assertNull(swaggerGenerator.getSwagger().getProduces()); - } - - @Test - public void processOnNoTag() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - apiProcessor.process(SwaggerTestTargetWithNoTag.class.getAnnotation(Api.class), swaggerGenerator); - - Set tags = swaggerGenerator.getDefaultTags(); - assertEquals(0, tags.size()); - assertNull(swaggerGenerator.getSwagger().getConsumes()); - assertNull(swaggerGenerator.getSwagger().getProduces()); - } - - @Test - public void processOverWriteEmptyConsumesAndProduces() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - swaggerGenerator.getSwagger().setConsumes(Arrays.asList("", " ")); - swaggerGenerator.getSwagger().setProduces(Arrays.asList("", " ")); - apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator); - - List consumes = swaggerGenerator.getSwagger().getConsumes(); - assertThat(consumes, Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - List produces = swaggerGenerator.getSwagger().getProduces(); - assertThat(produces, Matchers.contains(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)); - } - - @Test - public void processNotOverWriteValidConsumesAndProduces() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - swaggerGenerator.getSwagger().setConsumes(Collections.singletonList(MediaType.MULTIPART_FORM_DATA)); - swaggerGenerator.getSwagger().setProduces(Collections.singletonList(MediaType.MULTIPART_FORM_DATA)); - apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator); - - List consumes = swaggerGenerator.getSwagger().getConsumes(); - assertThat(consumes, Matchers.contains(MediaType.MULTIPART_FORM_DATA)); - List produces = swaggerGenerator.getSwagger().getProduces(); - assertThat(produces, Matchers.contains(MediaType.MULTIPART_FORM_DATA)); - } - - @Test - public void processWithConsumesAndProduces() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - apiProcessor.process(SwaggerTestTargetWithConsumesAndProduces.class.getAnnotation(Api.class), swaggerGenerator); - - List consumes = swaggerGenerator.getSwagger().getConsumes(); - assertThat(consumes, Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - List produces = swaggerGenerator.getSwagger().getProduces(); - assertThat(produces, Matchers.contains(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)); - } - - private SwaggerGenerator getSwaggerGenerator() { - return new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - null); - } - - @Api(tags = {"tag1", "tag2", "", "tag1"}) - private class SwaggerTestTarget { - } - - @Api - private class SwaggerTestTargetWithNoTag { - } - - @Api(consumes = MediaType.TEXT_PLAIN + " , " + MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_XML + "," + MediaType.APPLICATION_JSON) - private class SwaggerTestTargetWithConsumesAndProduces { - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessorTest.java new file mode 100644 index 00000000000..2d07ded7f7f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OpenAPIDefinitionProcessorTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.annotation; + +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.servers.Server; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.models.OpenAPI; + +public class OpenAPIDefinitionProcessorTest { + @OpenAPIDefinition(tags = { + @Tag(name = "testTag", description = "desc", externalDocs = @ExternalDocumentation(description = "testValue", url = "testUrl")) + }, + servers = {@Server(url = "127.0.0.1")}, + info = @Info(title = "title", version = "version", description = "desc", contact = @Contact(name = "contactName"), + license = @License(name = "licenseName"))) + private static class SwaggerTestTarget { + } + + @Test + public void testProcess() { + OpenAPI swagger = SwaggerGenerator.generate(SwaggerTestTarget.class); + + Assertions.assertEquals(1, swagger.getTags().size()); + io.swagger.v3.oas.models.tags.Tag tag = swagger.getTags().get(0); + Assertions.assertEquals("testTag", tag.getName()); + Assertions.assertEquals("desc", tag.getDescription()); + Assertions.assertEquals("testValue", tag.getExternalDocs().getDescription()); + Assertions.assertEquals("testUrl", tag.getExternalDocs().getUrl()); + Assertions.assertEquals("127.0.0.1", swagger.getServers().get(0).getUrl()); + + io.swagger.v3.oas.models.info.Info info = swagger.getInfo(); + Assertions.assertEquals("title", info.getTitle()); + Assertions.assertEquals("version", info.getVersion()); + Assertions.assertEquals("desc", info.getDescription()); + Assertions.assertEquals("contactName", info.getContact().getName()); + Assertions.assertEquals("licenseName", info.getLicense().getName()); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessorTest.java new file mode 100644 index 00000000000..fdc3cea273e --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/OperationMethodAnnotationProcessorTest.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.processor.annotation; + +import static org.hamcrest.Matchers.containsInAnyOrder; + +import java.util.Map; + +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.models.Components; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.core.MediaType; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class OperationMethodAnnotationProcessorTest { + SwaggerOperations swaggerOperations; + + @BeforeAll + public void setUp() { + swaggerOperations = SwaggerOperations.generate(TestClass.class); + } + + @AfterAll + public void tearDown() { + swaggerOperations = null; + } + + private static class TestClass { + @Operation(summary = "value1", tags = {"tag1", "tag2"}) + public void function() { + } + + @Operation(summary = "value2") + public void functionWithNoTag() { + } + + // mediaType will be ignored + @Operation(summary = "testSingleMediaType", + responses = {@ApiResponse(responseCode = "200", content = @Content( + mediaType = MediaType.TEXT_PLAIN, schema = @Schema(implementation = String.class)))}) + public String testSingleMediaType(String input) { + return input; + } + + @Operation(summary = "testMultiMediaType", + responses = { + @ApiResponse(responseCode = "200", content = { + @Content(mediaType = MediaType.APPLICATION_JSON), + @Content(mediaType = MediaType.TEXT_PLAIN) + })}) + public String testMultiMediaType(String input) { + return input; + } + + @Operation(summary = "testBlankMediaType", + responses = {@ApiResponse(responseCode = "200", content = @Content(mediaType = ""))}, + requestBody = @RequestBody(content = @Content(mediaType = "", + schema = @Schema(implementation = String.class)))) + public String testBlankMediaType(String input) { + return input; + } + + @Operation(summary = "testBodyParam") + public String testBodyParam(@RequestBody(content = @Content( + schema = @Schema( + implementation = TestBodyBean.class))) TestBodyBean user) { + return user.toString(); + } + } + + + private static class TestBodyBean { + + @NotBlank + private String age; + + @NotNull + private String name; + + @NotEmpty + private String sexes; + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSexes() { + return sexes; + } + + public void setSexes(String sexes) { + this.sexes = sexes; + } + } + + @Test + public void testConvertTags() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("function"); + MatcherAssert.assertThat(swaggerOperation.getOperation().getTags(), containsInAnyOrder("tag1", "tag2")); + } + + @Test + public void testConvertTagsOnMethodWithNoTag() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("functionWithNoTag"); + Assertions.assertNull(swaggerOperation.getOperation().getTags()); + } + + @Test + public void testMultiMediaType() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testMultiMediaType"); + MatcherAssert.assertThat(swaggerOperation.getOperation().getRequestBody().getContent().keySet(), + Matchers.contains(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, MediaType.TEXT_PLAIN)); + MatcherAssert.assertThat(swaggerOperation.getOperation().getResponses().get("200").getContent().keySet(), + Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); + } + + @Test + public void testSingleMediaType() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testSingleMediaType"); + MatcherAssert.assertThat(swaggerOperation.getOperation() + .getRequestBody().getContent().get(MediaType.APPLICATION_JSON).getSchema().get$ref(), + Matchers.equalTo(Components.COMPONENTS_SCHEMAS_REF + "testSingleMediaTypeBody")); + MatcherAssert.assertThat(swaggerOperation.getOperation() + .getResponses().get("200").getContent().get(MediaType.TEXT_PLAIN).getSchema().getType(), + Matchers.equalTo("string")); + } + + @Test + public void testBlankMediaType() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testBlankMediaType"); + MatcherAssert.assertThat(swaggerOperation.getOperation().getRequestBody().getContent().keySet(), + Matchers.contains(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, MediaType.TEXT_PLAIN)); + MatcherAssert.assertThat(swaggerOperation.getOperation().getResponses() + .get(SwaggerConst.SUCCESS_KEY).getContent().keySet(), + Matchers.contains(MediaType.APPLICATION_JSON, SwaggerConst.PROTOBUF_TYPE, MediaType.TEXT_PLAIN)); + } + + @Test + public void testBodyParam() { + SwaggerOperation swaggerOperation = swaggerOperations.findOperation("testBodyParam"); + io.swagger.v3.oas.models.media.Schema schema = swaggerOperation.getSwagger() + .getPaths().get("/testBodyParam").getPost().getRequestBody().getContent() + .get(MediaType.APPLICATION_JSON).getSchema(); + Assertions.assertEquals(Components.COMPONENTS_SCHEMAS_REF + "TestBodyBean", schema.get$ref()); + schema = swaggerOperation.getSwagger().getComponents().getSchemas().get("TestBodyBean"); + Map properties = schema.getProperties(); + Assertions.assertEquals(properties.get("age").getType(), "string"); + Assertions.assertEquals(properties.get("sexes").getType(), "string"); + Assertions.assertEquals(properties.get("name").getType(), "string"); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessorTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessorTest.java deleted file mode 100644 index 679b34ebbca..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/annotation/SwaggerDefinitionProcessorTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.core.processor.annotation; - -import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.hamcrest.Matchers; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.annotations.Contact; -import io.swagger.annotations.ExternalDocs; -import io.swagger.annotations.Info; -import io.swagger.annotations.License; -import io.swagger.annotations.SwaggerDefinition; -import io.swagger.annotations.SwaggerDefinition.Scheme; -import io.swagger.annotations.Tag; -import io.swagger.models.Swagger; - -public class SwaggerDefinitionProcessorTest { - - private SwaggerDefinitionProcessor swaggerDefinitionProcessor = new SwaggerDefinitionProcessor(); - - @Test - public void testProcess() { - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - null); - Swagger swagger = swaggerGenerator.getSwagger(); - // to test MediaType overwrite - swagger.addConsumes(MediaType.APPLICATION_XML); - swagger.addProduces(MediaType.APPLICATION_XML); - swaggerDefinitionProcessor.process(SwaggerTestTarget.class.getAnnotation(SwaggerDefinition.class), - swaggerGenerator); - - assertEquals(1, swagger.getTags().size()); - io.swagger.models.Tag tag = swagger.getTags().get(0); - assertEquals("testTag", tag.getName()); - assertEquals("desc", tag.getDescription()); - assertEquals("testValue", tag.getExternalDocs().getDescription()); - assertEquals("testUrl", tag.getExternalDocs().getUrl()); - assertEquals("127.0.0.1", swagger.getHost()); - assertThat(swagger.getSchemes(), contains(io.swagger.models.Scheme.HTTP, io.swagger.models.Scheme.HTTPS)); - io.swagger.models.Info info = swagger.getInfo(); - assertEquals("title", info.getTitle()); - assertEquals("version", info.getVersion()); - assertEquals("desc", info.getDescription()); - assertEquals("contactName", info.getContact().getName()); - assertEquals("licenseName", info.getLicense().getName()); - assertThat(swagger.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - assertThat(swagger.getProduces(), Matchers.contains(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - } - - @Test - public void testProcess_emptyMediaType() { - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - null); - Swagger swagger = swaggerGenerator.getSwagger(); - // to test MediaType overwrite - swagger.addConsumes(MediaType.APPLICATION_XML); - swagger.addProduces(MediaType.TEXT_PLAIN); - swaggerDefinitionProcessor.process(SwaggerTestTarget_EmptyMediaType.class.getAnnotation(SwaggerDefinition.class), - swaggerGenerator); - - // empty media type should not be set, so keep consumes/produces not modified - assertThat(swagger.getConsumes(), Matchers.contains(MediaType.APPLICATION_XML)); - assertThat(swagger.getProduces(), Matchers.contains(MediaType.TEXT_PLAIN)); - } - - @SwaggerDefinition(tags = { - @Tag(name = "testTag", description = "desc", externalDocs = @ExternalDocs(value = "testValue", url = "testUrl")) - }, - host = "127.0.0.1", - schemes = {Scheme.HTTP, Scheme.HTTPS}, - info = @Info(title = "title", version = "version", description = "desc", contact = @Contact(name = "contactName"), - license = @License(name = "licenseName")), - consumes = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}, - produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - private class SwaggerTestTarget { - } - - @SwaggerDefinition(consumes = "", produces = "") - private class SwaggerTestTarget_EmptyMediaType { - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestAbstractOneGenericResponseProcessor.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestAbstractOneGenericResponseProcessor.java deleted file mode 100644 index 911c8f15435..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestAbstractOneGenericResponseProcessor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.response; - -import java.lang.reflect.Method; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.properties.Property; -import io.swagger.models.properties.StringProperty; -import mockit.Expectations; -import mockit.Mocked; - -public class TestAbstractOneGenericResponseProcessor { - static ResponseTypeProcessor processor = new AbstractOneGenericResponseProcessor() { - @SuppressWarnings("unused") - public Holder generic() { - return null; - } - - @Override - public Class getResponseType() { - return null; - } - }; - - @Test - public void process(@Mocked OperationGenerator operationGenerator) { - Method providerMethod = ReflectUtils.findMethod(processor.getClass(), "generic"); - new Expectations() { - { - operationGenerator.getProviderMethod(); - result = providerMethod; - } - }; - Property property = processor.process(operationGenerator); - - Assert.assertThat(property, Matchers.instanceOf(StringProperty.class)); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestCompletableFutureProcessor.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestCompletableFutureProcessor.java deleted file mode 100644 index d8542acf578..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/processor/response/TestCompletableFutureProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.processor.response; - -import java.util.concurrent.CompletableFuture; - -import org.junit.Assert; -import org.junit.Test; - -public class TestCompletableFutureProcessor { - CompletableFutureProcessor processor = new CompletableFutureProcessor(); - - @Test - public void getResponseType() { - Assert.assertEquals(CompletableFuture.class, processor.getResponseType()); - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/AllType.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/AllType.java index 5ba1a4c0ed8..6314ed40ff0 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/AllType.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/AllType.java @@ -18,52 +18,49 @@ package org.apache.servicecomb.swagger.generator.core.schema; import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.servicecomb.foundation.test.scaffolding.model.Color; import org.apache.servicecomb.foundation.test.scaffolding.model.User; public class AllType { - public boolean bValue; - - public byte byteValue; - - public Byte byteObjectValue; - - public short sValue; - - public Short sObjectValue; - - public int iValue; - - public Integer iObjectValue; - - public long lValue; - - public Long lObjectValue; - - public float fValue; - - public Float fObjectValue; - - public double dValue; - - public Double dObjectValue; - - public Color enumValue; - - public char cValue; - - public Character cObjectValue; - - public byte[] bytes; - - public String strValue; - - public Set set; +// public boolean bValue; +// +// public byte byteValue; +// +// public Byte byteObjectValue; +// +// public short sValue; +// +// public Short sObjectValue; +// +// public int iValue; +// +// public Integer iObjectValue; +// +// public long lValue; +// +// public Long lObjectValue; +// +// public float fValue; +// +// public Float fObjectValue; +// +// public double dValue; +// +// public Double dObjectValue; +// +// public Color enumValue; +// +// public char cValue; +// +// public Character cObjectValue; +// +// public byte[] bytes; +// +// public String strValue; +// +// public Set set; public List list; - public Map map; +// public Map map; } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidResponseHeader.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidResponseHeader.java deleted file mode 100644 index 726d6b7ee8d..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidResponseHeader.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.schema; - -import io.swagger.annotations.ResponseHeader; - -public class InvalidResponseHeader { - @ResponseHeader(name = "h") - public void test() { - - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidType.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidType.java deleted file mode 100644 index 67e44f720d6..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/InvalidType.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.core.schema; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class InvalidType { - public static interface InvalidIntf { - - } - - public static abstract class InvalidClass { - - } - - public static class InvalidFieldClass { - public Object obj; - } - - public InvalidIntf testIntf(InvalidIntf input) { - return null; - } - - public InvalidClass testAbstractClass(InvalidClass input) { - return null; - } - - public Object testObject() { - return null; - } - - @SuppressWarnings("rawtypes") - public List testNotClearList() { - return null; - } - - @SuppressWarnings("rawtypes") - public Set testNotClearSet() { - return null; - } - - public Map testNotClearMap() { - return null; - } - - public InvalidFieldClass testInvalidFieldClass() { - return null; - } -} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/Schema.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/Schema.java index c56fa9bbba8..de65caa81e7 100644 --- a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/Schema.java +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/schema/Schema.java @@ -21,33 +21,40 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.servicecomb.foundation.test.scaffolding.model.Color; import org.apache.servicecomb.foundation.test.scaffolding.model.User; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.servlet.http.HttpServletRequest; +@SuppressWarnings("all") public class Schema { - @ApiOperation(value = "", hidden = true) + @Operation(method = "", hidden = true) public void hidden() { } - @ApiResponse(responseHeaders = {@ResponseHeader(name = "h", response = String.class)}, code = 200, message = "") + @ApiResponse(headers = {@Header(name = "h", + schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = String.class))}, responseCode = "200", description = "") public void testApiResponse() { } - @ApiOperation(responseHeaders = {@ResponseHeader(name = "h", response = String.class)}, value = "") + @ApiResponse(headers = {@Header(name = "h", + schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = String.class))}, description = "") public void testApiOperation() { } - @ResponseHeader(name = "h", response = String.class) + @ApiResponse(headers = {@Header(name = "h", + schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = String.class))}) public void testResponseHeader() { } @@ -108,6 +115,10 @@ public void testDouble(Double value) { } + public void testOneEnum(Color color) { + + } + public void testEnum(Color color, Color color1) { } @@ -144,6 +155,10 @@ public void testSet(Set value) { } + public List> nestedListString(List> param) { + return param; + } + public void testList(List value) { } @@ -164,6 +179,14 @@ public CompletableFuture testCompletableFuture() { return null; } + public Optional testOptional() { + return Optional.empty(); + } + + public CompletableFuture> testCompletableFutureOptional() { + return null; + } + public void testAllType(AllType obj) { } @@ -185,4 +208,12 @@ public List testMultiParam(AllType obj, Map map) { return Collections.emptyList(); } + + public void wrapToBodyWithDesc(@Parameter(name = "desc") int value) { + + } + + public void ignoreRequest(HttpServletRequest request, int value) { + + } } diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/TestMethodUtils.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/TestMethodUtils.java new file mode 100644 index 00000000000..873b9bb8e5f --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/TestMethodUtils.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils; + +import java.lang.reflect.Method; +import java.util.List; + +import org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel.AbstractBaseClass; +import org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel.BaseInterface; +import org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel.Hello2Endpoint; +import org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel.HelloEndpoint; +import org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel.ServiceInterface; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestMethodUtils { + @Test + public void testGetClassMethods() throws Exception { + List methods = MethodUtils.findSwaggerMethods(Hello2Endpoint.class); + Assertions.assertEquals(3, methods.size()); + Assertions.assertEquals(Hello2Endpoint.class, methods.get(0).getDeclaringClass()); + Assertions.assertEquals(Hello2Endpoint.class, methods.get(1).getDeclaringClass()); + Assertions.assertEquals(Hello2Endpoint.class, methods.get(2).getDeclaringClass()); + + methods = MethodUtils.findSwaggerMethods(HelloEndpoint.class); + Assertions.assertEquals(2, methods.size()); + Assertions.assertEquals(HelloEndpoint.class, methods.get(0).getDeclaringClass()); // get + Assertions.assertEquals(AbstractBaseClass.class, methods.get(1).getDeclaringClass()); // getBase + + methods = MethodUtils.findSwaggerMethods(ServiceInterface.class); + Assertions.assertEquals(3, methods.size()); + Assertions.assertEquals(BaseInterface.class, methods.get(0).getDeclaringClass()); // get + Assertions.assertEquals(BaseInterface.class, methods.get(1).getDeclaringClass()); // getArray + Assertions.assertEquals(ServiceInterface.class, methods.get(2).getDeclaringClass()); // getBase + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBaseClass.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBaseClass.java new file mode 100644 index 00000000000..f5d4f56a858 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBaseClass.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public abstract class AbstractBaseClass { + abstract T get(T param); + + public T getBase(T param) { + return param; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBean.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBean.java new file mode 100644 index 00000000000..521f5594a6d --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/AbstractBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public abstract class AbstractBean { + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/BaseInterface.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/BaseInterface.java new file mode 100644 index 00000000000..fd7b60f828c --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/BaseInterface.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public interface BaseInterface { + T get(T param); + + T[] getArray(T[] param); +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/Hello2Endpoint.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/Hello2Endpoint.java new file mode 100644 index 00000000000..42ec7d8e92e --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/Hello2Endpoint.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public class Hello2Endpoint implements ServiceInterface { + @Override + public HelloBean get(HelloBean param) { + return param; + } + + @Override + public HelloBean[] getArray(HelloBean[] param) { + return new HelloBean[0]; + } + + @Override + public HelloBean getBase(HelloBean param) { + return param; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloBean.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloBean.java new file mode 100644 index 00000000000..e8adb9cd400 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public class HelloBean extends AbstractBean { + private String hello; + + public String getHello() { + return hello; + } + + public void setHello(String hello) { + this.hello = hello; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloEndpoint.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloEndpoint.java new file mode 100644 index 00000000000..1736e044ec7 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/HelloEndpoint.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public class HelloEndpoint extends AbstractBaseClass { + @Override + public HelloBean get(HelloBean param) { + return param; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/ServiceInterface.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/ServiceInterface.java new file mode 100644 index 00000000000..5145876fd2c --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/methodUtilsModel/ServiceInterface.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.methodUtilsModel; + +public interface ServiceInterface extends BaseInterface { + HelloBean getBase(HelloBean param); +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBaseService.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBaseService.java new file mode 100644 index 00000000000..66bc3b59331 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBaseService.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +import java.util.List; + +public class AbstractBaseService implements IBaseService { + private final IBaseService target; + + protected AbstractBaseService(IBaseService t) { + target = t; + } + + @Override + public T hello(T a) { + return target.hello(a); + } + + @Override + public T[] helloBody(T[] a) { + return target.helloBody(a); + } + + @Override + public List helloList(List a) { + return a; + } + + @Override + public PersonBean actual(PersonBean bean) { + return target.actual(bean); + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBean.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBean.java new file mode 100644 index 00000000000..9e3dc72b2b8 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/AbstractBean.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +public abstract class AbstractBean { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IBaseService.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IBaseService.java new file mode 100644 index 00000000000..d2e0ec4736c --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IBaseService.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +import java.util.List; + +public interface IBaseService { + T hello(T a); + + T[] helloBody(T[] a); + + List helloList(List a); + + PersonBean actual(PersonBean bean); +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyService.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyService.java new file mode 100644 index 00000000000..47cc70e6993 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyService.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +public interface IMyService extends IBaseService { + List parentHello(List bean); +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild.java new file mode 100644 index 00000000000..d6025ce3a6a --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +public interface IMyServiceChild extends IMyService { +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild2.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild2.java new file mode 100644 index 00000000000..7f8c758a6cd --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/IMyServiceChild2.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +public interface IMyServiceChild2 extends IMyService, IBaseService { +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint.java new file mode 100644 index 00000000000..98ff0123997 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.multipart.MultipartFile; + +public class MyEndpoint extends AbstractBaseService implements IMyService { + public MyEndpoint(@Autowired IMyService other) { + super(other); + } + + @Override + public List parentHello(List bean) { + return null; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint2.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint2.java new file mode 100644 index 00000000000..f8fef7d660b --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/MyEndpoint2.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +import java.util.List; + +import org.springframework.web.multipart.MultipartFile; + +public class MyEndpoint2 implements IMyService { + @Override + public PersonBean hello(PersonBean a) { + return null; + } + + @Override + public PersonBean[] helloBody(PersonBean[] a) { + return new PersonBean[0]; + } + + @Override + public List helloList(List a) { + return null; + } + + @Override + public PersonBean actual(PersonBean bean) { + return null; + } + + @Override + public List parentHello(List bean) { + return null; + } +} diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/PersonBean.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/PersonBean.java new file mode 100644 index 00000000000..508d302fa51 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/utils/paramUtilsModel/PersonBean.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.core.utils.paramUtilsModel; + +public class PersonBean extends AbstractBean { +} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/log4j.properties b/swagger/swagger-generator/generator-core/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/swagger/swagger-generator/generator-core/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/ParameterAnnotation.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/ParameterAnnotation.yaml new file mode 100644 index 00000000000..af5f0a2e9de --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/ParameterAnnotation.yaml @@ -0,0 +1,68 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.TestPojo$ParameterAnnotation + version: 1.0.0 +servers: +- url: /ParameterAnnotation +paths: + /differentName: + post: + summary: differentName + operationId: differentName + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/differentNameBody" + application/protobuf: + schema: + $ref: "#/components/schemas/differentNameBody" + text/plain: + schema: + $ref: "#/components/schemas/differentNameBody" + x-name: differentNameBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + application/protobuf: + schema: + type: integer + format: int32 + text/plain: + schema: + type: integer + format: int32 +components: + schemas: + differentNameBody: + type: object + properties: + x: + type: integer + format: int32 + "y": + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/Schema.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/Schema.yaml new file mode 100644 index 00000000000..0894deeb672 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/Schema.yaml @@ -0,0 +1,1012 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /ignoreRequest: + post: + operationId: ignoreRequest + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ignoreRequestBody" + application/protobuf: + schema: + $ref: "#/components/schemas/ignoreRequestBody" + text/plain: + schema: + $ref: "#/components/schemas/ignoreRequestBody" + x-name: ignoreRequestBody + responses: + "200": + description: response of 200 + /nestedListString: + post: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/nestedListStringBody" + application/protobuf: + schema: + $ref: "#/components/schemas/nestedListStringBody" + text/plain: + schema: + $ref: "#/components/schemas/nestedListStringBody" + x-name: nestedListStringBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + application/protobuf: + schema: + type: array + items: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: array + items: + type: string + /testAllType: + post: + operationId: testAllType + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/AllType" + application/protobuf: + schema: + $ref: "#/components/schemas/AllType" + text/plain: + schema: + $ref: "#/components/schemas/AllType" + x-name: obj + responses: + "200": + description: response of 200 + /testApiOperation: + post: + operationId: testApiOperation + responses: + "200": + description: response of 200 + headers: + h: + schema: + type: string + description: "" + nullable: false + example: "" + /testApiResponse: + post: + operationId: testApiResponse + responses: + "200": + description: response of 200 + headers: + h: + schema: + type: string + description: "" + nullable: false + example: "" + /testArray: + post: + operationId: testArray + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testArrayBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testArrayBody" + text/plain: + schema: + $ref: "#/components/schemas/testArrayBody" + x-name: testArrayBody + responses: + "200": + description: response of 200 + /testBoolean: + post: + operationId: testBoolean + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testBooleanBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testBooleanBody" + text/plain: + schema: + $ref: "#/components/schemas/testBooleanBody" + x-name: testBooleanBody + responses: + "200": + description: response of 200 + /testByte: + post: + operationId: testByte + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testByteBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testByteBody" + text/plain: + schema: + $ref: "#/components/schemas/testByteBody" + x-name: testByteBody + responses: + "200": + description: response of 200 + /testBytes: + post: + operationId: testBytes + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testBytesBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testBytesBody" + text/plain: + schema: + $ref: "#/components/schemas/testBytesBody" + x-name: testBytesBody + responses: + "200": + description: response of 200 + /testChar: + post: + operationId: testChar + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testCharBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testCharBody" + text/plain: + schema: + $ref: "#/components/schemas/testCharBody" + x-name: testCharBody + responses: + "200": + description: response of 200 + /testCompletableFuture: + post: + operationId: testCompletableFuture + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testCompletableFutureOptional: + post: + operationId: testCompletableFutureOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testDate: + post: + operationId: testDate + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + format: date-time + application/protobuf: + schema: + type: string + format: date-time + text/plain: + schema: + type: string + format: date-time + /testDouble: + post: + operationId: testDouble + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testDoubleBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testDoubleBody" + text/plain: + schema: + $ref: "#/components/schemas/testDoubleBody" + x-name: testDoubleBody + responses: + "200": + description: response of 200 + /testEnum: + post: + operationId: testEnum + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testEnumBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testEnumBody" + text/plain: + schema: + $ref: "#/components/schemas/testEnumBody" + x-name: testEnumBody + responses: + "200": + description: response of 200 + /testFloat: + post: + operationId: testFloat + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testFloatBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testFloatBody" + text/plain: + schema: + $ref: "#/components/schemas/testFloatBody" + x-name: testFloatBody + responses: + "200": + description: response of 200 + /testInteger: + post: + operationId: testInteger + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testIntegerBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testIntegerBody" + text/plain: + schema: + $ref: "#/components/schemas/testIntegerBody" + x-name: testIntegerBody + responses: + "200": + description: response of 200 + /testList: + post: + operationId: testList + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testListBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testListBody" + text/plain: + schema: + $ref: "#/components/schemas/testListBody" + x-name: testListBody + responses: + "200": + description: response of 200 + /testLong: + post: + operationId: testLong + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testLongBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testLongBody" + text/plain: + schema: + $ref: "#/components/schemas/testLongBody" + x-name: testLongBody + responses: + "200": + description: response of 200 + /testMap: + post: + operationId: testMap + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testMapBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testMapBody" + text/plain: + schema: + $ref: "#/components/schemas/testMapBody" + x-name: testMapBody + responses: + "200": + description: response of 200 + /testMapList: + post: + operationId: testMapList + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testMapListBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testMapListBody" + text/plain: + schema: + $ref: "#/components/schemas/testMapListBody" + x-name: testMapListBody + responses: + "200": + description: response of 200 + /testMultiParam: + post: + operationId: testMultiParam + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testMultiParamBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testMultiParamBody" + text/plain: + schema: + $ref: "#/components/schemas/testMultiParamBody" + x-name: testMultiParamBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: string + application/protobuf: + schema: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: string + /testObject: + post: + operationId: testObject + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + $ref: "#/components/schemas/User" + text/plain: + schema: + $ref: "#/components/schemas/User" + x-name: user + responses: + "200": + description: response of 200 + /testOneEnum: + post: + operationId: testOneEnum + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testOneEnumBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testOneEnumBody" + text/plain: + schema: + $ref: "#/components/schemas/testOneEnumBody" + x-name: testOneEnumBody + responses: + "200": + description: response of 200 + /testOptional: + post: + operationId: testOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testResponseHeader: + post: + operationId: testResponseHeader + responses: + "200": + description: response of 200 + headers: + h: + schema: + type: string + description: "" + nullable: false + example: "" + /testSet: + post: + operationId: testSet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testSetBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testSetBody" + text/plain: + schema: + $ref: "#/components/schemas/testSetBody" + x-name: testSetBody + responses: + "200": + description: response of 200 + /testShort: + post: + operationId: testShort + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testShortBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testShortBody" + text/plain: + schema: + $ref: "#/components/schemas/testShortBody" + x-name: testShortBody + responses: + "200": + description: response of 200 + /testString: + post: + operationId: testString + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testStringBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testStringBody" + text/plain: + schema: + $ref: "#/components/schemas/testStringBody" + x-name: testStringBody + responses: + "200": + description: response of 200 + /testboolean: + post: + operationId: testboolean + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testbooleanBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testbooleanBody" + text/plain: + schema: + $ref: "#/components/schemas/testbooleanBody" + x-name: testbooleanBody + responses: + "200": + description: response of 200 + /testbyte: + post: + operationId: testbyte + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testbyteBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testbyteBody" + text/plain: + schema: + $ref: "#/components/schemas/testbyteBody" + x-name: testbyteBody + responses: + "200": + description: response of 200 + /testbytes: + post: + operationId: testbytes + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testbytesBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testbytesBody" + text/plain: + schema: + $ref: "#/components/schemas/testbytesBody" + x-name: testbytesBody + responses: + "200": + description: response of 200 + /testchar: + post: + operationId: testchar + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testcharBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testcharBody" + text/plain: + schema: + $ref: "#/components/schemas/testcharBody" + x-name: testcharBody + responses: + "200": + description: response of 200 + /testdouble: + post: + operationId: testdouble + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testdoubleBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testdoubleBody" + text/plain: + schema: + $ref: "#/components/schemas/testdoubleBody" + x-name: testdoubleBody + responses: + "200": + description: response of 200 + /testfloat: + post: + operationId: testfloat + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testfloatBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testfloatBody" + text/plain: + schema: + $ref: "#/components/schemas/testfloatBody" + x-name: testfloatBody + responses: + "200": + description: response of 200 + /testint: + post: + operationId: testint + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testintBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testintBody" + text/plain: + schema: + $ref: "#/components/schemas/testintBody" + x-name: testintBody + responses: + "200": + description: response of 200 + /testlong: + post: + operationId: testlong + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testlongBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testlongBody" + text/plain: + schema: + $ref: "#/components/schemas/testlongBody" + x-name: testlongBody + responses: + "200": + description: response of 200 + /testshort: + post: + operationId: testshort + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testshortBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testshortBody" + text/plain: + schema: + $ref: "#/components/schemas/testshortBody" + x-name: testshortBody + responses: + "200": + description: response of 200 + /wrapToBodyWithDesc: + post: + operationId: wrapToBodyWithDesc + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/wrapToBodyWithDescBody" + application/protobuf: + schema: + $ref: "#/components/schemas/wrapToBodyWithDescBody" + text/plain: + schema: + $ref: "#/components/schemas/wrapToBodyWithDescBody" + x-name: wrapToBodyWithDescBody + responses: + "200": + description: response of 200 +components: + schemas: + ignoreRequestBody: + type: object + properties: + value: + type: integer + format: int32 + nestedListStringBody: + type: object + properties: + param: + type: array + items: + type: array + items: + type: string + AllType: + type: object + properties: + list: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.swagger.generator.core.schema.AllType + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.foundation.test.scaffolding.model.User + testArrayBody: + type: object + properties: + value: + type: array + items: + type: string + testBooleanBody: + type: object + properties: + value: + type: boolean + testByteBody: + type: object + properties: + value: + type: integer + format: int32 + testBytesBody: + type: object + properties: + value: + type: string + format: byte + testCharBody: + type: object + properties: + value: + type: string + testDoubleBody: + type: object + properties: + value: + type: number + format: double + testEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE + color1: + type: string + enum: + - RED + - YELLOW + - BLUE + testFloatBody: + type: object + properties: + value: + type: number + format: float + testIntegerBody: + type: object + properties: + value: + type: integer + format: int32 + testListBody: + type: object + properties: + value: + type: array + items: + $ref: "#/components/schemas/User" + testLongBody: + type: object + properties: + value: + type: integer + format: int64 + testMapBody: + type: object + properties: + value: + type: object + additionalProperties: + $ref: "#/components/schemas/User" + testMapListBody: + type: object + properties: + value: + type: object + additionalProperties: + type: array + items: + $ref: "#/components/schemas/User" + testMultiParamBody: + type: object + properties: + obj: + $ref: "#/components/schemas/AllType" + bValue: + type: boolean + byteValue: + type: integer + format: int32 + sValue: + type: integer + format: int32 + iValue: + type: integer + format: int32 + lValue: + type: integer + format: int64 + fValue: + type: number + format: float + dValue: + type: number + format: double + enumValue: + type: string + enum: + - RED + - YELLOW + - BLUE + cValue: + type: string + bytes: + type: string + format: byte + strValue: + type: string + strArray: + type: array + items: + type: string + set: + uniqueItems: true + type: array + items: + type: string + list: + type: array + items: + $ref: "#/components/schemas/User" + map: + type: object + additionalProperties: + $ref: "#/components/schemas/User" + testOneEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE + testSetBody: + type: object + properties: + value: + uniqueItems: true + type: array + items: + type: string + testShortBody: + type: object + properties: + value: + type: integer + format: int32 + testStringBody: + type: object + properties: + value: + type: string + testbooleanBody: + type: object + properties: + value: + type: boolean + testbyteBody: + type: object + properties: + value: + type: integer + format: int32 + testbytesBody: + type: object + properties: + value: + type: string + format: byte + testcharBody: + type: object + properties: + value: + type: string + testdoubleBody: + type: object + properties: + value: + type: number + format: double + testfloatBody: + type: object + properties: + value: + type: number + format: float + testintBody: + type: object + properties: + value: + type: integer + format: int32 + testlongBody: + type: object + properties: + value: + type: integer + format: int64 + testshortBody: + type: object + properties: + value: + type: integer + format: int32 + wrapToBodyWithDescBody: + type: object + properties: + desc: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/allMethod.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/allMethod.yaml index 0191419229c..809dc9ccec8 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/allMethod.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/allMethod.yaml @@ -16,707 +16,835 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: - /testBoolean: + /ignoreRequest: + post: + operationId: ignoreRequest + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ignoreRequestBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /nestedListString: + post: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/nestedListStringBody' + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + /part: + post: + operationId: part + requestBody: + content: + multipart/form-data: + schema: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} + /partArray: + post: + operationId: partArray + requestBody: + content: + multipart/form-data: + schema: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} + /partList: + post: + operationId: partList + requestBody: + content: + multipart/form-data: + schema: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} + /testAllType: post: - operationId: "testBoolean" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testBooleanBody" + operationId: testAllType responses: - 200: - description: "response of 200" - /testInteger: + "200": + description: response of 200 + content: + application/json: {} + /testApiOperation: post: - operationId: "testInteger" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testIntegerBody" + operationId: testApiOperation responses: - 200: - description: "response of 200" - /testchar: + default: + description: response of default + headers: + h: + description: "" + schema: + type: string + description: "" + format: "" + content: {} + "200": + description: response of 200 + content: + application/json: {} + /testApiResponse: post: - operationId: "testchar" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testcharBody" + operationId: testApiResponse responses: - 200: - description: "response of 200" - /testSet: + "200": + description: response of 200 + headers: + h: + description: "" + schema: + type: string + description: "" + format: "" + content: + application/json: {} + /testArray: post: - operationId: "testSet" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testSetBody" - responses: - 200: - description: "response of 200" - /testbytes: + operationId: testArray + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testArrayBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testBoolean: post: - operationId: "testbytes" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbytesBody" - responses: - 200: - description: "response of 200" - /testfloat: + operationId: testBoolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testBooleanBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testByte: post: - operationId: "testfloat" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testfloatBody" - responses: - 200: - description: "response of 200" - /testLong: + operationId: testByte + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testByteBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testBytes: post: - operationId: "testLong" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testLongBody" + operationId: testBytes + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testBytesBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testChar: + post: + operationId: testChar + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testCharBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testCompletableFuture: + post: + operationId: testCompletableFuture responses: - 200: - description: "response of 200" - /testApiResponse: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /testCompletableFutureOptional: post: - operationId: "testApiResponse" - parameters: [] + operationId: testCompletableFutureOptional responses: - 200: - description: "response of 200" - headers: - h: - type: "string" - /testChar: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /testDate: post: - operationId: "testChar" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testCharBody" + operationId: testDate responses: - 200: - description: "response of 200" - /testMultiParam: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + format: date-time + /testDouble: post: - operationId: "testMultiParam" - parameters: - - in: "body" - name: "testMultiParamBody" - required: false - schema: - $ref: "#/definitions/testMultiParamBody" - responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - type: "string" - /testObject: + operationId: testDouble + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testDoubleBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testEnum: post: - operationId: "testObject" - parameters: - - in: "body" - name: "user" - required: false - schema: - $ref: "#/definitions/User" - responses: - 200: - description: "response of 200" - /testshort: + operationId: testEnum + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testEnumBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testFloat: post: - operationId: "testshort" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testshortBody" - responses: - 200: - description: "response of 200" - /testdouble: + operationId: testFloat + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testFloatBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testInteger: post: - operationId: "testdouble" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testdoubleBody" - responses: - 200: - description: "response of 200" + operationId: testInteger + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testIntegerBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testList: + post: + operationId: testList + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testListBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testLong: + post: + operationId: testLong + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testLongBody' + responses: + "200": + description: response of 200 + content: + application/json: {} /testMap: post: - operationId: "testMap" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testMapBody" - responses: - 200: - description: "response of 200" + operationId: testMap + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMapBody' + responses: + "200": + description: response of 200 + content: + application/json: {} /testMapList: post: - operationId: "testMapList" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testMapListBody" - responses: - 200: - description: "response of 200" - /testCompletableFuture: + operationId: testMapList + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMapListBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testMultiParam: post: - operationId: "testCompletableFuture" - parameters: [] - responses: - 200: - description: "response of 200" - schema: - type: "string" - /testDouble: + operationId: testMultiParam + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMultiParamBody' + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: string + /testObject: post: - operationId: "testDouble" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testDoubleBody" - responses: - 200: - description: "response of 200" + operationId: testObject + responses: + "200": + description: response of 200 + content: + application/json: {} + /testOneEnum: + post: + operationId: testOneEnum + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testOneEnumBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testOptional: + post: + operationId: testOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string /testResponseHeader: post: - operationId: "testResponseHeader" - parameters: [] + operationId: testResponseHeader responses: - 200: - description: "response of 200" + default: + description: response of default headers: h: - type: "string" - /testApiOperation: + description: "" + schema: + type: string + description: "" + format: "" + content: {} + "200": + description: response of 200 + content: + application/json: {} + /testSet: post: - operationId: "testApiOperation" - parameters: [] - responses: - 200: - description: "response of 200" - headers: - h: - type: "string" - /testArray: + operationId: testSet + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testSetBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testShort: post: - operationId: "testArray" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testArrayBody" - responses: - 200: - description: "response of 200" - /testByte: + operationId: testShort + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testShortBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testString: post: - operationId: "testByte" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testByteBody" - responses: - 200: - description: "response of 200" + operationId: testString + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testStringBody' + responses: + "200": + description: response of 200 + content: + application/json: {} /testboolean: post: - operationId: "testboolean" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbooleanBody" - responses: - 200: - description: "response of 200" - /testint: - post: - operationId: "testint" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testintBody" - responses: - 200: - description: "response of 200" - /testBytes: - post: - operationId: "testBytes" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testBytesBody" - responses: - 200: - description: "response of 200" - /testEnum: - post: - operationId: "testEnum" - parameters: - - in: "body" - name: "testEnumBody" - required: false - schema: - $ref: "#/definitions/testEnumBody" - responses: - 200: - description: "response of 200" - /testFloat: - post: - operationId: "testFloat" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testFloatBody" - responses: - 200: - description: "response of 200" - /testShort: + operationId: testboolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbooleanBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testbyte: post: - operationId: "testShort" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testShortBody" - responses: - 200: - description: "response of 200" - /testList: + operationId: testbyte + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbyteBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testbytes: post: - operationId: "testList" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testListBody" - responses: - 200: - description: "response of 200" - /testAllType: + operationId: testbytes + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbytesBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testchar: post: - operationId: "testAllType" - parameters: - - in: "body" - name: "obj" - required: false - schema: - $ref: "#/definitions/AllType" - responses: - 200: - description: "response of 200" - /testbyte: + operationId: testchar + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testcharBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testdouble: post: - operationId: "testbyte" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbyteBody" - responses: - 200: - description: "response of 200" - /testString: + operationId: testdouble + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testdoubleBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testfloat: post: - operationId: "testString" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testStringBody" - responses: - 200: - description: "response of 200" - /testDate: + operationId: testfloat + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testfloatBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testint: post: - operationId: "testDate" - parameters: [] - responses: - 200: - description: "response of 200" - schema: - type: "string" - format: "date-time" + operationId: testint + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testintBody' + responses: + "200": + description: response of 200 + content: + application/json: {} /testlong: post: - operationId: "testlong" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testlongBody" - responses: - 200: - description: "response of 200" -definitions: - AllType: - type: "object" - properties: - bValue: - type: "boolean" - byteValue: - type: "integer" - format: "int8" - byteObjectValue: - type: "integer" - format: "int8" - sValue: - type: "integer" - format: "int16" - sObjectValue: - type: "integer" - format: "int16" - iValue: - type: "integer" - format: "int32" - iObjectValue: - type: "integer" - format: "int32" - lValue: - type: "integer" - format: "int64" - lObjectValue: - type: "integer" - format: "int64" - fValue: - type: "number" - format: "float" - fObjectValue: - type: "number" - format: "float" - dValue: - type: "number" - format: "double" - dObjectValue: - type: "number" - format: "double" - enumValue: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - cValue: - type: "string" - cObjectValue: - type: "string" - bytes: - type: "string" - format: "byte" - strValue: - type: "string" - set: - type: "array" - uniqueItems: true - items: - type: "string" - list: - type: "array" - items: - $ref: "#/definitions/User" - map: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.swagger.generator.core.schema.AllType" - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" - testArrayBody: - type: "object" - properties: - value: - type: "array" - items: - type: "string" - testBooleanBody: - type: "object" - properties: - value: - type: "boolean" - testByteBody: - type: "object" - properties: - value: - type: "integer" - format: "int8" - testBytesBody: - type: "object" - properties: - value: - type: "string" - format: "byte" - testCharBody: - type: "object" - properties: - value: - type: "string" - testDoubleBody: - type: "object" - properties: - value: - type: "number" - format: "double" - testEnumBody: - type: "object" - properties: - color: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - color1: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - x-java-class: "gen.cse.ms.ut.testEnumBody" - testFloatBody: - type: "object" - properties: - value: - type: "number" - format: "float" - testIntegerBody: - type: "object" - properties: - value: - type: "integer" - format: "int32" - testListBody: - type: "object" - properties: - value: - type: "array" - items: - $ref: "#/definitions/User" - testLongBody: - type: "object" - properties: - value: - type: "integer" - format: "int64" - testMapBody: - type: "object" - properties: - value: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - testMapListBody: - type: "object" - properties: - value: - type: "object" - additionalProperties: - type: "array" + operationId: testlong + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testlongBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /testshort: + post: + operationId: testshort + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testshortBody' + responses: + "200": + description: response of 200 + content: + application/json: {} + /wrapToBodyWithDesc: + post: + operationId: wrapToBodyWithDesc + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/wrapToBodyWithDescBody' + responses: + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + ignoreRequestBody: + type: object + properties: + value: + type: integer + format: int32 + nestedListStringBody: + type: object + properties: + param: + type: array + items: + type: array + items: + type: string + AllType: + type: object + properties: + list: + type: array + items: + $ref: '#/components/schemas/User' + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' + testArrayBody: + type: object + properties: + value: + type: array + items: + type: string + testBooleanBody: + type: object + properties: + value: + type: boolean + testByteBody: + type: object + properties: + value: + type: string + format: byte + testBytesBody: + type: object + properties: + value: + type: array + items: + type: string + format: byte + testCharBody: + type: object + properties: + value: + type: string + testDoubleBody: + type: object + properties: + value: + type: number + format: double + testEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE + color1: + type: string + enum: + - RED + - YELLOW + - BLUE + testFloatBody: + type: object + properties: + value: + type: number + format: float + testIntegerBody: + type: object + properties: + value: + type: integer + format: int32 + testListBody: + type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/User' + testLongBody: + type: object + properties: + value: + type: integer + format: int64 + testMapBody: + type: object + properties: + value: + type: object + additionalProperties: + $ref: '#/components/schemas/User' + testMapListBody: + type: object + properties: + value: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/User' + testMultiParamBody: + type: object + properties: + obj: + $ref: '#/components/schemas/AllType' + bValue: + type: boolean + byteValue: + type: string + format: byte + sValue: + type: integer + format: int32 + iValue: + type: integer + format: int32 + lValue: + type: integer + format: int64 + fValue: + type: number + format: float + dValue: + type: number + format: double + enumValue: + type: string + enum: + - RED + - YELLOW + - BLUE + cValue: + type: string + bytes: + type: array + items: + type: string + format: byte + strValue: + type: string + strArray: + type: array + items: + type: string + set: + uniqueItems: true + type: array + items: + type: string + list: + type: array + items: + $ref: '#/components/schemas/User' + map: + type: object + additionalProperties: + $ref: '#/components/schemas/User' + testOneEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE + testSetBody: + type: object + properties: + value: + uniqueItems: true + type: array + items: + type: string + testShortBody: + type: object + properties: + value: + type: integer + format: int32 + testStringBody: + type: object + properties: + value: + type: string + testbooleanBody: + type: object + properties: + value: + type: boolean + testbyteBody: + type: object + properties: + value: + type: string + format: byte + testbytesBody: + type: object + properties: + value: + type: array items: - $ref: "#/definitions/User" - testMultiParamBody: - type: "object" - properties: - obj: - $ref: "#/definitions/AllType" - bValue: - type: "boolean" - byteValue: - type: "integer" - format: "int8" - sValue: - type: "integer" - format: "int16" - iValue: - type: "integer" - format: "int32" - lValue: - type: "integer" - format: "int64" - fValue: - type: "number" - format: "float" - dValue: - type: "number" - format: "double" - enumValue: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - cValue: - type: "string" - bytes: - type: "string" - format: "byte" - strValue: - type: "string" - strArray: - type: "array" - items: - type: "string" - set: - type: "array" - uniqueItems: true - items: - type: "string" - list: - type: "array" - items: - $ref: "#/definitions/User" - map: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - x-java-class: "gen.cse.ms.ut.testMultiParamBody" - testSetBody: - type: "object" - properties: - value: - type: "array" - uniqueItems: true - items: - type: "string" - testShortBody: - type: "object" - properties: - value: - type: "integer" - format: "int16" - testStringBody: - type: "object" - properties: - value: - type: "string" - testbooleanBody: - type: "object" - properties: - value: - type: "boolean" - testbyteBody: - type: "object" - properties: - value: - type: "integer" - format: "int8" - testbytesBody: - type: "object" - properties: - value: - type: "string" - format: "byte" - testcharBody: - type: "object" - properties: - value: - type: "string" - testdoubleBody: - type: "object" - properties: - value: - type: "number" - format: "double" - testfloatBody: - type: "object" - properties: - value: - type: "number" - format: "float" - testintBody: - type: "object" - properties: - value: - type: "integer" - format: "int32" - testlongBody: - type: "object" - properties: - value: - type: "integer" - format: "int64" - testshortBody: - type: "object" - properties: - value: - type: "integer" - format: "int16" + type: string + format: byte + testcharBody: + type: object + properties: + value: + type: string + testdoubleBody: + type: object + properties: + value: + type: number + format: double + testfloatBody: + type: object + properties: + value: + type: number + format: float + testintBody: + type: object + properties: + value: + type: integer + format: int32 + testlongBody: + type: object + properties: + value: + type: integer + format: int64 + testshortBody: + type: object + properties: + value: + type: integer + format: int32 + wrapToBodyWithDescBody: + type: object + properties: + desc: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/allType.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/allType.yaml index 0cf6e851818..b5b5102ae2a 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/allType.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/allType.yaml @@ -16,108 +16,36 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testAllType: post: - operationId: "testAllType" - parameters: - - in: "body" - name: "obj" - required: false - schema: - $ref: "#/definitions/AllType" + operationId: testAllType responses: - 200: - description: "response of 200" -definitions: - AllType: - type: "object" - properties: - bValue: - type: "boolean" - byteValue: - type: "integer" - format: "int8" - byteObjectValue: - type: "integer" - format: "int8" - sValue: - type: "integer" - format: "int16" - sObjectValue: - type: "integer" - format: "int16" - iValue: - type: "integer" - format: "int32" - iObjectValue: - type: "integer" - format: "int32" - lValue: - type: "integer" - format: "int64" - lObjectValue: - type: "integer" - format: "int64" - fValue: - type: "number" - format: "float" - fObjectValue: - type: "number" - format: "float" - dValue: - type: "number" - format: "double" - dObjectValue: - type: "number" - format: "double" - enumValue: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - cValue: - type: "string" - cObjectValue: - type: "string" - bytes: - type: "string" - format: "byte" - strValue: - type: "string" - set: - type: "array" - uniqueItems: true - items: - type: "string" - list: - type: "array" - items: - $ref: "#/definitions/User" - map: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.swagger.generator.core.schema.AllType" - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + AllType: + type: object + properties: + list: + type: array + items: + $ref: '#/components/schemas/User' + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiOperation.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiOperation.yaml index 84cdcb48855..d2262b48918 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiOperation.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiOperation.yaml @@ -16,24 +16,28 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testApiOperation: post: - operationId: "testApiOperation" - parameters: [] + operationId: testApiOperation responses: - 200: - description: "response of 200" + default: + description: response of default headers: h: - type: "string" + description: "" + schema: + type: string + description: "" + format: "" + content: {} + "200": + description: response of 200 + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiResponse.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiResponse.yaml index 9a010430d3d..e4b523415d7 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiResponse.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/apiResponse.yaml @@ -16,24 +16,25 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testApiResponse: post: - operationId: "testApiResponse" - parameters: [] + operationId: testApiResponse responses: - 200: - description: "response of 200" + "200": + description: response of 200 headers: h: - type: "string" + description: "" + schema: + type: string + description: "" + format: "" + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/array.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/array.yaml index d82251d65d6..ed2755cde79 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/array.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/array.yaml @@ -16,34 +16,32 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testArray: post: - operationId: "testArray" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testArrayBody" + operationId: testArray + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testArrayBody' responses: - 200: - description: "response of 200" -definitions: - testArrayBody: - type: "object" - properties: - value: - type: "array" - items: - type: "string" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testArrayBody: + type: object + properties: + value: + type: array + items: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/boolean.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/boolean.yaml index f142dd4796e..d2dd735f18c 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/boolean.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/boolean.yaml @@ -16,32 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testboolean: post: - operationId: "testboolean" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbooleanBody" + operationId: testboolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbooleanBody' + x-name: name responses: - 200: - description: "response of 200" -definitions: - testbooleanBody: - type: "object" - properties: - value: - type: "boolean" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testbooleanBody: + type: object + properties: + value: + type: boolean diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/booleanObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/booleanObject.yaml index b3d688eb240..f31f4e6fbe8 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/booleanObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/booleanObject.yaml @@ -16,32 +16,30 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testBoolean: post: - operationId: "testBoolean" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testBooleanBody" + operationId: testBoolean + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testBooleanBody' responses: - 200: - description: "response of 200" -definitions: - testBooleanBody: - type: "object" - properties: - value: - type: "boolean" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testBooleanBody: + type: object + properties: + value: + type: boolean diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/byte.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/byte.yaml index 26fdbd2f569..c12584a8cda 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/byte.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/byte.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testbyte: post: - operationId: "testbyte" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbyteBody" + operationId: testbyte + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbyteBody' responses: - 200: - description: "response of 200" -definitions: - testbyteBody: - type: "object" - properties: - value: - type: "integer" - format: "int8" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testbyteBody: + type: object + properties: + value: + type: string + format: byte diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/byteObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/byteObject.yaml index 50938363248..3e57a34434a 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/byteObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/byteObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testByte: post: - operationId: "testByte" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testByteBody" + operationId: testByte + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testByteBody' responses: - 200: - description: "response of 200" -definitions: - testByteBody: - type: "object" - properties: - value: - type: "integer" - format: "int8" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testByteBody: + type: object + properties: + value: + type: string + format: byte diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytes.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytes.yaml index 823c709e1c9..76180f8753c 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytes.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytes.yaml @@ -16,33 +16,33 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testbytes: post: - operationId: "testbytes" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testbytesBody" + operationId: testbytes + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testbytesBody' responses: - 200: - description: "response of 200" -definitions: - testbytesBody: - type: "object" - properties: - value: - type: "string" - format: "byte" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testbytesBody: + type: object + properties: + value: + type: array + items: + type: string + format: byte diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytesObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytesObject.yaml index 3b4986cfc3c..ed55ed0ca2a 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytesObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/bytesObject.yaml @@ -16,33 +16,33 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testBytes: post: - operationId: "testBytes" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testBytesBody" + operationId: testBytes + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testBytesBody' responses: - 200: - description: "response of 200" -definitions: - testBytesBody: - type: "object" - properties: - value: - type: "string" - format: "byte" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testBytesBody: + type: object + properties: + value: + type: array + items: + type: string + format: byte diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/char.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/char.yaml index 9bc81cbc7fc..5e1ce2a0132 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/char.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/char.yaml @@ -16,32 +16,30 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testchar: post: - operationId: "testchar" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testcharBody" + operationId: testchar + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testcharBody' responses: - 200: - description: "response of 200" -definitions: - testcharBody: - type: "object" - properties: - value: - type: "string" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testcharBody: + type: object + properties: + value: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/charObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/charObject.yaml index 4e1b55c5b10..22e2ced3400 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/charObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/charObject.yaml @@ -16,32 +16,30 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testChar: post: - operationId: "testChar" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testCharBody" + operationId: testChar + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testCharBody' responses: - 200: - description: "response of 200" -definitions: - testCharBody: - type: "object" - properties: - value: - type: "string" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testCharBody: + type: object + properties: + value: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/completableFuture.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/completableFuture.yaml index ffbdc840c80..449ec2cda52 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/completableFuture.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/completableFuture.yaml @@ -16,23 +16,22 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testCompletableFuture: post: - operationId: "testCompletableFuture" - parameters: [] + operationId: testCompletableFuture responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/date.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/date.yaml index fdb3aa3748b..52572264ec5 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/date.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/date.yaml @@ -16,24 +16,23 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testDate: post: - operationId: "testDate" - parameters: [] + operationId: testDate responses: - 200: - description: "response of 200" - schema: - type: "string" - format: "date-time" + "200": + description: response of 200 + content: + application/json: + schema: + type: string + format: date-time +components: + schemas: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/double.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/double.yaml index 23274d06340..65584bbf279 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/double.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/double.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testdouble: post: - operationId: "testdouble" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testdoubleBody" + operationId: testdouble + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testdoubleBody' responses: - 200: - description: "response of 200" -definitions: - testdoubleBody: - type: "object" - properties: - value: - type: "number" - format: "double" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testdoubleBody: + type: object + properties: + value: + type: number + format: double diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/doubleObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/doubleObject.yaml index 030554f07c0..e9ff78b1434 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/doubleObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/doubleObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testDouble: post: - operationId: "testDouble" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testDoubleBody" + operationId: testDouble + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testDoubleBody' responses: - 200: - description: "response of 200" -definitions: - testDoubleBody: - type: "object" - properties: - value: - type: "number" - format: "double" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testDoubleBody: + type: object + properties: + value: + type: number + format: double diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/enum.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/enum.yaml index b9c30be0301..b7a6d5248e5 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/enum.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/enum.yaml @@ -16,45 +16,40 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testEnum: post: - operationId: "testEnum" - parameters: - - in: "body" - name: "testEnumBody" - required: false - schema: - $ref: "#/definitions/testEnumBody" + operationId: testEnum + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testEnumBody' responses: - 200: - description: "response of 200" -definitions: - testEnumBody: - type: "object" - properties: - color: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - color1: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - x-java-class: "gen.cse.ms.ut.testEnumBody" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE + color1: + type: string + enum: + - RED + - YELLOW + - BLUE diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/float.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/float.yaml index 49d606e1abf..6839634c7c9 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/float.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/float.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testfloat: post: - operationId: "testfloat" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testfloatBody" + operationId: testfloat + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testfloatBody' responses: - 200: - description: "response of 200" -definitions: - testfloatBody: - type: "object" - properties: - value: - type: "number" - format: "float" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testfloatBody: + type: object + properties: + value: + type: number + format: float diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/floatObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/floatObject.yaml index e7757ba0775..112958f2281 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/floatObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/floatObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testFloat: post: - operationId: "testFloat" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testFloatBody" + operationId: testFloat + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testFloatBody' responses: - 200: - description: "response of 200" -definitions: - testFloatBody: - type: "object" - properties: - value: - type: "number" - format: "float" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testFloatBody: + type: object + properties: + value: + type: number + format: float diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/ignoreRequest.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/ignoreRequest.yaml new file mode 100644 index 00000000000..091b0168add --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/ignoreRequest.yaml @@ -0,0 +1,46 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /ignoreRequest: + post: + operationId: ignoreRequest + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ignoreRequestBody' + responses: + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + ignoreRequestBody: + type: object + properties: + value: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/int.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/int.yaml index b3e6aaa0ba6..19bd7678928 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/int.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/int.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testint: post: - operationId: "testint" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testintBody" + operationId: testint + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testintBody' responses: - 200: - description: "response of 200" -definitions: - testintBody: - type: "object" - properties: - value: - type: "integer" - format: "int32" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testintBody: + type: object + properties: + value: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/intObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/intObject.yaml index bbf92af4c85..da11ea13e2e 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/intObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/intObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testInteger: post: - operationId: "testInteger" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testIntegerBody" + operationId: testInteger + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testIntegerBody' responses: - 200: - description: "response of 200" -definitions: - testIntegerBody: - type: "object" - properties: - value: - type: "integer" - format: "int32" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testIntegerBody: + type: object + properties: + value: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/list.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/list.yaml index f3289705e97..e53bdd0ed49 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/list.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/list.yaml @@ -16,45 +16,41 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testList: post: - operationId: "testList" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testListBody" + operationId: testList + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testListBody' responses: - 200: - description: "response of 200" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" - testListBody: - type: "object" - properties: - value: - type: "array" - items: - $ref: "#/definitions/User" - + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' + testListBody: + type: object + properties: + value: + type: array + items: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/long.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/long.yaml index c5e6c1b5753..17f716eecac 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/long.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/long.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testlong: post: - operationId: "testlong" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testlongBody" + operationId: testlong + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testlongBody' responses: - 200: - description: "response of 200" -definitions: - testlongBody: - type: "object" - properties: - value: - type: "integer" - format: "int64" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testlongBody: + type: object + properties: + value: + type: integer + format: int64 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/longObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/longObject.yaml index a3c8c7ec683..9916d768c52 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/longObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/longObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testLong: post: - operationId: "testLong" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testLongBody" + operationId: testLong + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testLongBody' responses: - 200: - description: "response of 200" -definitions: - testLongBody: - type: "object" - properties: - value: - type: "integer" - format: "int64" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testLongBody: + type: object + properties: + value: + type: integer + format: int64 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/map.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/map.yaml index 229c90fc2dd..918305a1b2c 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/map.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/map.yaml @@ -16,44 +16,41 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testMap: post: - operationId: "testMap" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testMapBody" + operationId: testMap + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMapBody' responses: - 200: - description: "response of 200" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" - testMapBody: - type: "object" - properties: - value: - type: "object" - additionalProperties: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' + testMapBody: + type: object + properties: + value: + type: object + additionalProperties: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/mapList.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/mapList.yaml index a5cecd7f114..17cc9c53029 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/mapList.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/mapList.yaml @@ -16,46 +16,43 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testMapList: post: - operationId: "testMapList" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testMapListBody" + operationId: testMapList + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMapListBody' responses: - 200: - description: "response of 200" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" - testMapListBody: - type: "object" - properties: - value: - type: "object" - additionalProperties: - type: "array" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array items: - $ref: "#/definitions/User" + $ref: '#/components/schemas/User' + testMapListBody: + type: object + properties: + value: + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/multiParam.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/multiParam.yaml index fe39c2d605b..79f69bcdbd7 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/multiParam.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/multiParam.yaml @@ -16,169 +16,102 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testMultiParam: post: - operationId: "testMultiParam" - parameters: - - in: "body" - name: "testMultiParamBody" - required: false - schema: - $ref: "#/definitions/testMultiParamBody" + operationId: testMultiParam + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMultiParamBody' responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - type: "string" -definitions: - AllType: - type: "object" - properties: - bValue: - type: "boolean" - byteValue: - type: "integer" - format: "int8" - byteObjectValue: - type: "integer" - format: "int8" - sValue: - type: "integer" - format: "int16" - sObjectValue: - type: "integer" - format: "int16" - iValue: - type: "integer" - format: "int32" - iObjectValue: - type: "integer" - format: "int32" - lValue: - type: "integer" - format: "int64" - lObjectValue: - type: "integer" - format: "int64" - fValue: - type: "number" - format: "float" - fObjectValue: - type: "number" - format: "float" - dValue: - type: "number" - format: "double" - dObjectValue: - type: "number" - format: "double" - enumValue: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - cValue: - type: "string" - cObjectValue: - type: "string" - bytes: - type: "string" - format: "byte" - strValue: - type: "string" - set: - type: "array" - uniqueItems: true - items: - type: "string" - list: - type: "array" - items: - $ref: "#/definitions/User" - map: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.swagger.generator.core.schema.AllType" - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" - testMultiParamBody: - type: "object" - properties: - obj: - $ref: "#/definitions/AllType" - bValue: - type: "boolean" - byteValue: - type: "integer" - format: "int8" - sValue: - type: "integer" - format: "int16" - iValue: - type: "integer" - format: "int32" - lValue: - type: "integer" - format: "int64" - fValue: - type: "number" - format: "float" - dValue: - type: "number" - format: "double" - enumValue: - type: "string" - enum: - - "RED" - - "YELLOW" - - "BLUE" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.Color" - cValue: - type: "string" - bytes: - type: "string" - format: "byte" - strValue: - type: "string" - strArray: - type: "array" - items: - type: "string" - set: - type: "array" - uniqueItems: true - items: - type: "string" - list: - type: "array" - items: - $ref: "#/definitions/User" - map: - type: "object" - additionalProperties: - $ref: "#/definitions/User" - x-java-class: "gen.cse.ms.ut.testMultiParamBody" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: string +components: + schemas: + AllType: + type: object + properties: + list: + type: array + items: + $ref: '#/components/schemas/User' + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' + testMultiParamBody: + type: object + properties: + obj: + $ref: '#/components/schemas/AllType' + bValue: + type: boolean + byteValue: + type: string + format: byte + sValue: + type: integer + format: int32 + iValue: + type: integer + format: int32 + lValue: + type: integer + format: int64 + fValue: + type: number + format: float + dValue: + type: number + format: double + enumValue: + type: string + enum: + - RED + - YELLOW + - BLUE + cValue: + type: string + bytes: + type: array + items: + type: string + format: byte + strValue: + type: string + strArray: + type: array + items: + type: string + set: + uniqueItems: true + type: array + items: + type: string + list: + type: array + items: + $ref: '#/components/schemas/User' + map: + type: object + additionalProperties: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/nestedListString.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/nestedListString.yaml new file mode 100644 index 00000000000..a4f39dc9ccf --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/nestedListString.yaml @@ -0,0 +1,55 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /nestedListString: + post: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/nestedListStringBody' + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string +components: + schemas: + nestedListStringBody: + type: object + properties: + param: + type: array + items: + type: array + items: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/object.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/object.yaml index 9cff4cd05e9..b64684d360c 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/object.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/object.yaml @@ -16,37 +16,29 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testObject: post: - operationId: "testObject" - parameters: - - in: "body" - name: "user" - required: false - schema: - $ref: "#/definitions/User" + operationId: testObject responses: - 200: - description: "response of 200" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: '#/components/schemas/User' diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/oneEnum.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/oneEnum.yaml new file mode 100644 index 00000000000..e678748c974 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/oneEnum.yaml @@ -0,0 +1,49 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /testOneEnum: + post: + operationId: testOneEnum + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testOneEnumBody' + responses: + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testOneEnumBody: + type: object + properties: + color: + type: string + enum: + - RED + - YELLOW + - BLUE diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/part.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/part.yaml new file mode 100644 index 00000000000..dcc3438e6cf --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/part.yaml @@ -0,0 +1,39 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /part: + post: + operationId: part + requestBody: + content: + multipart/form-data: + schema: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/partArray.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/partArray.yaml new file mode 100644 index 00000000000..b308b794694 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/partArray.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /partArray: + post: + operationId: partArray + requestBody: + content: + multipart/form-data: + schema: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/partList.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/partList.yaml new file mode 100644 index 00000000000..359f1f00341 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/partList.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /partList: + post: + operationId: partList + requestBody: + content: + multipart/form-data: + schema: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/pojoExample1.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/pojoExample1.yaml new file mode 100644 index 00000000000..9dcf23ee148 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/pojoExample1.yaml @@ -0,0 +1,97 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.pojo.PojoExample1 + version: 1.0.0 +servers: +- url: /PojoExample1 +paths: + /testMultiParameter: + post: + operationId: testMultiParameter + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/testMultiParameterBody" + application/protobuf: + schema: + $ref: "#/components/schemas/testMultiParameterBody" + text/plain: + schema: + $ref: "#/components/schemas/testMultiParameterBody" + x-name: testMultiParameterBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/XXX" + application/protobuf: + schema: + $ref: "#/components/schemas/XXX" + text/plain: + schema: + $ref: "#/components/schemas/XXX" + /testOneParameter: + post: + operationId: testOneParameter + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/XXX" + application/protobuf: + schema: + $ref: "#/components/schemas/XXX" + text/plain: + schema: + $ref: "#/components/schemas/XXX" + x-name: testType1 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/XXX" + application/protobuf: + schema: + $ref: "#/components/schemas/XXX" + text/plain: + schema: + $ref: "#/components/schemas/XXX" +components: + schemas: + XXX: + type: object + properties: + val1: + type: integer + format: int32 + x-java-class: org.apache.servicecomb.swagger.generator.core.pojo.TestType1 + testMultiParameterBody: + type: object + properties: + testType1: + $ref: "#/components/schemas/XXX" + testString: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/responseHeader.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/responseHeader.yaml index 061f81d409b..a6c0498f54e 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/responseHeader.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/responseHeader.yaml @@ -16,24 +16,28 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testResponseHeader: post: - operationId: "testResponseHeader" - parameters: [] + operationId: testResponseHeader responses: - 200: - description: "response of 200" + default: + description: response of default headers: h: - type: "string" + description: "" + schema: + type: string + description: "" + format: "" + content: {} + "200": + description: response of 200 + content: + application/json: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/set.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/set.yaml index a3c585ac55d..b1286c94782 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/set.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/set.yaml @@ -16,35 +16,33 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testSet: post: - operationId: "testSet" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testSetBody" + operationId: testSet + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testSetBody' responses: - 200: - description: "response of 200" -definitions: - testSetBody: - type: "object" - properties: - value: - type: "array" - uniqueItems: true - items: - type: "string" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testSetBody: + type: object + properties: + value: + uniqueItems: true + type: array + items: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/short.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/short.yaml index 5832aa5acc0..794f5988caa 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/short.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/short.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testshort: post: - operationId: "testshort" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testshortBody" + operationId: testshort + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testshortBody' responses: - 200: - description: "response of 200" -definitions: - testshortBody: - type: "object" - properties: - value: - type: "integer" - format: "int16" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testshortBody: + type: object + properties: + value: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/shortObject.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/shortObject.yaml index b7d0ce7c035..9fe72b7a15f 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/shortObject.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/shortObject.yaml @@ -16,33 +16,31 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testShort: post: - operationId: "testShort" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testShortBody" + operationId: testShort + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testShortBody' responses: - 200: - description: "response of 200" -definitions: - testShortBody: - type: "object" - properties: - value: - type: "integer" - format: "int16" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testShortBody: + type: object + properties: + value: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/string.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/string.yaml index b7d10f3d5d8..4a6fc326df8 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/schemas/string.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/string.yaml @@ -16,32 +16,30 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema" - x-java-interface: "gen.cse.ms.ut.SchemaIntf" -basePath: "/Schema" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema paths: /testString: post: - operationId: "testString" - parameters: - - in: "body" - name: "value" - required: false - schema: - $ref: "#/definitions/testStringBody" + operationId: testString + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testStringBody' responses: - 200: - description: "response of 200" -definitions: - testStringBody: - type: "object" - properties: - value: - type: "string" + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + testStringBody: + type: object + properties: + value: + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/testCompletableFutureOptional.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/testCompletableFutureOptional.yaml new file mode 100644 index 00000000000..f2cbe41c1df --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/testCompletableFutureOptional.yaml @@ -0,0 +1,37 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /testCompletableFutureOptional: + post: + operationId: testCompletableFutureOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/testOptional.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/testOptional.yaml new file mode 100644 index 00000000000..dcad961f2a9 --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/testOptional.yaml @@ -0,0 +1,37 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /testOptional: + post: + operationId: testOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: {} diff --git a/swagger/swagger-generator/generator-core/src/test/resources/schemas/wrapToBodyWithDesc.yaml b/swagger/swagger-generator/generator-core/src/test/resources/schemas/wrapToBodyWithDesc.yaml new file mode 100644 index 00000000000..7897158842a --- /dev/null +++ b/swagger/swagger-generator/generator-core/src/test/resources/schemas/wrapToBodyWithDesc.yaml @@ -0,0 +1,46 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.core.schema.Schema + version: 1.0.0 +servers: +- url: /Schema +paths: + /wrapToBodyWithDesc: + post: + operationId: wrapToBodyWithDesc + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/wrapToBodyWithDescBody' + responses: + "200": + description: response of 200 + content: + application/json: {} +components: + schemas: + wrapToBodyWithDescBody: + type: object + properties: + desc: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-core/src/test/resources/swagger1.yaml b/swagger/swagger-generator/generator-core/src/test/resources/swagger1.yaml index 14d10c4d142..add83d161c5 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/swagger1.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/swagger1.yaml @@ -33,7 +33,7 @@ paths: required: true type: string responses: - 200: + "200": description: say hello schema: - type: string \ No newline at end of file + type: string diff --git a/swagger/swagger-generator/generator-core/src/test/resources/swagger2.yaml b/swagger/swagger-generator/generator-core/src/test/resources/swagger2.yaml index 5f2f23f66b4..628b6582558 100644 --- a/swagger/swagger-generator/generator-core/src/test/resources/swagger2.yaml +++ b/swagger/swagger-generator/generator-core/src/test/resources/swagger2.yaml @@ -34,7 +34,7 @@ paths: schema: type: string responses: - 200: + "200": description: say hello schema: - type: string \ No newline at end of file + type: string diff --git a/swagger/swagger-generator/generator-jaxrs/pom.xml b/swagger/swagger-generator/generator-jaxrs/pom.xml index db3c9588e2e..1a82b059f8a 100644 --- a/swagger/swagger-generator/generator-jaxrs/pom.xml +++ b/swagger/swagger-generator/generator-jaxrs/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger-generator - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-generator-jaxrs Java Chassis::Swagger::Generator::Jaxrs @@ -32,13 +32,13 @@ swagger-generator-core - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsOperationGenerator.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsOperationGenerator.java new file mode 100644 index 00000000000..829b64a4478 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsOperationGenerator.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.apache.servicecomb.swagger.generator.rest.RestOperationGenerator; + +import jakarta.ws.rs.BeanParam; + +public class JaxrsOperationGenerator extends RestOperationGenerator { + public JaxrsOperationGenerator(AbstractSwaggerGenerator swaggerGenerator, Method method) { + super(swaggerGenerator, method); + } + + @Override + protected void initMethodParameterGenerators(Map> methodAnnotationMap) { + super.initMethodParameterGenerators(methodAnnotationMap); + + parameterGenerators.stream() + .filter(pg -> pg.getHttpParameterType() == null) + .forEach(pg -> pg.setHttpParameterType(HttpParameterType.BODY)); + } + + @Override + protected boolean isAggregatedParameter(ParameterGenerator parameterGenerator, Parameter methodParameter) { + return methodParameter.getAnnotation(BeanParam.class) != null; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGenerator.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGenerator.java new file mode 100644 index 00000000000..6646941d3c8 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGenerator.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import jakarta.ws.rs.HttpMethod; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.rest.RestSwaggerGenerator; + +public class JaxrsSwaggerGenerator extends RestSwaggerGenerator { + public JaxrsSwaggerGenerator(Class cls) { + super(cls); + } + + @Override + protected boolean isSkipMethod(Method method) { + if (super.isSkipMethod(method)) { + return true; + } + + for (Annotation annotation : method.getAnnotations()) { + HttpMethod httpMethod = annotation.annotationType().getAnnotation(HttpMethod.class); + if (httpMethod != null) { + return false; + } + } + + return true; + } + + @SuppressWarnings("unchecked") + @Override + public T createOperationGenerator(Method method) { + return (T) new JaxrsOperationGenerator(this, method); + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorContext.java deleted file mode 100644 index 7acabe0c3ba..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorContext.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; - -import javax.ws.rs.BeanParam; -import javax.ws.rs.Consumes; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.BeanParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ConsumesAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.CookieParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.FormParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.HeaderParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.HttpMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ProducesAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.QueryParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.parameter.JaxrsDefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.rest.RestSwaggerGeneratorContext; - -public class JaxrsSwaggerGeneratorContext extends RestSwaggerGeneratorContext { - private static final int ORDER = 2000; - - @Override - public int getOrder() { - return ORDER; - } - - @Override - public boolean canProcess(Class cls) { - return ClassUtils.hasAnnotation(cls, Path.class); - } - - @Override - public boolean canProcess(Method method) { - for (Annotation annotation : method.getAnnotations()) { - HttpMethod httpMethod = annotation.annotationType().getAnnotation(HttpMethod.class); - if (httpMethod != null) { - return true; - } - } - - return false; - } - - @Override - protected void initDefaultParameterProcessor() { - defaultParameterProcessor = new JaxrsDefaultParameterProcessor(); - } - - @Override - protected void initClassAnnotationMgr() { - super.initClassAnnotationMgr(); - - classAnnotationMgr.register(Path.class, new PathClassAnnotationProcessor()); - } - - @Override - protected void initMethodAnnotationMgr() { - super.initMethodAnnotationMgr(); - - methodAnnotationMgr.register(Path.class, new PathMethodAnnotationProcessor()); - methodAnnotationMgr.register(Produces.class, new ProducesAnnotationProcessor()); - methodAnnotationMgr.register(Consumes.class, new ConsumesAnnotationProcessor()); - - HttpMethodAnnotationProcessor httpMethodProcessor = new HttpMethodAnnotationProcessor(); - methodAnnotationMgr.register(GET.class, httpMethodProcessor); - methodAnnotationMgr.register(POST.class, httpMethodProcessor); - methodAnnotationMgr.register(PUT.class, httpMethodProcessor); - methodAnnotationMgr.register(DELETE.class, httpMethodProcessor); - } - - @Override - protected void initParameterAnnotationMgr() { - super.initParameterAnnotationMgr(); - - parameterAnnotationMgr.register(PathParam.class, new PathParamAnnotationProcessor()); - parameterAnnotationMgr.register(FormParam.class, new FormParamAnnotationProcessor()); - parameterAnnotationMgr.register(CookieParam.class, new CookieParamAnnotationProcessor()); - - parameterAnnotationMgr.register(HeaderParam.class, new HeaderParamAnnotationProcessor()); - parameterAnnotationMgr.register(QueryParam.class, new QueryParamAnnotationProcessor()); - parameterAnnotationMgr.register(BeanParam.class, new BeanParamAnnotationProcessor()); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorFactory.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorFactory.java new file mode 100644 index 00000000000..8c60a85671c --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/JaxrsSwaggerGeneratorFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs; + +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory; + +public class JaxrsSwaggerGeneratorFactory implements SwaggerGeneratorFactory { + private static final int ORDER = 2000; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canProcess(Class cls) { + return SwaggerUtils.hasAnnotation(cls, Path.class); + } + + @Override + public SwaggerGenerator create(Class cls) { + return new JaxrsSwaggerGenerator(cls); + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessor.java deleted file mode 100644 index 0d7f32d5fa6..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessor.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import javax.ws.rs.CookieParam; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ParameterAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.Parameter; - -/** - * For {@link javax.ws.rs.BeanParam} - */ -public class BeanParamAnnotationProcessor implements ParameterAnnotationProcessor { - public static final Set> SUPPORTED_PARAM_ANNOTATIONS = new HashSet<>(); - - public static final String SETTER_METHOD_PREFIX = "set"; - - static { - SUPPORTED_PARAM_ANNOTATIONS.add(PathParam.class); - SUPPORTED_PARAM_ANNOTATIONS.add(QueryParam.class); - SUPPORTED_PARAM_ANNOTATIONS.add(HeaderParam.class); - SUPPORTED_PARAM_ANNOTATIONS.add(CookieParam.class); - SUPPORTED_PARAM_ANNOTATIONS.add(FormParam.class); - } - - @Override - public void process(Object annotation, OperationGenerator operationGenerator, int paramIdx) { - final Class beanParamClazz = operationGenerator.getProviderMethod().getParameterTypes()[paramIdx]; - Map swaggerParamMap = new HashMap<>(); - try { - // traversal fields, get those JAX-RS params - traversalParamField(operationGenerator, beanParamClazz, swaggerParamMap); - } catch (IllegalArgumentException | IntrospectionException e) { - throw new Error(String.format( - "Processing param failed, method=%s:%s, beanParamIdx=%d", - operationGenerator.getProviderMethod().getDeclaringClass().getName(), - operationGenerator.getProviderMethod().getName(), - paramIdx) - , e); - } - - // set swagger params into operationGenerator, in declared field order - Field[] declaredProducerFields = beanParamClazz.getDeclaredFields(); - Arrays.stream(declaredProducerFields) - .map(declaredProducerField -> swaggerParamMap.get(declaredProducerField.getName())) - .filter(Objects::nonNull) - .forEach(operationGenerator::addProviderParameter); - } - - /** - * Traversal fields of {@code beanParamClazz}, - * generate swagger params according to JAX-RS param annotations and set them into {@code swaggerParamMap}. - * - * @param swaggerParamMap the map contains the generated swagger param, - * key is the name defined by source code(the declared field name) and value is the swagger param - */ - private void traversalParamField(OperationGenerator operationGenerator, Class beanParamClazz, - Map swaggerParamMap) throws IntrospectionException { - for (Field beanParamField : beanParamClazz.getDeclaredFields()) { - // ignore synthetic member to avoid build failure - // see https://github.com/jacoco/jacoco/issues/168 - if (fieldShouldIgnore(beanParamField) || beanParamField.isSynthetic()) { - continue; - } - // try to process this field directly - Parameter swaggerParam = generateSwaggerParam(operationGenerator, beanParamField.getAnnotations(), - beanParamField.getGenericType()); - if (null == swaggerParam) { - // if swaggerParam is null, maybe the JAX-RS param annotation is tagged onto the write method - swaggerParam = processFieldSetter(operationGenerator, beanParamClazz, beanParamField); - } - - if (null == swaggerParam) { - throw new IllegalArgumentException(String.format( - "There is a field[%s] cannot be mapped to swagger param. Maybe you should tag @JsonIgnore on it.", - beanParamField.getName()) - ); - } - swaggerParamMap.put(beanParamField.getName(), swaggerParam); - } - } - - /** - * Sometimes user may tag JAX-RS param annotations on setter method instead of fields. - * - * @param beanParamClazz class of the BeanParam - * @param beanParamField the field of BeanParam whose setter method is processed - * @return the generated swagger param, or null if the setter method is not tagged by JAX-RS param annotations - * @throws IntrospectionException see {@linkplain PropertyDescriptor#PropertyDescriptor(String, Class)} - */ - private Parameter processFieldSetter(OperationGenerator operationGenerator, Class beanParamClazz, - Field beanParamField) throws IntrospectionException { - Parameter swaggerParam = null; - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(beanParamField.getName(), beanParamClazz); - Method writeMethod = propertyDescriptor.getWriteMethod(); - if (null != writeMethod) { - swaggerParam = generateSwaggerParam(operationGenerator, writeMethod.getAnnotations(), - beanParamField.getGenericType()); - } - return swaggerParam; - } - - /** - * Generate a swagger parameter according to {@code annotations} and {@code genericType}. - * - * @param operationGenerator operationGenerator - * @param annotations annotations on fields or setter methods - * @param genericType type of the fields, or the param type of the setter methods - * @return a swagger param, or null if there is no JAX-RS annotation in {@code annotations} - */ - private Parameter generateSwaggerParam( - OperationGenerator operationGenerator, - Annotation[] annotations, - Type genericType) { - String defaultValue = null; - for (Annotation fieldAnnotation : annotations) { - if (!SUPPORTED_PARAM_ANNOTATIONS.contains(fieldAnnotation.annotationType())) { - if (fieldAnnotation instanceof DefaultValue) { - defaultValue = ((DefaultValue) fieldAnnotation).value(); - } - continue; - } - - return setUpParameter(operationGenerator, fieldAnnotation, genericType, defaultValue); - } - return null; - } - - /** - * Generate swagger parameter, set default value, and return it. - * - * @param operationGenerator operationGenerator - * @param fieldAnnotation JAX-RS param annotation - * @param genericParamType type of the parameter - * @param defaultValue default value, can be null - * @return the generated swagger Parameter - */ - private Parameter setUpParameter( - OperationGenerator operationGenerator, - Annotation fieldAnnotation, - Type genericParamType, - String defaultValue) { - AbstractSerializableParameter parameter = createParameter( - operationGenerator.getContext(), - fieldAnnotation, - genericParamType); - - if (null != defaultValue) { - parameter.setDefaultValue(defaultValue); - } - return parameter; - } - - /** - * Generate a swagger parameter, set up name and type info. - * - * @param swaggerGeneratorContext context data carried by {@linkplain OperationGenerator} - * @param fieldAnnotation JAX-RS param annotation - * @param genericParamType default value, can be null - * @return the generated swagger parameter - */ - private AbstractSerializableParameter createParameter( - SwaggerGeneratorContext swaggerGeneratorContext, - Annotation fieldAnnotation, - Type genericParamType) { - // find the corresponding ParameterProcessor and process the parameter - final AbstractParameterProcessor parameterAnnotationProcessor = - (AbstractParameterProcessor) swaggerGeneratorContext - .findParameterAnnotationProcessor(fieldAnnotation.annotationType()); - AbstractSerializableParameter parameter = parameterAnnotationProcessor.createParameter(); - String paramName = parameterAnnotationProcessor.getAnnotationParameterName(fieldAnnotation); - parameter.setName(paramName); - ParamUtils.setParameterType(genericParamType, parameter); - return parameter; - } - - /** - * Those fields tagged by @JsonIgnore should be ignored. - */ - private boolean fieldShouldIgnore(Field beanParamField) { - for (Annotation annotation : beanParamField.getAnnotations()) { - if (annotation instanceof JsonIgnore) { - return true; - } - } - return false; - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessor.java deleted file mode 100644 index ec2f87c82c7..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import javax.ws.rs.Consumes; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.springframework.util.StringUtils; - -public class ConsumesAnnotationProcessor implements MethodAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - Consumes consumes = (Consumes) annotation; - - List consumeList = Arrays.stream(consumes.value()).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!consumeList.isEmpty()) { - operationGenerator.getOperation().setConsumes(consumeList); - } - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesClassAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesClassAnnotationProcessor.java new file mode 100644 index 00000000000..72ae4d20fc4 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesClassAnnotationProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import jakarta.ws.rs.Consumes; + +public class ConsumesClassAnnotationProcessor extends JaxrsClassAnnotationProcessor { + @Override + public Type getProcessType() { + return Consumes.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, Consumes consumes) { + if (consumes.value() != null && consumes.value().length > 0) { + swaggerGenerator.getSwaggerGeneratorContext().updateConsumes(Arrays.asList(consumes.value())); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesMethodAnnotationProcessor.java new file mode 100644 index 00000000000..2cfdb26dcda --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesMethodAnnotationProcessor.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import jakarta.ws.rs.Consumes; + +public class ConsumesMethodAnnotationProcessor extends JaxrsMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return Consumes.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Consumes consumes) { + if (consumes.value() != null && consumes.value().length > 0) { + operationGenerator.getOperationGeneratorContext().updateConsumes(Arrays.asList(consumes.value())); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamAnnotationProcessor.java deleted file mode 100644 index 41fc842d1a3..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamAnnotationProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import javax.ws.rs.CookieParam; - -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; - -import io.swagger.models.parameters.CookieParameter; - -public class CookieParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public String getAnnotationParameterName(Object annotation) { - return ((CookieParam) annotation).value(); - } - - @Override - public CookieParameter createParameter() { - return new CookieParameter(); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamParameterAnnotationProcessor.java new file mode 100644 index 00000000000..e1987510970 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/CookieParamParameterAnnotationProcessor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.CookieParam; + +public class CookieParamParameterAnnotationProcessor extends + JaxrsParameterAnnotationProcessor { + @Override + public Type getProcessType() { + return CookieParam.class; + } + + @Override + public String getParameterName(CookieParam annotation) { + if (StringUtils.isEmpty(annotation.value())) { + return null; + } + return annotation.value(); + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, CookieParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.COOKIE); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/DeleteMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/DeleteMethodAnnotationProcessor.java new file mode 100644 index 00000000000..41df1001556 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/DeleteMethodAnnotationProcessor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import jakarta.ws.rs.DELETE; + +public class DeleteMethodAnnotationProcessor extends GetMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return DELETE.class; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamAnnotationProcessor.java deleted file mode 100644 index c1abaf47744..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamAnnotationProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import javax.ws.rs.FormParam; - -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; - -import io.swagger.models.parameters.FormParameter; - -public class FormParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public String getAnnotationParameterName(Object annotation) { - return ((FormParam) annotation).value(); - } - - @Override - public FormParameter createParameter() { - return new FormParameter(); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamParameterAnnotationProcessor.java new file mode 100644 index 00000000000..42f5bab47c5 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/FormParamParameterAnnotationProcessor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.FormParam; + +public class FormParamParameterAnnotationProcessor extends JaxrsParameterAnnotationProcessor { + @Override + public Type getProcessType() { + return FormParam.class; + } + + @Override + public String getParameterName(FormParam annotation) { + if (StringUtils.isNotEmpty(annotation.value())) { + return annotation.value(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, FormParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.FORM); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/GetMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/GetMethodAnnotationProcessor.java new file mode 100644 index 00000000000..e8051063a28 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/GetMethodAnnotationProcessor.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HttpMethod; + +public class GetMethodAnnotationProcessor extends JaxrsMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return GET.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Annotation annotation) { + HttpMethod httpMethod = annotation.annotationType().getAnnotation(HttpMethod.class); + + operationGenerator.setHttpMethod(httpMethod.value()); + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamAnnotationProcessor.java deleted file mode 100644 index de2c7901fc2..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamAnnotationProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import javax.ws.rs.HeaderParam; - -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; - -import io.swagger.models.parameters.HeaderParameter; - -public class HeaderParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public HeaderParameter createParameter() { - return new HeaderParameter(); - } - - @Override - public String getAnnotationParameterName(Object annotation) { - return ((HeaderParam) annotation).value(); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamParameterAnnotationProcessor.java new file mode 100644 index 00000000000..41e3b68c82c --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HeaderParamParameterAnnotationProcessor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.HeaderParam; + +public class HeaderParamParameterAnnotationProcessor extends + JaxrsParameterAnnotationProcessor { + @Override + public Type getProcessType() { + return HeaderParam.class; + } + + @Override + public String getParameterName(HeaderParam annotation) { + if (StringUtils.isNotEmpty(annotation.value())) { + return annotation.value(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, HeaderParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.HEADER); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HttpMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HttpMethodAnnotationProcessor.java deleted file mode 100644 index 452c5425bbb..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/HttpMethodAnnotationProcessor.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.lang.annotation.Annotation; - -import javax.ws.rs.HttpMethod; - -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -public class HttpMethodAnnotationProcessor implements MethodAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - Annotation httpMethodAnnotation = (Annotation) annotation; - HttpMethod httpMethod = httpMethodAnnotation.annotationType().getAnnotation(HttpMethod.class); - - operationGenerator.setHttpMethod(httpMethod.value()); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsClassAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsClassAnnotationProcessor.java new file mode 100644 index 00000000000..f1f1eb48bbb --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsClassAnnotationProcessor.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; + +/** + * A generic class to help classify implementations. + */ +public abstract class JaxrsClassAnnotationProcessor + implements ClassAnnotationProcessor { +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsMethodAnnotationProcessor.java new file mode 100644 index 00000000000..cb8bd64e1ed --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsMethodAnnotationProcessor.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; + +/** + * A generic class to help classify implementations. + */ +public abstract class JaxrsMethodAnnotationProcessor + implements MethodAnnotationProcessor { +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsParameterAnnotationProcessor.java new file mode 100644 index 00000000000..126f48b31d5 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/JaxrsParameterAnnotationProcessor.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor; + +/** + * A generic class to help classify implementations. + */ +public abstract class JaxrsParameterAnnotationProcessor implements + ParameterAnnotationProcessor { +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PatchMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PatchMethodAnnotationProcessor.java new file mode 100644 index 00000000000..807abd6574d --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PatchMethodAnnotationProcessor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import jakarta.ws.rs.PATCH; + +public class PatchMethodAnnotationProcessor extends GetMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return PATCH.class; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathClassAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathClassAnnotationProcessor.java index 57bc1e9357f..376ef712832 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathClassAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathClassAnnotationProcessor.java @@ -17,17 +17,20 @@ package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; -import javax.ws.rs.Path; +import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; -public class PathClassAnnotationProcessor implements ClassAnnotationProcessor { +import jakarta.ws.rs.Path; +public class PathClassAnnotationProcessor extends JaxrsClassAnnotationProcessor { @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - Path path = (Path) annotation; + public Type getProcessType() { + return Path.class; + } + @Override + public void process(SwaggerGenerator swaggerGenerator, Path path) { swaggerGenerator.setBasePath(path.value()); } } diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathMethodAnnotationProcessor.java index b89d4a208e3..2eb1fd39e2b 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathMethodAnnotationProcessor.java @@ -17,16 +17,21 @@ package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; -import javax.ws.rs.Path; +import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; -public class PathMethodAnnotationProcessor implements MethodAnnotationProcessor { +import jakarta.ws.rs.Path; + +public class PathMethodAnnotationProcessor extends JaxrsMethodAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - Path path = (Path) annotation; + public Type getProcessType() { + return Path.class; + } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Path path) { operationGenerator.setPath(path.value()); } } diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamAnnotationProcessor.java deleted file mode 100644 index 9a88543d06b..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamAnnotationProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import javax.ws.rs.PathParam; - -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; - -import io.swagger.models.parameters.PathParameter; - -public class PathParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public PathParameter createParameter() { - return new PathParameter(); - } - - @Override - public String getAnnotationParameterName(Object annotation) { - return ((PathParam) annotation).value(); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamParameterAnnotationProcessor.java new file mode 100644 index 00000000000..9102ee32190 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PathParamParameterAnnotationProcessor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.PathParam; + +public class PathParamParameterAnnotationProcessor extends JaxrsParameterAnnotationProcessor { + @Override + public Type getProcessType() { + return PathParam.class; + } + + @Override + public String getParameterName(PathParam annotation) { + if (StringUtils.isNotEmpty(annotation.value())) { + return annotation.value(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, PathParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.PATH); + parameterGenerator.getParameterGeneratorContext().setRequired(true); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PostMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PostMethodAnnotationProcessor.java new file mode 100644 index 00000000000..e70d2727548 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PostMethodAnnotationProcessor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import jakarta.ws.rs.POST; + +public class PostMethodAnnotationProcessor extends GetMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return POST.class; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessor.java deleted file mode 100644 index 5786c3da34e..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import javax.ws.rs.Produces; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; - -public class ProducesAnnotationProcessor implements MethodAnnotationProcessor { - @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - Produces produces = (Produces) annotation; - - List produceList = Arrays.stream(produces.value()).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!produceList.isEmpty()) { - operationGenerator.getOperation().setProduces(produceList); - } - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesClassAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesClassAnnotationProcessor.java new file mode 100644 index 00000000000..9450504ce2f --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesClassAnnotationProcessor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import jakarta.ws.rs.Produces; + +public class ProducesClassAnnotationProcessor extends JaxrsClassAnnotationProcessor { + @Override + public Type getProcessType() { + return Produces.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, Produces produces) { + if (produces.value() != null && produces.value().length > 0) { + swaggerGenerator.getSwaggerGeneratorContext().updateProduces(Arrays.asList(produces.value())); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesMethodAnnotationProcessor.java new file mode 100644 index 00000000000..a148413efd2 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesMethodAnnotationProcessor.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; + +import jakarta.ws.rs.Produces; + +public class ProducesMethodAnnotationProcessor extends JaxrsMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return Produces.class; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, Produces produces) { + if (produces.value() != null && produces.value().length > 0) { + operationGenerator.getOperationGeneratorContext().updateProduces(Arrays.asList(produces.value())); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PutMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PutMethodAnnotationProcessor.java new file mode 100644 index 00000000000..9756b05feb1 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/PutMethodAnnotationProcessor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import jakarta.ws.rs.PUT; + +public class PutMethodAnnotationProcessor extends GetMethodAnnotationProcessor { + @Override + public Type getProcessType() { + return PUT.class; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamAnnotationProcessor.java deleted file mode 100644 index 98e0aa7be3a..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamAnnotationProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; - -import io.swagger.models.parameters.QueryParameter; - -public class QueryParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public QueryParameter createParameter() { - return new QueryParameter(); - } - - @Override - public String getAnnotationParameterName(Object annotation) { - return ((QueryParam) annotation).value(); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamParameterAnnotationProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamParameterAnnotationProcessor.java new file mode 100644 index 00000000000..9f5cb7fc3b6 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/QueryParamParameterAnnotationProcessor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; + +import jakarta.ws.rs.QueryParam; + +public class QueryParamParameterAnnotationProcessor extends JaxrsParameterAnnotationProcessor { + @Override + public Type getProcessType() { + return QueryParam.class; + } + + @Override + public String getParameterName(QueryParam annotation) { + if (StringUtils.isNotEmpty(annotation.value())) { + return annotation.value(); + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, QueryParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.QUERY); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/parameter/JaxrsDefaultParameterProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/parameter/JaxrsDefaultParameterProcessor.java deleted file mode 100644 index 39b3b4d458a..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/parameter/JaxrsDefaultParameterProcessor.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.parameter; - -import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.models.parameters.BodyParameter; - -public class JaxrsDefaultParameterProcessor implements DefaultParameterProcessor { - - @Override - public void process(OperationGenerator operationGenerator, int paramIndex) { - BodyParameter bodyParameter = ParamUtils.createBodyParameter(operationGenerator, paramIndex); - operationGenerator.addProviderParameter(bodyParameter); - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/response/JaxrsResponseProcessor.java b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/response/JaxrsResponseProcessor.java index cd9d9923c35..57b1381bd70 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/response/JaxrsResponseProcessor.java +++ b/swagger/swagger-generator/generator-jaxrs/src/main/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/response/JaxrsResponseProcessor.java @@ -17,40 +17,41 @@ package org.apache.servicecomb.swagger.generator.jaxrs.processor.response; import java.lang.reflect.Type; -import java.util.List; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.processor.response.DefaultResponseTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.Property; - -public class JaxrsResponseProcessor implements ResponseTypeProcessor { +public class JaxrsResponseProcessor extends DefaultResponseTypeProcessor { @Override - public Class getResponseType() { + public Class getProcessType() { return Response.class; } @Override - public Property process(OperationGenerator operationGenerator) { - // Response完全表达应答类型 - // 如果produces是text,那么可以假设是string,否则只能报错 - List produces = operationGenerator.getOperation().getProduces(); - if (produces == null) { - produces = operationGenerator.getSwagger().getProduces(); - } - if (produces != null) { - if (produces.contains(MediaType.TEXT_PLAIN)) { - Type responseType = String.class; - ParamUtils.addDefinitions(operationGenerator.getSwagger(), responseType); - return ModelConverters.getInstance().readAsProperty(responseType); + public Type extractResponseType(Type genericResponseType) { + return null; + } + + @Override + public Type extractResponseType(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType) { + ApiResponses responses = operationGenerator.getOperation().getResponses(); + if (responses != null) { + ApiResponse response = responses.get(SwaggerConst.SUCCESS_KEY); + if (response != null && response.getContent() != null) { + if (response.getContent().get(MediaType.TEXT_PLAIN) != null) { + return String.class; + } } } - throw new Error("Use ApiOperation or ApiResponses to declare response type"); + throw new IllegalStateException("Use ApiOperation or ApiResponses to declare response type"); } } diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor new file mode 100644 index 00000000000..bb469664ebd --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathClassAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ConsumesClassAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ProducesClassAnnotationProcessor diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor new file mode 100644 index 00000000000..647fe860ace --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ConsumesMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ProducesMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.GetMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PostMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PutMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.DeleteMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PatchMethodAnnotationProcessor diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor new file mode 100644 index 00000000000..e20efd576e7 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.PathParamParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.QueryParamParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.HeaderParamParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.CookieParamParameterAnnotationProcessor +org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.FormParamParameterAnnotationProcessor diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor new file mode 100644 index 00000000000..137ee9359bc --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.jaxrs.processor.response.JaxrsResponseProcessor diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory new file mode 100644 index 00000000000..c96c1805872 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorFactory diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor deleted file mode 100644 index 254f2dcf096..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.jaxrs.processor.response.JaxrsResponseProcessor \ No newline at end of file diff --git a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext b/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext deleted file mode 100644 index 7ffce9a050e..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorContext diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassAnnotation.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassAnnotation.java new file mode 100644 index 00000000000..60e1db6880a --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassAnnotation.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs; + +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/class") +@Consumes(value = {MediaType.APPLICATION_JSON}) +@Produces(value = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +@SuppressWarnings("unused") +public class ClassAnnotation { + @Path(value = "testBean") + @POST + public User testBean(User user) { + return null; + } + + @Path(value = "testString") + @POST + public String testString(String user) { + return null; + } + + // This case should cause error. Must implicitly specify consumes. + // For JAX RS, @FormParam can be url-encoded-form or multipart. + @Path(value = "testFormWrong") + @POST + public String testFormWrong(@FormParam("param") int param) { + return null; + } + + // This case should cause error. Must implicitly specify consumes + // For JAX RS, @FormParam can be url-encoded-form or multipart. + @Path(value = "testUploadWrong") + @POST + public String testUploadWrong(@FormParam("part") Part part) { + return null; + } + + @Path(value = "testForm") + @POST + @Consumes(value = MediaType.APPLICATION_FORM_URLENCODED) + public String testForm(@FormParam("param") int param) { + return null; + } + + @Path(value = "testUpload") + @POST + @Consumes(value = MediaType.MULTIPART_FORM_DATA) + public String testUpload(@FormParam("part") Part part) { + return null; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassMethodNoPath.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassMethodNoPath.java index c8071550967..fc4d2358124 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassMethodNoPath.java +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/ClassMethodNoPath.java @@ -16,8 +16,8 @@ */ package org.apache.servicecomb.swagger.generator.jaxrs; -import javax.ws.rs.GET; -import javax.ws.rs.Path; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; @Path("") public class ClassMethodNoPath { diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/Echo.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/Echo.java index 6f33e6c6eed..68820b8c6b9 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/Echo.java +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/Echo.java @@ -19,49 +19,62 @@ import java.util.List; -import javax.ws.rs.Consumes; -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; - import org.apache.servicecomb.foundation.test.scaffolding.model.Color; import org.apache.servicecomb.foundation.test.scaffolding.model.User; import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; - -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; +import org.apache.servicecomb.swagger.generator.jaxrs.model.AggregatedParam; +import org.apache.servicecomb.swagger.generator.jaxrs.model.BeanParamComplexField; +import org.apache.servicecomb.swagger.generator.jaxrs.model.BeanParamComplexSetter; +import org.apache.servicecomb.swagger.generator.jaxrs.model.BeanParamDefaultBody; +import org.apache.servicecomb.swagger.generator.jaxrs.model.BeanParamWithJsonIgnoredTagged; +import org.apache.servicecomb.swagger.generator.jaxrs.model.BeanParamWithPart; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.DynamicStatus; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.DynamicStatusBeanParam; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.DynamicStatusModel; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatus; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatusBeanParam; +import org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatusModel; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; @Path(value = "Echo") public class Echo { - @POST - @ApiResponse(response = int.class, code = 200, message = "") - public Response response() { - return null; + @PATCH + public void patch() { + } - @GET - public Response invalidResponse() { + @POST + @ApiResponse(content = { + @Content(schema = @Schema(implementation = Integer.class))}, responseCode = "200", description = "") + @Path("response") + public Response response() { return null; } @POST - @Produces("") - @Consumes("") - @ApiOperation(value = "") + @Operation(summary = "") + @Path("emptyPath") public void emptyPath() { } @Path(value = "echo/{targetName}") - @Consumes(value = {"json", "xml"}) - @Produces(value = {"json", "xml"}) @POST public String echo(User srcUser, @HeaderParam(value = "header") String header, @PathParam(value = "targetName") String targetName, @@ -87,13 +100,13 @@ public String query(@QueryParam(value = "query") String query) { return String.format("%s", query); } - @Path(value = "query") + @Path(value = "queryComplex") @GET - public String queryComplex(@QueryParam(value = "querys") List querys) { - return String.format("%s", querys); + public String queryComplex(@QueryParam(value = "queries") List queries) { + return String.format("%s", queries); } - @ApiOperation(value = "") + @Operation(summary = "") public void ignoredNonRestful() { } @@ -107,4 +120,62 @@ public void rawJsonStringMethod(@RawJsonRequestBody String jsonInput) { @POST public void enumBody(Color color) { } + + @Path("aggregatedParam") + @POST + public void aggregatedParam(@BeanParam AggregatedParam aggregatedParam) { + + } + + @Path("beanParamWithPart") + @POST + public void beanParamWithPart(@BeanParam BeanParamWithPart beanParamWithPart) { + + } + + @Path("beanParamComplexField") + @POST + public void beanParamComplexField(@BeanParam BeanParamComplexField beanParamComplexField) { + + } + + @Path("beanParamComplexSetter") + @POST + public void beanParamComplexSetter(@BeanParam BeanParamComplexSetter beanParamComplexSetter) { + + } + + @Path("beanParamDefaultBody") + @POST + public void beanParamDefaultBody(@BeanParam BeanParamDefaultBody beanParamDefaultBody) { + + } + + @Path("beanParamWithJsonIgnoredTaggedBody") + @POST + public void beanParamWithJsonIgnoredTagged(@BeanParam BeanParamWithJsonIgnoredTagged beanParamWithJsonIgnoredTagged) { + + } + + @Path("nestedListString") + @POST + public List> nestedListString(List> param) { + return param; + } + + @Path("/dynamicStatusEnum") + @POST + public DynamicStatus dynamicStatusEnum(@BeanParam DynamicStatusBeanParam statusBeanParam, + @QueryParam("status") @Parameter(description = "dynamic desc direct") DynamicStatus status, + DynamicStatusModel model) { + return null; + } + + @Path("/jdkStatusEnum") + @POST + public JdkStatus jdkStatusEnum(@BeanParam JdkStatusBeanParam statusBeanParam, + @QueryParam("status") @Parameter(description = "jdk desc direct") JdkStatus status, + JdkStatusModel model) { + return null; + } } diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/FullSwaggerService.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/FullSwaggerService.java new file mode 100644 index 00000000000..d8cb38fa481 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/FullSwaggerService.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.Explode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.ParameterStyle; +import jakarta.servlet.http.Part; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; + +@Path(value = "/FullSwaggerService") +public class FullSwaggerService { + @Path("/fileUpload") + @POST + @Produces(MediaType.TEXT_PLAIN) + public String fileUpload(@FormParam("file1") Part file1, @FormParam("file2") Part file2) throws IOException { + return null; + } + + @Path("/queryListMULTI") + @GET + public String queryListMULTI( + @Parameter(name = "queryList", in = ParameterIn.QUERY, style = ParameterStyle.FORM, explode = Explode.TRUE) + @QueryParam("queryList") List queryList) { + return queryList == null ? "null" : queryList.size() + ":" + queryList; + } + + @Path("/defaultValue") + @GET + public String defaultValue(@QueryParam("e") int e, @DefaultValue("20") @QueryParam("a") int a, + @DefaultValue("bobo") @QueryParam("b") String b, + @DefaultValue("40") @QueryParam("c") Integer c, @Min(value = 20) @Max(value = 30) @QueryParam("d") int d) { + return "Hello " + a + b + c + d + e; + } + + @Path("/textPlain") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String textPlain() { + return null; + } + + @Path("/fileDownload") + @GET + public File fileDownload() { + return null; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/MultiDefaultPath.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/MultiDefaultPath.java index f8e743f9f59..ab18732e479 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/MultiDefaultPath.java +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/MultiDefaultPath.java @@ -16,8 +16,8 @@ */ package org.apache.servicecomb.swagger.generator.jaxrs; -import javax.ws.rs.GET; -import javax.ws.rs.Path; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; @Path("/abc") public class MultiDefaultPath { diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestClassAnnotation.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestClassAnnotation.java new file mode 100644 index 00000000000..b17d04f7077 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestClassAnnotation.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs; + +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.junit.jupiter.api.Test; + +public class TestClassAnnotation { + @Test + public void test_generate_swagger_correct() { + UnitTestSwaggerUtils.testSwagger("schemas/ClassAnnotation.yaml", ClassAnnotation.class, + "testBean", "testString", "testForm", "testUpload"); + } + + @Test + public void test_form_wrong() { + UnitTestSwaggerUtils.testException("Generate swagger operation failed, " + + "method=ClassAnnotation:testFormWrong, cause=Consumes not provided for FORM parameter, " + + "or is empty by annotations rule.", + ClassAnnotation.class, + "testFormWrong"); + } + + @Test + public void test_upload_wrong() { + UnitTestSwaggerUtils.testException("Generate swagger operation failed, " + + "method=ClassAnnotation:testUploadWrong, " + + "cause=Part type must declare consumes multipart/form-data", + ClassAnnotation.class, + "testUploadWrong"); + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestJaxrs.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestJaxrs.java index f2060a47080..0b31ba695c5 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestJaxrs.java +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/TestJaxrs.java @@ -17,115 +17,57 @@ package org.apache.servicecomb.swagger.generator.jaxrs; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.swagger.generator.jaxrs.model.ConsumesAndProduces; +import org.junit.jupiter.api.Test; public class TestJaxrs { - ClassLoader classLoader = new ClassLoader() { - }; - - SwaggerGeneratorContext context = new JaxrsSwaggerGeneratorContext(); - - @After - public void tearDown() { - JavassistUtils.clearByClassLoader(classLoader); - } - @Test public void testMultiDefaultPath() { UnitTestSwaggerUtils.testException( - "Only allowed one default path. org.apache.servicecomb.swagger.generator.jaxrs.MultiDefaultPath:p2", - context, + "Duplicate operation path detected. method=org.apache.servicecomb.swagger.generator.jaxrs.MultiDefaultPath:p2.", MultiDefaultPath.class); } - @Test - public void testResponse() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/response.yaml", context, Echo.class, "response"); - } - - @Test - public void testInvalidResponse() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.jaxrs.Echo:invalidResponse", - "Use ApiOperation or ApiResponses to declare response type", - context, - Echo.class, - "invalidResponse"); - } - @Test public void testEcho() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/echo.yaml", context, Echo.class, "echo"); - } - - @Test - public void testForm() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/form.yaml", context, Echo.class, "form"); + UnitTestSwaggerUtils.testSwagger("schemas/echo.yaml", Echo.class); } - @Test - public void testQuery() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/query.yaml", context, Echo.class, "query"); - } - - @Test - public void testQueryComplex() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.jaxrs.Echo:queryComplex", - "not allow complex type for query parameter, method=org.apache.servicecomb.swagger.generator.jaxrs.Echo:queryComplex, paramIdx=0, type=java.util.List", - context, - Echo.class, - "queryComplex"); - } - - @Test - public void testCookie() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/cookie.yaml", context, Echo.class, "cookie"); - } - - @Test - public void testEmptyPath() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/emptyPath.yaml", context, Echo.class, "emptyPath"); - } - - @Test - public void testNonRestful() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/emptyContract.yaml", context, Echo.class, "ignoredNonRestful"); - } @Test public void testClassMethodNoPath() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.jaxrs.ClassMethodNoPath:p1", - "Path must not both be empty in class and method", - context, + "Generate swagger operation failed, " + + "method=ClassMethodNoPath:p1, cause=Path must not both be empty in class and method", ClassMethodNoPath.class); } @Test - public void testComposite() { - CompositeSwaggerGeneratorContext composite = new CompositeSwaggerGeneratorContext(); - SwaggerGeneratorContext context = composite.selectContext(Echo.class); + public void testFullSwaggerService() { + UnitTestSwaggerUtils.testSwagger("schemas/FullSwaggerService.yaml", FullSwaggerService.class); + } - Assert.assertEquals(JaxrsSwaggerGeneratorContext.class, context.getClass()); + @Test + public void consumesAndProduces_exception_testSingleMediaType() { + UnitTestSwaggerUtils.testException("Generate swagger operation failed, " + + "method=ConsumesAndProduces:testSingleMediaType, " + + "cause=Not support media type application/xml", + ConsumesAndProduces.class, "testSingleMediaType"); } @Test - public void testRawJsonStringMethod() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/rawJsonStringMethod.yaml", context, Echo.class, "rawJsonStringMethod"); + public void consumesAndProduces_exception_testMultipleMediaType() { + UnitTestSwaggerUtils.testException("Generate swagger operation failed, " + + "method=ConsumesAndProduces:testMultipleMediaType, " + + "cause=Not support media type application/xml", + ConsumesAndProduces.class, "testMultipleMediaType"); } @Test - public void testEnumBody() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/enumBody.yaml", context, Echo.class, "enumBody"); + public void consumesAndProduces_exception_testBlankMediaType() { + UnitTestSwaggerUtils.testException("Generate swagger operation failed, " + + "method=ConsumesAndProduces:testBlankMediaType, cause=Not support media type ", + ConsumesAndProduces.class, "testBlankMediaType"); } } diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/AggregatedParam.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/AggregatedParam.java new file mode 100644 index 00000000000..f4a5b6312d4 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/AggregatedParam.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import java.util.List; + +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; + +public class AggregatedParam { + @DefaultValue("pa") + @PathParam("path0") + private String strVal; + + @QueryParam("query1") + private int intVal; + + private long longVal; + + private long cookieVal; + + @HeaderParam("header2") + private String headerVal; + + @QueryParam("query-array") + private String[] queryArray; + + @QueryParam("query-list") + private List queryList; + + public String getStrVal() { + return strVal; + } + + public void setStrVal(String strVal) { + this.strVal = strVal; + } + + public int getIntVal() { + return intVal; + } + + public void setIntVal(int intVal) { + this.intVal = intVal; + } + + public long getLongVal() { + return longVal; + } + + @DefaultValue("12") + @FormParam("form3") + public void setLongVal(long longVal) { + this.longVal = longVal; + } + + public long getCookieVal() { + return cookieVal; + } + + @CookieParam("cookie4") + public void setCookieVal(long cookieVal) { + this.cookieVal = cookieVal; + } + + public String getHeaderVal() { + return headerVal; + } + + public void setHeaderVal(String headerVal) { + this.headerVal = headerVal; + } + + public String[] getQueryArray() { + return queryArray; + } + + public AggregatedParam setQueryArray(String[] queryArray) { + this.queryArray = queryArray; + return this; + } + + public List getQueryList() { + return queryList; + } + + public AggregatedParam setQueryList(List queryList) { + this.queryList = queryList; + return this; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexField.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexField.java new file mode 100644 index 00000000000..db6eb377943 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexField.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import jakarta.ws.rs.QueryParam; + +public class BeanParamComplexField { + @QueryParam("q") + private AggregatedParam complex; + + public AggregatedParam getComplex() { + return complex; + } + + public void setComplex(AggregatedParam complex) { + this.complex = complex; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexSetter.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexSetter.java new file mode 100644 index 00000000000..c2c6b537a41 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamComplexSetter.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import jakarta.ws.rs.HeaderParam; + +public class BeanParamComplexSetter { + private AggregatedParam complex; + + public AggregatedParam getComplex() { + return complex; + } + + @HeaderParam("h") + public void setComplex(AggregatedParam complex) { + this.complex = complex; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamDefaultBody.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamDefaultBody.java new file mode 100644 index 00000000000..7f5eb465045 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamDefaultBody.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +public class BeanParamDefaultBody { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamInvalidDefaultBody.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamInvalidDefaultBody.java new file mode 100644 index 00000000000..5960b88d3ca --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamInvalidDefaultBody.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +public class BeanParamInvalidDefaultBody { + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithJsonIgnoredTagged.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithJsonIgnoredTagged.java new file mode 100644 index 00000000000..5acea6d419e --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithJsonIgnoredTagged.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import jakarta.ws.rs.QueryParam; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class BeanParamWithJsonIgnoredTagged { + @QueryParam("name") + private String name; + + @JsonIgnore + private AggregatedParam ignored; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public AggregatedParam getIgnored() { + return ignored; + } + + public void setIgnored( + AggregatedParam ignored) { + this.ignored = ignored; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithPart.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithPart.java new file mode 100644 index 00000000000..85305b1a61b --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/BeanParamWithPart.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import jakarta.servlet.http.Part; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.QueryParam; + +public class BeanParamWithPart { + @QueryParam("queryStr") + private boolean queryStr; + + @FormParam("up0") + private Part up0; + + private Part up1; + + public boolean isQueryStr() { + return queryStr; + } + + public void setQueryStr(boolean queryStr) { + this.queryStr = queryStr; + } + + public Part getUp0() { + return up0; + } + + public void setUp0(Part up0) { + this.up0 = up0; + } + + public Part getUp1() { + return up1; + } + + @FormParam("up1") + public void setUp1(Part up1) { + this.up1 = up1; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/ConsumesAndProduces.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/ConsumesAndProduces.java new file mode 100644 index 00000000000..b39ea589b5d --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/ConsumesAndProduces.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +public class ConsumesAndProduces { + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_XML) + public String testSingleMediaType(String input) { + return input; + } + + @Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) + @Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML}) + public String testMultipleMediaType(String input) { + return input; + } + + @Consumes("") + @Produces("") + public String testBlankMediaType(String input) { + return input; + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatus.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatus.java new file mode 100644 index 00000000000..b8323664f4f --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatus.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import org.apache.servicecomb.foundation.common.base.DynamicEnum; +import org.apache.servicecomb.foundation.common.base.DynamicEnumCache; + +import com.fasterxml.jackson.annotation.JsonCreator; + +import io.swagger.v3.oas.annotations.Parameter; + +public class DynamicStatus extends DynamicEnum { + @Parameter(description = "dynamic bad request") + public static final DynamicStatus BAD_REQUEST = new DynamicStatus(400); + + @Parameter(description = "dynamic not found") + public static final DynamicStatus NOT_FOUND = new DynamicStatus(404); + + private static final DynamicEnumCache CACHE = new DynamicEnumCache<>(DynamicStatus.class); + + public DynamicStatus(Integer value) { + super(value); + } + + @JsonCreator + public static DynamicStatus fromValue(int value) { + return CACHE.fromValue(value); + } +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusBeanParam.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusBeanParam.java new file mode 100644 index 00000000000..ecbcf2b217e --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusBeanParam.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import io.swagger.v3.oas.annotations.Parameter; +import jakarta.ws.rs.QueryParam; + +public class DynamicStatusBeanParam { + @Parameter(description = "dynamic desc aggr") + @QueryParam("status-aggr") + public DynamicStatus queryStatus; +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusModel.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusModel.java new file mode 100644 index 00000000000..83222c1ce06 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/DynamicStatusModel.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import io.swagger.v3.oas.annotations.Parameter; + +public class DynamicStatusModel { + @Parameter(description = "dynamic status model") + public DynamicStatus status; +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatus.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatus.java new file mode 100644 index 00000000000..c3a549cde39 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatus.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import io.swagger.v3.oas.annotations.Parameter; + +public enum JdkStatus { + @Parameter(description = "jdk bad request") + BAD_REQUEST, + + @Parameter(description = "jdk not found") + NOT_FOUND +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusBeanParam.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusBeanParam.java new file mode 100644 index 00000000000..6462040cbb6 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusBeanParam.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import io.swagger.v3.oas.annotations.Parameter; +import jakarta.ws.rs.QueryParam; + +public class JdkStatusBeanParam { + @Parameter(description = "jdk desc aggr") + @QueryParam("status-aggr") + public JdkStatus queryStatus; +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusModel.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusModel.java new file mode 100644 index 00000000000..013adea499d --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/model/enums/JdkStatusModel.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.jaxrs.model.enums; + +import io.swagger.v3.oas.annotations.Parameter; + +public class JdkStatusModel { + @Parameter(description = "jdk status model") + public JdkStatus status; +} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessorTest.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessorTest.java deleted file mode 100644 index bc221698105..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/BeanParamAnnotationProcessorTest.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.lang.reflect.Method; -import java.util.List; - -import javax.servlet.http.Part; -import javax.ws.rs.BeanParam; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorContext; -import org.junit.Test; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.Parameter; - -public class BeanParamAnnotationProcessorTest { - - @Test - public void processSuccess() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - final OperationGenerator operationGenerator = mockOperationGenerator("testBeanParam", AggregatedParam.class); - - processor.process(null, operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - assertEquals(5, providerParameters.size()); - AbstractSerializableParameter parameter; - parameter = (AbstractSerializableParameter) providerParameters.get(0); - assertEquals("path", parameter.getIn()); - assertEquals("path0", parameter.getName()); - assertEquals("pa", parameter.getDefault()); - assertEquals("string", parameter.getType()); - parameter = (AbstractSerializableParameter) providerParameters.get(1); - assertEquals("query", parameter.getIn()); - assertEquals("query1", parameter.getName()); - assertEquals("integer", parameter.getType()); - assertEquals("int32", parameter.getFormat()); - parameter = (AbstractSerializableParameter) providerParameters.get(2); - assertEquals("formData", parameter.getIn()); - assertEquals("form3", parameter.getName()); - assertEquals(12L, parameter.getDefault()); - assertEquals("integer", parameter.getType()); - assertEquals("int64", parameter.getFormat()); - parameter = (AbstractSerializableParameter) providerParameters.get(3); - assertEquals("cookie", parameter.getIn()); - assertEquals("cookie4", parameter.getName()); - assertEquals("integer", parameter.getType()); - assertEquals("int64", parameter.getFormat()); - parameter = (AbstractSerializableParameter) providerParameters.get(4); - assertEquals("header", parameter.getIn()); - assertEquals("header2", parameter.getName()); - assertEquals("string", parameter.getType()); - } - - @Test - public void processOnParamWithPart() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - final OperationGenerator operationGenerator = mockOperationGenerator("testBeanParamWithPart", - BeanParamWithPart.class); - - processor.process(null, operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - assertEquals(3, providerParameters.size()); - AbstractSerializableParameter parameter; - parameter = (AbstractSerializableParameter) providerParameters.get(0); - assertEquals("queryStr", parameter.getName()); - assertEquals("query", parameter.getIn()); - assertEquals("boolean", parameter.getType()); - parameter = (AbstractSerializableParameter) providerParameters.get(1); - assertEquals("up0", parameter.getName()); - assertEquals("formData", parameter.getIn()); - assertEquals("file", parameter.getType()); - parameter = (AbstractSerializableParameter) providerParameters.get(2); - assertEquals("up1", parameter.getName()); - assertEquals("formData", parameter.getIn()); - assertEquals("file", parameter.getType()); - } - - @Test - public void processOnComplexBeanParamField() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - final OperationGenerator operationGenerator = mockOperationGenerator("testBeanParamComplexField", - BeanParamComplexField.class); - - try { - processor.process(null, operationGenerator, 0); - fail("A error is expected!"); - } catch (Error e) { - assertEquals("Processing param failed, method=org.apache.servicecomb.swagger.generator.jaxrs.processor" - + ".annotation.BeanParamAnnotationProcessorTest$TestProvider:testBeanParamComplexField, beanParamIdx=0", - e.getMessage()); - assertEquals("not allow such type of param:[class io.swagger.models.properties.RefProperty], " - + "param name is [q]", - e.getCause().getMessage()); - } - } - - @Test - public void processOnComplexBeanParamSetter() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - final OperationGenerator operationGenerator = mockOperationGenerator("testBeanParamComplexSetter", - BeanParamComplexSetter.class); - - try { - processor.process(null, operationGenerator, 0); - fail("A error is expected!"); - } catch (Error e) { - assertEquals("Processing param failed, method=org.apache.servicecomb.swagger.generator.jaxrs.processor" - + ".annotation.BeanParamAnnotationProcessorTest$TestProvider:testBeanParamComplexSetter, beanParamIdx=0", - e.getMessage()); - assertEquals("not allow such type of param:[class io.swagger.models.properties.RefProperty], " - + "param name is [h]", - e.getCause().getMessage()); - } - } - - @Test - public void processOnParamFieldUntagged() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - OperationGenerator operationGenerator = mockOperationGenerator("testBeanParamWithUntaggedField", - BeanParamWithUntaggedField.class); - - try { - processor.process(null, operationGenerator, 0); - fail("A error is expected!"); - } catch (Error e) { - assertEquals("There is a field[name] cannot be mapped to swagger param. " - + "Maybe you should tag @JsonIgnore on it.", - e.getCause().getMessage()); - } - } - - @Test - public void processOnParamFieldWithJsonIgnore() throws NoSuchMethodException { - BeanParamAnnotationProcessor processor = new BeanParamAnnotationProcessor(); - OperationGenerator operationGenerator = mockOperationGenerator("testBeanParamWithJsonIgnore", - BeanParamWithJsonIgnoredTagged.class); - - processor.process(null, operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - assertEquals(1, providerParameters.size()); - AbstractSerializableParameter parameter = (AbstractSerializableParameter) providerParameters.get(0); - assertEquals("name", parameter.getName()); - assertEquals("query", parameter.getIn()); - assertEquals("string", parameter.getType()); - } - - private OperationGenerator mockOperationGenerator(String methodName, Class... paramTypes) - throws NoSuchMethodException { - final Method providerMethod = TestProvider.class.getDeclaredMethod(methodName, paramTypes); - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new JaxrsSwaggerGeneratorContext(), - TestProvider.class); - return new OperationGenerator(swaggerGenerator, providerMethod); - } - - static class TestProvider { - public String testBeanParam(@BeanParam AggregatedParam aggregatedParam) { - return aggregatedParam.toString(); - } - - public String testBeanParamWithPart(@BeanParam BeanParamWithPart aggregatedParam) { - return aggregatedParam.toString(); - } - - public String testBeanParamComplexField(@BeanParam BeanParamComplexField param) { - return param.toString(); - } - - public String testBeanParamComplexSetter(@BeanParam BeanParamComplexSetter param) { - return param.toString(); - } - - public String testBeanParamWithUntaggedField(@BeanParam BeanParamWithUntaggedField param) { - return param.toString(); - } - - public String testBeanParamWithJsonIgnore(@BeanParam BeanParamWithJsonIgnoredTagged param) { - return param.toString(); - } - } - - static class AggregatedParam { - @DefaultValue("pa") - @PathParam("path0") - private String strVal; - - @QueryParam("query1") - private int intVal; - - private long longVal; - - private long cookieVal; - - @HeaderParam("header2") - private String headerVal; - - public String getStrVal() { - return strVal; - } - - public void setStrVal(String strVal) { - this.strVal = strVal; - } - - public int getIntVal() { - return intVal; - } - - public void setIntVal(int intVal) { - this.intVal = intVal; - } - - public long getLongVal() { - return longVal; - } - - @DefaultValue("12") - @FormParam("form3") - public void setLongVal(long longVal) { - this.longVal = longVal; - } - - public long getCookieVal() { - return cookieVal; - } - - @CookieParam("cookie4") - public void setCookieVal(long cookieVal) { - this.cookieVal = cookieVal; - } - - public String getHeaderVal() { - return headerVal; - } - - public void setHeaderVal(String headerVal) { - this.headerVal = headerVal; - } - } - - static class BeanParamWithPart { - @QueryParam("queryStr") - private boolean queryStr; - - @FormParam("up0") - private Part up0; - - private Part up1; - - public boolean isQueryStr() { - return queryStr; - } - - public void setQueryStr(boolean queryStr) { - this.queryStr = queryStr; - } - - public Part getUp0() { - return up0; - } - - public void setUp0(Part up0) { - this.up0 = up0; - } - - public Part getUp1() { - return up1; - } - - @FormParam("up1") - public void setUp1(Part up1) { - this.up1 = up1; - } - } - - static class BeanParamComplexField { - @QueryParam("q") - private AggregatedParam complex; - - public AggregatedParam getComplex() { - return complex; - } - - public void setComplex(AggregatedParam complex) { - this.complex = complex; - } - } - - static class BeanParamComplexSetter { - private AggregatedParam complex; - - public AggregatedParam getComplex() { - return complex; - } - - @HeaderParam("h") - public void setComplex(AggregatedParam complex) { - this.complex = complex; - } - } - - static class BeanParamWithUntaggedField { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - - static class BeanParamWithJsonIgnoredTagged { - @QueryParam("name") - private String name; - - @JsonIgnore - private AggregatedParam ignored; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public AggregatedParam getIgnored() { - return ignored; - } - - public void setIgnored( - AggregatedParam ignored) { - this.ignored = ignored; - } - } -} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessorTest.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessorTest.java deleted file mode 100644 index d0e3fa9f8d1..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ConsumesAnnotationProcessorTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.lang.annotation.Annotation; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.models.Operation; - -public class ConsumesAnnotationProcessorTest { - @Test - public void testProcess() throws NoSuchMethodException { - ConsumesAnnotationProcessor processor = new ConsumesAnnotationProcessor(); - Operation operation = new Operation(); - OperationGenerator operationGenerator = mockOperationGenerator(operation); - - Annotation consumesAnnotation = TestProducer.class.getMethod("testSingleMediaType", String.class) - .getAnnotation(Consumes.class); - processor.process(consumesAnnotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_JSON)); - - consumesAnnotation = TestProducer.class.getMethod("testMultipleMediaType", String.class) - .getAnnotation(Consumes.class); - processor.process(consumesAnnotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - - consumesAnnotation = TestProducer.class.getMethod("testBlankMediaType", String.class) - .getAnnotation(Consumes.class); - processor.process(consumesAnnotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - - operation.addConsumes(MediaType.APPLICATION_XML); - Assert.assertThat(operation.getConsumes(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - } - - static OperationGenerator mockOperationGenerator(Operation operation) { - OperationGenerator operationGenerator = Mockito.mock(OperationGenerator.class); - Mockito.when(operationGenerator.getOperation()).thenReturn(operation); - return operationGenerator; - } - - static class TestProducer { - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_XML) - public String testSingleMediaType(String input) { - return input; - } - - @Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) - @Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML}) - public String testMultipleMediaType(String input) { - return input; - } - - @Consumes("") - @Produces("") - public String testBlankMediaType(String input) { - return input; - } - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessorTest.java b/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessorTest.java deleted file mode 100644 index d4d3c0c09bc..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/test/java/org/apache/servicecomb/swagger/generator/jaxrs/processor/annotation/ProducesAnnotationProcessorTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation; - -import java.lang.annotation.Annotation; - -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.ConsumesAnnotationProcessorTest.TestProducer; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.Operation; - -public class ProducesAnnotationProcessorTest { - @Test - public void testProcess() throws NoSuchMethodException { - ProducesAnnotationProcessor processor = new ProducesAnnotationProcessor(); - Operation operation = new Operation(); - OperationGenerator operationGenerator = ConsumesAnnotationProcessorTest.mockOperationGenerator(operation); - - Annotation produceAnnotation = TestProducer.class.getMethod("testSingleMediaType", String.class) - .getAnnotation(Produces.class); - processor.process(produceAnnotation, operationGenerator); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - - produceAnnotation = TestProducer.class.getMethod("testMultipleMediaType", String.class) - .getAnnotation(Produces.class); - processor.process(produceAnnotation, operationGenerator); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML)); - - produceAnnotation = TestProducer.class.getMethod("testBlankMediaType", String.class) - .getAnnotation(Produces.class); - processor.process(produceAnnotation, operationGenerator); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML)); - - operation.addProduces(MediaType.APPLICATION_JSON); - Assert.assertThat(operation.getProduces(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)); - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/log4j.properties b/swagger/swagger-generator/generator-jaxrs/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/ClassAnnotation.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/ClassAnnotation.yaml new file mode 100644 index 00000000000..5f8df8369d6 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/ClassAnnotation.yaml @@ -0,0 +1,119 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.ClassAnnotation + version: 1.0.0 +servers: +- url: /class +paths: + /testBean: + post: + operationId: testBean + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/User" + x-name: user + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/User" + text/plain: + schema: + $ref: "#/components/schemas/User" + /testForm: + post: + operationId: testForm + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + param: + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string + /testString: + post: + operationId: testString + requestBody: + content: + application/json: + schema: + type: string + x-name: user + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string + /testUpload: + post: + operationId: testUpload + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.foundation.test.scaffolding.model.User diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/FullSwaggerService.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/FullSwaggerService.yaml new file mode 100644 index 00000000000..39ae7960507 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/FullSwaggerService.yaml @@ -0,0 +1,141 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.FullSwaggerService + version: 1.0.0 +servers: +- url: /FullSwaggerService +paths: + /defaultValue: + get: + operationId: defaultValue + parameters: + - name: e + in: query + schema: + type: integer + format: int32 + - name: a + in: query + schema: + type: integer + format: int32 + default: 20 + - name: b + in: query + schema: + type: string + default: bobo + - name: c + in: query + schema: + type: integer + format: int32 + default: 40 + - name: d + in: query + schema: + maximum: 30 + minimum: 20 + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /fileDownload: + get: + operationId: fileDownload + responses: + "200": + description: response of 200 + content: + '*/*': + schema: + type: string + format: binary + /fileUpload: + post: + operationId: fileUpload + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file1: + type: string + format: binary + file2: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + /queryListMULTI: + get: + operationId: queryListMULTI + parameters: + - name: queryList + in: query + required: false + style: form + explode: true + schema: + type: array + items: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /textPlain: + get: + operationId: textPlain + responses: + "200": + description: response of 200 + content: + text/plain: + schema: + type: string +components: {} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/aggregatedParam.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/aggregatedParam.yaml new file mode 100644 index 00000000000..a074d0c78c7 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/aggregatedParam.yaml @@ -0,0 +1,77 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /aggregatedParam: + post: + operationId: "aggregatedParam" + parameters: + - name: "path0" + in: "path" + required: true + type: "string" + default: "pa" + - name: "query1" + in: "query" + required: false + type: "integer" + default: 0 + format: "int32" + - name: "form3" + in: "formData" + required: false + type: "integer" + default: 12 + format: "int64" + - name: "cookie4" + in: "cookie" + required: false + type: "integer" + default: 0 + format: "int64" + - name: "header2" + in: "header" + required: false + type: "string" + - name: "query-array" + in: "query" + required: false + type: "array" + items: + type: "string" + collectionFormat: "multi" + - name: "query-list" + in: "query" + required: false + type: "array" + items: + type: "string" + collectionFormat: "multi" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamDefaultBody.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamDefaultBody.yaml new file mode 100644 index 00000000000..768741ed1af --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamDefaultBody.yaml @@ -0,0 +1,41 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /beanParamDefaultBody: + post: + operationId: "beanParamDefaultBody" + parameters: + - in: "body" + name: "name" + required: false + schema: + type: "string" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithJsonIgnoredTagged.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithJsonIgnoredTagged.yaml new file mode 100644 index 00000000000..6ce1e66e5b0 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithJsonIgnoredTagged.yaml @@ -0,0 +1,40 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /beanParamWithJsonIgnoredTaggedBody: + post: + operationId: "beanParamWithJsonIgnoredTagged" + parameters: + - name: "name" + in: "query" + required: false + type: "string" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithPart.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithPart.yaml new file mode 100644 index 00000000000..4423f07ec6f --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/beanParamWithPart.yaml @@ -0,0 +1,51 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /beanParamWithPart: + post: + operationId: "beanParamWithPart" + consumes: + - "multipart/form-data" + parameters: + - name: "queryStr" + in: "query" + required: false + type: "boolean" + default: false + - name: "up0" + in: "formData" + required: false + type: "file" + - name: "up1" + in: "formData" + required: false + type: "file" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/consumes.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/consumes.yaml new file mode 100644 index 00000000000..8da5da55a28 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/consumes.yaml @@ -0,0 +1,90 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.model.ConsumesAndProduces + version: 1.0.0 +servers: +- url: /ConsumesAndProduces +paths: + /testBlankMediaType: + post: + operationId: testBlankMediaType + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testBlankMediaTypeBody' + x-name: testBlankMediaTypeBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /testMultipleMediaType: + post: + operationId: testMultipleMediaType + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testMultipleMediaTypeBody' + x-name: testMultipleMediaTypeBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /testSingleMediaType: + post: + operationId: testSingleMediaType + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/testSingleMediaTypeBody' + x-name: testSingleMediaTypeBody + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string +components: + schemas: + testBlankMediaTypeBody: + type: object + properties: + input: + type: string + testMultipleMediaTypeBody: + type: object + properties: + input: + type: string + testSingleMediaTypeBody: + type: object + properties: + input: + type: string diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/cookie.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/cookie.yaml index 13c4e1d61c5..896793e188c 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/cookie.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/cookie.yaml @@ -36,7 +36,7 @@ paths: required: false type: "string" responses: - 200: + "200": description: "response of 200" schema: type: "string" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/dynamicStatusEnum.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/dynamicStatusEnum.yaml new file mode 100644 index 00000000000..c3c5263661d --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/dynamicStatusEnum.yaml @@ -0,0 +1,65 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo + version: 1.0.0 +servers: +- url: Echo +paths: + /dynamicStatusEnum: + post: + operationId: dynamicStatusEnum + parameters: + - name: status-aggr + in: query + description: | + dynamic desc aggr + - 400: dynamic bad request + - 404: dynamic not found + - name: status + in: query + description: | + dynamic desc direct + - 400: dynamic bad request + - 404: dynamic not found + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DynamicStatusModel' + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + description: | + - 400: dynamic bad request + - 404: dynamic not found + format: int32 +components: + schemas: + DynamicStatusModel: + type: object + properties: + status: + type: integer + format: int32 diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml index e6e943cb02c..7e0fe3b59c4 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml @@ -16,57 +16,548 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" - x-java-interface: "gen.cse.ms.ut.EchoIntf" -basePath: "/Echo" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo + version: 1.0.0 +servers: +- url: Echo paths: - /echo/{targetName}: + /aggregatedParam: + post: + operationId: aggregatedParam + parameters: + - name: path0 + in: path + required: true + schema: + type: string + default: pa + - name: query1 + in: query + schema: + type: integer + format: int32 + - name: cookie4 + in: cookie + schema: + type: integer + format: int64 + - name: header2 + in: header + schema: + type: string + - name: query-array + in: query + schema: + type: array + items: + type: string + - name: query-list + in: query + schema: + type: array + items: + type: string + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + form3: + type: integer + format: int64 + responses: + "200": + description: response of 200 + /beanParamComplexField: + post: + operationId: beanParamComplexField + parameters: + - name: q + in: query + schema: + $ref: "#/components/schemas/AggregatedParam" + responses: + "200": + description: response of 200 + /beanParamComplexSetter: + post: + operationId: beanParamComplexSetter + parameters: + - name: h + in: header + schema: + $ref: "#/components/schemas/AggregatedParam" + responses: + "200": + description: response of 200 + /beanParamDefaultBody: post: - operationId: "echo" - consumes: - - "json" - - "xml" - produces: - - "json" - - "xml" + operationId: beanParamDefaultBody + requestBody: + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + x-name: name + responses: + "200": + description: response of 200 + /beanParamWithJsonIgnoredTaggedBody: + post: + operationId: beanParamWithJsonIgnoredTagged parameters: - - in: "body" - name: "srcUser" + - name: name + in: query + schema: + type: string + responses: + "200": + description: response of 200 + /beanParamWithPart: + post: + operationId: beanParamWithPart + parameters: + - name: queryStr + in: query + schema: + type: boolean + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + up0: + type: string + format: binary + up1: + type: string + format: binary + responses: + "200": + description: response of 200 + /cookie: + post: + operationId: cookie + parameters: + - name: cookie + in: cookie + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /dynamicStatusEnum: + post: + operationId: dynamicStatusEnum + parameters: + - name: status-aggr + in: query + description: dynamic desc aggr required: false schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" + type: integer + format: int32 + - name: status + in: query + description: dynamic desc direct required: false - type: "string" - - name: "targetName" - in: "path" + schema: + type: integer + format: int32 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DynamicStatusModel" + application/protobuf: + schema: + $ref: "#/components/schemas/DynamicStatusModel" + text/plain: + schema: + $ref: "#/components/schemas/DynamicStatusModel" + x-name: model + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + application/protobuf: + schema: + type: integer + format: int32 + text/plain: + schema: + type: integer + format: int32 + /echo/{targetName}: + post: + operationId: echo + parameters: + - name: header + in: header + schema: + type: string + - name: targetName + in: path required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + $ref: "#/components/schemas/User" + text/plain: + schema: + $ref: "#/components/schemas/User" + x-name: srcUser + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /emptyPath: + post: + operationId: emptyPath + responses: + "200": + description: response of 200 + /enumBody: + post: + operationId: enumBody + requestBody: + content: + application/json: + schema: + type: string + enum: + - RED + - YELLOW + - BLUE + application/protobuf: + schema: + type: string + enum: + - RED + - YELLOW + - BLUE + text/plain: + schema: + type: string + enum: + - RED + - YELLOW + - BLUE + x-name: color + responses: + "200": + description: response of 200 + /form: + post: + operationId: form + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + form: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /jdkStatusEnum: + post: + operationId: jdkStatusEnum + parameters: + - name: status-aggr + in: query + description: jdk desc aggr + required: false + schema: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + - name: status + in: query + description: jdk desc direct required: false - type: "string" - responses: - 200: - description: "response of 200" - schema: - type: "string" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" + schema: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/JdkStatusModel" + application/protobuf: + schema: + $ref: "#/components/schemas/JdkStatusModel" + text/plain: + schema: + $ref: "#/components/schemas/JdkStatusModel" + x-name: model + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + application/protobuf: + schema: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + text/plain: + schema: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + /nestedListString: + post: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + application/protobuf: + schema: + type: array + items: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: array + items: + type: string + x-name: param + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + application/protobuf: + schema: + type: array + items: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: array + items: + type: string + /: + patch: + operationId: patch + responses: + "200": + description: response of 200 + /query: + get: + operationId: query + parameters: + - name: query + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /queryComplex: + get: + operationId: queryComplex + parameters: + - name: queries + in: query + schema: + type: array + items: + $ref: "#/components/schemas/User" + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testRawJson: + post: + operationId: rawJsonStringMethod + requestBody: + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string + required: true + x-raw-json: true + x-name: jsonInput + responses: + "200": + description: response of 200 + /response: + post: + operationId: response + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + application/protobuf: + schema: + type: integer + format: int32 + text/plain: + schema: + type: integer + format: int32 +components: + schemas: + AggregatedParam: + type: object + properties: + strVal: + type: string + intVal: + type: integer + format: int32 + longVal: + type: integer + format: int64 + cookieVal: + type: integer + format: int64 + headerVal: + type: string + queryArray: + type: array + items: + type: string + queryList: + type: array + items: + type: string + x-java-class: org.apache.servicecomb.swagger.generator.jaxrs.model.AggregatedParam + DynamicStatusModel: + type: object + properties: + status: + type: integer + format: int32 + x-java-class: org.apache.servicecomb.swagger.generator.jaxrs.model.enums.DynamicStatusModel + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.foundation.test.scaffolding.model.User + JdkStatusModel: + type: object + properties: + status: + type: string + enum: + - BAD_REQUEST + - NOT_FOUND + x-java-class: org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatusModel diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/emptyPath.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/emptyPath.yaml index ed7dd880cc7..f76bd99fdf8 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/emptyPath.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/emptyPath.yaml @@ -32,5 +32,5 @@ paths: operationId: "emptyPath" parameters: [] responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/enumBody.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/enumBody.yaml index 65c47316845..b5b78b0232a 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/enumBody.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/enumBody.yaml @@ -41,5 +41,5 @@ paths: - "YELLOW" - "BLUE" responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/form.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/form.yaml index 46d7c822c6b..911269c20de 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/form.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/form.yaml @@ -36,7 +36,7 @@ paths: required: false type: "string" responses: - 200: + "200": description: "response of 200" schema: type: "string" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/jdkStatusEnum.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/jdkStatusEnum.yaml new file mode 100644 index 00000000000..67efb0def4c --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/jdkStatusEnum.yaml @@ -0,0 +1,78 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /jdkStatusEnum: + post: + operationId: "jdkStatusEnum" + parameters: + - name: "status-aggr" + in: "query" + description: "jdk desc aggr\n- BAD_REQUEST: jdk bad request\n- NOT_FOUND:\ + \ jdk not found\n" + required: false + type: "string" + enum: + - "BAD_REQUEST" + - "NOT_FOUND" + - name: "status" + in: "query" + description: "jdk desc direct\n- BAD_REQUEST: jdk bad request\n- NOT_FOUND:\ + \ jdk not found\n" + required: false + type: "string" + enum: + - "BAD_REQUEST" + - "NOT_FOUND" + - in: "body" + name: "model" + required: false + schema: + $ref: "#/definitions/JdkStatusModel" + responses: + "200": + description: "response of 200" + schema: + type: "string" + description: "- BAD_REQUEST: jdk bad request\n- NOT_FOUND: jdk not found\n" + enum: + - "BAD_REQUEST" + - "NOT_FOUND" + x-java-class: "org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatus" +definitions: + JdkStatusModel: + type: "object" + properties: + status: + type: "string" + description: "jdk status model\n- BAD_REQUEST: jdk bad request\n- NOT_FOUND:\ + \ jdk not found\n" + enum: + - "BAD_REQUEST" + - "NOT_FOUND" + x-java-class: "org.apache.servicecomb.swagger.generator.jaxrs.model.enums.JdkStatusModel" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/nestedListString.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/nestedListString.yaml new file mode 100644 index 00000000000..338ccdb8d67 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/nestedListString.yaml @@ -0,0 +1,50 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo + version: 1.0.0 +servers: +- url: Echo +paths: + /nestedListString: + post: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string +components: + schemas: {} diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/patch.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/patch.yaml new file mode 100644 index 00000000000..6a89b056f59 --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/patch.yaml @@ -0,0 +1,36 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /: + patch: + operationId: "patch" + parameters: [] + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/query.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/query.yaml index 78b36ea6072..be256d1d65a 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/query.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/query.yaml @@ -36,7 +36,7 @@ paths: required: false type: "string" responses: - 200: + "200": description: "response of 200" schema: type: "string" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/rawJsonStringMethod.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/rawJsonStringMethod.yaml index 27f968f3872..a482f6c6625 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/rawJsonStringMethod.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/rawJsonStringMethod.yaml @@ -38,5 +38,5 @@ paths: type: "string" x-raw-json: true responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/response.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/response.yaml index 01398bf80f2..b4db5ae2b39 100644 --- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/response.yaml +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/response.yaml @@ -32,7 +32,7 @@ paths: operationId: "response" parameters: [] responses: - 200: + "200": description: "response of 200" schema: type: "integer" diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/responseText.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/responseText.yaml new file mode 100644 index 00000000000..c596de61aac --- /dev/null +++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/responseText.yaml @@ -0,0 +1,40 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.jaxrs.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /: + get: + operationId: "responseText" + produces: + - "text/plain" + parameters: [] + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-spring-data/pom.xml b/swagger/swagger-generator/generator-spring-data/pom.xml new file mode 100644 index 00000000000..13c8923cd57 --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/pom.xml @@ -0,0 +1,42 @@ + + + + + + org.apache.servicecomb + swagger-generator + 3.4.0-SNAPSHOT + + 4.0.0 + + swagger-generator-spring-data + Java Chassis::Swagger::Generator::Spring data + + + + org.apache.servicecomb + swagger-generator-core + + + org.springframework.data + spring-data-commons + + + diff --git a/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataConcreteTypeRegister.java b/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataConcreteTypeRegister.java new file mode 100644 index 00000000000..90b82e2bef8 --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataConcreteTypeRegister.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springdata; + +import java.lang.reflect.Type; +import java.util.Set; + +import org.apache.servicecomb.swagger.extend.ConcreteTypeRegister; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public class SpringDataConcreteTypeRegister implements ConcreteTypeRegister { + @Override + public void register(Set types) { + types.add(Page.class); + types.add(Pageable.class); + } +} diff --git a/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataModule.java b/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataModule.java new file mode 100644 index 00000000000..b2fb8ccdbaa --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/main/java/org/apache/servicecomb/swagger/generator/springdata/SpringDataModule.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springdata; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.foundation.common.utils.SPIOrder; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.databind.util.Converter; + +public class SpringDataModule extends SimpleModule implements SPIOrder { + private static final long serialVersionUID = 1L; + + @JsonDeserialize(as = PageImpl.class) + @JsonPropertyOrder(alphabetic = true) + public static class PageMixin { + @JsonCreator + public PageMixin(@JsonProperty(value = "content") List content, + @JsonProperty("pageable") Pageable pageable, + @JsonProperty("total") long total) { + } + } + + @JsonDeserialize(as = PageRequest.class) + @JsonPropertyOrder(alphabetic = true) + public static class PageableMixin { + @JsonCreator + public PageableMixin(@JsonProperty(value = "pageNumber") int page, + @JsonProperty("pageSize") int size, @JsonProperty(value = "sort") Sort sort) { + } + } + + public static class SortConverter implements Converter { + @Override + public Sort convert(SortMixin value) { + return Sort.by(value.getProperties()); + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(SortMixin.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(Sort.class); + } + } + + public static class SortMixinConverter implements Converter { + @Override + public SortMixin convert(Sort value) { + List properties = new ArrayList<>(); + for (Order order : value) { + properties.add(order.getProperty()); + } + SortMixin result = new SortMixin(); + result.setProperties(properties.toArray(new String[0])); + return result; + } + + @Override + public JavaType getInputType(TypeFactory typeFactory) { + return typeFactory.constructType(Sort.class); + } + + @Override + public JavaType getOutputType(TypeFactory typeFactory) { + return typeFactory.constructType(SortMixin.class); + } + } + + @JsonPropertyOrder(alphabetic = true) + @JsonDeserialize(converter = SortConverter.class) + @JsonSerialize(converter = SortMixinConverter.class) + public static class SortMixin { + private String[] properties; + + @JsonCreator + public SortMixin() { + } + + public void setProperties(String[] properties) { + this.properties = properties; + } + + public String[] getProperties() { + return this.properties; + } + } + + public SpringDataModule() { + super("springData"); + + setMixInAnnotation(Page.class, PageMixin.class); + setMixInAnnotation(Pageable.class, PageableMixin.class); + setMixInAnnotation(Sort.class, SortMixin.class); + + setMixInAnnotation(PageImpl.class, PageMixin.class); + setMixInAnnotation(PageRequest.class, PageableMixin.class); + } + + @Override + public Object getTypeId() { + return getModuleName(); + } + + @Override + public int getOrder() { + return Short.MAX_VALUE; + } +} diff --git a/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module new file mode 100644 index 00000000000..161ee4f9e12 --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springdata.SpringDataModule diff --git a/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.ConcreteTypeRegister b/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.ConcreteTypeRegister new file mode 100644 index 00000000000..42f7ef4bb1a --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.ConcreteTypeRegister @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springdata.SpringDataConcreteTypeRegister diff --git a/swagger/swagger-generator/generator-spring-data/src/test/java/org/apache/servicecomb/swagger/generator/springdata/TestPageResponseTypeProcessor.java b/swagger/swagger-generator/generator-spring-data/src/test/java/org/apache/servicecomb/swagger/generator/springdata/TestPageResponseTypeProcessor.java new file mode 100644 index 00000000000..2a856ce3d89 --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/test/java/org/apache/servicecomb/swagger/generator/springdata/TestPageResponseTypeProcessor.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springdata; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; + +import io.swagger.v3.core.util.Json; + +public class TestPageResponseTypeProcessor { + interface PageSchema { + Page test(Page page); + } + + @Test + public void swagger() { + UnitTestSwaggerUtils.testSwagger("pageSchema.yaml", PageSchema.class); + } + + @Test + public void deserialize() throws IOException { + Json.mapper().registerModule(new SpringDataModule()); + + Sort sort = Sort.by(Direction.ASC, "name"); + Pageable pageable = PageRequest.of(1, 10, sort); + Page page = new PageImpl<>(Arrays.asList("c1", "c2"), pageable, 2); + String json = Json.mapper().writeValueAsString(page); + Assertions.assertEquals( + "{\"content\":[\"c1\",\"c2\"],\"pageable\":{\"pageNumber\":1,\"pageSize\":10,\"sort\":{\"properties\":[\"name\"]},\"offset\":10,\"paged\":true,\"unpaged\":false},\"empty\":false,\"first\":false,\"last\":true,\"number\":1,\"numberOfElements\":2,\"size\":10,\"sort\":{\"properties\":[\"name\"]},\"totalElements\":12,\"totalPages\":2}", + json); + + Page page2 = Json.mapper().readValue(json, Page.class); + + Assertions.assertEquals(json, + Json.mapper().writeValueAsString(page2)); + } +} diff --git a/swagger/swagger-generator/generator-spring-data/src/test/resources/pageSchema.yaml b/swagger/swagger-generator/generator-spring-data/src/test/resources/pageSchema.yaml new file mode 100644 index 00000000000..255ccceaca7 --- /dev/null +++ b/swagger/swagger-generator/generator-spring-data/src/test/resources/pageSchema.yaml @@ -0,0 +1,117 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springdata.TestPageResponseTypeProcessor$PageSchema + version: 1.0.0 +servers: +- url: /PageSchema +paths: + /test: + post: + operationId: test + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PageString" + application/protobuf: + schema: + $ref: "#/components/schemas/PageString" + text/plain: + schema: + $ref: "#/components/schemas/PageString" + x-name: page + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/PageString" + application/protobuf: + schema: + $ref: "#/components/schemas/PageString" + text/plain: + schema: + $ref: "#/components/schemas/PageString" +components: + schemas: + PageString: + type: object + properties: + content: + type: array + items: + type: string + empty: + type: boolean + first: + type: boolean + last: + type: boolean + number: + type: integer + format: int32 + numberOfElements: + type: integer + format: int32 + pageable: + $ref: "#/components/schemas/Pageable" + size: + type: integer + format: int32 + sort: + $ref: "#/components/schemas/Sort" + totalElements: + type: integer + format: int64 + totalPages: + type: integer + format: int32 + x-java-class: org.springframework.data.domain.Page + Pageable: + type: object + properties: + offset: + type: integer + format: int64 + pageNumber: + type: integer + format: int32 + pageSize: + type: integer + format: int32 + paged: + type: boolean + sort: + $ref: "#/components/schemas/Sort" + unpaged: + type: boolean + x-java-class: org.springframework.data.domain.Pageable + Sort: + type: object + properties: + empty: + type: boolean + sorted: + type: boolean + unsorted: + type: boolean + x-java-class: org.springframework.data.domain.Sort diff --git a/swagger/swagger-generator/generator-springmvc/pom.xml b/swagger/swagger-generator/generator-springmvc/pom.xml index 94b59394fc3..c4225f11a96 100644 --- a/swagger/swagger-generator/generator-springmvc/pom.xml +++ b/swagger/swagger-generator/generator-springmvc/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger-generator - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-generator-springmvc Java Chassis::Swagger::Generator::Spring MVC @@ -36,13 +36,13 @@ swagger-generator-core - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcOperationGenerator.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcOperationGenerator.java new file mode 100644 index 00000000000..f9112f36676 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcOperationGenerator.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.core.AbstractSwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.apache.servicecomb.swagger.generator.rest.RestOperationGenerator; +import org.springframework.web.bind.annotation.RequestBody; + +public class SpringmvcOperationGenerator extends RestOperationGenerator { + public SpringmvcOperationGenerator(AbstractSwaggerGenerator swaggerGenerator, Method method) { + super(swaggerGenerator, method); + } + + @Override + protected void initMethodParameterGenerators(Map> methodAnnotationMap) { + super.initMethodParameterGenerators(methodAnnotationMap); + + parameterGenerators.stream() + .filter(pg -> pg.getHttpParameterType() == null) + .forEach(pg -> pg.setHttpParameterType(HttpParameterType.QUERY)); + } + + @Override + protected boolean isAggregatedParameter(ParameterGenerator parameterGenerator, Parameter methodParameter) { + return !isRequestBody(parameterGenerator) + && SwaggerUtils.isBean(methodParameter.getParameterizedType()); + } + + private boolean isRequestBody(ParameterGenerator parameterGenerator) { + for (Annotation annotation : parameterGenerator.getAnnotations()) { + if (annotation.annotationType() == RequestBody.class) { + return true; + } + } + return false; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGenerator.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGenerator.java new file mode 100644 index 00000000000..d6bfeac60c7 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGenerator.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc; + +import java.lang.reflect.Method; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.rest.RestSwaggerGenerator; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +public class SpringmvcSwaggerGenerator extends RestSwaggerGenerator { + public SpringmvcSwaggerGenerator(Class cls) { + super(cls); + } + + @Override + protected boolean isSkipMethod(Method method) { + if (super.isSkipMethod(method)) { + return true; + } + + return method.getAnnotation(RequestMapping.class) == null && + method.getAnnotation(GetMapping.class) == null && + method.getAnnotation(PutMapping.class) == null && + method.getAnnotation(PostMapping.class) == null && + method.getAnnotation(PatchMapping.class) == null && + method.getAnnotation(DeleteMapping.class) == null; + } + + @SuppressWarnings("unchecked") + @Override + public T createOperationGenerator(Method method) { + return (T) new SpringmvcOperationGenerator(this, method); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorContext.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorContext.java deleted file mode 100644 index 6e14a877922..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorContext.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc; - -import java.lang.reflect.Method; - -import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils; -import org.apache.servicecomb.swagger.generator.rest.RestSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.CookieValueAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.DeleteMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.GetMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PatchMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PathVariableAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PostMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PutMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestAttributeAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestBodyAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestHeaderAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestMappingClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestMappingMethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestParamAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestPartAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RestControllerClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.SpringmvcDefaultParameterProcessor; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.RestController; - -public class SpringmvcSwaggerGeneratorContext extends RestSwaggerGeneratorContext { - private static final int ORDER = 1000; - - @Override - public int getOrder() { - return ORDER; - } - - @Override - public boolean canProcess(Class cls) { - return ClassUtils.hasAnnotation(cls, RequestMapping.class) || ClassUtils.hasAnnotation(cls, RestController.class); - } - - @Override - public boolean canProcess(Method method) { - return method.getAnnotation(RequestMapping.class) != null || - method.getAnnotation(GetMapping.class) != null || - method.getAnnotation(PutMapping.class) != null || - method.getAnnotation(PostMapping.class) != null || - method.getAnnotation(PatchMapping.class) != null || - method.getAnnotation(DeleteMapping.class) != null; - } - - @Override - protected void initClassAnnotationMgr() { - super.initClassAnnotationMgr(); - - classAnnotationMgr.register(RequestMapping.class, new RequestMappingClassAnnotationProcessor()); - classAnnotationMgr.register(RestController.class, new RestControllerClassAnnotationProcessor()); - } - - @Override - protected void initMethodAnnotationMgr() { - super.initMethodAnnotationMgr(); - - methodAnnotationMgr.register(RequestMapping.class, new RequestMappingMethodAnnotationProcessor()); - methodAnnotationMgr.register(GetMapping.class, new GetMappingMethodAnnotationProcessor()); - methodAnnotationMgr.register(PutMapping.class, new PutMappingMethodAnnotationProcessor()); - methodAnnotationMgr.register(PostMapping.class, new PostMappingMethodAnnotationProcessor()); - methodAnnotationMgr.register(PatchMapping.class, new PatchMappingMethodAnnotationProcessor()); - methodAnnotationMgr.register(DeleteMapping.class, new DeleteMappingMethodAnnotationProcessor()); - } - - @Override - protected void initParameterAnnotationMgr() { - super.initParameterAnnotationMgr(); - - parameterAnnotationMgr.register(CookieValue.class, new CookieValueAnnotationProcessor()); - parameterAnnotationMgr.register(PathVariable.class, new PathVariableAnnotationProcessor()); - parameterAnnotationMgr.register(RequestBody.class, new RequestBodyAnnotationProcessor()); - parameterAnnotationMgr.register(RequestHeader.class, new RequestHeaderAnnotationProcessor()); - parameterAnnotationMgr.register(RequestParam.class, new RequestParamAnnotationProcessor()); - parameterAnnotationMgr.register(RequestAttribute.class, new RequestAttributeAnnotationProcessor()); - parameterAnnotationMgr.register(RequestPart.class, new RequestPartAnnotationProcessor()); - } - - @Override - protected void initParameterTypeProcessorMgr() { - super.initParameterTypeProcessorMgr(); - } - - @Override - protected void initDefaultParameterProcessor() { - defaultParameterProcessor = new SpringmvcDefaultParameterProcessor(); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorFactory.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorFactory.java new file mode 100644 index 00000000000..e85f10edb9f --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/SpringmvcSwaggerGeneratorFactory.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +public class SpringmvcSwaggerGeneratorFactory implements SwaggerGeneratorFactory { + private static final int ORDER = 1000; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public boolean canProcess(Class cls) { + return SwaggerUtils.hasAnnotation(cls, RequestMapping.class) || SwaggerUtils + .hasAnnotation(cls, RestController.class); + } + + @Override + public SwaggerGenerator create(Class cls) { + return new SpringmvcSwaggerGenerator(cls); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java index d481844bc92..8fe797bbba5 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java @@ -18,58 +18,41 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.servicecomb.swagger.generator.core.MethodAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.springframework.util.StringUtils; +import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.OperationGenerator; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; -abstract class AbstractHttpMethodMappingAnnotationProcessor implements MethodAnnotationProcessor { +abstract class AbstractHttpMethodMappingAnnotationProcessor implements + MethodAnnotationProcessor { + protected void doProcess(OperationGenerator operationGenerator, String[] paths, String[] pathValues, + RequestMethod requestMethod, String[] consumes, String[] produces) { + // paths same to pathValues + this.processPath(operationGenerator, paths); + this.processPath(operationGenerator, pathValues); - protected void processPath(String[] paths, OperationGenerator operationGenerator) { - if (null == paths || paths.length == 0) { - return; + if (requestMethod != null) { + operationGenerator.setHttpMethod(requestMethod.name()); } - - // swagger仅支持配一个path,否则将会出现重复的operationId - if (paths.length > 1) { - throw new Error(String.format("not allowed multi path for %s:%s", - operationGenerator.getProviderMethod().getDeclaringClass().getName(), - operationGenerator.getProviderMethod().getName())); + if (consumes.length > 0) { + operationGenerator.getOperationGeneratorContext().updateConsumes(Arrays.asList(consumes)); } - - operationGenerator.setPath(paths[0]); - } - - protected void processMethod(RequestMethod requestMethod, OperationGenerator operationGenerator) { - operationGenerator.setHttpMethod(requestMethod.name()); - } - - protected void processConsumes(String[] consumes, Operation operation) { - if (null == consumes || consumes.length == 0) { - return; - } - - List consumeList = Arrays.stream(consumes).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!consumeList.isEmpty()) { - operation.setConsumes(consumeList); + if (produces.length > 0) { + operationGenerator.getOperationGeneratorContext().updateProduces(Arrays.asList(produces)); } } - protected void processProduces(String[] produces, Operation operation) { - if (null == produces || produces.length == 0) { + protected void processPath(OperationGenerator operationGenerator, String[] paths) { + if (null == paths || paths.length == 0) { return; } - List produceList = Arrays.stream(produces).filter(s -> !StringUtils.isEmpty(s)) - .collect(Collectors.toList()); - if (!produceList.isEmpty()) { - operation.setProduces(produceList); + // swagger仅支持配一个path,否则将会出现重复的operationId + if (paths.length > 1) { + throw new IllegalStateException("not allowed multi path."); } + + operationGenerator.setPath(paths[0]); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java index 7fb4d91811d..d9b9df3f62a 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java @@ -17,49 +17,48 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.springframework.util.ObjectUtils; +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.ValueConstants; -import io.swagger.models.parameters.CookieParameter; - -public class CookieValueAnnotationProcessor extends AbstractParameterProcessor { +public class CookieValueAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((CookieValue) annotation).value(); - if (value.isEmpty()) { - value = ((CookieValue) annotation).name(); - } - return value; + public Type getProcessType() { + return CookieValue.class; } @Override - public CookieParameter createParameter() { - return new CookieParameter(); - } - - @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - CookieParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - - Object defaultValue = parameter.getDefaultValue(); - if (!ObjectUtils.isEmpty(defaultValue)) { - parameter.setRequired(false); - return; + public String getParameterName(CookieValue annotation) { + String value = annotation.value(); + if (value.isEmpty()) { + value = annotation.name(); } - CookieValue cookie = (CookieValue) annotation; - parameter.setRequired(cookie.required()); + if (StringUtils.isNotEmpty(value)) { + return value; + } + return null; } @Override - protected String getAnnotationParameterDefaultValue(Object annotation) { - String defaultValue = ((CookieValue) annotation).defaultValue(); - if (defaultValue.equals(ValueConstants.DEFAULT_NONE)) { - return ""; + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, CookieValue annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.COOKIE); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); + if (!ValueConstants.DEFAULT_NONE.equals(annotation.defaultValue())) { + parameterGenerator.getParameterGeneratorContext() + .setDefaultValue(annotation.defaultValue()); + // if default value is set, must be required false. + parameterGenerator.getParameterGeneratorContext().setRequired(false); } - return defaultValue; } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/DeleteMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/DeleteMappingMethodAnnotationProcessor.java index f2b6c4fdcee..994bf773e00 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/DeleteMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/DeleteMappingMethodAnnotationProcessor.java @@ -17,30 +17,26 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class DeleteMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class DeleteMappingMethodAnnotationProcessor extends + AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - DeleteMapping mappingAnnotation = (DeleteMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(mappingAnnotation.path(), operationGenerator); - this.processPath(mappingAnnotation.value(), operationGenerator); - this.processMethod(RequestMethod.DELETE, operationGenerator); - this.processConsumes(mappingAnnotation.consumes(), operation); - this.processProduces(mappingAnnotation.produces(), operation); + public Type getProcessType() { + return DeleteMapping.class; + } - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + DeleteMapping deleteMapping) { + doProcess(operationGenerator, + deleteMapping.path(), deleteMapping.value(), + RequestMethod.DELETE, + deleteMapping.consumes(), deleteMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/GetMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/GetMappingMethodAnnotationProcessor.java index daaae139af1..f140fc41d62 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/GetMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/GetMappingMethodAnnotationProcessor.java @@ -17,30 +17,22 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class GetMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class GetMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - GetMapping mappingAnnotation = (GetMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(mappingAnnotation.path(), operationGenerator); - this.processPath(mappingAnnotation.value(), operationGenerator); - this.processMethod(RequestMethod.GET, operationGenerator); - this.processConsumes(mappingAnnotation.consumes(), operation); - this.processProduces(mappingAnnotation.produces(), operation); + public Type getProcessType() { + return GetMapping.class; + } - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, GetMapping getMapping) { + doProcess(operationGenerator, + getMapping.path(), getMapping.value(), RequestMethod.GET, getMapping.consumes(), getMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PatchMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PatchMappingMethodAnnotationProcessor.java index daa20b6fee4..41193fd8c48 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PatchMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PatchMappingMethodAnnotationProcessor.java @@ -17,30 +17,25 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class PatchMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class PatchMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - PatchMapping mappingAnnotation = (PatchMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(mappingAnnotation.path(), operationGenerator); - this.processPath(mappingAnnotation.value(), operationGenerator); - this.processMethod(RequestMethod.PATCH, operationGenerator); - this.processConsumes(mappingAnnotation.consumes(), operation); - this.processProduces(mappingAnnotation.produces(), operation); + public Type getProcessType() { + return PatchMapping.class; + } - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + PatchMapping patchMapping) { + doProcess(operationGenerator, + patchMapping.path(), patchMapping.value(), + RequestMethod.PATCH, + patchMapping.consumes(), patchMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PathVariableAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PathVariableAnnotationProcessor.java index ea52624f4aa..ac89b8db84d 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PathVariableAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PathVariableAnnotationProcessor.java @@ -17,33 +17,41 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.springframework.web.bind.annotation.PathVariable; +import java.lang.reflect.Type; -import io.swagger.models.parameters.PathParameter; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.springframework.web.bind.annotation.PathVariable; -public class PathVariableAnnotationProcessor extends AbstractParameterProcessor { +public class PathVariableAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { @Override - public PathParameter createParameter() { - return new PathParameter(); + public Type getProcessType() { + return PathVariable.class; } @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((PathVariable) annotation).value(); + public String getParameterName(PathVariable annotation) { + String value = annotation.value(); if (value.isEmpty()) { - value = ((PathVariable) annotation).name(); + value = annotation.name(); + } + if (StringUtils.isNotEmpty(value)) { + return value; } - return value; + return null; } - - @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - PathParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - PathVariable pathVariable = (PathVariable) annotation; - parameter.setRequired(pathVariable.required()); + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, PathVariable annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.PATH); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PostMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PostMappingMethodAnnotationProcessor.java index bde80d73e9c..4ed80a7b8c5 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PostMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PostMappingMethodAnnotationProcessor.java @@ -17,30 +17,23 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class PostMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class PostMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - PostMapping mappingAnnotation = (PostMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(mappingAnnotation.path(), operationGenerator); - this.processPath(mappingAnnotation.value(), operationGenerator); - this.processMethod(RequestMethod.POST, operationGenerator); - this.processConsumes(mappingAnnotation.consumes(), operation); - this.processProduces(mappingAnnotation.produces(), operation); + public Type getProcessType() { + return PostMapping.class; + } - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + PostMapping postMapping) { + doProcess(operationGenerator, + postMapping.path(), postMapping.value(), RequestMethod.POST, postMapping.consumes(), postMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PutMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PutMappingMethodAnnotationProcessor.java index c2ceae3a842..e5672bfe303 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PutMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/PutMappingMethodAnnotationProcessor.java @@ -17,30 +17,22 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class PutMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class PutMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - PutMapping mappingAnnotation = (PutMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(mappingAnnotation.path(), operationGenerator); - this.processPath(mappingAnnotation.value(), operationGenerator); - this.processMethod(RequestMethod.PUT, operationGenerator); - this.processConsumes(mappingAnnotation.consumes(), operation); - this.processProduces(mappingAnnotation.produces(), operation); + public Type getProcessType() { + return PutMapping.class; + } - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, PutMapping putMapping) { + doProcess(operationGenerator, + putMapping.path(), putMapping.value(), RequestMethod.PUT, putMapping.consumes(), putMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestAttributeAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestAttributeAnnotationProcessor.java index 5a9f69dcb33..0b412afd984 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestAttributeAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestAttributeAnnotationProcessor.java @@ -17,32 +17,48 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; import org.springframework.web.bind.annotation.RequestAttribute; -import io.swagger.models.parameters.FormParameter; -public class RequestAttributeAnnotationProcessor extends AbstractParameterProcessor { +/** + * Use RequestAttribute to annotate a Form parameter. + * + * NOTICE: In spring-web, RequestAttribute is used to annotate request attribute, and use RequestParam + * to annotate query param and form param. This is implementation based. We can't use RequestParam to express + * both query and form in OpenAPI 3.0. And there is no request attribute. + */ +public class RequestAttributeAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { @Override - public FormParameter createParameter() { - return new FormParameter(); + public Type getProcessType() { + return RequestAttribute.class; } @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((RequestAttribute) annotation).value(); + public String getParameterName(RequestAttribute annotation) { + String value = annotation.value(); if (value.isEmpty()) { - value = ((RequestAttribute) annotation).name(); + value = annotation.name(); } - return value; + if (StringUtils.isNotEmpty(value)) { + return value; + } + return null; } @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - FormParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - - RequestAttribute requestAttribute = (RequestAttribute) annotation; - parameter.setRequired(requestAttribute.required()); + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RequestAttribute annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.FORM); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestBodyAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestBodyAnnotationProcessor.java index 346add427c0..e7e755b3a5a 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestBodyAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestBodyAnnotationProcessor.java @@ -17,18 +17,30 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.ParameterAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; import org.springframework.web.bind.annotation.RequestBody; -import io.swagger.models.parameters.BodyParameter; +public class RequestBodyAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { + @Override + public Type getProcessType() { + return RequestBody.class; + } + + @Override + public String getParameterName(RequestBody annotation) { + return null; + } -public class RequestBodyAnnotationProcessor implements ParameterAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator, int paramIdx) { - BodyParameter bodyParameter = ParamUtils.createBodyParameter(operationGenerator, paramIdx); - bodyParameter.setRequired(((RequestBody) annotation).required()); - operationGenerator.addProviderParameter(bodyParameter); + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RequestBody annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.BODY); + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java index 63be3056e59..dac8e2e0586 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java @@ -17,49 +17,48 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.springframework.util.ObjectUtils; +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.ValueConstants; -import io.swagger.models.parameters.HeaderParameter; - -public class RequestHeaderAnnotationProcessor extends AbstractParameterProcessor { +public class RequestHeaderAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { @Override - public HeaderParameter createParameter() { - return new HeaderParameter(); + public Type getProcessType() { + return RequestHeader.class; } @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((RequestHeader) annotation).value(); + public String getParameterName(RequestHeader annotation) { + String value = annotation.value(); if (value.isEmpty()) { - value = ((RequestHeader) annotation).name(); + value = annotation.name(); } - return value; - } - - @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - HeaderParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - - Object defaultValue = parameter.getDefaultValue(); - if (!ObjectUtils.isEmpty(defaultValue)) { - parameter.setRequired(false); - return; + if (StringUtils.isNotEmpty(value)) { + return value; } - RequestHeader requestHeader = (RequestHeader) annotation; - parameter.setRequired(requestHeader.required()); + return null; } @Override - protected String getAnnotationParameterDefaultValue(Object annotation) { - String defaultValue = ((RequestHeader) annotation).defaultValue(); - if (defaultValue.equals(ValueConstants.DEFAULT_NONE)) { - return ""; + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RequestHeader annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.HEADER); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); + if (!ValueConstants.DEFAULT_NONE.equals(annotation.defaultValue())) { + parameterGenerator.getParameterGeneratorContext() + .setDefaultValue(annotation.defaultValue()); + // if default value is set, must be required false. + parameterGenerator.getParameterGeneratorContext().setRequired(false); } - return defaultValue; } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java index d1b25cc9831..df18070f97a 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java @@ -17,29 +17,34 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; +import java.lang.reflect.Type; import java.util.Arrays; -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Swagger; - -public class RequestMappingClassAnnotationProcessor implements ClassAnnotationProcessor { - +public class RequestMappingClassAnnotationProcessor implements ClassAnnotationProcessor { @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - RequestMapping requestMapping = (RequestMapping) annotation; - Swagger swagger = swaggerGenerator.getSwagger(); + public Type getProcessType() { + return RequestMapping.class; + } + @Override + public void process(SwaggerGenerator swaggerGenerator, RequestMapping requestMapping) { this.processMethod(requestMapping.method(), swaggerGenerator); // path/value是等同的 this.processPath(requestMapping.path(), swaggerGenerator); this.processPath(requestMapping.value(), swaggerGenerator); - this.processConsumes(requestMapping.consumes(), swagger); - this.processProduces(requestMapping.produces(), swagger); + + if (requestMapping.consumes().length > 0) { + swaggerGenerator.getSwaggerGeneratorContext().updateConsumes(Arrays.asList(requestMapping.consumes())); + } + if (requestMapping.produces().length > 0) { + swaggerGenerator.getSwaggerGeneratorContext().updateProduces(Arrays.asList(requestMapping.produces())); + } } protected void processPath(String[] paths, SwaggerGenerator swaggerGenerator) { @@ -49,7 +54,8 @@ protected void processPath(String[] paths, SwaggerGenerator swaggerGenerator) { // swagger仅支持配一个basePath if (paths.length > 1) { - throw new Error("not support multi path for " + swaggerGenerator.getCls().getName()); + throw new IllegalStateException( + String.format("not support multi path, class=%s.", swaggerGenerator.getClazz().getName())); } swaggerGenerator.setBasePath(paths[0]); @@ -61,26 +67,10 @@ protected void processMethod(RequestMethod[] requestMethods, SwaggerGenerator sw } if (requestMethods.length > 1) { - throw new Error( - "not allowed multi http method for " + swaggerGenerator.getCls().getName()); + throw new IllegalStateException( + String.format("not support multi http method, class=%s.", swaggerGenerator.getClazz().getName())); } swaggerGenerator.setHttpMethod(requestMethods[0].name()); } - - private void processConsumes(String[] consumes, Swagger swagger) { - if (null == consumes || consumes.length == 0) { - return; - } - - swagger.setConsumes(Arrays.asList(consumes)); - } - - protected void processProduces(String[] produces, Swagger swagger) { - if (null == produces || produces.length == 0) { - return; - } - - swagger.setProduces(Arrays.asList(produces)); - } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessor.java index a0875a9de47..b17505cac09 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessor.java @@ -17,46 +17,33 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; +import java.lang.reflect.Type; + import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import io.swagger.models.Operation; - -public class RequestMappingMethodAnnotationProcessor extends AbstractHttpMethodMappingAnnotationProcessor { - +public class RequestMappingMethodAnnotationProcessor extends + AbstractHttpMethodMappingAnnotationProcessor { @Override - public void process(Object annotation, OperationGenerator operationGenerator) { - RequestMapping requestMapping = (RequestMapping) annotation; - Operation operation = operationGenerator.getOperation(); - - // path/value是等同的 - this.processPath(requestMapping.path(), operationGenerator); - this.processPath(requestMapping.value(), operationGenerator); - this.processMethod(requestMapping.method(), operationGenerator); - - this.processConsumes(requestMapping.consumes(), operation); - this.processProduces(requestMapping.produces(), operation); - - if (StringUtils.isEmpty(operationGenerator.getHttpMethod()) - && StringUtils.isEmpty(operationGenerator.getSwaggerGenerator().getHttpMethod())) { - throw new Error("HttpMethod must not both be empty in class and method"); - } + public Type getProcessType() { + return RequestMapping.class; } - private void processMethod(RequestMethod[] requestMethods, OperationGenerator operationGenerator) { - if (null == requestMethods || requestMethods.length == 0) { - return; - } - - if (requestMethods.length > 1) { - throw new Error( - String.format("not allowed multi http method for %s:%s", - operationGenerator.getProviderMethod().getDeclaringClass().getName(), - operationGenerator.getProviderMethod().getName())); + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + RequestMapping requestMapping) { + if (requestMapping.method().length > 1) { + throw new IllegalStateException("not allowed multi http method."); } - super.processMethod(requestMethods[0], operationGenerator); + doProcess(operationGenerator, + requestMapping.path(), requestMapping.value(), + requestMapping.method().length == 0 ? + (StringUtils.isEmpty(operationGenerator.getHttpMethod()) ? RequestMethod.GET : null) : + requestMapping.method()[0], + requestMapping.consumes(), requestMapping.produces()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java deleted file mode 100644 index 828a7828b97..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; - -import io.swagger.models.parameters.QueryParameter; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.springframework.util.ObjectUtils; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ValueConstants; - -public class RequestParamAnnotationProcessor extends AbstractParameterProcessor { - @Override - public QueryParameter createParameter() { - return new QueryParameter(); - } - - @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((RequestParam) annotation).value(); - if (value.isEmpty()) { - value = ((RequestParam) annotation).name(); - } - return value; - } - - @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - QueryParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - - Object defaultValue = parameter.getDefaultValue(); - if (!ObjectUtils.isEmpty(defaultValue)) { - parameter.setRequired(false); - return; - } - RequestParam requestParam = (RequestParam) annotation; - parameter.setRequired(requestParam.required()); - } - - @Override - protected String getAnnotationParameterDefaultValue(Object annotation) { - String defaultValue = ((RequestParam) annotation).defaultValue(); - if (defaultValue.equals(ValueConstants.DEFAULT_NONE)) { - return ""; - } - return defaultValue; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamParameterProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamParameterProcessor.java new file mode 100644 index 00000000000..66785a337cf --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamParameterProcessor.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ValueConstants; + +/** + * Use RequestParam to annotate a Query parameter. + * + * NOTICE: In spring-web, RequestParam is used to annotate query param and form param. + * This is implementation based. We can't use RequestParam to express + * both query and form in OpenAPI 3.0. + */ +public class RequestParamParameterProcessor extends + SpringmvcParameterAnnotationsProcessor { + @Override + public Type getProcessType() { + return RequestParam.class; + } + + @Override + public String getParameterName(RequestParam annotation) { + String value = annotation.value(); + if (value.isEmpty()) { + value = annotation.name(); + } + if (StringUtils.isNotEmpty(value)) { + return value; + } + return null; + } + + @Override + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RequestParam annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.QUERY); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); + if (!ValueConstants.DEFAULT_NONE.equals(annotation.defaultValue())) { + parameterGenerator.getParameterGeneratorContext() + .setDefaultValue(annotation.defaultValue()); + // if default value is set, must be required false. + parameterGenerator.getParameterGeneratorContext().setRequired(false); + } + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessor.java index 859235a70e0..4333201032e 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessor.java @@ -17,33 +17,41 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor; -import org.springframework.web.bind.annotation.RequestPart; +import java.lang.reflect.Type; -import io.swagger.models.parameters.FormParameter; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.ParameterGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType; +import org.springframework.web.bind.annotation.RequestPart; -public class RequestPartAnnotationProcessor extends AbstractParameterProcessor { +public class RequestPartAnnotationProcessor extends + SpringmvcParameterAnnotationsProcessor { @Override - public FormParameter createParameter() { - return new FormParameter(); + public Type getProcessType() { + return RequestPart.class; } @Override - public String getAnnotationParameterName(Object annotation) { - String value = ((RequestPart) annotation).value(); + public String getParameterName(RequestPart annotation) { + String value = annotation.value(); if (value.isEmpty()) { - value = ((RequestPart) annotation).name(); + value = annotation.name(); + } + if (StringUtils.isNotEmpty(value)) { + return value; } - return value; + return null; } @Override - protected void fillParameter(Object annotation, OperationGenerator operationGenerator, int paramIdx, - FormParameter parameter) { - super.fillParameter(annotation, operationGenerator, paramIdx, parameter); - - RequestPart requestPart = (RequestPart) annotation; - parameter.setRequired(requestPart.required()); + public void process(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + ParameterGenerator parameterGenerator, RequestPart annotation) { + parameterGenerator.setHttpParameterType(HttpParameterType.FORM); + if (StringUtils.isNotEmpty(getParameterName(annotation))) { + parameterGenerator.getParameterGeneratorContext().setParameterName(getParameterName(annotation)); + } + parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required()); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RestControllerClassAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RestControllerClassAnnotationProcessor.java index 01819d6caf7..66ac987a442 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RestControllerClassAnnotationProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RestControllerClassAnnotationProcessor.java @@ -17,19 +17,23 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.swagger.generator.core.ClassAnnotationProcessor; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; +import java.lang.reflect.Type; -import io.swagger.models.Swagger; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.springframework.web.bind.annotation.RestController; -public class RestControllerClassAnnotationProcessor implements ClassAnnotationProcessor { +public class RestControllerClassAnnotationProcessor implements ClassAnnotationProcessor { + @Override + public Type getProcessType() { + return RestController.class; + } @Override - public void process(Object annotation, SwaggerGenerator swaggerGenerator) { - Swagger swagger = swaggerGenerator.getSwagger(); - if (StringUtils.isEmpty(swagger.getBasePath())) { - swagger.setBasePath("/"); + public void process(SwaggerGenerator swaggerGenerator, RestController restController) { + if (SwaggerUtils.getBasePath(swaggerGenerator.getOpenAPI()) == null) { + swaggerGenerator.setBasePath("/"); } } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/SpringmvcParameterAnnotationsProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/SpringmvcParameterAnnotationsProcessor.java new file mode 100644 index 00000000000..4774d5c6256 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/SpringmvcParameterAnnotationsProcessor.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; + +import org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor; + +/** + * A generic class to help classify implementations. + */ +public abstract class SpringmvcParameterAnnotationsProcessor implements + ParameterAnnotationProcessor { +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileArrayProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileArrayProcessor.java new file mode 100644 index 00000000000..be51858656d --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileArrayProcessor.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; + +import org.apache.servicecomb.swagger.generator.core.processor.parameter.PartArrayParameterTypeProcessor; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +public class MultipartFileArrayProcessor extends PartArrayParameterTypeProcessor { + @Override + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType(MultipartFile[].class); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileListProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileListProcessor.java new file mode 100644 index 00000000000..85d4648c126 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileListProcessor.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; + +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.apache.servicecomb.swagger.generator.core.processor.parameter.PartArrayParameterTypeProcessor; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; + +public class MultipartFileListProcessor extends PartArrayParameterTypeProcessor { + @Override + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType( + ParameterizedTypeUtil.make(List.class, MultipartFile.class)); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileTypeProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileTypeProcessor.java index 12e4974b576..3781c2b128f 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileTypeProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/MultipartFileTypeProcessor.java @@ -17,25 +17,15 @@ package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; -import org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import org.apache.servicecomb.swagger.generator.core.processor.parameter.PartParameterTypeProcessor; import org.springframework.web.multipart.MultipartFile; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.properties.FileProperty; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.type.TypeFactory; -public class MultipartFileTypeProcessor implements CommonParameterTypeProcessor { +public class MultipartFileTypeProcessor extends PartParameterTypeProcessor { @Override - public Class getParameterType() { - return MultipartFile.class; - } - - @Override - public void process(OperationGenerator operationGenerator, int paramIdx) { - FormParameter parameter = new FormParameter(); - parameter.setType(new FileProperty().getType()); - parameter.setName(ParamUtils.getParameterName(operationGenerator.getProviderMethod(), paramIdx)); - operationGenerator.addProviderParameter(parameter); + public JavaType getProcessType() { + return TypeFactory.defaultInstance().constructType(MultipartFile.class); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java deleted file mode 100644 index ed0aa9e7bce..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import java.lang.reflect.Type; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.Model; -import io.swagger.models.parameters.AbstractSerializableParameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; - -/** - * Flatten a object parameter into a set of flatten simple parameters. - * Nesting object params and generic Object params are NOT supported. - * We support query object just for aggregating query params instead of transporting objects in query param. - * So we don't support a generic param whose generic type is complex, but a simple generic type param can be supported. - */ -public class SpringmvcDefaultObjectParameterProcessor implements DefaultParameterProcessor { - - private static final Logger LOGGER = LoggerFactory.getLogger(SpringmvcDefaultObjectParameterProcessor.class); - - @Override - public void process(OperationGenerator operationGenerator, int paramIndex) { - Model paramModel = getParamModel(operationGenerator, paramIndex); - - if (null == paramModel) { - throw new Error(String.format("cannot find param, provider method is [%s], paramIndex = [%d]. " - + "Please check your parameter definition.", - operationGenerator.getProviderMethod().getName(), paramIndex)); - } - - LinkedHashMap> resultParamMap = getFlattenParams(paramModel); - - addProviderParams(operationGenerator, resultParamMap); - } - - private void addProviderParams(OperationGenerator operationGenerator, - LinkedHashMap> resultParamMap) { - resultParamMap.forEach((paramName, param) -> operationGenerator.addProviderParameter(param)); - } - - private Model getParamModel(OperationGenerator operationGenerator, int paramIndex) { - Type paramType = ParamUtils.getGenericParameterType(operationGenerator.getProviderMethod(), paramIndex); - Property property = ModelConverters.getInstance().readAsProperty(paramType); - // ensure type - if (!RefProperty.class.isInstance(property)) { - LOGGER.error("Unsupported property type: [{}], paramIndex is [{}]", property.getClass().getName(), paramIndex); - return null; - } - - Map models = ModelConverters.getInstance().readAll(paramType); - - // find param root - RefProperty refProperty = (RefProperty) property; - String refTypeName = refProperty.getSimpleRef(); - Model paramRoot = null; - for (Entry entry : models.entrySet()) { - if (refTypeName.equals(entry.getKey())) { - paramRoot = entry.getValue(); - break; - } - } - return paramRoot; - } - - private LinkedHashMap> getFlattenParams(Model paramModel) { - LinkedHashMap> flattenParamMap = new LinkedHashMap<>(); - // traversal the properties of current paramModel - // create simple parameters, nesting object param is ignored - for (Entry propertyEntry : paramModel.getProperties().entrySet()) { - if (ParamUtils.isComplexProperty(propertyEntry.getValue())) { - throw new Error( - "A nesting complex field is found in the query object and this is not supported, field name = [" - + propertyEntry.getKey() + "]. Please remove this field or tag @JsonIgnore on it."); - } - AbstractSerializableParameter newParameter = createSimpleParam(propertyEntry); - flattenParamMap.put(propertyEntry.getKey(), newParameter); - } - - return flattenParamMap; - } - - private AbstractSerializableParameter createSimpleParam(Entry propertyEntry) { - AbstractSerializableParameter newParameter = new QueryParameter(); - newParameter.setName(propertyEntry.getKey()); - newParameter.setProperty(propertyEntry.getValue()); - return newParameter; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java deleted file mode 100644 index d9b5a5d7314..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import java.lang.reflect.Type; - -import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; - -public class SpringmvcDefaultParameterProcessor implements DefaultParameterProcessor { - private SpringmvcDefaultSimpleParameterProcessor simpleParameterProcessor = new SpringmvcDefaultSimpleParameterProcessor(); - - private SpringmvcDefaultObjectParameterProcessor objectParameterProcessor = new SpringmvcDefaultObjectParameterProcessor(); - - @Override - public void process(OperationGenerator operationGenerator, int paramIdx) { - Type paramType = ParamUtils.getGenericParameterType(operationGenerator.getProviderMethod(), paramIdx); - Property property = ModelConverters.getInstance().readAsProperty(paramType); - - if (RefProperty.class.isInstance(property)) { - objectParameterProcessor.process(operationGenerator, paramIdx); - return; - } - if (!ParamUtils.isComplexProperty(property)) { - simpleParameterProcessor.process(operationGenerator, paramIdx); - return; - } - - // unsupported param type - String msg = String.format("cannot process parameter [%s], method=%s:%s, paramIdx=%d, type=%s", - ParamUtils.getParameterName(operationGenerator.getProviderMethod(), paramIdx), - operationGenerator.getProviderMethod().getDeclaringClass().getName(), - operationGenerator.getProviderMethod().getName(), - paramIdx, - paramType.getTypeName()); - throw new Error(msg); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java deleted file mode 100644 index 3d9f5a1151c..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; - -import io.swagger.models.parameters.QueryParameter; - -public class SpringmvcDefaultSimpleParameterProcessor implements DefaultParameterProcessor { - - @Override - public void process(OperationGenerator operationGenerator, int paramIdx) { - String paramName = ParamUtils.getParameterName(operationGenerator.getProviderMethod(), paramIdx); - - QueryParameter queryParameter = new QueryParameter(); - queryParameter.setName(paramName); - ParamUtils.setParameterType(operationGenerator.getSwagger(), - operationGenerator.getProviderMethod(), - paramIdx, - queryParameter); - operationGenerator.addProviderParameter(queryParameter); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/response/ResponseEntityProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/response/ResponseEntityProcessor.java index 3530ee7c779..e6bed78ef83 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/response/ResponseEntityProcessor.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/response/ResponseEntityProcessor.java @@ -16,12 +16,16 @@ */ package org.apache.servicecomb.swagger.generator.springmvc.processor.response; -import org.apache.servicecomb.swagger.generator.core.processor.response.AbstractOneGenericResponseProcessor; +import org.apache.servicecomb.swagger.generator.core.processor.response.DefaultResponseTypeProcessor; import org.springframework.http.ResponseEntity; -public class ResponseEntityProcessor extends AbstractOneGenericResponseProcessor { +public class ResponseEntityProcessor extends DefaultResponseTypeProcessor { + public ResponseEntityProcessor() { + extractActualType = true; + } + @Override - public Class getResponseType() { + public Class getProcessType() { return ResponseEntity.class; } } diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/springmvc/MultipartFilePropertyCreator.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreator.java similarity index 82% rename from swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/springmvc/MultipartFilePropertyCreator.java rename to swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreator.java index 2cfb87df199..6666f7813c5 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/extend/property/creator/springmvc/MultipartFilePropertyCreator.java +++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreator.java @@ -15,21 +15,20 @@ * limitations under the License. */ -package org.apache.servicecomb.swagger.extend.property.creator.springmvc; +package org.apache.servicecomb.swagger.generator.springmvc.property.creator; import org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator; import org.springframework.web.multipart.MultipartFile; -import io.swagger.models.properties.FileProperty; -import io.swagger.models.properties.Property; +import io.swagger.v3.oas.models.media.FileSchema; +import io.swagger.v3.oas.models.media.Schema; public class MultipartFilePropertyCreator implements PropertyCreator { - private final Class[] classes = {MultipartFile.class}; @Override - public Property createProperty() { - return new FileProperty(); + public Schema createProperty() { + return new FileSchema(); } @Override diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator index 09c3783aadb..11b81b52e9b 100644 --- a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.extend.property.creator.PropertyCreator @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.swagger.extend.property.creator.springmvc.MultipartFilePropertyCreator +org.apache.servicecomb.swagger.generator.springmvc.property.creator.MultipartFilePropertyCreator diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor new file mode 100644 index 00000000000..e7d511d2796 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RestControllerClassAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestMappingClassAnnotationProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor new file mode 100644 index 00000000000..21a0a455679 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestMappingMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.GetMappingMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.DeleteMappingMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PostMappingMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PutMappingMethodAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PatchMappingMethodAnnotationProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor new file mode 100644 index 00000000000..a1deb93045f --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterAnnotationProcessor @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.CookieValueAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.PathVariableAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestBodyAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestParamParameterProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestHeaderAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestPartAnnotationProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestAttributeAnnotationProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor new file mode 100644 index 00000000000..c99b5978635 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ParameterTypeProcessor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.MultipartFileTypeProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.MultipartFileArrayProcessor +org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.MultipartFileListProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor new file mode 100644 index 00000000000..91110b15c86 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.processor.response.ResponseEntityProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory new file mode 100644 index 00000000000..88f6b99eb19 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerGeneratorFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorFactory diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor deleted file mode 100644 index 0bad0b7e0c1..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.MultipartFileTypeProcessor diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor deleted file mode 100644 index 78548c4b806..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.ResponseTypeProcessor +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.springmvc.processor.response.ResponseEntityProcessor \ No newline at end of file diff --git a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext b/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext deleted file mode 100644 index 9b0f37f7647..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_base.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_base.java deleted file mode 100644 index 3ef0189d225..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_base.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerConst; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext; - -import io.swagger.models.Model; -import io.swagger.models.Swagger; - -public class TestSwaggerToClassGenerator_base { - ClassLoader classLoader = new ClassLoader() { - }; - - SwaggerGeneratorContext context = new SpringmvcSwaggerGeneratorContext(); - - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(context, ToClassSchema.class); - - Swagger swagger = swaggerGenerator.generate(); - - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(classLoader, swagger, "gen"); - - Class swaggerIntf; - - public TestSwaggerToClassGenerator_base(boolean clearXJavaClass) { - if (clearXJavaClass) { - for (Model model : swagger.getDefinitions().values()) { - model.getVendorExtensions().remove(SwaggerConst.EXT_JAVA_CLASS); - } - } - swaggerIntf = swaggerToClassGenerator.convert(); - } - - public void tearDown() { - JavassistUtils.clearByClassLoader(classLoader); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_create.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_create.java deleted file mode 100644 index bfd713812c4..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_create.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator; - -import java.lang.reflect.Method; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -public class TestSwaggerToClassGenerator_create { - static TestSwaggerToClassGenerator_base base = new TestSwaggerToClassGenerator_base(true); - - @AfterClass - public static void tearDown() { - base.tearDown(); - } - - @Test - public void recursiveSelf() throws NoSuchFieldException { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "recursiveSelf"); - Class returnType = method.getReturnType(); - - Assert.assertEquals("gen.RecursiveSelfType", returnType.getName()); - Assert.assertEquals("gen.RecursiveSelfType", returnType.getField("field").getType().getName()); - } - - @Test - public void dependType() throws NoSuchFieldException { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "dependType"); - Class returnType = method.getReturnType(); - - Assert.assertEquals("gen.DependTypeA", returnType.getName()); - Assert.assertEquals("gen.DependTypeB", returnType.getField("b").getType().getName()); - } - - @Test - public void generic() throws NoSuchFieldException { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "generic"); - Class returnType = method.getReturnType(); - - Assert.assertEquals("gen.GenericRecursiveSelfTypeDependTypeA", returnType.getName()); - Assert.assertEquals("gen.RecursiveSelfType", returnType.getField("v1").getType().getName()); - Assert.assertEquals("gen.DependTypeA", returnType.getField("v2").getType().getName()); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_reuse.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_reuse.java deleted file mode 100644 index e4a0671170d..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/TestSwaggerToClassGenerator_reuse.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator; - -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.DependTypeA; -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.Generic; -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.RecursiveSelfType; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; - -public class TestSwaggerToClassGenerator_reuse { - static TestSwaggerToClassGenerator_base base = new TestSwaggerToClassGenerator_base(false); - - @AfterClass - public static void tearDown() { - base.tearDown(); - } - - @Test - public void recursiveSelf() { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "recursiveSelf"); - Class returnType = method.getReturnType(); - - Assert.assertSame(RecursiveSelfType.class, returnType); - } - - @Test - public void dependType() { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "dependType"); - Class returnType = method.getReturnType(); - - Assert.assertSame(DependTypeA.class, returnType); - } - - @Test - public void generic() { - Method method = ReflectUtils.findMethod(base.swaggerIntf, "generic"); - ParameterizedType returnType = (ParameterizedType) method.getGenericReturnType(); - - Assert.assertSame(Generic.class, returnType.getRawType()); - Assert.assertSame(RecursiveSelfType.class, returnType.getActualTypeArguments()[0]); - Assert.assertSame(DependTypeA.class, returnType.getActualTypeArguments()[1]); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/ToClassSchema.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/ToClassSchema.java deleted file mode 100644 index e0f6cacdd44..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/ToClassSchema.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator; - - -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.DependTypeA; -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.Generic; -import org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model.RecursiveSelfType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@RequestMapping(path = "/") -public class ToClassSchema { - @GetMapping(path = "recursiveSelf") - public RecursiveSelfType recursiveSelf() { - return null; - } - - @GetMapping(path = "dependType") - public DependTypeA dependType() { - return null; - } - - @GetMapping(path = "generic") - public Generic generic() { - return null; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeA.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeA.java deleted file mode 100644 index 3fc8a96d1fa..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeA.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model; - -public class DependTypeA { - private DependTypeB b; - - public DependTypeB getB() { - return b; - } - - public void setB(DependTypeB b) { - this.b = b; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeB.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeB.java deleted file mode 100644 index 5957ca32f20..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/DependTypeB.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model; - -public class DependTypeB { - private DependTypeA a; - - public DependTypeA getA() { - return a; - } - - public void setA(DependTypeA a) { - this.a = a; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/Generic.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/Generic.java deleted file mode 100644 index 69aec3d6b8d..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/Generic.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model; - -public class Generic { - private T1 v1; - - private T2 v2; - - public T1 getV1() { - return v1; - } - - public void setV1(T1 v1) { - this.v1 = v1; - } - - public T2 getV2() { - return v2; - } - - public void setV2(T2 v2) { - this.v2 = v2; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/RecursiveSelfType.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/RecursiveSelfType.java deleted file mode 100644 index 9b8b663d4b9..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/converter/swaggerToClassGenerator/model/RecursiveSelfType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.converter.swaggerToClassGenerator.model; - -public class RecursiveSelfType { - private RecursiveSelfType field; - - public RecursiveSelfType getField() { - return field; - } - - public void setField(RecursiveSelfType field) { - this.field = field; - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java index 1f023cbd0ba..48ac1256c53 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java @@ -17,36 +17,96 @@ package org.apache.servicecomb.swagger.generator.springmvc; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + import org.apache.servicecomb.foundation.test.scaffolding.model.Color; import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.ws.rs.core.MediaType; @RequestMapping( path = "Echo", method = {RequestMethod.PUT}, - consumes = {"a", "b"}, - produces = {"a", "b"}) + consumes = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}, + produces = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) public class Echo { - @RequestMapping + @RequestMapping("emptyPath") public void emptyPath() { } - @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}) - public void multiHttpMethod() { + @RequestMapping("inheritHttpMethod") + public void inheritHttpMethod(int query) { } - @RequestMapping - public void inheritHttpMethod(int query) { + @RequestMapping("cookie") + public void cookie(@CookieValue(value = "cookie", required = false) int cookie) { } - @RequestMapping + @RequestMapping("rawJsonStringMethod") public void rawJsonStringMethod(@RawJsonRequestBody String jsonInput) { } - @RequestMapping + @RequestMapping("enumBody") public void enumBody(@RequestBody Color color) { } + + @RequestMapping("asyncResponseEntity") + public CompletableFuture>> asyncResponseEntity() { + return null; + } + + @RequestMapping("testResponseEntityOptional") + public ResponseEntity> testResponseEntityOptional() { + return null; + } + + @RequestMapping("testCompletableFutureResponseEntityOptional") + public CompletableFuture>> testCompletableFutureResponseEntityOptional() { + return null; + } + + @RequestMapping(value = "part", consumes = MediaType.MULTIPART_FORM_DATA) + public void part(@RequestPart MultipartFile part) { + + } + + @RequestMapping(value = "partArray", consumes = MediaType.MULTIPART_FORM_DATA) + public void partArray(@RequestPart MultipartFile[] part) { + + } + + @RequestMapping(value = "partList", consumes = MediaType.MULTIPART_FORM_DATA) + public void partList(@RequestPart List part) { + + } + + @RequestMapping(value = "partAnnotation", consumes = MediaType.MULTIPART_FORM_DATA) + public void partAnnotation(@RequestPart MultipartFile part) { + + } + + @RequestMapping(value = "partArrayAnnotation", consumes = MediaType.MULTIPART_FORM_DATA) + public void partArrayAnnotation(@RequestPart MultipartFile[] part) { + + } + + @RequestMapping(value = "partListAnnotation", consumes = MediaType.MULTIPART_FORM_DATA) + public void partListAnnotation(@RequestPart List part) { + + } + + @RequestMapping("nestedListString") + public List> nestedListString(@RequestBody List> param) { + return param; + } } diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodEmptyPath.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodEmptyPath.java index 655bfba9339..59b62412647 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodEmptyPath.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodEmptyPath.java @@ -24,7 +24,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; @RequestMapping(path = "MethodEmptyPath") public class MethodEmptyPath { @@ -56,7 +56,7 @@ public void usingPatchMapping() { // this will be ignored in the generation of service contract // as ApiOperation is not a restful annotation - @ApiOperation(value = "") + @Operation(summary = "") public void ignoredNonRestful() { } diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java index 56e3d622990..5d93a2862f3 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java @@ -17,74 +17,158 @@ package org.apache.servicecomb.swagger.generator.springmvc; +import java.time.LocalDateTime; + import org.apache.servicecomb.foundation.test.scaffolding.model.User; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.Part; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +@SuppressWarnings("unused") @RequestMapping(path = "MethodMixupAnnotations") public class MethodMixupAnnotations { @RequestMapping( path = "usingRequestMapping/{targetName}", method = {RequestMethod.POST}, - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingRequestMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); } @GetMapping( path = "usingGetMapping/{targetName}", - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingGetMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); } @PutMapping( path = "usingPutMapping/{targetName}", - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingPutMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); } @PostMapping( path = "usingPostMapping/{targetName}", - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingPostMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); } @PatchMapping( path = "usingPatchMapping/{targetName}", - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingPatchMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); } @DeleteMapping( path = "usingDeleteMapping/{targetName}", - consumes = {"text/plain", "application/*"}, - produces = {"text/plain", "application/*"}) + consumes = {"text/plain", "application/json"}, + produces = {"text/plain", "application/json"}) public String usingDeleteMapping(@RequestBody User srcUser, @RequestHeader String header, - @PathVariable String targetName, @RequestParam(name = "word") String word, @RequestAttribute String form) { - return String.format("%s %s %s %s %s", srcUser.name, header, targetName, word, form); + @PathVariable String targetName, @RequestParam(name = "word") String word) { + return String.format("%s %s %s %s", srcUser.name, header, targetName, word); + } + + @PostMapping(path = "/uploadFileAndAttribute") + public String uploadFileAndAttribute(@RequestPart(name = "file") MultipartFile file, + @RequestPart(name = "attribute") String attribute) { + return null; + } + + @PostMapping(path = "/uploadFilesAndAttribute") + public String uploadFilesAndAttribute(@RequestPart(name = "files") MultipartFile[] files, + @RequestPart(name = "attribute") String attribute) { + return null; + } + + @GetMapping(path = "/reduce") + @Parameters({@Parameter(name = "a", schema = @Schema(implementation = String.class), in = ParameterIn.QUERY)}) + public int reduce(HttpServletRequest request, @CookieValue(name = "b") int b) { + return 0; + } + + @RequestMapping(path = "/defaultQueryParam", method = RequestMethod.POST) + public String defaultQueryParam(String prefix, @RequestBody User user) { + return null; + } + + @GetMapping(path = "/diffNames") + @Operation(summary = "differentName", operationId = "differentName") + public int diffNames(@RequestParam("x") int a, @RequestParam("y") int b) { + return a * 2 + b; + } + + @GetMapping(path = "/bytes") + public byte[] bytes(@RequestBody byte[] value) { + return null; + } + + @PostMapping(path = "/upload", produces = MediaType.TEXT_PLAIN_VALUE) + public String fileUpload(@RequestPart(name = "file1") MultipartFile file1, + @RequestPart(name = "someFile") Part file2) { + return null; + } + + @PostMapping(path = "/testImplicitForm") + @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = {@Content(mediaType = SwaggerConst.FORM_MEDIA_TYPE, + schema = @Schema(name = "form1", implementation = String.class, + nullable = false, description = "a required form param")), + @Content(mediaType = SwaggerConst.FORM_MEDIA_TYPE, + schema = @Schema(name = "form2", implementation = String.class, + nullable = true, description = "an optional form param"))}) + public String testImplicitForm(HttpServletRequest request) { + return null; + } + + @GetMapping("/testDefaultValue") + public String testDefaultValue(@RequestParam(name = "e", required = false) int e, + @RequestHeader(name = "a", defaultValue = "20") int a, + @CookieValue(name = "b", defaultValue = "bobo") String b, + @RequestParam(name = "c", defaultValue = "40") Integer c, + @Min(value = 20) @Max(value = 30) @RequestParam(name = "d", required = false) int d) { + return "Hello " + a + b + c + d + e; + } + + @GetMapping(path = "/testLocalDateTime") + public LocalDateTime testLocalDateTime(@RequestParam("date") LocalDateTime date) { + return date; } } diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodResponseEntity.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodResponseEntity.java index c772f3770e9..93b02db5a3f 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodResponseEntity.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodResponseEntity.java @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -@RequestMapping(path = "MethodResponseEntity") +@RequestMapping(path = "MethodResponseEntity", method = RequestMethod.POST) public class MethodResponseEntity { @RequestMapping(method = RequestMethod.PUT, path = "usingRequestMapping") diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MultiDefaultPath.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MultiDefaultPath.java index 8a3b926196e..dc84054c7e7 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MultiDefaultPath.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MultiDefaultPath.java @@ -20,7 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -@RequestMapping(path = "abc") +@RequestMapping(path = "abc", method = RequestMethod.POST) public class MultiDefaultPath { @GetMapping public void p1() { diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestResponseEntityProcessor.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestResponseEntityProcessor.java deleted file mode 100644 index cbffa706105..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestResponseEntityProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.generator.springmvc; - -import org.apache.servicecomb.swagger.generator.springmvc.processor.response.ResponseEntityProcessor; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.ResponseEntity; - -public class TestResponseEntityProcessor { - ResponseEntityProcessor processor = new ResponseEntityProcessor(); - - @Test - public void getResponseType() { - Assert.assertEquals(ResponseEntity.class, processor.getResponseType()); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestSpringmvc.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestSpringmvc.java index 8bda7931e68..a0bb9b996c7 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestSpringmvc.java +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestSpringmvc.java @@ -17,113 +17,69 @@ package org.apache.servicecomb.swagger.generator.springmvc; -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; +import org.apache.servicecomb.swagger.generator.springmvc.model.DefaultParameterSchema; +import org.apache.servicecomb.swagger.generator.springmvc.model.RestControllerWithPathSchema; +import org.apache.servicecomb.swagger.generator.springmvc.model.SwaggerTestTarget; +import org.apache.servicecomb.swagger.generator.springmvc.model.SwaggerTestTarget_ValueOverWritePath; +import org.junit.jupiter.api.Test; public class TestSpringmvc { - ClassLoader classLoader = new ClassLoader() { - }; - - SwaggerGeneratorContext context = new SpringmvcSwaggerGeneratorContext(); - - @After - public void tearDown() { - JavassistUtils.clearByClassLoader(classLoader); - } - @Test public void testMultiDefaultPath() { UnitTestSwaggerUtils.testException( - "Only allowed one default path. org.apache.servicecomb.swagger.generator.springmvc.MultiDefaultPath:p2", - context, + "Duplicate operation path detected. method=org.apache.servicecomb.swagger.generator.springmvc.MultiDefaultPath:p2.", MultiDefaultPath.class); } @Test public void testResponseEntity() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/responseEntity.yaml", context, MethodResponseEntity.class); + UnitTestSwaggerUtils.testSwagger("schemas/responseEntity.yaml", MethodResponseEntity.class); } @Test - public void testEmptyPath() { - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/emptyPath.yaml", context, Echo.class, "emptyPath"); - UnitTestSwaggerUtils.testSwagger(classLoader, "schemas/MethodEmptyPath.yaml", - context, - MethodEmptyPath.class); + public void testEcho() { + UnitTestSwaggerUtils.testSwagger("schemas/echo.yaml", Echo.class); } @Test public void testMixupAnnotations() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/mixupAnnotations.yaml", context, MethodMixupAnnotations.class); + UnitTestSwaggerUtils.testSwagger("schemas/mixupAnnotations.yaml", MethodMixupAnnotations.class); } @Test public void testDefaultParameter() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/defaultParameter.yaml", context, MethodDefaultParameter.class); + UnitTestSwaggerUtils.testSwagger("schemas/defaultParameter.yaml", MethodDefaultParameter.class); } - @Test - public void testInheritHttpMethod() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/inheritHttpMethod.yaml", context, Echo.class, "inheritHttpMethod"); - } - - @Test - public void testRawJsonStringMethod() { - UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/rawJsonStringMethod.yaml", context, Echo.class, "rawJsonStringMethod"); - } @Test public void testClassMethodNoPath() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.ClassMethodNoPath:noPath", - "Path must not both be empty in class and method", - context, + "Generate swagger operation failed, method=ClassMethodNoPath:noPath, " + + "cause=Path must not both be empty in class and method", ClassMethodNoPath.class, "noPath"); } @Test - public void testClassMethodNoHttpMetod() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.ClassMethodNoHttpMethod:noHttpMethod", - "HttpMethod must not both be empty in class and method", - context, - ClassMethodNoHttpMethod.class); + public void testClassMethodNoHttpMethod() { + UnitTestSwaggerUtils + .testSwagger("schemas/requestMappingHttpMethod.yaml", ClassMethodNoHttpMethod.class, "noHttpMethod"); } - @Test - public void testMethodMultiHttpMethod() { - UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.Echo:multiHttpMethod", - "not allowed multi http method for org.apache.servicecomb.swagger.generator.springmvc.Echo:multiHttpMethod", - context, - Echo.class, - "multiHttpMethod"); - } @Test public void testClassMultiHttpMethod() { UnitTestSwaggerUtils.testException( - "not allowed multi http method for org.apache.servicecomb.swagger.generator.springmvc.ClassMultiHttpMethod", - context, + "not support multi http method, class=org.apache.servicecomb.swagger.generator.springmvc.ClassMultiHttpMethod.", ClassMultiHttpMethod.class); } @Test public void testMethodMultiPathUsingRequestMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingRequestMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingRequestMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingRequestMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingRequestMapping"); } @@ -131,9 +87,7 @@ public void testMethodMultiPathUsingRequestMapping() { @Test public void testMethodMultiPathUsingGetMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingGetMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingGetMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingGetMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingGetMapping"); } @@ -141,9 +95,7 @@ public void testMethodMultiPathUsingGetMapping() { @Test public void testMethodMultiPathUsingPutMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPutMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPutMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingPutMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingPutMapping"); } @@ -151,9 +103,7 @@ public void testMethodMultiPathUsingPutMapping() { @Test public void testMethodMultiPathUsingPostMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPostMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPostMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingPostMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingPostMapping"); } @@ -161,9 +111,7 @@ public void testMethodMultiPathUsingPostMapping() { @Test public void testMethodMultiPathUsingPatchMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPatchMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingPatchMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingPatchMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingPatchMapping"); } @@ -171,9 +119,7 @@ public void testMethodMultiPathUsingPatchMapping() { @Test public void testMethodMultiPathUsingDeleteMapping() { UnitTestSwaggerUtils.testException( - "generate operation swagger failed, org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingDeleteMapping", - "not allowed multi path for org.apache.servicecomb.swagger.generator.springmvc.MethodMultiPath:usingDeleteMapping", - context, + "Generate swagger operation failed, method=MethodMultiPath:usingDeleteMapping, cause=not allowed multi path.", MethodMultiPath.class, "usingDeleteMapping"); } @@ -181,22 +127,29 @@ public void testMethodMultiPathUsingDeleteMapping() { @Test public void testClassMultiPath() { UnitTestSwaggerUtils.testException( - "not support multi path for org.apache.servicecomb.swagger.generator.springmvc.ClassMultiPath", - context, + "not support multi path, class=org.apache.servicecomb.swagger.generator.springmvc.ClassMultiPath.", ClassMultiPath.class); } + + @Test + public void testDefaultParameterSchema() { + UnitTestSwaggerUtils.testSwagger("schemas/DefaultParameterSchema.yaml", DefaultParameterSchema.class); + } + @Test - public void testComposite() { - CompositeSwaggerGeneratorContext composite = new CompositeSwaggerGeneratorContext(); - SwaggerGeneratorContext context = composite.selectContext(Echo.class); + public void testRestControllerWithPathSchema() { + UnitTestSwaggerUtils.testSwagger("schemas/RestControllerWithPathSchema.yaml", RestControllerWithPathSchema.class); + } - Assert.assertEquals(SpringmvcSwaggerGeneratorContext.class, context.getClass()); + @Test + public void swaggerTestTarget() { + UnitTestSwaggerUtils.testSwagger("schemas/swaggerTestTarget.yaml", SwaggerTestTarget.class); } @Test - public void testEnumBody() { + public void swaggerTestTarget_ValueOverWritePath() { UnitTestSwaggerUtils - .testSwagger(classLoader, "schemas/enumBody.yaml", context, Echo.class, "enumBody"); + .testSwagger("schemas/swaggerTestTarget_ValueOverWritePath.yaml", SwaggerTestTarget_ValueOverWritePath.class); } } diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestTwoSameNameModels.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestTwoSameNameModels.java new file mode 100644 index 00000000000..5bcb3b3fda6 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/TestTwoSameNameModels.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.springmvc.model.Generic; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import io.swagger.v3.oas.models.OpenAPI; +import jakarta.ws.rs.core.MediaType; + +public class TestTwoSameNameModels { + private static final String SCHEMA_CONTENT = """ + openapi: 3.0.1 + info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.TestTwoSameNameModels$TwoSameModelService + version: 1.0.0 + servers: + - url: /TwoSameModelService + paths: + /sameGeneric: + post: + operationId: genericService + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/GenericSameModel" + required: true + x-name: param + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/GenericSameModel" + /same: + post: + operationId: service + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SameModel" + required: true + x-name: param + responses: + "200": + description: response of 200 + content: + application/json: + schema: + $ref: "#/components/schemas/SameModel" + components: + schemas: + GenericSameModel: + type: object + properties: + data: + $ref: "#/components/schemas/SameModel" + x-java-class: org.apache.servicecomb.swagger.generator.springmvc.model.Generic + SameModel: + type: object + properties: + name: + type: string + x-java-class: org.apache.servicecomb.swagger.generator.springmvc.model.same1.SameModel + """; + + interface TwoSameModelService { + @RequestMapping( + path = "/same", + method = {RequestMethod.POST}, + consumes = {MediaType.APPLICATION_JSON}, + produces = {MediaType.APPLICATION_JSON}) + org.apache.servicecomb.swagger.generator.springmvc.model.same1.SameModel service + (@RequestBody org.apache.servicecomb.swagger.generator.springmvc.model.same1.SameModel param); + + @RequestMapping( + path = "/sameGeneric", + method = {RequestMethod.POST}, + consumes = {MediaType.APPLICATION_JSON}, + produces = {MediaType.APPLICATION_JSON}) + Generic genericService + (@RequestBody Generic param); + } + + interface SameModelService { + @RequestMapping( + path = "/same", + method = {RequestMethod.POST}, + consumes = {MediaType.APPLICATION_JSON}, + produces = {MediaType.APPLICATION_JSON}) + org.apache.servicecomb.swagger.generator.springmvc.model.same1.SameModel service + (@RequestBody org.apache.servicecomb.swagger.generator.springmvc.model.same2.SameModel param); + } + + interface SameModelThrowService { + @RequestMapping( + path = "/same", + method = {RequestMethod.POST}, + consumes = {MediaType.APPLICATION_JSON}, + produces = {MediaType.APPLICATION_JSON}) + org.apache.servicecomb.swagger.generator.springmvc.model.same1.SameModelThrow service + (@RequestBody org.apache.servicecomb.swagger.generator.springmvc.model.same2.SameModelThrow param); + } + + @Test + public void testTwoSameModelWork() { + SwaggerGenerator generator = SwaggerGenerator.create(TwoSameModelService.class); + OpenAPI openAPI = generator.generate(); + Assertions.assertEquals(SCHEMA_CONTENT, SwaggerUtils.swaggerToString(openAPI)); + } + + @Test + public void testSameModelThrowThrowException() { + SwaggerGenerator generator = SwaggerGenerator.create(SameModelThrowService.class); + Assertions.assertThrows(IllegalStateException.class, () -> generator.generate()); + } + + @Test + public void testSameModelThrowException() { + SwaggerGenerator generator = SwaggerGenerator.create(SameModelService.class); + Assertions.assertThrows(IllegalStateException.class, () -> generator.generate()); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java new file mode 100644 index 00000000000..9a2bae4d569 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +import java.util.List; +import java.util.Map; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.ws.rs.core.MediaType; + +@RestController +public class DefaultParameterSchema { + @GetMapping("/testSimpleParam") + public String testSimpleParam(String strParam) { + return strParam; + } + + @GetMapping("/testObjectParam") + public String testObjectParam(TestParam objParam) { + return objParam.toString(); + } + + @GetMapping("/testUnsupportedParamType") + public String testUnsupportedParamType(int i, List integerList, Map stringMap) { + return null; + } + + @RequestMapping(path = "testSingleMediaType", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + public String testSingleMediaType(String input) { + return input; + } + + @RequestMapping(path = "testMultipleMediaType", method = RequestMethod.PUT, consumes = {MediaType.TEXT_PLAIN, + MediaType.APPLICATION_JSON}, + produces = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) + public String testMultipleMediaType(String input) { + return input; + } + + @RequestMapping(path = "testBlankMediaType", method = RequestMethod.POST) + public String testBlankMediaType(String input) { + return input; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/Generic.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/Generic.java new file mode 100644 index 00000000000..6c419dd39f9 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/Generic.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +public class Generic { + private T data; + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/RestControllerWithPathSchema.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/RestControllerWithPathSchema.java new file mode 100644 index 00000000000..c6553ba8c15 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/RestControllerWithPathSchema.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/prefix") +public class RestControllerWithPathSchema { + @GetMapping("/testSimpleParam") + public String testSimpleParam(String strParam) { + return strParam; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget.java new file mode 100644 index 00000000000..1eb7d967835 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +import jakarta.ws.rs.core.MediaType; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@RequestMapping(path = "/test", method = RequestMethod.POST, + consumes = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}, + produces = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) +public class SwaggerTestTarget { + @RequestMapping + public void method() { + + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget_ValueOverWritePath.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget_ValueOverWritePath.java new file mode 100644 index 00000000000..8d014633157 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/SwaggerTestTarget_ValueOverWritePath.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@RequestMapping(value = "/testValue", path = "/testPath", method = RequestMethod.GET) +public class SwaggerTestTarget_ValueOverWritePath { + @RequestMapping + public void method() { + + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestParam.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestParam.java new file mode 100644 index 00000000000..ab96c6a8daf --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestParam.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +public class TestParam { + private String name; + + private int age; + + public String getName() { + return name; + } + + public TestParam setName(String name) { + this.name = name; + return this; + } + + public int getAge() { + return age; + } + + public TestParam setAge(int age) { + this.age = age; + return this; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestProducer.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestProducer.java new file mode 100644 index 00000000000..3dcfee2026e --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/TestProducer.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model; + +import jakarta.ws.rs.core.MediaType; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@RequestMapping(path = "/") +public class TestProducer { + @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_XML, produces = MediaType.APPLICATION_XML) + public String testSingleMediaType(String input) { + return input; + } + + @RequestMapping(method = RequestMethod.PUT, consumes = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}, + produces = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) + public String testMultipleMediaType(String input) { + return input; + } + + @RequestMapping(method = RequestMethod.POST, consumes = "", produces = "") + public String testBlankMediaType(String input) { + return input; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModel.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModel.java new file mode 100644 index 00000000000..eab9313fb71 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModel.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model.same1; + +public class SameModel { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModelThrow.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModelThrow.java new file mode 100644 index 00000000000..06a1f61769a --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same1/SameModelThrow.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model.same1; + +public class SameModelThrow { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModel.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModel.java new file mode 100644 index 00000000000..afa8c27fc52 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModel.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model.same2; + +public class SameModel { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModelThrow.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModelThrow.java new file mode 100644 index 00000000000..f7c7d52749b --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/same2/SameModelThrow.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.generator.springmvc.model.same2; + +public class SameModelThrow { + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java deleted file mode 100644 index 35d829aac4c..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessorTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import io.swagger.annotations.Api; -import mockit.Mock; -import mockit.MockUp; - -public class RequestMappingClassAnnotationProcessorTest { - - private RequestMappingClassAnnotationProcessor processor = new RequestMappingClassAnnotationProcessor(); - - @Test - public void process() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - processor.process(SwaggerTestTarget.class.getAnnotation(RequestMapping.class), swaggerGenerator); - - Assert.assertEquals("/test", swaggerGenerator.getSwagger().getBasePath()); - Assert.assertEquals("post", swaggerGenerator.getHttpMethod()); - Assert.assertThat(swaggerGenerator.getSwagger().getConsumes(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - Assert.assertThat(swaggerGenerator.getSwagger().getProduces(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - } - - /** - * {@link RequestMapping#value()} takes higher priority than {@link RequestMapping#path()} - */ - @Test - public void process_ValueOverWritePath() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - processor.process(SwaggerTestTarget_ValueOverWritePath.class.getAnnotation(RequestMapping.class), swaggerGenerator); - - Assert.assertEquals("/testValue", swaggerGenerator.getSwagger().getBasePath()); - } - - /** - * {@link RequestMapping} takes higher priority than {@link Api} on setting {@code consumes} and {@code produces} - */ - @Test - public void process_OverWriteConsumesAndProduces() { - SwaggerGenerator swaggerGenerator = getSwaggerGenerator(); - swaggerGenerator.getSwagger().addConsumes(MediaType.APPLICATION_XML); - swaggerGenerator.getSwagger().addProduces(MediaType.APPLICATION_XML); - processor.process(SwaggerTestTarget.class.getAnnotation(RequestMapping.class), swaggerGenerator); - - Assert.assertThat(swaggerGenerator.getSwagger().getConsumes(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - Assert.assertThat(swaggerGenerator.getSwagger().getProduces(), - Matchers.contains(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - } - - private SwaggerGenerator getSwaggerGenerator() { - SwaggerGeneratorContext swaggerGeneratorContext = new MockUp() { - @Mock - String resolveStringValue(String strVal) { - return strVal; - } - }.getMockInstance(); - - return new SwaggerGenerator(swaggerGeneratorContext, null); - } - - @RequestMapping(path = "/test", method = RequestMethod.POST, - consumes = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}, - produces = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) - private class SwaggerTestTarget { - } - - @RequestMapping(value = "/testValue", path = "/testPath") - private class SwaggerTestTarget_ValueOverWritePath { - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessorTest.java deleted file mode 100644 index 04cfaf51a9b..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingMethodAnnotationProcessorTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; - -import javax.ws.rs.core.MediaType; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import io.swagger.models.Operation; - -public class RequestMappingMethodAnnotationProcessorTest { - @Test - public void testProcess() throws NoSuchMethodException { - RequestMappingMethodAnnotationProcessor processor = new RequestMappingMethodAnnotationProcessor(); - SwaggerGenerator swaggerGenerator = new SwaggerGenerator(null, null); - OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, null); - Operation operation = operationGenerator.getOperation(); - - RequestMapping annotation = TestProducer.class.getMethod("testSingleMediaType", String.class) - .getAnnotation(RequestMapping.class); - processor.process(annotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.APPLICATION_XML)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.APPLICATION_XML)); - - annotation = TestProducer.class.getMethod("testMultipleMediaType", String.class) - .getAnnotation(RequestMapping.class); - processor.process(annotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - - annotation = TestProducer.class.getMethod("testBlankMediaType", String.class) - .getAnnotation(RequestMapping.class); - processor.process(annotation, operationGenerator); - Assert.assertThat(operation.getConsumes(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - Assert.assertThat(operation.getProduces(), Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON)); - - operation.addConsumes(MediaType.APPLICATION_XML); - operation.addProduces(MediaType.APPLICATION_XML); - Assert.assertThat(operation.getConsumes(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - Assert.assertThat(operation.getProduces(), - Matchers.contains(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - } - - static class TestProducer { - @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_XML, produces = MediaType.APPLICATION_XML) - public String testSingleMediaType(String input) { - return input; - } - - @RequestMapping(method = RequestMethod.PUT, consumes = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}, - produces = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) - public String testMultipleMediaType(String input) { - return input; - } - - @RequestMapping(method = RequestMethod.POST, consumes = "", produces = "") - public String testBlankMediaType(String input) { - return input; - } - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessorTest.java new file mode 100644 index 00000000000..a17f85d1584 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestPartAnnotationProcessorTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation; + +import java.util.List; + +import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +public class RequestPartAnnotationProcessorTest { + @Test + public void testDemoRest() { + UnitTestSwaggerUtils.testSwagger("schemas/DemoRest.yaml", DemoRest.class); + } + + @RequestMapping("/") + public static class DemoRest { + @RequestMapping(method = RequestMethod.POST, path = "/fun") + public void fun(@RequestPart("stringParam") String stringParam, + @RequestPart(name = "intParam") int intParam, + @RequestPart("stringParamArray") String[] stringParamArray, + @RequestPart("stringParamCollection") List stringParamCollection, + @RequestPart("file") MultipartFile file, + @RequestPart("fileArray") MultipartFile[] fileArray, + @RequestPart("fileCollection") List fileCollection) { + } + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java deleted file mode 100644 index 7d948d75073..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import static org.junit.Assert.fail; - -import java.lang.reflect.Method; -import java.util.List; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; -import mockit.Deencapsulation; - -public class SpringmvcDefaultObjectParameterProcessorTest { - - @Test - public void processOnObjectParam() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testObjectParam", "/test", TestParam.class); - - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(2, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("name", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - parameter = providerParameters.get(1); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("age", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("integer", queryParameter.getType()); - Assert.assertEquals("int32", queryParameter.getFormat()); - } - - @Test - public void processOnRecursiveObjectParam() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testRecursiveParam", "/test", - RecursiveParamA.class); - - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(1, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("name", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - } - - @Test - public void processOnRecursiveObjectParamWithNoJsonIgnore() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testRecursiveParamWithNoJsonIgnore", "/test", - RecursiveParamB.class); - - try { - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - fail("an error is expected"); - } catch (Throwable e) { - Assert.assertEquals(Error.class, e.getClass()); - Assert.assertEquals( - "A nesting complex field is found in the query object and this is not supported," - + " field name = [recursiveParamA]. Please remove this field or tag @JsonIgnore on it.", - e.getMessage()); - } - } - - @Test - public void processOnGenericObjectParam() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testGenericObjectParam", "/test", - GenericParam.class); - try { - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - fail("an error is expected"); - } catch (Throwable e) { - Assert.assertEquals(Error.class, e.getClass()); - Assert.assertEquals( - "A nesting complex field is found in the query object and this is not supported," - + " field name = [data]. Please remove this field or tag @JsonIgnore on it.", - e.getMessage()); - } - } - - @Test - public void processOnGenericObjectParamWithJsonIgnore() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testGenericObjectParamWithJsonIgnore", - "/test", - GenericParamWithJsonIgnore.class); - - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(2, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("num", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("integer", queryParameter.getType()); - Assert.assertEquals("int32", queryParameter.getFormat()); - parameter = providerParameters.get(1); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("str", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - } - - @Test - public void processOnGenericSimpleParam() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testGenericSimpleParam", "/test", - GenericParam.class); - - new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(3, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("num", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("integer", queryParameter.getType()); - Assert.assertEquals("int32", queryParameter.getFormat()); - parameter = providerParameters.get(1); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("str", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - parameter = providerParameters.get(2); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("data", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - } - - private OperationGenerator mockOperationGenerator(String providerParamName, String path, Class... classes) - throws NoSuchMethodException { - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - TestProvider.class); - final Method providerMethod = TestProvider.class.getDeclaredMethod(providerParamName, classes); - final OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, providerMethod); - Deencapsulation.setField(operationGenerator, "path", path); - return operationGenerator; - } - - static class TestProvider { - public String testObjectParam(TestParam objParam) { - return objParam.toString(); - } - - public String testRecursiveParam(RecursiveParamA recursiveParamA) { - return null; - } - - public String testRecursiveParamWithNoJsonIgnore(RecursiveParamB recursiveParamB) { - return null; - } - - public String testGenericObjectParam(GenericParam genericParam) { - return genericParam.toString(); - } - - public String testGenericObjectParamWithJsonIgnore(GenericParamWithJsonIgnore genericParam) { - return genericParam.toString(); - } - - public String testGenericSimpleParam(GenericParam genericParam) { - return genericParam.toString(); - } - } - - static class TestParam { - private String name; - - private int age; - - public String getName() { - return name; - } - - public TestParam setName(String name) { - this.name = name; - return this; - } - - public int getAge() { - return age; - } - - public TestParam setAge(int age) { - this.age = age; - return this; - } - } - - static class GenericParam { - private int num; - - private String str; - - T data; - - public int getNum() { - return num; - } - - public void setNum(int num) { - this.num = num; - } - - public String getStr() { - return str; - } - - public void setStr(String str) { - this.str = str; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } - } - - static class GenericParamWithJsonIgnore { - private int num; - - private String str; - - @JsonIgnore - T data; - - public int getNum() { - return num; - } - - public void setNum(int num) { - this.num = num; - } - - public String getStr() { - return str; - } - - public void setStr(String str) { - this.str = str; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } - } - - static class RecursiveParamA { - private String name; - - @JsonIgnore - private RecursiveParamB recursiveParamB; - - @JsonIgnore - private RecursiveParamC recursiveParamC; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public RecursiveParamB getRecursiveParamB() { - return recursiveParamB; - } - - public void setRecursiveParamB( - RecursiveParamB recursiveParamB) { - this.recursiveParamB = recursiveParamB; - } - - public RecursiveParamC getRecursiveParamC() { - return recursiveParamC; - } - - public void setRecursiveParamC( - RecursiveParamC recursiveParamC) { - this.recursiveParamC = recursiveParamC; - } - } - - static class RecursiveParamB { - private int age; - - private RecursiveParamA recursiveParamA; - - private RecursiveParamC recursiveParamC; - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public RecursiveParamA getRecursiveParamA() { - return recursiveParamA; - } - - public void setRecursiveParamA( - RecursiveParamA recursiveParamA) { - this.recursiveParamA = recursiveParamA; - } - - public RecursiveParamC getRecursiveParamC() { - return recursiveParamC; - } - - public void setRecursiveParamC( - RecursiveParamC recursiveParamC) { - this.recursiveParamC = recursiveParamC; - } - } - - static class RecursiveParamC { - private String address; - - private RecursiveParamB recursiveParamB; - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public RecursiveParamB getRecursiveParamB() { - return recursiveParamB; - } - - public void setRecursiveParamB( - RecursiveParamB recursiveParamB) { - this.recursiveParamB = recursiveParamB; - } - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java deleted file mode 100644 index 4d194a1bcc8..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import static org.junit.Assert.fail; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; -import mockit.Deencapsulation; - -public class SpringmvcDefaultParameterProcessorTest { - @Test - public void processOnSimpleParam() throws NoSuchMethodException { - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - TestProvider.class); - final Method providerMethod = TestProvider.class.getDeclaredMethod("testSimpleParam", String.class); - final OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, providerMethod); - - new SpringmvcDefaultParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(1, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("strParam", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - } - - @Test - public void processOnObjectParam() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testObjectParam", "/test", TestParam.class); - - new SpringmvcDefaultParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(2, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("name", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - parameter = providerParameters.get(1); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("age", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("integer", queryParameter.getType()); - Assert.assertEquals("int32", queryParameter.getFormat()); - } - - /** - * Map and List param is not supported - */ - @Test - public void processOnUnsupportedParam() throws NoSuchMethodException { - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - TestProvider.class); - final Method providerMethod = TestProvider.class.getDeclaredMethod("testUnsupportedParamType", - int.class, List.class, Map.class); - final OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, providerMethod); - - try { - new SpringmvcDefaultParameterProcessor().process(operationGenerator, 1); - fail("an error is expected!"); - } catch (Error e) { - Assert.assertEquals( - "cannot process parameter [integerList], method=org.apache.servicecomb.swagger.generator.springmvc" - + ".processor.parameter.SpringmvcDefaultParameterProcessorTest$TestProvider:testUnsupportedParamType, " - + "paramIdx=1, type=java.util.List", - e.getMessage()); - } - try { - new SpringmvcDefaultParameterProcessor().process(operationGenerator, 2); - fail("an error is expected!"); - } catch (Error e) { - Assert.assertEquals( - "cannot process parameter [stringMap], method=org.apache.servicecomb.swagger.generator.springmvc" - + ".processor.parameter.SpringmvcDefaultParameterProcessorTest$TestProvider:testUnsupportedParamType, " - + "paramIdx=2, type=java.util.Map", - e.getMessage()); - } - } - - @Test - public void processOnMultiObjectParamsWithSameFieldName() throws NoSuchMethodException { - final OperationGenerator operationGenerator = mockOperationGenerator("testMultiObjParamsWithSameFiledName", "/test", - String.class, TestParam.class, TestParam.class, int.class); - - final SpringmvcDefaultParameterProcessor springmvcDefaultParameterProcessor = new SpringmvcDefaultParameterProcessor(); - springmvcDefaultParameterProcessor.process(operationGenerator, 0); - springmvcDefaultParameterProcessor.process(operationGenerator, 1); - springmvcDefaultParameterProcessor.process(operationGenerator, 2); - springmvcDefaultParameterProcessor.process(operationGenerator, 3); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(2, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("name", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - parameter = providerParameters.get(1); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("age", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - queryParameter = (QueryParameter) parameter; - Assert.assertEquals("integer", queryParameter.getType()); - Assert.assertEquals("int32", queryParameter.getFormat()); - } - - private OperationGenerator mockOperationGenerator(String providerParamName, String path, Class... classes) - throws NoSuchMethodException { - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - TestProvider.class); - final Method providerMethod = TestProvider.class.getDeclaredMethod(providerParamName, classes); - final OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, providerMethod); - Deencapsulation.setField(operationGenerator, "path", path); - return operationGenerator; - } - - static class TestProvider { - public String testSimpleParam(String strParam) { - return strParam; - } - - public String testObjectParam(TestParam objParam) { - return objParam.toString(); - } - - public String testUnsupportedParamType(int i, List integerList, Map stringMap) { - return null; - } - - public String testMultiObjParamsWithSameFiledName(String name, TestParam objParam0, TestParam objParam1, int age) { - return objParam0 + "-" + objParam1; - } - } - - static class TestParam { - private String name; - - private int age; - - public String getName() { - return name; - } - - public TestParam setName(String name) { - this.name = name; - return this; - } - - public int getAge() { - return age; - } - - public TestParam setAge(int age) { - this.age = age; - return this; - } - } -} \ No newline at end of file diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java deleted file mode 100644 index dd29928836d..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter; - -import java.lang.reflect.Method; -import java.util.List; - -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.SpringmvcDefaultParameterProcessorTest.TestProvider; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; - -public class SpringmvcDefaultSimpleParameterProcessorTest { - @Test - public void process() throws NoSuchMethodException { - final SwaggerGenerator swaggerGenerator = new SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class), - TestProvider.class); - final Method providerMethod = TestProvider.class.getDeclaredMethod("testSimpleParam", String.class); - final OperationGenerator operationGenerator = new OperationGenerator(swaggerGenerator, providerMethod); - - new SpringmvcDefaultSimpleParameterProcessor().process(operationGenerator, 0); - - final List providerParameters = operationGenerator.getProviderParameters(); - Assert.assertEquals(1, providerParameters.size()); - Parameter parameter = providerParameters.get(0); - Assert.assertEquals(QueryParameter.class, parameter.getClass()); - Assert.assertEquals("strParam", parameter.getName()); - Assert.assertEquals("query", parameter.getIn()); - QueryParameter queryParameter = (QueryParameter) parameter; - Assert.assertEquals("string", queryParameter.getType()); - } -} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreatorTest.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreatorTest.java new file mode 100644 index 00000000000..5597874ee66 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/property/creator/MultipartFilePropertyCreatorTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.generator.springmvc.property.creator; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.springframework.web.multipart.MultipartFile; + +import io.swagger.v3.oas.models.media.FileSchema; +import io.swagger.v3.oas.models.media.Schema; + +public class MultipartFilePropertyCreatorTest { + private final MultipartFilePropertyCreator multipartFilePropertyCreator = new MultipartFilePropertyCreator(); + + @Test + public void createProperty() { + Schema property = multipartFilePropertyCreator.createProperty(); + MatcherAssert.assertThat(property, Matchers.instanceOf(FileSchema.class)); + } + + @Test + public void classes() { + Class[] classes = multipartFilePropertyCreator.classes(); + MatcherAssert.assertThat(classes, Matchers.arrayContaining(MultipartFile.class)); + } +} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/log4j.properties b/swagger/swagger-generator/generator-springmvc/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml new file mode 100644 index 00000000000..7ba6ea4d9dc --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml @@ -0,0 +1,171 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.DefaultParameterSchema + version: 1.0.0 +servers: +- url: / +paths: + /testBlankMediaType: + post: + operationId: testBlankMediaType + parameters: + - name: input + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testMultipleMediaType: + put: + operationId: testMultipleMediaType + parameters: + - name: input + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string + /testObjectParam: + get: + operationId: testObjectParam + parameters: + - name: name + in: query + schema: + type: string + - name: age + in: query + schema: + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testSimpleParam: + get: + operationId: testSimpleParam + parameters: + - name: strParam + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testSingleMediaType: + post: + operationId: testSingleMediaType + parameters: + - name: input + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + /testUnsupportedParamType: + get: + operationId: testUnsupportedParamType + parameters: + - name: i + in: query + schema: + type: integer + format: int32 + - name: integerList + in: query + schema: + type: array + items: + $ref: "#/components/schemas/TestParam" + - name: stringMap + in: query + schema: + type: object + additionalProperties: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string +components: + schemas: + TestParam: + type: object + properties: + name: + type: string + age: + type: integer + format: int32 + x-java-class: org.apache.servicecomb.swagger.generator.springmvc.model.TestParam diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DemoRest.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DemoRest.yaml new file mode 100644 index 00000000000..9656cc47a5c --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DemoRest.yaml @@ -0,0 +1,64 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.processor.annotation.RequestPartAnnotationProcessorTest$DemoRest + version: 1.0.0 +servers: +- url: / +paths: + /fun: + post: + operationId: fun + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + stringParam: + type: string + intParam: + type: integer + format: int32 + stringParamArray: + type: array + items: + type: string + stringParamCollection: + type: array + items: + type: string + file: + type: string + format: binary + fileArray: + type: array + items: + type: string + format: binary + fileCollection: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/MethodEmptyPath.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/MethodEmptyPath.yaml index cab4658e36c..958dc7d43d7 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/MethodEmptyPath.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/MethodEmptyPath.yaml @@ -32,29 +32,29 @@ paths: operationId: "usingGetMapping" parameters: [] responses: - 200: + "200": description: "response of 200" post: operationId: "usingPostMapping" parameters: [] responses: - 200: + "200": description: "response of 200" put: operationId: "usingPutMapping" parameters: [] responses: - 200: + "200": description: "response of 200" delete: operationId: "usingDeleteMapping" parameters: [] responses: - 200: + "200": description: "response of 200" patch: operationId: "usingPatchMapping" parameters: [] responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/RestControllerWithPathSchema.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/RestControllerWithPathSchema.yaml new file mode 100644 index 00000000000..20786b5d695 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/RestControllerWithPathSchema.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.RestControllerWithPathSchema + version: 1.0.0 +servers: +- url: /prefix +paths: + /testSimpleParam: + get: + operationId: testSimpleParam + parameters: + - name: strParam + in: query + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/asyncResponseEntity.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/asyncResponseEntity.yaml new file mode 100644 index 00000000000..cb3125f8d0f --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/asyncResponseEntity.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "asyncResponseEntity" + parameters: [] + responses: + "200": + description: "response of 200" + schema: + type: "array" + items: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/cookie.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/cookie.yaml new file mode 100644 index 00000000000..5ec6b6d7f95 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/cookie.yaml @@ -0,0 +1,43 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "cookie" + parameters: + - name: "cookie" + in: "cookie" + required: false + type: "integer" + format: "int32" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/defaultParameter.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/defaultParameter.yaml index 98b49ec6f02..f1003fea277 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/defaultParameter.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/defaultParameter.yaml @@ -16,86 +16,83 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodDefaultParameter" - x-java-interface: "gen.cse.ms.ut.MethodDefaultParameterIntf" -basePath: "/MethodDefaultParameter" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodDefaultParameter + version: 1.0.0 +servers: +- url: MethodDefaultParameter paths: - /usingRequestMapping: - put: - operationId: "usingRequestMapping" + /usingDeleteMapping: + delete: + operationId: usingDeleteMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" + "200": + description: response of 200 /usingGetMapping: get: - operationId: "usingGetMapping" + operationId: usingGetMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" - /usingPutMapping: - put: - operationId: "usingPutMapping" + "200": + description: response of 200 + /usingPatchMapping: + patch: + operationId: usingPatchMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" + "200": + description: response of 200 /usingPostMapping: post: - operationId: "usingPostMapping" + operationId: usingPostMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" - /usingPatchMapping: - patch: - operationId: "usingPatchMapping" + "200": + description: response of 200 + /usingPutMapping: + put: + operationId: usingPutMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" - /usingDeleteMapping: - delete: - operationId: "usingDeleteMapping" + "200": + description: response of 200 + /usingRequestMapping: + put: + operationId: usingRequestMapping parameters: - - name: "query" - in: "query" - required: false - type: "integer" - format: "int32" + - name: query + in: query + schema: + type: integer + format: int32 responses: - 200: - description: "response of 200" + "200": + description: response of 200 +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml new file mode 100644 index 00000000000..a2f75700c1f --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml @@ -0,0 +1,278 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo + version: 1.0.0 +servers: +- url: Echo +paths: + /asyncResponseEntity: + put: + operationId: asyncResponseEntity + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: string + /cookie: + put: + operationId: cookie + parameters: + - name: cookie + in: cookie + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: response of 200 + /emptyPath: + put: + operationId: emptyPath + responses: + "200": + description: response of 200 + /enumBody: + put: + operationId: enumBody + requestBody: + content: + application/json: + schema: + type: string + enum: + - RED + - YELLOW + - BLUE + text/plain: + schema: + type: string + enum: + - RED + - YELLOW + - BLUE + required: true + x-name: color + responses: + "200": + description: response of 200 + /inheritHttpMethod: + put: + operationId: inheritHttpMethod + parameters: + - name: query + in: query + schema: + type: integer + format: int32 + responses: + "200": + description: response of 200 + /nestedListString: + put: + operationId: nestedListString + requestBody: + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: array + items: + type: string + required: true + x-name: param + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + type: array + items: + type: string + text/plain: + schema: + type: array + items: + type: array + items: + type: string + /part: + put: + operationId: part + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: string + format: binary + responses: + "200": + description: response of 200 + /partAnnotation: + put: + operationId: partAnnotation + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: string + format: binary + responses: + "200": + description: response of 200 + /partArray: + put: + operationId: partArray + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + /partArrayAnnotation: + put: + operationId: partArrayAnnotation + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + /partList: + put: + operationId: partList + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + /partListAnnotation: + put: + operationId: partListAnnotation + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + part: + type: array + items: + type: string + format: binary + responses: + "200": + description: response of 200 + /rawJsonStringMethod: + put: + operationId: rawJsonStringMethod + requestBody: + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string + required: true + x-raw-json: true + x-name: jsonInput + responses: + "200": + description: response of 200 + /testCompletableFutureResponseEntityOptional: + put: + operationId: testCompletableFutureResponseEntityOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string + /testResponseEntityOptional: + put: + operationId: testResponseEntityOptional + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + text/plain: + schema: + type: string +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/emptyPath.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/emptyPath.yaml index 6b760529b84..cd9b531492b 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/emptyPath.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/emptyPath.yaml @@ -16,23 +16,16 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" - x-java-interface: "gen.cse.ms.ut.EchoIntf" -basePath: "/Echo" -consumes: -- "a" -- "b" -produces: -- "a" -- "b" + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo + version: 1.0.0 +servers: +- url: Echo paths: /: put: - operationId: "emptyPath" - parameters: [] + operationId: emptyPath responses: - 200: - description: "response of 200" + "200": + description: response of 200 diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/enumBody.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/enumBody.yaml index b7e877b713c..449ac41cf2c 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/enumBody.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/enumBody.yaml @@ -43,5 +43,5 @@ paths: - "YELLOW" - "BLUE" responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/inheritHttpMethod.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/inheritHttpMethod.yaml index 86f5c579a2c..69f8051f284 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/inheritHttpMethod.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/inheritHttpMethod.yaml @@ -39,5 +39,5 @@ paths: type: "integer" format: "int32" responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml index 3b5fe1dec37..25f68d289f4 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml @@ -16,241 +16,575 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodMixupAnnotations" - x-java-interface: "gen.cse.ms.ut.MethodMixupAnnotationsIntf" -basePath: "/MethodMixupAnnotations" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodMixupAnnotations + version: 1.0.0 +servers: +- url: MethodMixupAnnotations paths: + /bytes: + get: + operationId: bytes + requestBody: + content: + application/json: + schema: + type: string + format: byte + application/protobuf: + schema: + type: string + format: byte + text/plain: + schema: + type: string + format: byte + required: true + x-name: value + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + format: byte + application/protobuf: + schema: + type: string + format: byte + text/plain: + schema: + type: string + format: byte + /defaultQueryParam: + post: + operationId: defaultQueryParam + parameters: + - name: prefix + in: query + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + $ref: "#/components/schemas/User" + text/plain: + schema: + $ref: "#/components/schemas/User" + required: true + x-name: user + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /diffNames: + get: + summary: differentName + operationId: differentName + parameters: + - name: x + in: query + required: true + schema: + type: integer + format: int32 + - name: "y" + in: query + required: true + schema: + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + application/protobuf: + schema: + type: integer + format: int32 + text/plain: + schema: + type: integer + format: int32 + /upload: + post: + operationId: fileUpload + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file1: + type: string + format: binary + someFile: + type: string + format: binary + responses: + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + /reduce: + get: + operationId: reduce + parameters: + - name: b + in: cookie + required: true + schema: + type: integer + format: int32 + - name: a + in: query + required: false + schema: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: integer + format: int32 + application/protobuf: + schema: + type: integer + format: int32 + text/plain: + schema: + type: integer + format: int32 + /testDefaultValue: + get: + operationId: testDefaultValue + parameters: + - name: e + in: query + required: false + schema: + type: integer + format: int32 + - name: a + in: header + required: false + schema: + type: integer + format: int32 + default: 20 + - name: b + in: cookie + required: false + schema: + type: string + default: bobo + - name: c + in: query + required: false + schema: + type: integer + format: int32 + default: 40 + - name: d + in: query + required: false + schema: + maximum: 30 + minimum: 20 + type: integer + format: int32 + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testImplicitForm: + post: + operationId: testImplicitForm + requestBody: + content: + application/x-www-form-urlencoded: + schema: + properties: + form1: + type: string + description: a required form param + nullable: false + example: "" + form2: + type: string + description: an optional form param + nullable: true + example: "" + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /testLocalDateTime: + get: + operationId: testLocalDateTime + parameters: + - name: date + in: query + required: true + schema: + type: string + format: date-time + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + format: date-time + application/protobuf: + schema: + type: string + format: date-time + text/plain: + schema: + type: string + format: date-time + /uploadFileAndAttribute: + post: + operationId: uploadFileAndAttribute + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + attribute: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string + /uploadFilesAndAttribute: + post: + operationId: uploadFilesAndAttribute + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + files: + type: array + items: + type: string + format: binary + attribute: + type: string + responses: + "200": + description: response of 200 + content: + application/json: + schema: + type: string + application/protobuf: + schema: + type: string + text/plain: + schema: + type: string /usingDeleteMapping/{targetName}: delete: - operationId: "usingDeleteMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingDeleteMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "targetName" - in: "path" - required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string /usingGetMapping/{targetName}: get: - operationId: "usingGetMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingGetMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "targetName" - in: "path" - required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string /usingPatchMapping/{targetName}: patch: - operationId: "usingPatchMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingPatchMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" - required: true - type: "string" - - name: "targetName" - in: "path" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string /usingPostMapping/{targetName}: post: - operationId: "usingPostMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingPostMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "targetName" - in: "path" - required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string /usingPutMapping/{targetName}: put: - operationId: "usingPutMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingPutMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" - required: true - type: "string" - - name: "targetName" - in: "path" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string /usingRequestMapping/{targetName}: post: - operationId: "usingRequestMapping" - consumes: - - "text/plain" - - "application/*" - produces: - - "text/plain" - - "application/*" + operationId: usingRequestMapping parameters: - - in: "body" - name: "srcUser" + - name: header + in: header required: true schema: - $ref: "#/definitions/User" - - name: "header" - in: "header" + type: string + - name: targetName + in: path required: true - type: "string" - - name: "targetName" - in: "path" - required: true - type: "string" - - name: "word" - in: "query" + schema: + type: string + - name: word + in: query required: true - type: "string" - - name: "form" - in: "formData" + schema: + type: string + requestBody: + content: + text/plain: + schema: + $ref: "#/components/schemas/User" + application/json: + schema: + $ref: "#/components/schemas/User" required: true - type: "string" + x-name: srcUser responses: - 200: - description: "response of 200" - schema: - type: "string" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" + "200": + description: response of 200 + content: + text/plain: + schema: + type: string + application/json: + schema: + type: string +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.foundation.test.scaffolding.model.User diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/nestedListString.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/nestedListString.yaml new file mode 100644 index 00000000000..4375c9e0b39 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/nestedListString.yaml @@ -0,0 +1,53 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /nestedListString: + post: + operationId: "nestedListString" + parameters: + - in: "body" + name: "param" + required: true + schema: + type: "array" + items: + type: "array" + items: + type: "string" + responses: + "200": + description: "response of 200" + schema: + type: "array" + items: + type: "array" + items: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/part.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/part.yaml new file mode 100644 index 00000000000..fcfa80f5b43 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/part.yaml @@ -0,0 +1,44 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "part" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: false + type: "file" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partAnnotation.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partAnnotation.yaml new file mode 100644 index 00000000000..1d12b4283ab --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partAnnotation.yaml @@ -0,0 +1,44 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "partAnnotation" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: true + type: "file" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArray.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArray.yaml new file mode 100644 index 00000000000..579eb52cd0c --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArray.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "partArray" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: false + type: "array" + items: + type: "file" + collectionFormat: "multi" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArrayAnnotation.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArrayAnnotation.yaml new file mode 100644 index 00000000000..510e0a68e21 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partArrayAnnotation.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "partArrayAnnotation" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: true + type: "array" + items: + type: "file" + collectionFormat: "multi" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partList.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partList.yaml new file mode 100644 index 00000000000..f1621bf6077 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partList.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "partList" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: false + type: "array" + items: + type: "file" + collectionFormat: "multi" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partListAnnotation.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partListAnnotation.yaml new file mode 100644 index 00000000000..1adfd9ac37a --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/partListAnnotation.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "partListAnnotation" + consumes: + - "multipart/form-data" + parameters: + - name: "part" + in: "formData" + required: true + type: "array" + items: + type: "file" + collectionFormat: "multi" + responses: + "200": + description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/rawJsonStringMethod.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/rawJsonStringMethod.yaml index bed74e27bf3..94c17f0b76c 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/rawJsonStringMethod.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/rawJsonStringMethod.yaml @@ -40,5 +40,5 @@ paths: type: "string" x-raw-json: true responses: - 200: + "200": description: "response of 200" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/requestMappingHttpMethod.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/requestMappingHttpMethod.yaml new file mode 100644 index 00000000000..dade54c3f01 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/requestMappingHttpMethod.yaml @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.ClassMethodNoHttpMethod + version: 1.0.0 +servers: +- url: c +paths: + /m: + get: + operationId: noHttpMethod + responses: + "200": + description: response of 200 +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/responseEntity.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/responseEntity.yaml index 455afb440e6..c3763d4600d 100644 --- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/responseEntity.yaml +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/responseEntity.yaml @@ -16,91 +16,154 @@ ## --------------------------------------------------------------------------- --- -swagger: "2.0" +openapi: 3.0.1 info: - version: "1.0.0" - title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodResponseEntity" - x-java-interface: "gen.cse.ms.ut.MethodResponseEntityIntf" -basePath: "/MethodResponseEntity" -consumes: -- "application/json" -produces: -- "application/json" + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.MethodResponseEntity + version: 1.0.0 +servers: +- url: MethodResponseEntity paths: /usingDeleteMapping: delete: - operationId: "usingDeleteMapping" - parameters: [] + operationId: usingDeleteMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" /usingGetMapping: get: - operationId: "usingGetMapping" - parameters: [] + operationId: usingGetMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" /usingPatchMapping: patch: - operationId: "usingPatchMapping" - parameters: [] + operationId: usingPatchMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" /usingPostMapping: post: - operationId: "usingPostMapping" - parameters: [] + operationId: usingPostMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" /usingPutMapping: put: - operationId: "usingPutMapping" - parameters: [] + operationId: usingPutMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" /usingRequestMapping: put: - operationId: "usingRequestMapping" - parameters: [] + operationId: usingRequestMapping responses: - 200: - description: "response of 200" - schema: - type: "array" - items: - $ref: "#/definitions/User" -definitions: - User: - type: "object" - properties: - name: - type: "string" - friends: - type: "array" - items: - $ref: "#/definitions/User" - x-java-class: "org.apache.servicecomb.foundation.test.scaffolding.model.User" + "200": + description: response of 200 + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/User" + application/protobuf: + schema: + type: array + items: + $ref: "#/components/schemas/User" + text/plain: + schema: + type: array + items: + $ref: "#/components/schemas/User" +components: + schemas: + User: + type: object + properties: + name: + type: string + friends: + type: array + items: + $ref: "#/components/schemas/User" + x-java-class: org.apache.servicecomb.foundation.test.scaffolding.model.User diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget.yaml new file mode 100644 index 00000000000..ea7c551bff2 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget.yaml @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.SwaggerTestTarget + version: 1.0.0 +servers: +- url: /test +paths: + /: + post: + operationId: method + responses: + "200": + description: response of 200 +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget_ValueOverWritePath.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget_ValueOverWritePath.yaml new file mode 100644 index 00000000000..781f06649f2 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/swaggerTestTarget_ValueOverWritePath.yaml @@ -0,0 +1,32 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +openapi: 3.0.1 +info: + title: swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.SwaggerTestTarget_ValueOverWritePath + version: 1.0.0 +servers: +- url: /testValue +paths: + /: + get: + operationId: method + responses: + "200": + description: response of 200 +components: {} diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testBlankMediaType.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testBlankMediaType.yaml new file mode 100644 index 00000000000..242dec4d4ce --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testBlankMediaType.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.TestProducer" + x-java-interface: "gen.cse.ms.ut.TestProducerIntf" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /: + post: + operationId: "testBlankMediaType" + parameters: + - name: "input" + in: "query" + required: false + type: "string" + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testCompletableFutureResponseEntityOptional.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testCompletableFutureResponseEntityOptional.yaml new file mode 100644 index 00000000000..d7970e1a099 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testCompletableFutureResponseEntityOptional.yaml @@ -0,0 +1,40 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "testCompletableFutureResponseEntityOptional" + parameters: [] + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testMultipleMediaType.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testMultipleMediaType.yaml new file mode 100644 index 00000000000..4ecccae23fb --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testMultipleMediaType.yaml @@ -0,0 +1,48 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.TestProducer" + x-java-interface: "gen.cse.ms.ut.TestProducerIntf" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /: + put: + operationId: "testMultipleMediaType" + consumes: + - "text/plain" + - "application/json" + produces: + - "text/plain" + - "application/json" + parameters: + - name: "input" + in: "query" + required: false + type: "string" + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testObjectParam.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testObjectParam.yaml new file mode 100644 index 00000000000..a28f15bfc84 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testObjectParam.yaml @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.DefaultParameterSchema" + x-java-interface: "gen.cse.ms.ut.DefaultParameterSchemaIntf" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /testObjectParam: + get: + operationId: "testObjectParam" + parameters: + - name: "name" + in: "query" + required: false + type: "string" + - name: "age" + in: "query" + required: false + type: "integer" + format: "int32" + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testResponseEntityOptional.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testResponseEntityOptional.yaml new file mode 100644 index 00000000000..b31a1731ff3 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testResponseEntityOptional.yaml @@ -0,0 +1,40 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.Echo" + x-java-interface: "gen.cse.ms.ut.EchoIntf" +basePath: "/Echo" +consumes: +- "a" +- "b" +produces: +- "a" +- "b" +paths: + /: + put: + operationId: "testResponseEntityOptional" + parameters: [] + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSimpleParam.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSimpleParam.yaml new file mode 100644 index 00000000000..a6406ff606d --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSimpleParam.yaml @@ -0,0 +1,42 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.DefaultParameterSchema" + x-java-interface: "gen.cse.ms.ut.DefaultParameterSchemaIntf" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /testSimpleParam: + get: + operationId: "testSimpleParam" + parameters: + - name: "strParam" + in: "query" + required: false + type: "string" + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSingleMediaType.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSingleMediaType.yaml new file mode 100644 index 00000000000..47f8bd011c4 --- /dev/null +++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/testSingleMediaType.yaml @@ -0,0 +1,46 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +--- +swagger: "2.0" +info: + version: "1.0.0" + title: "swagger definition for org.apache.servicecomb.swagger.generator.springmvc.model.TestProducer" + x-java-interface: "gen.cse.ms.ut.TestProducerIntf" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /: + post: + operationId: "testSingleMediaType" + consumes: + - "application/xml" + produces: + - "application/xml" + parameters: + - name: "input" + in: "query" + required: false + type: "string" + responses: + "200": + description: "response of 200" + schema: + type: "string" diff --git a/swagger/swagger-generator/pom.xml b/swagger/swagger-generator/pom.xml index 6cce91f8281..e9a03a9c579 100644 --- a/swagger/swagger-generator/pom.xml +++ b/swagger/swagger-generator/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-generator Java Chassis::Swagger::Generator @@ -30,5 +30,6 @@ generator-core generator-jaxrs generator-springmvc + generator-spring-data diff --git a/swagger/swagger-invocation/invocation-core/pom.xml b/swagger/swagger-invocation/invocation-core/pom.xml index 3dd32e48ea6..20897dafd3a 100644 --- a/swagger/swagger-invocation/invocation-core/pom.xml +++ b/swagger/swagger-invocation/invocation-core/pom.xml @@ -21,34 +21,35 @@ org.apache.servicecomb swagger-invocation - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-invocation-core Java Chassis::Swagger::Invocation::Core - org.apache.servicecomb swagger-generator-core + org.apache.servicecomb - swagger-generator-jaxrs + foundation-test-scaffolding - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + swagger-generator-jaxrs test - log4j - log4j + org.apache.servicecomb + swagger-generator-springmvc test - org.springframework - spring-web + org.jmockit + jmockit + test - \ No newline at end of file + diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerBootstrap.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerBootstrap.java deleted file mode 100644 index 2d70995550a..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerBootstrap.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.engine; - -public interface SwaggerBootstrap { - SwaggerEnvironment boot(); -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumer.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumer.java index 25976fe0b83..0925c264248 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumer.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumer.java @@ -16,15 +16,18 @@ */ package org.apache.servicecomb.swagger.engine; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.annotations.VisibleForTesting; public class SwaggerConsumer { private Class consumerIntf; - private Class swaggerIntf; - - private Map opMap = new HashMap<>(); + // key is consumer method name + private final Map operations = new HashMap<>(); public Class getConsumerIntf() { return consumerIntf; @@ -34,19 +37,25 @@ public void setConsumerIntf(Class consumerIntf) { this.consumerIntf = consumerIntf; } - public Class getSwaggerIntf() { - return swaggerIntf; + public void addOperation(SwaggerConsumerOperation op) { + operations.put(op.getConsumerMethod(), op); } - public void setSwaggerIntf(Class swaggerIntf) { - this.swaggerIntf = swaggerIntf; + @VisibleForTesting + public SwaggerConsumerOperation findOperation(String consumerMethodName) { + for (Entry operationEntry : operations.entrySet()) { + if (operationEntry.getKey().getName().equals(consumerMethodName)) { + return operationEntry.getValue(); + } + } + return null; } - public void addOperation(SwaggerConsumerOperation op) { - opMap.put(op.getName(), op); + public SwaggerConsumerOperation findOperation(Method consumerMethod) { + return operations.get(consumerMethod); } - public SwaggerConsumerOperation findOperation(String name) { - return opMap.get(name); + public Map getOperations() { + return operations; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumerOperation.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumerOperation.java index b2574e49f23..627119fe9fe 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumerOperation.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerConsumerOperation.java @@ -17,28 +17,27 @@ package org.apache.servicecomb.swagger.engine; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; -import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapper; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; public class SwaggerConsumerOperation { - private String name; + private Class consumerClass; private Method consumerMethod; - private Method swaggerMethod; + private String[] consumerParameterNames; - private ConsumerArgumentsMapper argumentsMapper; + private SwaggerOperation swaggerOperation; - private ConsumerResponseMapper responseMapper; - - public String getName() { - return name; - } + private ArgumentsMapper argumentsMapper; - public void setName(String name) { - this.name = name; - } + private ConsumerResponseMapper responseMapper; public Method getConsumerMethod() { return consumerMethod; @@ -46,21 +45,33 @@ public Method getConsumerMethod() { public void setConsumerMethod(Method consumerMethod) { this.consumerMethod = consumerMethod; + + this.consumerParameterNames = Arrays.stream(consumerMethod.getParameters()) + .map(Parameter::getName) + .toArray(String[]::new); } - public Method getSwaggerMethod() { - return swaggerMethod; + public Class getConsumerClass() { + return consumerClass; } - public void setSwaggerMethod(Method swaggerMethod) { - this.swaggerMethod = swaggerMethod; + public void setConsumerClass(Class consumerClass) { + this.consumerClass = consumerClass; } - public ConsumerArgumentsMapper getArgumentsMapper() { + public SwaggerOperation getSwaggerOperation() { + return swaggerOperation; + } + + public void setSwaggerOperation(SwaggerOperation swaggerOperation) { + this.swaggerOperation = swaggerOperation; + } + + public ArgumentsMapper getArgumentsMapper() { return argumentsMapper; } - public void setArgumentsMapper(ConsumerArgumentsMapper argumentsMapper) { + public void setArgumentsMapper(ArgumentsMapper argumentsMapper) { this.argumentsMapper = argumentsMapper; } @@ -71,4 +82,12 @@ public ConsumerResponseMapper getResponseMapper() { public void setResponseMapper(ConsumerResponseMapper responseMapper) { this.responseMapper = responseMapper; } + + public Map toInvocationArguments(Object[] args) { + Map arguments = new HashMap<>(); + for (int i = 0; i < consumerParameterNames.length; i++) { + arguments.put(consumerParameterNames[i], args[i]); + } + return arguments; + } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java index 8a5aa2d08fc..655e7a2c6a1 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java @@ -17,107 +17,59 @@ package org.apache.servicecomb.swagger.engine; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; -import javax.inject.Inject; - -import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapper; -import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapperFactory; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperations; +import org.apache.servicecomb.swagger.generator.core.utils.MethodUtils; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; +import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapperCreator; +import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory; import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapper; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperCreator; +import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import io.swagger.annotations.ApiOperation; -import io.swagger.models.Operation; +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.models.OpenAPI; -@Component public class SwaggerEnvironment { private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerEnvironment.class); - @Inject - protected CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext; - - /** - * default producerArgumentsFactory + /* + * For Consumer, first load swagger from resources. Generate one if not exists. */ - @Inject - private ProducerArgumentsMapperFactory producerArgumentsFactory; - - @Autowired - private List producerArgumentsMapperFactoryList = new ArrayList<>(0); - - private ResponseMapperFactorys producerResponseMapperFactorys = - new ResponseMapperFactorys<>(ProducerResponseMapperFactory.class); - - @Inject - private ConsumerArgumentsMapperFactory consumerArgumentsFactory; - - private ResponseMapperFactorys consumerResponseMapperFactorys = - new ResponseMapperFactorys<>(ConsumerResponseMapperFactory.class); - - @Inject - public void setConverterMgr(ConverterMgr converterMgr) { - consumerResponseMapperFactorys.setConverterMgr(converterMgr); - producerResponseMapperFactorys.setConverterMgr(converterMgr); - } - - public CompositeSwaggerGeneratorContext getCompositeSwaggerGeneratorContext() { - return compositeSwaggerGeneratorContext; - } - - public void setCompositeSwaggerGeneratorContext( - CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext) { - this.compositeSwaggerGeneratorContext = compositeSwaggerGeneratorContext; - } - - public ProducerArgumentsMapperFactory getProducerArgumentsFactory() { - return producerArgumentsFactory; - } - - public void setProducerArgumentsFactory(ProducerArgumentsMapperFactory producerArgumentsFactory) { - this.producerArgumentsFactory = producerArgumentsFactory; - } - - public ConsumerArgumentsMapperFactory getConsumerArgumentsFactory() { - return consumerArgumentsFactory; - } + public SwaggerConsumer createConsumer(Class consumerIntf, OpenAPI swagger) { + swagger = checkAndGenerateSwagger(consumerIntf, swagger); - public void setConsumerArgumentsFactory(ConsumerArgumentsMapperFactory consumerArgumentsFactory) { - this.consumerArgumentsFactory = consumerArgumentsFactory; - } + Map, ContextArgumentMapperFactory> contextFactories = SPIServiceUtils + .getOrLoadSortedService(ConsumerContextArgumentMapperFactory.class) + .stream() + .collect(Collectors.toMap(ConsumerContextArgumentMapperFactory::getContextClass, Function.identity())); + ResponseMapperFactories consumerResponseMapperFactories = + new ResponseMapperFactories<>(ConsumerResponseMapperFactory.class); - public SwaggerConsumer createConsumer(Class consumerIntf) { - // consumer interface equals to contract interface - return createConsumer(consumerIntf, consumerIntf); - } + SwaggerOperations swaggerOperations = new SwaggerOperations(swagger); - public SwaggerConsumer createConsumer(Class consumerIntf, Class swaggerIntf) { SwaggerConsumer consumer = new SwaggerConsumer(); consumer.setConsumerIntf(consumerIntf); - consumer.setSwaggerIntf(swaggerIntf); - for (Method consumerMethod : consumerIntf.getMethods()) { - String swaggerMethodName = findSwaggerMethodName(consumerMethod); - // consumer参数不一定等于swagger参数 - Method swaggerMethod = ReflectUtils.findMethod(swaggerIntf, swaggerMethodName); - if (swaggerMethod == null) { - // consumer method set bigger than contract, it's invalid + for (Method consumerMethod : MethodUtils.findSwaggerMethods(consumerIntf)) { + String operationId = findOperationId(consumerMethod); + SwaggerOperation swaggerOperation = swaggerOperations.findOperation(operationId); + if (swaggerOperation == null) { + // consumer method set is bigger than contract, it's invalid // but we need to support consumer upgrade before producer, so only log and ignore it. LOGGER.warn("consumer method {}:{} not exist in contract.", consumerIntf.getName(), @@ -125,20 +77,20 @@ public SwaggerConsumer createConsumer(Class consumerIntf, Class swaggerInt continue; } - ArgumentsMapperConfig config = new ArgumentsMapperConfig(); - config.setSwaggerMethod(swaggerMethod); - config.setProviderMethod(consumerMethod); - - ConsumerArgumentsMapper argsMapper = - consumerArgumentsFactory.createArgumentsMapper(config); - ConsumerResponseMapper responseMapper = consumerResponseMapperFactorys.createResponseMapper( - swaggerMethod.getGenericReturnType(), - consumerMethod.getGenericReturnType()); + ConsumerArgumentsMapperCreator creator = new ConsumerArgumentsMapperCreator( + Json.mapper().getSerializationConfig(), + contextFactories, + consumerIntf, + consumerMethod, + swaggerOperation); + ArgumentsMapper argsMapper = creator.createArgumentsMapper(); + ConsumerResponseMapper responseMapper = consumerResponseMapperFactories + .createResponseMapper(consumerMethod.getGenericReturnType()); SwaggerConsumerOperation op = new SwaggerConsumerOperation(); - op.setName(consumerMethod.getName()); + op.setConsumerClass(consumerIntf); op.setConsumerMethod(consumerMethod); - op.setSwaggerMethod(swaggerMethod); + op.setSwaggerOperation(swaggerOperation); op.setArgumentsMapper(argsMapper); op.setResponseMapper(responseMapper); @@ -148,53 +100,68 @@ public SwaggerConsumer createConsumer(Class consumerIntf, Class swaggerInt return consumer; } - protected String findSwaggerMethodName(Method consumerMethod) { - ApiOperation apiOperationAnnotation = consumerMethod.getAnnotation(ApiOperation.class); - if (apiOperationAnnotation == null || StringUtils.isEmpty(apiOperationAnnotation.nickname())) { - return consumerMethod.getName(); - } + protected String findOperationId(Method consumerMethod) { + return MethodUtils.findSwaggerMethodName(consumerMethod); + } - return apiOperationAnnotation.nickname(); + /* + * For producer, always generate swagger from code. + */ + public SwaggerProducer createProducer(Object producerInstance) { + return createProducer(producerInstance, null); } - public SwaggerProducer createProducer(Object producerInstance, Class swaggerIntf, - Map swaggerOperationMap) { - Class producerCls = BeanUtils.getImplClassFromBean(producerInstance); - Map visibleProducerMethods = retrieveVisibleMethods(producerCls); + /* + * For producer, always generate swagger from code. + */ + public SwaggerProducer createProducer(Object producerInstance, Class schemaInterface) { + Class producerCls = targetSwaggerClass(producerInstance, schemaInterface); + + OpenAPI swagger = SwaggerGenerator.generate(producerCls); + + Map, ContextArgumentMapperFactory> contextFactories = SPIServiceUtils + .getOrLoadSortedService(ProducerContextArgumentMapperFactory.class) + .stream() + .collect(Collectors.toMap(ProducerContextArgumentMapperFactory::getContextClass, Function.identity())); + ResponseMapperFactories producerResponseMapperFactories = + new ResponseMapperFactories<>(ProducerResponseMapperFactory.class); + + SwaggerOperations swaggerOperations = new SwaggerOperations(swagger); + + Map visibleProducerMethods = MethodUtils.findSwaggerMethodsMapOfOperationId(producerCls); SwaggerProducer producer = new SwaggerProducer(); + producer.setSwagger(swagger); producer.setProducerCls(producerCls); - producer.setSwaggerIntf(swaggerIntf); - for (Method swaggerMethod : swaggerIntf.getMethods()) { - String methodName = swaggerMethod.getName(); + producer.setProducerInstance(producerInstance); + for (SwaggerOperation swaggerOperation : swaggerOperations.getOperations().values()) { + String operationId = swaggerOperation.getOperationId(); // producer参数不一定等于swagger参数 - Method producerMethod = visibleProducerMethods.getOrDefault(methodName, null); + Method producerMethod = visibleProducerMethods.getOrDefault(operationId, null); if (producerMethod == null) { // producer未实现契约,非法 - String msg = String.format("swagger method %s not exist in producer %s.", - methodName, + String msg = String.format("operationId %s not exist in producer %s.", + operationId, producerInstance.getClass().getName()); - throw new Error(msg); + throw new IllegalStateException(msg); } - ArgumentsMapperConfig config = new ArgumentsMapperConfig(); - config.setSwaggerMethod(swaggerMethod); - config.setProviderMethod(producerMethod); - config.setSwaggerOperation(swaggerOperationMap.get(methodName)); - config.setSwaggerGeneratorContext(compositeSwaggerGeneratorContext.selectContext(producerCls)); - - ProducerArgumentsMapperFactory argumentsMapperFactory = selectProducerArgumentsMapperFactory(config); - ProducerArgumentsMapper argsMapper = argumentsMapperFactory.createArgumentsMapper(config); - ProducerResponseMapper responseMapper = producerResponseMapperFactorys.createResponseMapper( - swaggerMethod.getGenericReturnType(), + ProducerArgumentsMapperCreator creator = new ProducerArgumentsMapperCreator( + Json.mapper().getSerializationConfig(), + contextFactories, + producerCls, + producerMethod, + swaggerOperation); + ProducerArgumentsMapper argsMapper = creator.createArgumentsMapper(); + ProducerResponseMapper responseMapper = producerResponseMapperFactories.createResponseMapper( producerMethod.getGenericReturnType()); SwaggerProducerOperation op = new SwaggerProducerOperation(); - op.setName(methodName); op.setProducerClass(producerCls); op.setProducerInstance(producerInstance); op.setProducerMethod(producerMethod); - op.setSwaggerMethod(swaggerMethod); + op.setSwaggerOperation(swaggerOperation); + op.setSwaggerParameterTypes(creator.getSwaggerParameterTypes()); op.setArgumentsMapper(argsMapper); op.setResponseMapper(responseMapper); @@ -204,37 +171,17 @@ public SwaggerProducer createProducer(Object producerInstance, Class swaggerI return producer; } - ProducerArgumentsMapperFactory selectProducerArgumentsMapperFactory(ArgumentsMapperConfig config) { - ProducerArgumentsMapperFactory argumentsMapperFactory = null; - for (ProducerArgumentsMapperFactory producerArgumentsMapperFactory : this.producerArgumentsMapperFactoryList) { - if (producerArgumentsMapperFactory.canProcess(config)) { - argumentsMapperFactory = producerArgumentsMapperFactory; - break; - } - } - if (null == argumentsMapperFactory) { - argumentsMapperFactory = this.producerArgumentsFactory; + private OpenAPI checkAndGenerateSwagger(Class swaggerClass, OpenAPI swagger) { + if (swagger == null) { + swagger = SwaggerGenerator.generate(swaggerClass); } - return argumentsMapperFactory; + return swagger; } - private Map retrieveVisibleMethods(Class clazz) { - Map visibleMethods = new HashMap<>(); - for (Method method : clazz.getMethods()) { - String methodName = method.getName(); - ApiOperation apiOperationAnnotation = method.getAnnotation(ApiOperation.class); - if (apiOperationAnnotation != null) { - if (apiOperationAnnotation.hidden()) { - continue; - } - - if (StringUtils.isNotEmpty(apiOperationAnnotation.nickname())) { - methodName = apiOperationAnnotation.nickname(); - } - } - - visibleMethods.put(methodName, method); + private Class targetSwaggerClass(Object producerInstance, Class schemaInterface) { + if (schemaInterface != null && !Object.class.equals(schemaInterface)) { + return schemaInterface; } - return visibleMethods; + return BeanUtils.getImplClassFromBean(producerInstance); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducer.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducer.java index d1e9eef042e..43d0577937a 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducer.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducer.java @@ -20,12 +20,17 @@ import java.util.HashMap; import java.util.Map; +import io.swagger.v3.oas.models.OpenAPI; + public class SwaggerProducer { private Class producerCls; - private Class swaggerIntf; + private Object producerInstance; + + private OpenAPI swagger; - private Map opMap = new HashMap<>(); + // key is operationId + private final Map opMap = new HashMap<>(); public Class getProducerCls() { return producerCls; @@ -35,20 +40,28 @@ public void setProducerCls(Class producerCls) { this.producerCls = producerCls; } - public Class getSwaggerIntf() { - return swaggerIntf; + public Object getProducerInstance() { + return producerInstance; + } + + public void setProducerInstance(Object producerInstance) { + this.producerInstance = producerInstance; + } + + public OpenAPI getSwagger() { + return swagger; } - public void setSwaggerIntf(Class swaggerIntf) { - this.swaggerIntf = swaggerIntf; + public void setSwagger(OpenAPI swagger) { + this.swagger = swagger; } public void addOperation(SwaggerProducerOperation op) { - opMap.put(op.getName(), op); + opMap.put(op.getOperationId(), op); } - public SwaggerProducerOperation findOperation(String name) { - return opMap.get(name); + public SwaggerProducerOperation findOperation(String operationId) { + return opMap.get(operationId); } public Collection getAllOperations() { diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java index cca21c5da8e..ad4728aacff 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java @@ -16,27 +16,15 @@ */ package org.apache.servicecomb.swagger.engine; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.List; -import java.util.concurrent.CompletableFuture; +import java.lang.reflect.Type; +import java.util.Map; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapper; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.extension.ProducerInvokeExtension; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; public class SwaggerProducerOperation { - private String name; // 因为存在aop场景,所以,producerClass不一定等于producerInstance.getClass() private Class producerClass; @@ -45,21 +33,19 @@ public class SwaggerProducerOperation { private Method producerMethod; - private Method swaggerMethod; + private SwaggerOperation swaggerOperation; + + // swagger parameter types relate to producer + // because features of @BeanParam/query wrapper/rpc mode parameter wrapper + // types is not direct equals to producerMethod parameter types + private Map swaggerParameterTypes; private ProducerArgumentsMapper argumentsMapper; private ProducerResponseMapper responseMapper; - private List producerInvokeExtenstionList = - SPIServiceUtils.getSortedService(ProducerInvokeExtension.class); - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; + public String getOperationId() { + return swaggerOperation.getOperationId(); } public Class getProducerClass() { @@ -86,12 +72,21 @@ public void setProducerMethod(Method producerMethod) { this.producerMethod = producerMethod; } - public Method getSwaggerMethod() { - return swaggerMethod; + public SwaggerOperation getSwaggerOperation() { + return swaggerOperation; + } + + public void setSwaggerOperation(SwaggerOperation swaggerOperation) { + this.swaggerOperation = swaggerOperation; + } + + + public Map getSwaggerParameterTypes() { + return swaggerParameterTypes; } - public void setSwaggerMethod(Method swaggerMethod) { - this.swaggerMethod = swaggerMethod; + public void setSwaggerParameterTypes(Map swaggerParameterTypes) { + this.swaggerParameterTypes = swaggerParameterTypes; } public ProducerArgumentsMapper getArgumentsMapper() { @@ -110,98 +105,7 @@ public void setResponseMapper(ProducerResponseMapper responseMapper) { this.responseMapper = responseMapper; } - public void invoke(SwaggerInvocation invocation, AsyncResponse asyncResp) { - if (CompletableFuture.class.equals(producerMethod.getReturnType())) { - completableFutureInvoke(invocation, asyncResp); - return; - } - - syncInvoke(invocation, asyncResp); - } - - public void completableFutureInvoke(SwaggerInvocation invocation, AsyncResponse asyncResp) { - ContextUtils.setInvocationContext(invocation); - doCompletableFutureInvoke(invocation, asyncResp); - ContextUtils.removeInvocationContext(); - } - - @SuppressWarnings("unchecked") - public void doCompletableFutureInvoke(SwaggerInvocation invocation, AsyncResponse asyncResp) { - try { - invocation.onBusinessMethodStart(); - - Object[] args = argumentsMapper.toProducerArgs(invocation); - for (ProducerInvokeExtension producerInvokeExtension : producerInvokeExtenstionList) { - producerInvokeExtension.beforeMethodInvoke(invocation, this, args); - } - - Object result = producerMethod.invoke(producerInstance, args); - invocation.onBusinessMethodFinish(); - - ((CompletableFuture) result).whenComplete((realResult, ex) -> { - invocation.onBusinessFinish(); - if (ex == null) { - asyncResp.handle(responseMapper.mapResponse(invocation.getStatus(), realResult)); - return; - } - - asyncResp.handle(processException(invocation, ex)); - }); - } catch (IllegalArgumentException ae) { - invocation.onBusinessMethodFinish(); - invocation.onBusinessFinish(); - asyncResp.handle(processException(invocation, - new InvocationException(Status.BAD_REQUEST.getStatusCode(), "", - new CommonExceptionData("Parameters not valid or types not match."), ae))); - } catch (Throwable e) { - invocation.onBusinessMethodFinish(); - invocation.onBusinessFinish(); - asyncResp.handle(processException(invocation, e)); - } - } - - public void syncInvoke(SwaggerInvocation invocation, AsyncResponse asyncResp) { - ContextUtils.setInvocationContext(invocation); - Response response = doInvoke(invocation); - ContextUtils.removeInvocationContext(); - asyncResp.handle(response); - } - - public Response doInvoke(SwaggerInvocation invocation) { - Response response = null; - try { - invocation.onBusinessMethodStart(); - - Object[] args = argumentsMapper.toProducerArgs(invocation); - for (ProducerInvokeExtension producerInvokeExtension : producerInvokeExtenstionList) { - producerInvokeExtension.beforeMethodInvoke(invocation, this, args); - } - - Object result = producerMethod.invoke(producerInstance, args); - response = responseMapper.mapResponse(invocation.getStatus(), result); - - invocation.onBusinessMethodFinish(); - invocation.onBusinessFinish(); - } catch (IllegalArgumentException ae) { - invocation.onBusinessMethodFinish(); - invocation.onBusinessFinish(); - // ae.getMessage() is always null. Give a custom error message. - response = processException(invocation, - new InvocationException(Status.BAD_REQUEST.getStatusCode(), "", - new CommonExceptionData("Parameters not valid or types not match."), ae)); - } catch (Throwable e) { - invocation.onBusinessMethodFinish(); - invocation.onBusinessFinish(); - response = processException(invocation, e); - } - return response; - } - - protected Response processException(SwaggerInvocation invocation, Throwable e) { - if (InvocationTargetException.class.isInstance(e)) { - e = ((InvocationTargetException) e).getTargetException(); - } - - return ExceptionFactory.convertExceptionToResponse(invocation, e); + public Type getSwaggerParameterType(String name) { + return this.swaggerParameterTypes.get(name); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java deleted file mode 100644 index 9ed501a58de..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.engine.bootstrap; - -import java.util.Arrays; - -import org.apache.servicecomb.swagger.engine.SwaggerBootstrap; -import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; -import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerInvocationContextMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerInvocationContextMapperFactory; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; - -public class BootstrapNormal implements SwaggerBootstrap { - public SwaggerEnvironment boot() { - SwaggerEnvironment env = new SwaggerEnvironment(); - - ConverterMgr converterMgr = new ConverterMgr(); - - ProducerArgumentsMapperFactory producerArgumentsFactory = new ProducerArgumentsMapperFactory(); - producerArgumentsFactory.setFactoryList(Arrays.asList(new ProducerInvocationContextMapperFactory())); - producerArgumentsFactory.setConverterMgr(converterMgr); - env.setProducerArgumentsFactory(producerArgumentsFactory); - - ConsumerArgumentsMapperFactory consumerArgumentsFactory = new ConsumerArgumentsMapperFactory(); - consumerArgumentsFactory.setFactoryList(Arrays.asList(new ConsumerInvocationContextMapperFactory())); - consumerArgumentsFactory.setConverterMgr(converterMgr); - env.setConsumerArgumentsFactory(consumerArgumentsFactory); - - env.setConverterMgr(converterMgr); - env.setCompositeSwaggerGeneratorContext(new CompositeSwaggerGeneratorContext()); - - return env; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/unittest/LocalProducerInvoker.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/unittest/LocalProducerInvoker.java deleted file mode 100644 index 31bf31abcf4..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/unittest/LocalProducerInvoker.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.engine.unittest; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.swagger.engine.SwaggerConsumer; -import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; -import org.apache.servicecomb.swagger.engine.SwaggerProducer; -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -public class LocalProducerInvoker implements InvocationHandler { - private Object proxy; - - private SwaggerConsumer consumer; - - private SwaggerProducer producer; - - private SwaggerInvocation invocation; - - private Response producerResponse; - - public LocalProducerInvoker(SwaggerConsumer consumer, SwaggerProducer producer) { - this.consumer = consumer; - this.producer = producer; - - proxy = Proxy.newProxyInstance(consumer.getConsumerIntf().getClassLoader(), - new Class[] {consumer.getConsumerIntf()}, - this); - } - - @SuppressWarnings("unchecked") - public T getProxy() { - return (T) proxy; - } - - public SwaggerInvocation getInvocation() { - return invocation; - } - - public T getSwaggerArgument(int idx) { - return invocation.getSwaggerArgument(idx); - } - - public String getContext(String key) { - return invocation.getContext(key); - } - - public Response getProducerResponse() { - return producerResponse; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - invocation = new SwaggerInvocation(); - - SwaggerConsumerOperation consumerOp = consumer.findOperation(method.getName()); - SwaggerProducerOperation producerOp = producer.findOperation(consumerOp.getSwaggerMethod().getName()); - - consumerOp.getArgumentsMapper().toInvocation(args, invocation); - - CompletableFuture future = new CompletableFuture<>(); - producerOp.invoke(invocation, ar -> { - producerResponse = ar; - Object realResult = consumerOp.getResponseMapper().mapResponse(producerResponse); - future.complete(realResult); - }); - - if (CompletableFuture.class.equals(method.getReturnType())) { - return future; - } - - return future.get(); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/InvocationContextParameter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/InvocationContextParameter.java deleted file mode 100644 index 6d838d8d300..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/extend/parameter/InvocationContextParameter.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.extend.parameter; - -import io.swagger.models.parameters.AbstractParameter; - -public class InvocationContextParameter extends AbstractParameter implements ContextParameter { - -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/AsyncResponse.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/AsyncResponse.java index e8b8895898c..0e0bffa24cb 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/AsyncResponse.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/AsyncResponse.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.swagger.invocation; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; public interface AsyncResponse { void handle(Response response); diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/InvocationType.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/InvocationType.java index 9ce4273a204..351c876de71 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/InvocationType.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/InvocationType.java @@ -19,5 +19,6 @@ public enum InvocationType { CONSUMER, - PRODUCER + PROVIDER, + EDGE } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/Response.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/Response.java index c5866f62f3f..26cfb48d322 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/Response.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/Response.java @@ -16,14 +16,17 @@ */ package org.apache.servicecomb.swagger.invocation; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; +import java.util.List; + +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.Headers; + +import io.vertx.core.MultiMap; /** * 用jaxrs的Response能表达所有概念 @@ -34,17 +37,17 @@ public class Response { private StatusType status; - private Headers headers = new Headers(); + private MultiMap headers; // 失败场景中,result是Throwable private Object result; - public boolean isSuccessed() { + public boolean isSucceed() { return HttpStatus.isSuccess(status); } public boolean isFailed() { - return !isSuccessed(); + return !isSucceed(); } public int getStatusCode() { @@ -63,12 +66,53 @@ public void setStatus(StatusType status) { this.status = status; } - public Headers getHeaders() { + public String getHeader(String name) { + if (headers == null) { + return null; + } + + return headers.get(name); + } + + public List getHeaders(String name) { + if (headers == null) { + return null; + } + + return headers.getAll(name); + } + + public MultiMap getHeaders() { return headers; } - public void setHeaders(Headers headers) { + public Response setHeaders(MultiMap headers) { this.headers = headers; + return this; + } + + public Response addHeader(String name, String value) { + if (value == null) { + return this; + } + if (headers == null) { + headers = MultiMap.caseInsensitiveMultiMap(); + } + + headers.add(name, value); + return this; + } + + public Response setHeader(String name, String value) { + if (value == null) { + return this; + } + if (headers == null) { + headers = MultiMap.caseInsensitiveMultiMap(); + } + + headers.set(name, value); + return this; } @SuppressWarnings("unchecked") @@ -130,6 +174,11 @@ public static Response createConsumerFail(Throwable throwable) { return createFail(exception); } + public static Response createConsumerFail(Throwable throwable, String message) { + InvocationException exception = ExceptionFactory.convertConsumerException(throwable, message); + return createFail(exception); + } + public static Response createProducerFail(Throwable throwable) { InvocationException exception = ExceptionFactory.convertProducerException(throwable); return createFail(exception); diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/SwaggerInvocation.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/SwaggerInvocation.java index e4c4cb6f43c..52386716189 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/SwaggerInvocation.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/SwaggerInvocation.java @@ -24,8 +24,6 @@ public class SwaggerInvocation extends InvocationContext { // 本实例是在consumer端,还是在provider端 protected InvocationType invocationType; - protected Object[] swaggerArguments; - protected InvocationContext parentContext; public SwaggerInvocation() { @@ -44,33 +42,7 @@ public InvocationType getInvocationType() { return invocationType; } - public Object[] getSwaggerArguments() { - return swaggerArguments; - } - - @SuppressWarnings("unchecked") - public T getSwaggerArgument(int idx) { - return (T) swaggerArguments[idx]; - } - - public void setSwaggerArguments(Object[] swaggerArguments) { - this.swaggerArguments = swaggerArguments; - } - - public void setSwaggerArgument(int idx, Object swaggerArgument) { - this.swaggerArguments[idx] = swaggerArgument; - } - public String getInvocationQualifiedName() { return invocationType.name(); } - - public void onBusinessMethodStart() { - } - - public void onBusinessMethodFinish() { - } - - public void onBusinessFinish() { - } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java new file mode 100644 index 00000000000..28022c898ed --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java @@ -0,0 +1,297 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.collectParameterName; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; + +import com.fasterxml.jackson.databind.SerializationConfig; + +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; + +/** + *
+ *   1.common
+ *     context type parameter is not swagger parameter:
+ *       InvocationContext
+ *       HttpServletRequest
+ *
+ *   2.same version
+ *     1) direct map (most scenes)
+ *       interface method:
+ *         class AddParam {
+ *           int x;
+ *           int y;
+ *         }
+ *         int add(InvocationContext context, AddParam param)
+ *       swagger parameters:
+ *         param
+ *
+ *       interface method:
+ *         int add(int x, int y)
+ *       swagger parameters:
+ *         x, y
+ *    2) swagger only one POJO parameter, extract all field to method parameters (POJO dev mode)
+ *      interface method:
+ *        int add(int x, int y)
+ *      swagger parameters:
+ *        param
+ *    3) wrap some simple continuously swagger parameters to POJO (springmvc query parameters)
+ *      interface method:
+ *        int add(String name, AddParam param, Body body)
+ *      swagger parameters:
+ *        name, x, y, body
+ *    4) wrap some simple and complex continuously swagger parameters to POJO  (JaxRS BeanParam)
+ *      interface method:
+ *        class BeanWrapper {
+ *          int x;
+ *          int y;
+ *          Body body;
+ *        }
+ *        int add(String name, AddParam param, Body body)
+ *      swagger parameters:
+ *        name, x, y, body
+ *  2. invoke old version
+ *    interface method:
+ *      int add(int x, int y, int z)
+ *    swagger parameter:
+ *      x, y
+ *  3. invoke new version
+ *    interface method:
+ *      int add(int x, int y)
+ *    swagger parameter:
+ *      x, y, z
+ * 
+ */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public abstract class AbstractArgumentsMapperCreator { + protected boolean isSwaggerBodyField = false; + + protected SerializationConfig serializationConfig; + + // key is context class + protected Map, ContextArgumentMapperFactory> contextFactories; + + // consumer or producer + protected Method providerMethod; + + protected Class providerClass; + + protected SwaggerOperation swaggerOperation; + + protected List mappers = new ArrayList<>(); + + protected List swaggerParameters; + + protected RequestBody bodyParameter; + + // For pojo wrapped bodies only + protected Map swaggerBodyProperties; + + protected Set processedSwaggerParameters; + + public AbstractArgumentsMapperCreator(SerializationConfig serializationConfig, + Map, ContextArgumentMapperFactory> contextFactories, Class providerClass, + Method providerMethod, SwaggerOperation swaggerOperation) { + this.serializationConfig = serializationConfig; + this.contextFactories = contextFactories; + this.providerClass = providerClass; + this.providerMethod = providerMethod; + this.swaggerOperation = swaggerOperation; + + this.swaggerParameters = this.swaggerOperation.getOperation().getParameters(); + + this.bodyParameter = this.swaggerOperation.getOperation().getRequestBody(); + this.swaggerBodyProperties = readSwaggerBodyProperties(); + this.processedSwaggerParameters = new HashSet<>(); + } + + private Map readSwaggerBodyProperties() { + if (bodyParameter == null || bodyParameter.getContent() == null + || bodyParameter.getContent().size() == 0) { + return null; + } + // For pojo wrapped bodies only + if (bodyParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE) != null || + bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + return null; + } + Schema schema = bodyParameter.getContent().entrySet().iterator().next().getValue().getSchema(); + if (schema != null && schema.get$ref() != null) { + schema = SwaggerUtils.getSchema(swaggerOperation.getSwagger(), schema.get$ref()); + } + if (schema != null && schema.getProperties() != null) { + return schema.getProperties(); + } + return null; + } + + protected void doCreateArgumentsMapper() { + java.lang.reflect.Parameter[] providerParameters = providerMethod.getParameters(); + for (int providerParamIdx = 0; providerParamIdx < providerParameters.length; providerParamIdx++) { + java.lang.reflect.Parameter providerParameter = providerParameters[providerParamIdx]; + if (processContextParameter(providerParameter)) { + continue; + } + + String parameterName = collectParameterName(providerParameter); + if (processKnownParameter(providerParamIdx, parameterName)) { + processedSwaggerParameters.add(parameterName); + continue; + } + + if (processSwaggerBodyField(providerParamIdx, parameterName)) { + processedSwaggerParameters.add(parameterName); + isSwaggerBodyField = true; + continue; + } + + if (processBeanParameter(providerParamIdx, providerParameter)) { + continue; + } + + processUnknownParameter(providerParamIdx, providerParameter, parameterName); + } + + // Process swagger parameters that not in method parameters + if (swaggerParameters != null) { + for (Parameter parameter : swaggerParameters) { + if (!processedSwaggerParameters.contains(parameter.getName())) { + processPendingSwaggerParameter(parameter); + } + } + } + if (bodyParameter != null) { + processPendingBodyParameter(bodyParameter); + } + } + + /** + * + * @param providerParameter processing provider parameter + * @return true means processed + */ + protected boolean processContextParameter(java.lang.reflect.Parameter providerParameter) { + ContextArgumentMapperFactory contextFactory = contextFactories.get(providerParameter.getType()); + if (contextFactory == null) { + return false; + } + + mappers.add(contextFactory + .create(providerParameter.getName(), providerParameter.getName())); + return true; + } + + /** + * Parameters has the same name in method and swagger. + */ + protected boolean processKnownParameter(int providerParamIdx, String invocationArgumentName) { + if (!parameterNameExistsInSwagger(invocationArgumentName)) { + return false; + } + + ArgumentMapper mapper = createKnownParameterMapper(providerParamIdx, invocationArgumentName); + mappers.add(mapper); + return true; + } + + protected boolean parameterNameExistsInSwagger(String parameterName) { + if (this.swaggerParameters != null) { + for (Parameter parameter : this.swaggerParameters) { + if (parameterName.equals(parameter.getName())) { + return true; + } + } + } + if (this.bodyParameter != null && this.bodyParameter.getContent() != null) { + if (this.bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null && + this.bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema() != null && + this.bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties() != null) { + return this.bodyParameter.getContent() + .get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties().get(parameterName) != null; + } + if (this.bodyParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE) != null && + this.bodyParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE).getSchema() != null && + this.bodyParameter.getContent().get(SwaggerConst.FILE_MEDIA_TYPE).getSchema().getProperties() != null) { + return this.bodyParameter.getContent() + .get(SwaggerConst.FILE_MEDIA_TYPE).getSchema().getProperties().get(parameterName) != null; + } + } + if (this.bodyParameter != null && this.bodyParameter.getExtensions() != null) { + return parameterName.equals(this.bodyParameter.getExtensions().get(SwaggerConst.EXT_BODY_NAME)); + } + return false; + } + + protected abstract ArgumentMapper createKnownParameterMapper(int providerParamIdx, String parameterName); + + /** + * Process POJO wrapped parameters, e.g. + * method(int foo, int bar) + * and Form parameters, e.g. + * method(@FormParam("foo") int foo, @FormParam("bar") int bar) + */ + protected boolean processSwaggerBodyField(int providerParamIdx, String parameterName) { + if (swaggerBodyProperties == null || swaggerBodyProperties.get(parameterName) == null) { + return false; + } + + ArgumentMapper mapper = createSwaggerBodyFieldMapper(providerParamIdx, parameterName); + mappers.add(mapper); + return true; + } + + protected abstract ArgumentMapper createSwaggerBodyFieldMapper(int providerParamIdx, String parameterName); + + /** + * Bean parameters, e.g. + * + * method(QueryModels queries) + * + * where swagger should be: + * - in: query + * name: foo + * - in: query + * name: bar + */ + protected abstract boolean processBeanParameter(int providerParamIdx, java.lang.reflect.Parameter providerParameter); + + protected abstract void processUnknownParameter(int providerParamIdx, java.lang.reflect.Parameter providerParameter, + String parameterName); + + /** + * Process parameters that in swagger but not in method. + */ + protected abstract void processPendingSwaggerParameter(Parameter parameter); + + /** + * Process body parameter that in swagger but not in method. + */ + protected abstract void processPendingBodyParameter(RequestBody parameter); +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentMapper.java index 375ebd80d67..0800ee136f6 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentMapper.java @@ -17,8 +17,14 @@ package org.apache.servicecomb.swagger.invocation.arguments; +import java.util.Map; + import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; public interface ArgumentMapper { - void mapArgument(SwaggerInvocation invocation, Object[] arguments); + void swaggerArgumentToInvocationArguments(SwaggerInvocation swaggerInvocation, Map swaggerArguments, + Map invocationArguments); + + void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, Map swaggerArguments, + Map invocationArguments); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapper.java new file mode 100644 index 00000000000..776dbff69d8 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapper.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments; + +import java.util.Map; + +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; + +public interface ArgumentsMapper { + default Map swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments) { + throw new IllegalStateException("not implemented."); + } + + /** + *
+   * for scenes that consumer arguments not same to contract arguments, eg:
+   * 1.consumer: int add(QueryWrapper query)
+   *             class QueryWrapper {
+   *               public int x;
+   *               public int y;
+   *             }
+   *   contract: int add(int x, int y)
+   *
+   * 2.consumer: int add(InvocationContext context, int x, int y);
+   *   contract: int add(int x, int y)
+   *
+   * 3.consumer: int add(int x, int y)
+   *   contract: int add(BodyRequest body)
+   *             class BodyRequest {
+   *               public int x;
+   *               public int y;
+   *             }
+   *
+   * notice:
+   *   no convert logic when map arguments
+   *   map arguments by name, DO NOT use duplicated contract argument names
+   * 
+ * + */ + default Map invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map invocationArguments) { + throw new IllegalStateException("not implemented."); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java deleted file mode 100644 index da2708308c3..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; - -import io.swagger.models.Operation; - -public class ArgumentsMapperConfig { - // input - private Method swaggerMethod; - - private Method providerMethod; - - private Operation swaggerOperation; - - private SwaggerGeneratorContext swaggerGeneratorContext; - - // output - private List argumentMapperList = new ArrayList<>(); - - public Method getSwaggerMethod() { - return swaggerMethod; - } - - public void setSwaggerMethod(Method swaggerMethod) { - this.swaggerMethod = swaggerMethod; - } - - public Method getProviderMethod() { - return providerMethod; - } - - public void setProviderMethod(Method providerMethod) { - this.providerMethod = providerMethod; - } - - public Operation getSwaggerOperation() { - return swaggerOperation; - } - - public void setSwaggerOperation(Operation swaggerOperation) { - this.swaggerOperation = swaggerOperation; - } - - public SwaggerGeneratorContext getSwaggerGeneratorContext() { - return swaggerGeneratorContext; - } - - public void setSwaggerGeneratorContext( - SwaggerGeneratorContext swaggerGeneratorContext) { - this.swaggerGeneratorContext = swaggerGeneratorContext; - } - - public List getArgumentMapperList() { - return argumentMapperList; - } - - public void setArgumentMapperList(List argumentMapperList) { - this.argumentMapperList = argumentMapperList; - } - - public void addArgumentMapper(ArgumentMapper argumentMapper) { - argumentMapperList.add(argumentMapper); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("ArgumentsMapperConfig{"); - sb.append("swaggerMethod=").append(swaggerMethod); - sb.append(", providerMethod=").append(providerMethod); - sb.append(", swaggerOperation=").append(swaggerOperation); - sb.append(", swaggerGeneratorContext=").append(swaggerGeneratorContext); - sb.append(", argumentMapperList=").append(argumentMapperList); - sb.append('}'); - return sb.toString(); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java deleted file mode 100644 index 001f80820c7..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon; -import org.springframework.util.TypeUtils; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestAttribute; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; - - -/** - * @param type of the generated ArgumentsMapper - */ -public abstract class ArgumentsMapperFactory { - @Inject - protected ConverterMgr converterMgr; - - protected InvocationType type; - - // key为ContextParameter - private Map, ContextArgumentMapperFactory> factoryMap = new HashMap<>(); - - public void setConverterMgr(ConverterMgr converterMgr) { - this.converterMgr = converterMgr; - } - - protected void createFactoryMap(List factoryList) { - factoryList.forEach(factory -> { - factoryMap.put(factory.getContextClass(), factory); - }); - } - - protected ContextArgumentMapperFactory findFactory(Type type) { - if (type.getClass().equals(Class.class)) { - return factoryMap.get((Class) type); - } - return null; - } - - protected void collectArgumentsMapper(ArgumentsMapperConfig config) { - List providerNormalParams = collectContextArgumentsMapper(config); - if (providerNormalParams.isEmpty()) { - return; - } - - if (isSwaggerWrapBody(config, providerNormalParams)) { - collectWrapBodyMapper(config, providerNormalParams); - return; - } - - collectSwaggerArgumentsMapper(config, providerNormalParams); - } - - protected boolean isSwaggerWrapBody(ArgumentsMapperConfig config, List providerNormalParams) { - Method swaggerMethod = config.getSwaggerMethod(); - if (swaggerMethod.getParameterCount() != 1) { - return false; - } - - Type swaggerType = config.getSwaggerMethod().getGenericParameterTypes()[0]; - if (!swaggerType.getClass().equals(Class.class)) { - return false; - } - - Type firstProviderParam = providerNormalParams.get(0).getType(); - if (TypeUtils.isAssignable(firstProviderParam, swaggerType)) { - return false; - } - - // no public field, it's not rpc wrapper class - if (((Class) swaggerType).getFields().length == 0) { - return false; - } - - swaggerType = ((Class) swaggerType).getFields()[0].getGenericType(); - Converter converter = converterMgr.findConverter(type, firstProviderParam, swaggerType); - if (ConverterCommon.class.isInstance(converter)) { - return false; - } - // 透明rpc的包装场景 - return true; - } - - // 处理所有context类型的参数 - // 剩余的参数返回 - protected List collectContextArgumentsMapper(ArgumentsMapperConfig config) { - List providerNormalParams = new ArrayList<>(); - - final Annotation[][] parameterAnnotations = config.getProviderMethod().getParameterAnnotations(); - Type[] providerParameterTypes = config.getProviderMethod().getGenericParameterTypes(); - for (int providerIdx = 0; providerIdx < providerParameterTypes.length; providerIdx++) { - Type parameterType = providerParameterTypes[providerIdx]; - ContextArgumentMapperFactory factory = findFactory(parameterType); - if (factory != null) { - ArgumentMapper mapper = factory.create(providerIdx); - config.addArgumentMapper(mapper); - continue; - } - - ProviderParameter pp = new ProviderParameter(providerIdx, parameterType, - retrieveVisibleParamName(config.getProviderMethod(), providerIdx)) - .setAnnotations(parameterAnnotations[providerIdx]); - providerNormalParams.add(pp); - } - - return providerNormalParams; - } - - /** - * Try to get the swagger param name of the corresponding producer/consumer method param - * @param method producer/consumer method - * @param paramIndex index of the producer/consumer method - * @return the param name specified by param annotations, or the param name defined in code - */ - public static String retrieveVisibleParamName(Method method, int paramIndex) { - final Annotation[] annotations = method.getParameterAnnotations()[paramIndex]; - String paramName = null; - for (Annotation annotation : annotations) { - paramName = retrieveVisibleParamName(annotation); - } - if (null == paramName) { - paramName = ParamUtils.getParameterName(method, paramIndex); - } - return paramName; - } - - public static String retrieveVisibleParamName(Annotation annotation) { - if (CookieParam.class.isInstance(annotation)) { - return ((CookieParam) annotation).value(); - } - if (CookieValue.class.isInstance(annotation)) { - return ((CookieValue) annotation).name(); - } - if (FormParam.class.isInstance(annotation)) { - return ((FormParam) annotation).value(); - } - if (HeaderParam.class.isInstance(annotation)) { - return ((HeaderParam) annotation).value(); - } - if (PathParam.class.isInstance(annotation)) { - return ((PathParam) annotation).value(); - } - if (PathVariable.class.isInstance(annotation)) { - return ((PathVariable) annotation).value(); - } - if (QueryParam.class.isInstance(annotation)) { - return ((QueryParam) annotation).value(); - } - if (RequestAttribute.class.isInstance(annotation)) { - return ((RequestAttribute) annotation).name(); - } - if (RequestHeader.class.isInstance(annotation)) { - return ((RequestHeader) annotation).name(); - } - if (RequestParam.class.isInstance(annotation)) { - return ((RequestParam) annotation).name(); - } - if (RequestPart.class.isInstance(annotation)) { - return ((RequestPart) annotation).name(); - } - - return null; - } - - protected void collectSwaggerArgumentsMapper(ArgumentsMapperConfig config, - List providerNormalParams) { - Method swaggerMethod = config.getSwaggerMethod(); - Type[] swaggerParams = swaggerMethod.getGenericParameterTypes(); - - // 普通场景,要求除了provider上的context,其他参数必须按顺序一一对应,provider上的有效参数可以与契约不一致 - int minParamCount = Math.min(providerNormalParams.size(), swaggerParams.length); - for (int swaggerIdx = 0; swaggerIdx < minParamCount; swaggerIdx++) { - ProviderParameter providerParameter = providerNormalParams.get(swaggerIdx); - Type swaggerParameter = swaggerParams[swaggerIdx]; - - Converter converter = converterMgr.findConverter(type, providerParameter.getType(), swaggerParameter); - ArgumentMapper mapper = - createArgumentMapperWithConverter(swaggerIdx, providerParameter.getIndex(), converter); - config.addArgumentMapper(mapper); - } - } - - protected void collectWrapBodyMapper(ArgumentsMapperConfig config, List providerNormalParams) { - // 将provider的参数存入唯一swagger参数的field - // 或是将唯一swagger参数的field存入provider参数 - Method swaggerMethod = config.getSwaggerMethod(); - Class swaggerParam = swaggerMethod.getParameterTypes()[0]; - Field[] swaggerParamFields = swaggerParam.getFields(); - - // 普通场景,要求除了provider上的context,其他参数必须按顺序一一对应,provider上的有效参数可以与契约不一致 - int minParamCount = Math.min(providerNormalParams.size(), swaggerParamFields.length); - - Map fieldMap = new HashMap<>(); - for (int swaggerIdx = 0; swaggerIdx < minParamCount; swaggerIdx++) { - ProviderParameter providerParameter = providerNormalParams.get(swaggerIdx); - Field swaggerField = swaggerParamFields[swaggerIdx]; - swaggerField.setAccessible(true); - - Converter converter = converterMgr.findConverter(type, - providerParameter.getType(), - swaggerField.getGenericType()); - FieldInfo info = new FieldInfo(swaggerField, converter); - fieldMap.put(providerParameter.getIndex(), info); - } - - ArgumentMapper bodyFieldArg = createBodyFieldArgMapper(config, fieldMap); - config.addArgumentMapper(bodyFieldArg); - } - - public abstract T createArgumentsMapper(ArgumentsMapperConfig config); - - protected abstract ArgumentMapper createArgumentMapperWithConverter(int swaggerIdx, int providerIdx, - Converter converter); - - protected abstract ArgumentMapper createBodyFieldArgMapper(ArgumentsMapperConfig config, - Map fieldMap); -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ContextArgumentMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ContextArgumentMapperFactory.java index a0a33b17df9..6e67b7b2e62 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ContextArgumentMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ContextArgumentMapperFactory.java @@ -20,5 +20,5 @@ public interface ContextArgumentMapperFactory { Class getContextClass(); - ArgumentMapper create(int argumentIdx); + ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/FieldInfo.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/FieldInfo.java deleted file mode 100644 index 71a53c918da..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/FieldInfo.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.lang.reflect.Field; - -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -public class FieldInfo { - private Field field; - - private Converter converter; - - public FieldInfo(Field field, Converter converter) { - this.field = field; - this.converter = converter; - } - - public Field getField() { - return field; - } - - public Converter getConverter() { - return converter; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java deleted file mode 100644 index 988efc15c3e..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.Arrays; - -public class ProviderParameter { - private int index; - - private Type type; - - /** - * the param name specified by param annotations(i.e. the param name in schema), or the param name defined in code - */ - private String name; - - private Annotation[] annotations; - - public ProviderParameter(int index, Type type, String name) { - this.index = index; - this.type = type; - this.name = name; - } - - public int getIndex() { - return index; - } - - public ProviderParameter setIndex(int index) { - this.index = index; - return this; - } - - public Type getType() { - return type; - } - - public ProviderParameter setType(Type type) { - this.type = type; - return this; - } - - public String getName() { - return name; - } - - public ProviderParameter setName(String name) { - this.name = name; - return this; - } - - public Annotation[] getAnnotations() { - return annotations; - } - - public ProviderParameter setAnnotations(Annotation[] annotations) { - this.annotations = annotations; - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("ProviderParameter{"); - sb.append("index=").append(index); - sb.append(", type=").append(type); - sb.append(", name='").append(name).append('\''); - sb.append(", annotations=").append(Arrays.toString(annotations)); - sb.append('}'); - return sb.toString(); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperCommon.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperCommon.java new file mode 100644 index 00000000000..3beb4194236 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperCommon.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; + +/** + * map consumer arguments to swagger arguments + */ +public class ArgumentsMapperCommon implements ArgumentsMapper { + private final List mappers; + + public ArgumentsMapperCommon(List mappers) { + this.mappers = mappers; + } + + @Override + public Map invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map invocationArguments) { + Map swaggerParameters = new HashMap<>(invocationArguments.size()); + for (ArgumentMapper argMapper : mappers) { + argMapper.invocationArgumentToSwaggerArguments(swaggerInvocation, swaggerParameters, invocationArguments); + } + return swaggerParameters; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperDirectReuse.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperDirectReuse.java new file mode 100644 index 00000000000..6a243407b26 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ArgumentsMapperDirectReuse.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.Map; + +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; + +public class ArgumentsMapperDirectReuse implements ArgumentsMapper { + @Override + public Map invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map invocationArguments) { + return invocationArguments; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentMapper.java new file mode 100644 index 00000000000..0034717ce64 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentMapper.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.Map; + +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; + +public abstract class ConsumerArgumentMapper implements ArgumentMapper { + public void swaggerArgumentToInvocationArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, + Map invocationArguments) { + throw new IllegalStateException("not expected"); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSame.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSame.java index eaad2cd743c..2768590a1de 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSame.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSame.java @@ -17,34 +17,28 @@ package org.apache.servicecomb.swagger.invocation.arguments.consumer; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.Map; -public final class ConsumerArgumentSame implements ArgumentMapper { - private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerArgumentSame.class); +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - private int consumerIdx; +public final class ConsumerArgumentSame extends ConsumerArgumentMapper { + private final String invocationArgumentName; - private int swaggerIdx; + private final String swaggerArgumentName; - private Converter converter; + public ConsumerArgumentSame(String invocationArgumentName, String swaggerArgumentName) { + this.invocationArgumentName = invocationArgumentName; + this.swaggerArgumentName = swaggerArgumentName; + } - public ConsumerArgumentSame(int consumerIdx, int swaggerIdx, Converter converter) { - this.consumerIdx = consumerIdx; - this.swaggerIdx = swaggerIdx; - this.converter = converter; + public boolean isSameMapping() { + return this.invocationArgumentName.equals(this.swaggerArgumentName); } @Override - public void mapArgument(SwaggerInvocation invocation, Object[] consumerArguments) { - if (null == consumerArguments[consumerIdx]) { - LOGGER.debug("null argument is ignored, consumerIdx = [{}]", consumerIdx); - return; - } - Object swaggerParam = converter.convert(consumerArguments[consumerIdx]); - invocation.setSwaggerArgument(swaggerIdx, swaggerParam); + public void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, + Map invocationArguments) { + swaggerArguments.put(swaggerArgumentName, invocationArguments.get(invocationArgumentName)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentToBodyField.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentToBodyField.java index ab666f2f8d7..1fd5fda66ed 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentToBodyField.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentToBodyField.java @@ -17,68 +17,40 @@ package org.apache.servicecomb.swagger.invocation.arguments.consumer; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.FieldInfo; /** - * 透明RPC的典型场景 - * 因为没有标注指明RESTful映射方式 - * 所以,所有参数被包装为一个class,每个参数是一个field + *
+ * Typical scene of transparent RPC
+ * all parameters of consumer method wrapped to a bean in contract
+ * 
*/ -public class ConsumerArgumentToBodyField implements ArgumentMapper { - private Class swaggerParamType; +public final class ConsumerArgumentToBodyField extends ConsumerArgumentMapper { + private final String invocationArgumentName; - // key为consumerArgs的下标 - private Map fieldMap; + private final String parameterName; - public ConsumerArgumentToBodyField(Class swaggerParamType, Map fieldMap) { - this.swaggerParamType = correctType(swaggerParamType); - this.fieldMap = fieldMap; - } - - protected Class correctType(Class swaggerParamType) { - if (!Modifier.isAbstract(swaggerParamType.getModifiers())) { - return swaggerParamType; - } - - if (List.class.isAssignableFrom(swaggerParamType)) { - return ArrayList.class; - } + private final String swaggerArgumentName; - if (Set.class.isAssignableFrom(swaggerParamType)) { - return HashSet.class; - } - - throw new Error("not support " + swaggerParamType.getName()); - } - - public Class getSwaggerParamType() { - return swaggerParamType; + public ConsumerArgumentToBodyField(String invocationArgumentName, + String swaggerArgumentName, String parameterName) { + this.invocationArgumentName = invocationArgumentName; + this.parameterName = parameterName; + this.swaggerArgumentName = swaggerArgumentName; } + @SuppressWarnings("unchecked") @Override - public void mapArgument(SwaggerInvocation invocation, Object[] consumerArguments) { - try { - Object body = swaggerParamType.newInstance(); - for (Entry entry : fieldMap.entrySet()) { - FieldInfo info = entry.getValue(); - - Object consumerParam = consumerArguments[entry.getKey()]; - Object swaggerParam = info.getConverter().convert(consumerParam); - info.getField().set(body, swaggerParam); - } - invocation.setSwaggerArgument(0, body); - } catch (Throwable e) { - throw new Error(e); + public void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, + Map invocationArguments) { + Object consumerArgument = invocationArguments.get(invocationArgumentName); + swaggerArguments.computeIfAbsent(swaggerArgumentName, k -> new LinkedHashMap()); + if (consumerArgument != null) { + ((Map) swaggerArguments.get(swaggerArgumentName)).put(parameterName, consumerArgument); } } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapper.java deleted file mode 100644 index 594950ceb8b..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapper.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.consumer; - -import java.util.List; - -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; - -/** - * 将consumer参数保存到invocation中去(args/context) - * 比如契约原型是 int add(int x, int y) - * 而consumer原型是int add(InvocationContext context, int x, int y) - * - * 除了context参数,剩下的参数,必须与契约中的一一匹配,包括顺序、类型 - */ -public class ConsumerArgumentsMapper { - private List consumerArgMapperList; - - private int swaggerParameterCount; - - // for test - public ArgumentMapper getArgumentMapper(int idx) { - return consumerArgMapperList.get(idx); - } - - public ConsumerArgumentsMapper(List consumerArgMapperList, int swaggerParameterCount) { - this.consumerArgMapperList = consumerArgMapperList; - this.swaggerParameterCount = swaggerParameterCount; - } - - public void toInvocation(Object[] consumerArguments, SwaggerInvocation invocation) { - Object[] swaggerArguments = new Object[swaggerParameterCount]; - invocation.setSwaggerArguments(swaggerArguments); - - for (ArgumentMapper argMapper : consumerArgMapperList) { - argMapper.mapArgument(invocation, consumerArguments); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperCreator.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperCreator.java new file mode 100644 index 00000000000..84c7a6fa926 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperCreator.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.collectParameterName; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.invocation.arguments.AbstractArgumentsMapperCreator; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; + +public class ConsumerArgumentsMapperCreator extends AbstractArgumentsMapperCreator { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerArgumentsMapperCreator.class); + + private int unknownConsumerParams = 0; + + public ConsumerArgumentsMapperCreator(SerializationConfig serializationConfig, + Map, ContextArgumentMapperFactory> contextFactories, Class consumerClass, + Method consumerMethod, SwaggerOperation swaggerOperation) { + super(serializationConfig, contextFactories, consumerClass, consumerMethod, swaggerOperation); + } + + private boolean isAllSameMapper() { + for (ArgumentMapper mapper : mappers) { + if (mapper instanceof ConsumerArgumentSame && ((ConsumerArgumentSame) mapper).isSameMapping()) { + continue; + } + + return false; + } + + return true; + } + + public ArgumentsMapper createArgumentsMapper() { + doCreateArgumentsMapper(); + + // if all mappers are SameMapper, then no need any mapper + if (unknownConsumerParams == 0 + && mappers.size() == swaggerOperation.parameterCount() + && isAllSameMapper()) { + return new ArgumentsMapperDirectReuse(); + } + + return new ArgumentsMapperCommon(mappers); + } + + @Override + protected void processUnknownParameter(int providerParamIdx, java.lang.reflect.Parameter providerParameter, + String parameterName) { + LOGGER.warn("Consumer parameter({}) is not exist in contract, method={}:{}.", + parameterName, providerMethod.getDeclaringClass().getName(), providerMethod.getName()); + unknownConsumerParams++; + } + + @Override + protected void processPendingSwaggerParameter(Parameter parameter) { + + } + + @Override + protected void processPendingBodyParameter(RequestBody parameter) { + + } + + @Override + protected ArgumentMapper createKnownParameterMapper(int providerParamIdx, String invocationArgumentName) { + return new ConsumerArgumentSame(this.providerMethod.getParameters()[providerParamIdx].getName(), + invocationArgumentName); + } + + @Override + protected ArgumentMapper createSwaggerBodyFieldMapper(int consumerParamIdx, String parameterName) { + return new ConsumerArgumentToBodyField(this.providerMethod.getParameters()[consumerParamIdx].getName(), + (String) this.bodyParameter.getExtensions().get(SwaggerConst.EXT_BODY_NAME), parameterName); + } + + @Override + protected boolean processBeanParameter(int consumerParamIdx, java.lang.reflect.Parameter consumerParameter) { + JavaType consumerType = TypeFactory.defaultInstance().constructType(consumerParameter.getParameterizedType()); + if (!SwaggerUtils.isBean(consumerType)) { + return false; + } + boolean result = false; + ConsumerBeanParamMapper mapper = new ConsumerBeanParamMapper( + this.providerMethod.getParameters()[consumerParamIdx].getName()); + for (BeanPropertyDefinition propertyDefinition : serializationConfig.introspect(consumerType).findProperties()) { + String parameterName = collectParameterName(providerMethod, propertyDefinition); + if (!parameterNameExistsInSwagger(parameterName)) { + continue; + } + + mapper.addField(parameterName, LambdaMetafactoryUtils.createObjectGetter(propertyDefinition)); + processedSwaggerParameters.add(parameterName); + result = true; + } + mappers.add(mapper); + return result; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java deleted file mode 100644 index 0a72be033f7..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.consumer; - -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.FieldInfo; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -@Component -public class ConsumerArgumentsMapperFactory extends ArgumentsMapperFactory { - public ConsumerArgumentsMapperFactory() { - type = InvocationType.CONSUMER; - } - - @Inject - @Qualifier("consumer") - public void setFactoryList(List factoryList) { - createFactoryMap(factoryList); - } - - @Override - public ConsumerArgumentsMapper createArgumentsMapper(ArgumentsMapperConfig config) { - collectArgumentsMapper(config); - return new ConsumerArgumentsMapper(config.getArgumentMapperList(), - config.getSwaggerMethod().getParameterCount()); - } - - @Override - protected ArgumentMapper createArgumentMapperWithConverter(int swaggerIdx, int consumerIdx, Converter converter) { - return new ConsumerArgumentSame(consumerIdx, swaggerIdx, converter); - } - - @Override - protected ArgumentMapper createBodyFieldArgMapper(ArgumentsMapperConfig config, - Map fieldMap) { - Class swaggerParamType = config.getSwaggerMethod().getParameterTypes()[0]; - return new ConsumerArgumentToBodyField(swaggerParamType, fieldMap); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerBeanParamMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerBeanParamMapper.java new file mode 100644 index 00000000000..ae5468ce5b2 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerBeanParamMapper.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.bean.Getter; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; + +/** + *
+ * consumer: void add(QueryWrapper query)
+ *           class QueryWrapper {
+ *             int x;
+ *             int y;
+ *           }
+ * contract; void add(int x, int y)
+ * 
+ */ +public final class ConsumerBeanParamMapper extends ConsumerArgumentMapper { + private static class FieldMeta { + String swaggerArgumentName; + + Getter getter; + + public FieldMeta(String swaggerArgumentName, Getter getter) { + this.swaggerArgumentName = swaggerArgumentName; + this.getter = getter; + } + } + + private final String invocationArgumentName; + + private final List fields = new ArrayList<>(); + + public ConsumerBeanParamMapper(String invocationArgumentName) { + this.invocationArgumentName = invocationArgumentName; + } + + public void addField(String invocationArgumentName, Getter getter) { + fields.add(new FieldMeta(invocationArgumentName, getter)); + } + + @Override + public void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, + Map invocationArguments) { + Object consumerArgument = invocationArguments.get(invocationArgumentName); + if (consumerArgument == null) { + return; + } + for (FieldMeta fieldMeta : fields) { + swaggerArguments.put(fieldMeta.swaggerArgumentName, fieldMeta.getter.get(consumerArgument)); + } + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerContextArgumentMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerContextArgumentMapperFactory.java new file mode 100644 index 00000000000..dd472db3b77 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerContextArgumentMapperFactory.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; + +public interface ConsumerContextArgumentMapperFactory extends ContextArgumentMapperFactory { +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapper.java index 44bbfdde1f3..df324635bb2 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapper.java @@ -17,20 +17,24 @@ package org.apache.servicecomb.swagger.invocation.arguments.consumer; +import java.util.Map; + import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -public class ConsumerInvocationContextMapper implements ArgumentMapper { - private int consumerIdx; +public class ConsumerInvocationContextMapper extends ConsumerArgumentMapper { + protected String invocationArgumentName; - public ConsumerInvocationContextMapper(int consumerIdx) { - this.consumerIdx = consumerIdx; + public ConsumerInvocationContextMapper(String invocationArgumentName) { + this.invocationArgumentName = invocationArgumentName; } @Override - public void mapArgument(SwaggerInvocation invocation, Object[] consumerArguments) { - InvocationContext context = (InvocationContext) consumerArguments[consumerIdx]; + public void invocationArgumentToSwaggerArguments(SwaggerInvocation invocation, + Map swaggerArguments, + Map invocationArguments) { + InvocationContext context = (InvocationContext) invocationArguments.get(invocationArgumentName); invocation.addContext(context.getContext()); + invocation.addLocalContext(context.getLocalContext()); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapperFactory.java index 6d57950c444..0de0f2e9595 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerInvocationContextMapperFactory.java @@ -18,22 +18,16 @@ package org.apache.servicecomb.swagger.invocation.arguments.consumer; import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -@Component -@Qualifier("consumer") -public class ConsumerInvocationContextMapperFactory implements ContextArgumentMapperFactory { +public class ConsumerInvocationContextMapperFactory implements ConsumerContextArgumentMapperFactory { @Override public Class getContextClass() { return InvocationContext.class; } @Override - public ArgumentMapper create(int consumerArgIdx) { - return new ConsumerInvocationContextMapper(consumerArgIdx); + public ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName) { + return new ConsumerInvocationContextMapper(invocationArgumentName); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/AbstractProducerContextArgMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/AbstractProducerContextArgMapper.java index 9322ee94b2a..83ca5b06185 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/AbstractProducerContextArgMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/AbstractProducerContextArgMapper.java @@ -17,20 +17,25 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; +import java.util.Map; + import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -public abstract class AbstractProducerContextArgMapper implements ArgumentMapper { - protected int producerArgIdx; +public abstract class AbstractProducerContextArgMapper extends ProducerArgumentMapper { + protected String invocationArgumentName; + + protected String swaggerArgumentName; - public AbstractProducerContextArgMapper(int producerArgIdx) { - this.producerArgIdx = producerArgIdx; + public AbstractProducerContextArgMapper(String invocationArgumentName, String swaggerArgumentName) { + this.invocationArgumentName = invocationArgumentName; + this.swaggerArgumentName = swaggerArgumentName; } @Override - public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { + public void swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments, Map invocationArguments) { Object producerArg = createContextArg(invocation); - producerArguments[producerArgIdx] = producerArg; + invocationArguments.put(this.invocationArgumentName, producerArg); } public abstract Object createContextArg(SwaggerInvocation invocation); diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactory.java deleted file mode 100644 index d0b84cd211c..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactory.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import static org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.BeanParamAnnotationProcessor.SETTER_METHOD_PREFIX; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.ws.rs.BeanParam; - -import org.apache.servicecomb.swagger.generator.jaxrs.processor.annotation.BeanParamAnnotationProcessor; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.ProviderParameter; -import org.springframework.stereotype.Component; - -import io.swagger.models.parameters.Parameter; - -@Component -public class JaxRSProducerArgumentsMapperFactory extends ProducerArgumentsMapperFactory { - @Override - public boolean canProcess(ArgumentsMapperConfig config) { - return config.getSwaggerGeneratorContext().getClass().getCanonicalName().equals( - "org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorContext"); - } - - @Override - protected Set findAggregatedParamNames(Map providerParamMap, - Map> swaggerParamMap) { - Set aggregatedParamNames = new HashSet<>(); - for (Entry providerParameterEntry : providerParamMap.entrySet()) { - if (null == providerParameterEntry.getValue().getAnnotations()) { - // request body may have no annotation - continue; - } - for (Annotation annotation : providerParameterEntry.getValue().getAnnotations()) { - if (annotation instanceof BeanParam) { - aggregatedParamNames.add(providerParameterEntry.getKey()); - } - } - } - - return aggregatedParamNames; - } - - @Override - protected void generateAggregatedParamMapper(ArgumentsMapperConfig config, - Map providerParamMap, Map> swaggerParamMap, - Set aggregatedParamNames) { - for (String aggregatedProducerParamName : aggregatedParamNames) { - ProviderParameter aggregatedParam = providerParamMap.get(aggregatedProducerParamName); - // producer param name -> swagger param name - Map producerToSwaggerParamNameMapper = getProducerToSwaggerParamNameMap(aggregatedParam); - // producer param name -> swagger param index - Map producerNameToSwaggerIndexMap = new HashMap<>(producerToSwaggerParamNameMapper.size()); - for (Entry producerSwaggerNameMapEntry : producerToSwaggerParamNameMapper.entrySet()) { - producerNameToSwaggerIndexMap.put( - producerSwaggerNameMapEntry.getKey(), - swaggerParamMap.get(producerSwaggerNameMapEntry.getValue()).getIndex()); - } - - // create&add aggregated param mapper - ArgumentMapper mapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, - aggregatedParam.getIndex(), - aggregatedParam.getType()); - config.addArgumentMapper(mapper); - } - } - - /** - *
-   * public class AggregatedParam {
-   *   \@PathParam("pathSwaggerParam")
-   *   private String pathProducerParam;
-   *
-   *   private String queryProducerParam;
-   *
-   *   \@QueryParam(value = "querySwaggerParam")
-   *   public void setQueryProducerParam(String queryParam) {
-   *     this.queryProducerParam = queryParam;
-   *   }
-   * }
-   * 
- * Given a BeanParam like above, will return a map like below: - * { - * "pathProducerParam" -> "pathSwaggerParam", - * "queryProducerParam" -> "querySwaggerParam" - * } - */ - private Map getProducerToSwaggerParamNameMap(ProviderParameter aggregatedParam) { - Map producerToSwaggerParamNameMapper = new HashMap<>(); - Class aggregatedParamClazz = (Class) aggregatedParam.getType(); - // map those params defined by BeanParam fields - for (Field field : aggregatedParamClazz.getDeclaredFields()) { - for (Annotation fieldAnnotation : field.getAnnotations()) { - if (BeanParamAnnotationProcessor.SUPPORTED_PARAM_ANNOTATIONS.contains(fieldAnnotation.annotationType())) { - producerToSwaggerParamNameMapper.put( - field.getName(), - retrieveVisibleParamName(fieldAnnotation)); - break; - } - } - } - // map those params defined by setter methods - for (Method method : aggregatedParamClazz.getDeclaredMethods()) { - final String methodName = method.getName(); - if (!methodName.startsWith(SETTER_METHOD_PREFIX)) { - // only process setter methods - continue; - } - // There should be one and only one param in a setter method - for (Annotation setterAnnotation : method.getAnnotations()) { - if (BeanParamAnnotationProcessor.SUPPORTED_PARAM_ANNOTATIONS.contains(setterAnnotation.annotationType())) { - producerToSwaggerParamNameMapper.put( - methodName.substring( // setParamName() -> "paramName" - SETTER_METHOD_PREFIX.length(), SETTER_METHOD_PREFIX.length() + 1).toLowerCase() - + methodName.substring(SETTER_METHOD_PREFIX.length() + 1), - retrieveVisibleParamName(setterAnnotation)); - break; - } - } - } - return producerToSwaggerParamNameMapper; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentMapper.java new file mode 100644 index 00000000000..21eae4ea842 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentMapper.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.util.Map; + +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; + +public abstract class ProducerArgumentMapper implements ArgumentMapper { + public void invocationArgumentToSwaggerArguments(SwaggerInvocation swaggerInvocation, + Map swaggerArguments, + Map invocationArguments) { + throw new IllegalStateException("not expected"); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentSame.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentSame.java index 84c6466a7f0..f22456a83e5 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentSame.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentSame.java @@ -17,27 +17,23 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.converter.Converter; +import java.util.Map; -public class ProducerArgumentSame implements ArgumentMapper { - private int swaggerIdx; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - private int producerIdx; +public class ProducerArgumentSame extends ProducerArgumentMapper { + protected String invocationArgumentName; - private Converter converter; + protected String swaggerArgumentName; - public ProducerArgumentSame(int swaggerIdx, int producerIdx, Converter converter) { - this.swaggerIdx = swaggerIdx; - this.producerIdx = producerIdx; - this.converter = converter; + public ProducerArgumentSame(String invocationArgumentName, String swaggerArgumentName) { + this.invocationArgumentName = invocationArgumentName; + this.swaggerArgumentName = swaggerArgumentName; } @Override - public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { - Object swaggerParam = invocation.getSwaggerArgument(swaggerIdx); - Object producerParam = converter.convert(swaggerParam); - producerArguments[producerIdx] = producerParam; + public void swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments, Map invocationArguments) { + invocationArguments.put(invocationArgumentName, swaggerArguments.get(swaggerArgumentName)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapper.java index 0a2eb1ac857..91339cca0e9 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapper.java @@ -17,33 +17,32 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; /** - * 将契约参数转为producer原型 - * 比如契约原型是 int add(int x, int y) - * 而producer原型是int add(HttpRequest request, int x, int y) + * map swagger arguments to producer arguments */ -public class ProducerArgumentsMapper { - private List producerArgMapperList; +public class ProducerArgumentsMapper implements ArgumentsMapper { + private final List producerArgMapperList; - private int producerParameterCount; - - public ProducerArgumentsMapper(List producerArgMapperList, int producerParameterCount) { + public ProducerArgumentsMapper(List producerArgMapperList) { this.producerArgMapperList = producerArgMapperList; - this.producerParameterCount = producerParameterCount; } - public Object[] toProducerArgs(SwaggerInvocation invocation) { - Object[] producerArgs = new Object[producerParameterCount]; - + @Override + public Map swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments) { + Map invocationArguments = new HashMap<>(swaggerArguments.size()); for (ArgumentMapper argMapper : producerArgMapperList) { - argMapper.mapArgument(invocation, producerArgs); + argMapper.swaggerArgumentToInvocationArguments(invocation, swaggerArguments, invocationArguments); } - return producerArgs; + return invocationArguments; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java new file mode 100644 index 00000000000..9aea4bec37d --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import static org.apache.servicecomb.swagger.generator.SwaggerGeneratorUtils.collectParameterName; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.generator.core.model.SwaggerOperation; +import org.apache.servicecomb.swagger.invocation.arguments.AbstractArgumentsMapperCreator; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.google.common.reflect.TypeToken; + +import io.swagger.v3.oas.models.parameters.RequestBody; + +@SuppressWarnings("unchecked") +public class ProducerArgumentsMapperCreator extends AbstractArgumentsMapperCreator { + // swagger parameter types relate to producer + // because features of @BeanParam/query, and rpc mode parameter wrapper + // types is not always equals to producerMethod parameter types directly + private final Map swaggerParameterTypes; + + public ProducerArgumentsMapperCreator(SerializationConfig serializationConfig, + Map, ContextArgumentMapperFactory> contextFactories, Class producerClass, + Method producerMethod, SwaggerOperation swaggerOperation) { + super(serializationConfig, contextFactories, producerClass, producerMethod, swaggerOperation); + + swaggerParameterTypes = new HashMap<>(); + } + + public Map getSwaggerParameterTypes() { + return swaggerParameterTypes; + } + + public ProducerArgumentsMapper createArgumentsMapper() { + doCreateArgumentsMapper(); + return new ProducerArgumentsMapper(mappers); + } + + @Override + protected void processUnknownParameter(int providerParamIdx, java.lang.reflect.Parameter providerParameter, + String parameterName) { + throw new IllegalStateException(String + .format("failed to find producer parameter in contract, method=%s:%s, parameter name=%s.", + providerMethod.getDeclaringClass().getSimpleName(), providerMethod.getName(), parameterName)); + } + + @Override + protected void processPendingSwaggerParameter(io.swagger.v3.oas.models.parameters.Parameter parameter) { + swaggerParameterTypes.put(parameter.getName(), Object.class); + } + + @Override + protected void processPendingBodyParameter(RequestBody bodyParameter) { + if (bodyParameter.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE) != null + && !processedSwaggerParameters.contains( + (String) bodyParameter.getExtensions().get(SwaggerConst.EXT_BODY_NAME))) { + swaggerParameterTypes.put((String) bodyParameter + .getExtensions().get(SwaggerConst.EXT_BODY_NAME), Object.class); + } + if (bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null) { + bodyParameter.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties().forEach((k, v) -> { + if (!processedSwaggerParameters.contains((String) k)) { + swaggerParameterTypes.put((String) k, Object.class); + } + }); + } + } + + @Override + protected ArgumentMapper createKnownParameterMapper(int providerParamIdx, String invocationArgumentName) { + Type providerType = TypeToken.of(providerClass) + .resolveType(providerMethod.getGenericParameterTypes()[providerParamIdx]) + .getType(); + swaggerParameterTypes + .put(invocationArgumentName, providerType); + return new ProducerArgumentSame(providerMethod.getParameters()[providerParamIdx].getName(), invocationArgumentName); + } + + @Override + protected ArgumentMapper createSwaggerBodyFieldMapper(int producerParamIdx, String parameterName) { + String swaggerArgumentName = (String) this.bodyParameter.getExtensions().get(SwaggerConst.EXT_BODY_NAME); + swaggerParameterTypes.put(swaggerArgumentName, Object.class); + Type parameterType = TypeToken.of(providerClass) + .resolveType(providerMethod.getGenericParameterTypes()[producerParamIdx]) + .getType(); + return new SwaggerBodyFieldToProducerArgument(providerMethod.getParameters()[producerParamIdx].getName(), + swaggerArgumentName, + parameterName, parameterType); + } + + @Override + protected boolean processBeanParameter(int producerParamIdx, Parameter producerParameter) { + JavaType providerType = TypeFactory.defaultInstance().constructType(producerParameter.getParameterizedType()); + if (!SwaggerUtils.isBean(providerType)) { + return false; + } + ProducerBeanParamMapper mapper = new ProducerBeanParamMapper( + providerMethod.getParameters()[producerParamIdx].getName(), producerParameter.getType()); + boolean result = false; + for (BeanPropertyDefinition propertyDefinition : serializationConfig.introspect(providerType) + .findProperties()) { + String parameterName = collectParameterName(providerMethod, propertyDefinition); + + if (!parameterNameExistsInSwagger(parameterName)) { + continue; + } + + swaggerParameterTypes.put(parameterName, propertyDefinition.getPrimaryType()); + mapper.addField(parameterName, LambdaMetafactoryUtils.createObjectSetter(propertyDefinition)); + processedSwaggerParameters.add(parameterName); + result = true; + } + mappers.add(mapper); + return result; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java deleted file mode 100644 index 3423bedbc25..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.inject.Inject; - -import org.apache.servicecomb.swagger.generator.rest.RestSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.FieldInfo; -import org.apache.servicecomb.swagger.invocation.arguments.ProviderParameter; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; - -import io.swagger.models.parameters.Parameter; - -@Component -@Primary -public class ProducerArgumentsMapperFactory extends ArgumentsMapperFactory { - - private static final Logger LOGGER = LoggerFactory.getLogger(ProducerArgumentsMapperFactory.class); - - public ProducerArgumentsMapperFactory() { - type = InvocationType.PRODUCER; - } - - @Inject - @Qualifier("producer") - public void setFactoryList(List factoryList) { - createFactoryMap(factoryList); - } - - @Override - public ProducerArgumentsMapper createArgumentsMapper(ArgumentsMapperConfig config) { - collectArgumentsMapper(config); - return new ProducerArgumentsMapper(config.getArgumentMapperList(), - config.getProviderMethod().getParameterCount()); - } - - public boolean canProcess(ArgumentsMapperConfig config) { - return false; - } - - @Override - protected void collectSwaggerArgumentsMapper(ArgumentsMapperConfig config, - List providerNormalParams) { - if (!RestSwaggerGeneratorContext.class.isInstance(config.getSwaggerGeneratorContext())) { - // POJO style provider does not support aggregated param - super.collectSwaggerArgumentsMapper(config, providerNormalParams); - return; - } - - // JAX-RS and SpringMVC style provider support aggregated param, i.e. @BeanParam and query object, respectively - Map providerParamMap = getProviderParamMap(providerNormalParams); - Map> swaggerParamMap = getSwaggerParamMap(config); - - Set aggregatedParamNames = findAggregatedParamNames(providerParamMap, swaggerParamMap); - if (aggregatedParamNames.isEmpty()) { - // there is no aggregated param, run as 1-to-1 param mapping mode - super.collectSwaggerArgumentsMapper(config, providerNormalParams); - return; - } - - // There is at lease one aggregated param, so the param mapping mode becomes to M-to-N - // try to map params by name - generateParamMapperByName(config, providerParamMap, swaggerParamMap, aggregatedParamNames); - } - - private void generateParamMapperByName(ArgumentsMapperConfig config, Map providerParamMap, - Map> swaggerParamMap, Set aggregatedParamNames) { - LOGGER.info("mapping aggregated params: [{}]", aggregatedParamNames); - generateAggregatedParamMapper(config, providerParamMap, swaggerParamMap, aggregatedParamNames); - generateDefaultParamMapper(config, providerParamMap, swaggerParamMap, aggregatedParamNames); - } - - /** - * Generate default argument mappers. One swagger argument is mapped to one producer argument. - */ - private void generateDefaultParamMapper(ArgumentsMapperConfig config, Map providerParamMap, - Map> swaggerParamMap, Set aggregatedParamNames) { - Type[] swaggerParamTypes = config.getSwaggerMethod().getGenericParameterTypes(); - for (Entry providerParamEntry : providerParamMap.entrySet()) { - if (aggregatedParamNames.contains(providerParamEntry.getKey())) { - continue; - } - - final int swaggerIdx = swaggerParamMap.get(providerParamEntry.getKey()).getIndex(); - Converter converter = converterMgr.findConverter(type, providerParamEntry.getValue().getType(), - swaggerParamTypes[swaggerIdx]); - ArgumentMapper mapper = - createArgumentMapperWithConverter(swaggerIdx, providerParamEntry.getValue().getIndex(), converter); - config.addArgumentMapper(mapper); - } - } - - /** - * Generate argument mappers for aggregated params. - * Collect related swagger params and map them to an aggregated param. - * It's implemented by SpringMVC and JAX-RS. - */ - protected void generateAggregatedParamMapper(ArgumentsMapperConfig config, - Map providerParamMap, Map> swaggerParamMap, - Set aggregatedParamNames) { - // do nothing, not supported by default - } - - protected Map> getSwaggerParamMap(ArgumentsMapperConfig config) { - Map> swaggerParamMap = new HashMap<>(); - if (null == config.getSwaggerOperation() || null == config.getSwaggerOperation().getParameters()) { - return swaggerParamMap; - } - List parameters = config.getSwaggerOperation().getParameters(); - for (int i = 0; i < parameters.size(); i++) { - Parameter parameter = parameters.get(i); - swaggerParamMap.put(parameter.getName(), new ParamWrapper<>(parameter).setIndex(i)); - } - return swaggerParamMap; - } - - protected Map getProviderParamMap(List providerNormalParams) { - Map providerParamMap = new HashMap<>(providerNormalParams.size()); - providerNormalParams.forEach( - providerParameter -> providerParamMap.put(providerParameter.getName(), providerParameter)); - return providerParamMap; - } - - /** - * Find all aggregated params - * @return the names of the aggregated params - */ - protected Set findAggregatedParamNames(Map providerParamMap, - Map> swaggerParamMap) { - return Collections.emptySet(); - } - - @Override - protected ArgumentMapper createArgumentMapperWithConverter(int swaggerIdx, int producerIdx, Converter converter) { - return new ProducerArgumentSame(swaggerIdx, producerIdx, converter); - } - - @Override - protected ArgumentMapper createBodyFieldArgMapper(ArgumentsMapperConfig config, - Map fieldMap) { - return new SwaggerArgumentToProducerBodyField(fieldMap); - } - - public static class ParamWrapper { - T param; - - int index; - - public ParamWrapper(T param) { - this.param = param; - } - - public T getParam() { - return param; - } - - public ParamWrapper setParam(T param) { - this.param = param; - return this; - } - - public int getIndex() { - return index; - } - - public ParamWrapper setIndex(int index) { - this.index = index; - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("ParamWrapper{"); - sb.append("param=").append(param); - sb.append(", index=").append(index); - sb.append('}'); - return sb.toString(); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapper.java index b5c404b7bd2..3b4778f778d 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapper.java @@ -17,47 +17,56 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; -import java.lang.reflect.Type; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; +import org.apache.servicecomb.foundation.common.utils.bean.Setter; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon; - -public class ProducerBeanParamMapper implements ArgumentMapper { - - private int producerIdx; - - private Map swaggerParamIndexMap; - - private Converter converter; - - /** - * @param producerNameToSwaggerIndexMap name of the fields and setters defined in @BeanParam parameter to swagger - * param index - * @param producerIdx index of producer param - * @param producerParamType type of producer param - */ - public ProducerBeanParamMapper(Map producerNameToSwaggerIndexMap, int producerIdx, - Type producerParamType) { - this.producerIdx = producerIdx; - this.swaggerParamIndexMap = new HashMap<>(); - this.swaggerParamIndexMap.putAll(producerNameToSwaggerIndexMap); - converter = new ConverterCommon(producerParamType); + +public class ProducerBeanParamMapper extends ProducerArgumentMapper { + private static class FieldMeta { + String swaggerParameterName; + + Setter setter; + + public FieldMeta(String swaggerParameterName, Setter setter) { + this.swaggerParameterName = swaggerParameterName; + this.setter = setter; + } + } + + protected String invocationArgumentName; + + private final Class producerParamType; + + private final List fields = new ArrayList<>(); + + public ProducerBeanParamMapper(String invocationArgumentName, Class producerParamType) { + this.invocationArgumentName = invocationArgumentName; + this.producerParamType = producerParamType; + } + + public void addField(String swaggerParameterName, Setter setter) { + fields.add(new FieldMeta(swaggerParameterName, setter)); } @Override - public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { - Map jsonMap = new HashMap<>(swaggerParamIndexMap.size()); + public void swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments, Map invocationArguments) { + try { + Object paramInstance = producerParamType.getDeclaredConstructor().newInstance(); + invocationArguments.put(invocationArgumentName, paramInstance); - for (Entry swaggerIndexEntry : swaggerParamIndexMap.entrySet()) { - jsonMap.put(swaggerIndexEntry.getKey(), invocation.getSwaggerArgument(swaggerIndexEntry.getValue())); + for (FieldMeta fieldMeta : fields) { + Object value = swaggerArguments.get(fieldMeta.swaggerParameterName); + if (value != null) { + // can not set primitive data + fieldMeta.setter.set(paramInstance, value); + } + } + } catch (Throwable e) { + throw new IllegalStateException("failed to map bean param.", e); } - - final Object producerParam = converter.convert(jsonMap); - producerArguments[producerIdx] = producerParam; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerContextArgumentMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerContextArgumentMapperFactory.java new file mode 100644 index 00000000000..64e569fc9ad --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerContextArgumentMapperFactory.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; + +public interface ProducerContextArgumentMapperFactory extends ContextArgumentMapperFactory { +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapper.java index 251e99436b0..5e1454cad1e 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapper.java @@ -20,9 +20,8 @@ import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; public class ProducerInvocationContextMapper extends AbstractProducerContextArgMapper { - - public ProducerInvocationContextMapper(int producerIdx) { - super(producerIdx); + public ProducerInvocationContextMapper(String invocationArgumentName, String swaggerArgumentName) { + super(invocationArgumentName, swaggerArgumentName); } @Override diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapperFactory.java index d370627f6a6..1e99e896d15 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerInvocationContextMapperFactory.java @@ -18,22 +18,16 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -@Component -@Qualifier("producer") -public class ProducerInvocationContextMapperFactory implements ContextArgumentMapperFactory { +public class ProducerInvocationContextMapperFactory implements ProducerContextArgumentMapperFactory { @Override public Class getContextClass() { return InvocationContext.class; } @Override - public ArgumentMapper create(int producerArgIdx) { - return new ProducerInvocationContextMapper(producerArgIdx); + public ArgumentMapper create(String invocationArgumentName, String swaggerArgumentName) { + return new ProducerInvocationContextMapper(invocationArgumentName, swaggerArgumentName); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java deleted file mode 100644 index 6f6a3eca5e4..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon; - -/** - * Argument mapper for object params. - * Collect all query swagger params as json and deserialize to object param. - */ -public class ProducerSpringMVCQueryObjectMapper implements ArgumentMapper { - private int producerIdx; - - private Map swaggerParamIndexMap; - - private Converter converter; - - public ProducerSpringMVCQueryObjectMapper(Map swaggerParamIndexMap, int producerIdx, - Type producerParamType) { - this.producerIdx = producerIdx; - this.swaggerParamIndexMap = new HashMap<>(); - this.swaggerParamIndexMap.putAll(swaggerParamIndexMap); - converter = new ConverterCommon(producerParamType); - } - - @Override - public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { - Map jsonMap = new HashMap<>(swaggerParamIndexMap.size()); - - for (Entry swaggerIndexEntry : swaggerParamIndexMap.entrySet()) { - jsonMap.put(swaggerIndexEntry.getKey(), invocation.getSwaggerArgument(swaggerIndexEntry.getValue())); - } - - final Object producerParam = converter.convert(jsonMap); - producerArguments[producerIdx] = producerParam; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SpringMVCProducerArgumentsMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SpringMVCProducerArgumentsMapperFactory.java deleted file mode 100644 index f7d1edad092..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SpringMVCProducerArgumentsMapperFactory.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.ProviderParameter; -import org.springframework.stereotype.Component; - -import io.swagger.converter.ModelConverters; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.QueryParameter; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; - -@Component -public class SpringMVCProducerArgumentsMapperFactory extends ProducerArgumentsMapperFactory { - - @Override - public boolean canProcess(ArgumentsMapperConfig config) { - return config.getSwaggerGeneratorContext().getClass().getCanonicalName().equals( - "org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext"); - } - - /** - * Find all query object params - * @return the names of the query object params - */ - @Override - protected Set findAggregatedParamNames(Map providerParamMap, - Map> swaggerParamMap) { - // find all reference type producer params, and exclude body param - Set queryObjectSet = new HashSet<>(); - - for (Entry paramEntry : providerParamMap.entrySet()) { - Type paramType = paramEntry.getValue().getType(); - Property property = ModelConverters.getInstance().readAsProperty(paramType); - if (RefProperty.class.isInstance(property)) { - queryObjectSet.add(paramEntry.getKey()); - } - } - - for (Entry> paramEntry : swaggerParamMap.entrySet()) { - if (ParamUtils.isRealBodyParameter(paramEntry.getValue().getParam())) { - queryObjectSet.remove(paramEntry.getKey()); - } - } - - return queryObjectSet; - } - - protected void generateAggregatedParamMapper(ArgumentsMapperConfig config, - Map providerParamMap, Map> swaggerParamMap, - Set aggregatedParamNames) { - // collect all query params - Map querySwaggerParamsIndex = new HashMap<>(); - for (Entry> wrapperEntry : swaggerParamMap.entrySet()) { - if (wrapperEntry.getValue().getParam() instanceof QueryParameter) { - querySwaggerParamsIndex.put(wrapperEntry.getKey(), wrapperEntry.getValue().getIndex()); - } - } - // create mapper for each query objects - for (String queryObjectName : aggregatedParamNames) { - final ProviderParameter providerParameter = providerParamMap.get(queryObjectName); - ArgumentMapper mapper = new ProducerSpringMVCQueryObjectMapper(querySwaggerParamsIndex, - providerParameter.getIndex(), - providerParameter.getType()); - config.addArgumentMapper(mapper); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerArgumentToProducerBodyField.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerArgumentToProducerBodyField.java deleted file mode 100644 index d1541a3fcf7..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerArgumentToProducerBodyField.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.FieldInfo; - -/** - * 透明RPC的典型场景 - * 因为没有标注指明RESTful映射方式 - * 所以,所有参数被包装为一个class,每个参数是一个field - * producer在处理时,需要将这些field取出来当作参数使用 - */ -public class SwaggerArgumentToProducerBodyField implements ArgumentMapper { - // key为producerArgs的下标 - private Map fieldMap; - - public SwaggerArgumentToProducerBodyField(Map fieldMap) { - this.fieldMap = fieldMap; - } - - @Override - public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { - Object body = invocation.getSwaggerArgument(0); - - try { - for (Entry entry : fieldMap.entrySet()) { - FieldInfo info = entry.getValue(); - - Object fieldValue = info.getField().get(body); - Object producerParam = info.getConverter().convert(fieldValue); - producerArguments[entry.getKey()] = producerParam; - } - } catch (IllegalArgumentException e) { - throw e; - } catch (Throwable e) { - throw new Error(e); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java new file mode 100644 index 00000000000..254c47949dc --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.lang.reflect.Type; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.JsonUtils; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +public class SwaggerBodyFieldToProducerArgument extends ProducerArgumentMapper { + public static ObjectMapper mapper = JsonUtils.OBJ_MAPPER; + + private final String invocationArgumentName; + + private final String parameterName; + + private final JavaType producerParamType; + + private final String swaggerArgumentName; + + public SwaggerBodyFieldToProducerArgument(String invocationArgumentName, + String swaggerArgumentName, String parameterName, Type producerParamType) { + this.invocationArgumentName = invocationArgumentName; + this.parameterName = parameterName; + this.producerParamType = TypeFactory.defaultInstance().constructType(producerParamType); + this.swaggerArgumentName = swaggerArgumentName; + } + + @Override + @SuppressWarnings("unchecked") + public void swaggerArgumentToInvocationArguments(SwaggerInvocation invocation, + Map swaggerArguments, Map invocationArguments) { + Map body = (Map) swaggerArguments.get(swaggerArgumentName); + invocationArguments.put(invocationArgumentName, + body == null ? null : mapper.convertValue(body.get(parameterName), producerParamType)); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/ContextUtils.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/ContextUtils.java index 4f6430ea9e5..c0b20d0d9ea 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/ContextUtils.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/ContextUtils.java @@ -26,7 +26,7 @@ public final class ContextUtils { private ContextUtils() { } - private static ThreadLocal contextMgr = new ThreadLocal<>(); + private static final ThreadLocal contextMgr = new ThreadLocal<>(); public static InvocationContext getInvocationContext() { return contextMgr.get(); diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContext.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContext.java index 0807beb1c6d..8f7da8d0bd3 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContext.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContext.java @@ -19,23 +19,23 @@ import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; /** - * 设置特定的Cse Context数据 + * InvocationContext is used to pass data between microservices or in microservice different layer. */ public class InvocationContext { - private static HttpStatusManager statusMgr = new HttpStatusManager(); + private static final HttpStatusManager statusMgr = new HttpStatusManager(); protected StatusType httpStatus; - // value只能是简单类型 - protected Map context = new HashMap<>(); + protected final Map context = new HashMap<>(); - protected Map localContext = new HashMap<>(); + protected final Map localContext = new HashMap<>(); + + protected TransportContext transportContext; public InvocationContext() { httpStatus = Status.OK; @@ -46,7 +46,8 @@ public Map getContext() { } public void setContext(Map context) { - this.context = context; + this.context.clear(); + this.addContext(context); } public void addContext(String key, String value) { @@ -77,13 +78,6 @@ public void mergeContext(Map otherContext) { if (otherContext == null) { return; } - if (otherContext.size() > context.size()) { - for (Entry entry : context.entrySet()) { - otherContext.putIfAbsent(entry.getKey(), entry.getValue()); - } - this.context = otherContext; - return; - } context.putAll(otherContext); } @@ -92,7 +86,8 @@ public Map getLocalContext() { } public void setLocalContext(Map localContext) { - this.localContext = localContext; + this.localContext.clear(); + this.addLocalContext(localContext); } public void addLocalContext(String key, Object value) { @@ -127,4 +122,13 @@ public void setStatus(int statusCode, String reason) { public void setStatus(int statusCode) { this.httpStatus = statusMgr.getOrCreateByStatusCode(statusCode); } + + @SuppressWarnings("unchecked") + public T getTransportContext() { + return (T) transportContext; + } + + public void setTransportContext(TransportContext transportContext) { + this.transportContext = transportContext; + } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContextCompletableFuture.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContextCompletableFuture.java index 222eb5d0647..363025afae7 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContextCompletableFuture.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/InvocationContextCompletableFuture.java @@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture; public class InvocationContextCompletableFuture extends CompletableFuture { - private InvocationContext context; + private final InvocationContext context; public InvocationContextCompletableFuture(InvocationContext context) { this.context = context; @@ -29,4 +29,4 @@ public InvocationContextCompletableFuture(InvocationContext context) { public InvocationContext getContext() { return context; } -} \ No newline at end of file +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/TransportContext.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/TransportContext.java new file mode 100644 index 00000000000..7991e6b5fa3 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/TransportContext.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.context; + +/** + * currently, only for server side + */ +public interface TransportContext { +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/VertxTransportContext.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/VertxTransportContext.java new file mode 100644 index 00000000000..103af476331 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/context/VertxTransportContext.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.context; + +import io.vertx.core.Context; + +public interface VertxTransportContext extends TransportContext { + Context getVertxContext(); +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/Converter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/Converter.java index 34cc5ab7662..f3b27538409 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/Converter.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/Converter.java @@ -16,6 +16,12 @@ */ package org.apache.servicecomb.swagger.invocation.converter; +import java.lang.reflect.Type; + public interface Converter { + Type getSrcType(); + + Type getTargetType(); + Object convert(Object value); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgr.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgr.java deleted file mode 100644 index 94b8570d002..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgr.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.lang3.reflect.TypeUtils; -import org.apache.servicecomb.swagger.invocation.InvocationType; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterSame; -import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementArrayToList; -import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementArrayToSet; -import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementCollectionToArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class ConverterMgr { - private static final Logger LOGGER = LoggerFactory.getLogger(ConverterMgr.class); - - // 第一层key是src type,第二层key是target type - private Map> srcTargetMap = new HashMap<>(); - - // key为target type,这个场景,不关注源实例类型,直接用jackson convert - // 效率最低,走到这个处理流程的,都需要打印日志,说明这是很坏的实践 - // 但是如果不做这个功能,又会有一堆人觉得约束太多 - private Map commonMap = new ConcurrentHashMap<>(); - - private Converter same = ConverterSame.getInstance(); - - private Converter arrayToList = SameElementArrayToList.getInstance(); - - private Converter arrayToSet = SameElementArrayToSet.getInstance(); - - // array的构造需要有类型,不能使用统一的处理 - private Map collectionToArrayMap = new ConcurrentHashMap<>(); - - @Autowired(required = false) - public void setCustomizedConverters(List converters) { - for (CustomizedConverter converter : converters) { - Map map = srcTargetMap.computeIfAbsent(converter.getSrcType(), k -> new HashMap<>()); - map.put(converter.getTargetType(), converter); - } - } - - public Converter findConverter(InvocationType invocationType, Type provider, Type swagger) { - if (InvocationType.CONSUMER.equals(invocationType)) { - return findConverter(provider, swagger); - } - - return findConverter(swagger, provider); - } - - public Converter findConverter(Type src, Type target) { - Converter converter = findSrcTarget(src, target); - if (converter != null) { - return converter; - } - - converter = findAssignable(src, target); - if (converter != null) { - return converter; - } - - converter = findCollectionToArray(src, target); - if (converter != null) { - return converter; - } - - converter = findArrayToCollection(src, target); - if (converter != null) { - return converter; - } - - LOGGER.warn("Bad practice, low performance, convert from {} to {}", src, target); - return findCommonConverter(target); - } - - protected Converter findSrcTarget(Type src, Type target) { - Map map = srcTargetMap.get(src); - if (map == null) { - return null; - } - - return map.get(target); - } - - protected Converter findCommonConverter(Type target) { - Converter converter = commonMap.get(target); - if (converter != null) { - return converter; - } - - // 并发导致重复创建没有问题 - converter = new ConverterCommon(target); - commonMap.put(target, converter); - return converter; - } - - protected Converter findArrayToCollection(Type src, Type target) { - if (src.getClass().equals(Class.class) && ParameterizedType.class.isAssignableFrom(target.getClass())) { - Class srcCls = (Class) src; - ParameterizedType targetType = (ParameterizedType) target; - Class targetCls = (Class) targetType.getRawType(); - - if (srcCls.isArray() && srcCls.getComponentType().equals(targetType.getActualTypeArguments()[0])) { - if (List.class.isAssignableFrom(targetCls)) { - return arrayToList; - } - if (Set.class.isAssignableFrom(targetCls)) { - return arrayToSet; - } - } - } - - return null; - } - - protected Converter findAssignable(Type src, Type target) { - if (isAssignable(src, target)) { - return same; - } - - return null; - } - - boolean isAssignable(Type src, Type target) { - boolean assignable = TypeUtils.isAssignable(src, target); - if (!assignable) { - // void <--> java.lang.Void convert should be covered - assignable = (src == void.class || src == Void.class) && (target == void.class || target == Void.class); - } - return assignable; - } - - protected Converter findCollectionToArray(Type src, Type target) { - if (ParameterizedType.class.isAssignableFrom(src.getClass()) && target.getClass().equals(Class.class)) { - ParameterizedType srcType = (ParameterizedType) src; - Class srcCls = (Class) srcType.getRawType(); - Class targetCls = (Class) target; - - if (Collection.class.isAssignableFrom(srcCls) && targetCls.isArray() - && srcType.getActualTypeArguments()[0].equals(targetCls.getComponentType())) { - Converter converter = collectionToArrayMap - .computeIfAbsent(target, k -> new SameElementCollectionToArray(targetCls.getComponentType())); - return converter; - } - } - - return null; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/CustomizedConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/CustomizedConverter.java deleted file mode 100644 index 02417b735ee..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/CustomizedConverter.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter; - -import java.lang.reflect.Type; - -public interface CustomizedConverter extends Converter { - Type getSrcType(); - - Type getTargetType(); -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterCommon.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterCommon.java deleted file mode 100644 index 1ab9e6527b4..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterCommon.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter.impl; - -import java.lang.reflect.Type; - -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -public class ConverterCommon implements Converter { - private JavaType targetJavaType; - - public ConverterCommon(Type targetType) { - targetJavaType = TypeFactory.defaultInstance().constructType(targetType); - } - - @Override - public Object convert(Object value) { - return JsonUtils.OBJ_MAPPER.convertValue(value, targetJavaType); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterSame.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterSame.java deleted file mode 100644 index e856c0d2139..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/ConverterSame.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter.impl; - -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -public final class ConverterSame implements Converter { - private static final Converter INSTANCE = new ConverterSame(); - - public static Converter getInstance() { - return INSTANCE; - } - - private ConverterSame() { - } - - @Override - public Object convert(Object value) { - return value; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToList.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToList.java deleted file mode 100644 index f5323bccdf5..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToList.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter.impl; - -import java.util.Arrays; - -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -public final class SameElementArrayToList implements Converter { - private static final Converter INSTANCE = new SameElementArrayToList(); - - public static Converter getInstance() { - return INSTANCE; - } - - private SameElementArrayToList() { - } - - @Override - public Object convert(Object value) { - if (value == null) { - return null; - } - - Object[] array = (Object[]) value; - return Arrays.asList(array); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToSet.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToSet.java deleted file mode 100644 index 767697d53e3..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementArrayToSet.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter.impl; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -public final class SameElementArrayToSet implements Converter { - private static final Converter INSTANCE = new SameElementArrayToSet(); - - public static Converter getInstance() { - return INSTANCE; - } - - private SameElementArrayToSet() { - } - - @Override - public Object convert(Object value) { - if (value == null) { - return null; - } - - Object[] array = (Object[]) value; - Set set = new HashSet<>(); - set.addAll(Arrays.asList(array)); - return set; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementCollectionToArray.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementCollectionToArray.java deleted file mode 100644 index 44afe3cf211..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/SameElementCollectionToArray.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.converter.impl; - -import java.lang.reflect.Array; -import java.util.Collection; - -import org.apache.servicecomb.swagger.invocation.converter.Converter; - -public class SameElementCollectionToArray implements Converter { - private Class elementCls; - - public SameElementCollectionToArray(Class elementCls) { - this.elementCls = elementCls; - } - - @Override - public Object convert(Object value) { - if (value == null) { - return null; - } - - @SuppressWarnings("unchecked") - Collection collection = (Collection) value; - Object array = Array.newInstance(elementCls, collection.size()); - return collection.toArray((Object[]) array); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/BytesToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/BytesToPartConverter.java index 44265040e06..affccb1e104 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/BytesToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/BytesToPartConverter.java @@ -20,14 +20,12 @@ import java.io.ByteArrayInputStream; import java.lang.reflect.Type; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.servicecomb.foundation.common.part.InputStreamPart; -import org.apache.servicecomb.swagger.invocation.converter.CustomizedConverter; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.swagger.invocation.converter.Converter; -@Component -public class BytesToPartConverter implements CustomizedConverter { +public class BytesToPartConverter implements Converter { @Override public Type getSrcType() { return byte[].class; diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/FileToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/FileToPartConverter.java index 40ea0eb8bdf..66964377cbb 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/FileToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/FileToPartConverter.java @@ -20,14 +20,12 @@ import java.io.File; import java.lang.reflect.Type; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.servicecomb.foundation.common.part.FilePart; -import org.apache.servicecomb.swagger.invocation.converter.CustomizedConverter; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.swagger.invocation.converter.Converter; -@Component -public class FileToPartConverter implements CustomizedConverter { +public class FileToPartConverter implements Converter { @Override public Type getSrcType() { return File.class; diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/InputStreamToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/InputStreamToPartConverter.java index fca6edff231..81216cadda0 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/InputStreamToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/InputStreamToPartConverter.java @@ -20,14 +20,12 @@ import java.io.InputStream; import java.lang.reflect.Type; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.servicecomb.foundation.common.part.InputStreamPart; -import org.apache.servicecomb.swagger.invocation.converter.CustomizedConverter; -import org.springframework.stereotype.Component; +import org.apache.servicecomb.swagger.invocation.converter.Converter; -@Component -public class InputStreamToPartConverter implements CustomizedConverter { +public class InputStreamToPartConverter implements Converter { @Override public Type getSrcType() { return InputStream.class; diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverter.java new file mode 100644 index 00000000000..bbdb244f58e --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverter.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.apache.servicecomb.swagger.invocation.converter.Converter; + +import jakarta.servlet.http.Part; + +public class PartListToPartArrayConverter implements Converter { + @Override + public Type getSrcType() { + return ParameterizedTypeUtil.make(List.class, Part.class); + } + + @Override + public Type getTargetType() { + return Part[].class; + } + + @Override + public Object convert(Object value) { + if (value == null) { + return null; + } + + @SuppressWarnings("unchecked") + List partList = (List) value; + return partList.toArray(new Part[0]); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverter.java new file mode 100644 index 00000000000..5c2ee3284ac --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverter.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.apache.servicecomb.swagger.invocation.converter.Converter; + +import jakarta.servlet.http.Part; + +public class PartListToPartListConverter implements Converter { + @Override + public Type getSrcType() { + return ParameterizedTypeUtil.make(List.class, Part.class); + } + + @Override + public Type getTargetType() { + return ParameterizedTypeUtil.make(List.class, Part.class); + } + + @Override + public Object convert(Object value) { + return value; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverter.java new file mode 100644 index 00000000000..912f18852c7 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverter.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import java.lang.reflect.Type; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.swagger.invocation.converter.Converter; + +public class PartToPartConverter implements Converter { + @Override + public Type getSrcType() { + return Part.class; + } + + @Override + public Type getTargetType() { + return Part.class; + } + + @Override + public Object convert(Object value) { + return value; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/ResourceToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/ResourceToPartConverter.java index 58e99c5e363..d85d1bf64c0 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/ResourceToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/ResourceToPartConverter.java @@ -19,15 +19,13 @@ import java.lang.reflect.Type; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.servicecomb.foundation.common.part.ResourcePart; -import org.apache.servicecomb.swagger.invocation.converter.CustomizedConverter; +import org.apache.servicecomb.swagger.invocation.converter.Converter; import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; -@Component -public class ResourceToPartConverter implements CustomizedConverter { +public class ResourceToPartConverter implements Converter { @Override public Type getSrcType() { return Resource.class; diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionData.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionData.java index 80d50c9123c..fdec294eca6 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionData.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionData.java @@ -17,10 +17,18 @@ package org.apache.servicecomb.swagger.invocation.exception; +import org.apache.servicecomb.foundation.common.DynamicObject; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + /** * 将普通异常转换为InvocationException时,保存message信息 */ -public class CommonExceptionData { +public class CommonExceptionData extends DynamicObject { + @JsonInclude(Include.NON_NULL) + private String code; + private String message; public CommonExceptionData() { @@ -30,16 +38,39 @@ public CommonExceptionData(String message) { this.message = message; } + public CommonExceptionData(String code, String message) { + this.code = code; + this.message = message; + } + + public String getCode() { + return code; + } + + public CommonExceptionData setCode(String code) { + this.code = code; + return this; + } + public String getMessage() { return message; } - public void setMessage(String message) { + public CommonExceptionData setMessage(String message) { this.message = message; + return this; } @Override public String toString() { - return "CommonExceptionData [message=" + message + "]"; + if (code == null) { + return "CommonExceptionData [message=" + message + "]"; + } + + return "CommonExceptionData{" + + "code='" + code + '\'' + + ", message='" + message + '\'' + + ", dynamic=" + dynamic + + '}'; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/DefaultExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/DefaultExceptionToProducerResponseConverter.java deleted file mode 100644 index 3dbd0ccccf1..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/DefaultExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DefaultExceptionToProducerResponseConverter implements ExceptionToProducerResponseConverter { - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionToProducerResponseConverter.class); - - @Override - public Class getExceptionClass() { - // default logic, not bind to special class - return null; - } - - @Override - public Response convert(SwaggerInvocation swaggerInvocation, Throwable e) { - LOGGER.error("invoke failed, invocation={}", swaggerInvocation.getInvocationQualifiedName(), e); - //not only producer but also consumer - return Response.failResp(swaggerInvocation.getInvocationType(), e); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionFactory.java index 7bdd7f7cca7..a4050b2f7ec 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionFactory.java @@ -17,13 +17,13 @@ package org.apache.servicecomb.swagger.invocation.exception; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; -import javax.ws.rs.core.Response.StatusType; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; +import jakarta.ws.rs.core.Response.StatusType; + public final class ExceptionFactory { // cse内置的错误 // 考虑到springmvc不支持自定义http错误码,所以只能使用“标准”错误码 @@ -32,7 +32,7 @@ public final class ExceptionFactory { // private static final int PROVIDER_INNER_STATUS_CODE = 510; public static final int PRODUCER_INNER_STATUS_CODE = 590; - public static final String PRODUCER_INNER_REASON_PHRASE = "Cse Internal Server Error"; + public static final String PRODUCER_INNER_REASON_PHRASE = "Unexpected producer error, please check logs for details"; public static final StatusType PRODUCER_INNER_STATUS = new HttpStatus(PRODUCER_INNER_STATUS_CODE, PRODUCER_INNER_REASON_PHRASE); @@ -42,9 +42,7 @@ public final class ExceptionFactory { // private static final int CONSUMER_INNER_STATUS_CODE = 420; public static final int CONSUMER_INNER_STATUS_CODE = 490; - public static final String CONSUMER_INNER_REASON_PHRASE = "Cse Internal Bad Request"; - - private static ExceptionToProducerResponseConverters exceptionToProducerResponseConverters = new ExceptionToProducerResponseConverters(); + public static final String CONSUMER_INNER_REASON_PHRASE = "Unexpected consumer error, please check logs for details"; public static final StatusType CONSUMER_INNER_STATUS = new HttpStatus(CONSUMER_INNER_STATUS_CODE, CONSUMER_INNER_REASON_PHRASE); @@ -54,7 +52,7 @@ private ExceptionFactory() { public static InvocationException create(StatusType status, Object exceptionOrErrorData) { - if (InvocationException.class.isInstance(exceptionOrErrorData)) { + if (exceptionOrErrorData instanceof InvocationException) { return (InvocationException) exceptionOrErrorData; } @@ -69,12 +67,12 @@ public static InvocationException createProducerException(Object errorData) { return create(PRODUCER_INNER_STATUS, errorData); } - protected static InvocationException doCreate(StatusType status, + private static InvocationException doCreate(StatusType status, Object errorData) { return new InvocationException(status, errorData); } - protected static InvocationException doCreate(int statusCode, String reasonPhrase, CommonExceptionData data, + private static InvocationException doCreate(int statusCode, String reasonPhrase, CommonExceptionData data, Throwable e) { return new InvocationException(statusCode, reasonPhrase, data, e); } @@ -110,13 +108,11 @@ public static InvocationException convertProducerException(Throwable e, String e // 如果e中取不出可以直接返回的InvocationException // 则需要创建新的InvocationException实例,此时不允许使用e.getMessage,因为可能会涉及关键信息被传给远端 // 新创建的InvocationException,会使用errorMsg来构建CommonExceptionData - protected static InvocationException convertException(int statusCode, String reasonPhrase, Throwable e, + private static InvocationException convertException(int statusCode, String reasonPhrase, Throwable e, String errorMsg) { - if (InvocationTargetException.class.isInstance(e)) { - e = ((InvocationTargetException) e).getTargetException(); - } + e = unwrap(e); - if (InvocationException.class.isInstance(e)) { + if (e instanceof InvocationException) { return (InvocationException) e; } @@ -124,7 +120,25 @@ protected static InvocationException convertException(int statusCode, String rea return doCreate(statusCode, reasonPhrase, data, e); } - public static Response convertExceptionToResponse(SwaggerInvocation swaggerInvocation, Throwable e) { - return exceptionToProducerResponseConverters.convertExceptionToResponse(swaggerInvocation, e); + public static Throwable unwrapIncludeInvocationException(Throwable throwable) { + throwable = unwrap(throwable); + if (throwable instanceof InvocationException) { + throwable = throwable.getCause(); + } + return throwable; + } + + @SuppressWarnings("unchecked") + public static T unwrap(Throwable throwable) { + if (throwable instanceof InvocationTargetException) { + throwable = ((InvocationTargetException) throwable).getTargetException(); + } + if (throwable instanceof CompletionException) { + throwable = throwable.getCause(); + } + if (throwable instanceof ExecutionException) { + throwable = throwable.getCause(); + } + return (T) throwable; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverter.java deleted file mode 100644 index a74b4714a2e..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -public interface ExceptionToProducerResponseConverter { - Class getExceptionClass(); - - default int getOrder() { - return 0; - } - - Response convert(SwaggerInvocation swaggerInvocation, T e); -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverters.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverters.java deleted file mode 100644 index d9f50da0958..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/ExceptionToProducerResponseConverters.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -public class ExceptionToProducerResponseConverters { - private Map, ExceptionToProducerResponseConverter> exceptionToProducerResponseConverters = - new HashMap<>(); - - private ExceptionToProducerResponseConverter defaultConverter; - - /** - * Load the {@link ExceptionToProducerResponseConverter} implementations. Ensure that those converters whose {@link ExceptionToProducerResponseConverter#getOrder()} - * return smaller value takes higher priority. - */ - @SuppressWarnings("unchecked") - public ExceptionToProducerResponseConverters() { - SPIServiceUtils.getSortedService(ExceptionToProducerResponseConverter.class).forEach(converter -> { - if (converter.getExceptionClass() == null) { - if (defaultConverter == null) { - defaultConverter = converter; - } - return; - } - - exceptionToProducerResponseConverters.putIfAbsent(converter.getExceptionClass(), converter); - }); - } - - public Response convertExceptionToResponse(SwaggerInvocation swaggerInvocation, Throwable e) { - ExceptionToProducerResponseConverter converter = null; - Class clazz = e.getClass(); - while (converter == null) { - converter = exceptionToProducerResponseConverters.get(clazz); - if (clazz == Throwable.class) { - break; - } - clazz = clazz.getSuperclass(); - } - if (converter == null) { - converter = defaultConverter; - } - return converter.convert(swaggerInvocation, e); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationException.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationException.java index 273be286734..bd6ba5cc194 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationException.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationException.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.swagger.invocation.exception; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; @@ -33,9 +33,9 @@ public class InvocationException extends RuntimeException { * http header中的statusCode * 不直接使用Status类型,是为了支持业务自定义code */ - private StatusType status; + private final StatusType status; - private Object errorData; + private final Object errorData; public InvocationException(StatusType status, Object errorData) { this.status = status; @@ -43,21 +43,31 @@ public InvocationException(StatusType status, Object errorData) { } public InvocationException(StatusType status, String msg) { - this.status = status; - this.errorData = new CommonExceptionData(msg); + this(status, new CommonExceptionData(msg)); } public InvocationException(int statusCode, String reasonPhrase, Object errorData, Throwable cause) { - super(cause); - status = new HttpStatus(statusCode, reasonPhrase); - this.errorData = errorData; + this(new HttpStatus(statusCode, reasonPhrase), errorData, cause); } public InvocationException(int statusCode, String reasonPhrase, Object errorData) { - status = new HttpStatus(statusCode, reasonPhrase); + this(new HttpStatus(statusCode, reasonPhrase), errorData); + } + + public InvocationException(StatusType status, Object errorData, Throwable cause) { + super(cause); + this.status = status; this.errorData = errorData; } + public InvocationException(StatusType status, String code, String msg) { + this(status, new CommonExceptionData(code, msg)); + } + + public InvocationException(StatusType status, String code, String msg, Throwable cause) { + this(status, new CommonExceptionData(code, msg), cause); + } + public StatusType getStatus() { return status; } @@ -74,6 +84,11 @@ public Object getErrorData() { return errorData; } + @SuppressWarnings("unchecked") + public T getError() { + return (T) errorData; + } + @Override public String getMessage() { return this.toString(); @@ -81,11 +96,7 @@ public String getMessage() { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("InvocationException: code="); - sb.append(getStatusCode()); - sb.append(";msg="); - sb.append(getErrorData()); - return sb.toString(); + return "InvocationException: code=" + getStatusCode() + + ";msg=" + getErrorData(); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationExceptionToProducerResponseConverter.java deleted file mode 100644 index 2c3ddfd4b5d..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/exception/InvocationExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -public class InvocationExceptionToProducerResponseConverter implements - ExceptionToProducerResponseConverter { - @Override - public Class getExceptionClass() { - return InvocationException.class; - } - - @Override - public Response convert(SwaggerInvocation swaggerInvocation, InvocationException e) { - return Response.failResp(e); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/extension/ProducerInvokeExtension.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/extension/ProducerInvokeExtension.java deleted file mode 100644 index 370b3d192a6..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/extension/ProducerInvokeExtension.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.extension; - -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -/** - * Producer method invocation extension to handle the required validations/checks before invoking the actual method. - */ -public interface ProducerInvokeExtension { - - public int getOrder(); - - ///Invoked before the method execution to handle the required checks before method invocation. - void beforeMethodInvoke(SwaggerInvocation invocation, SwaggerProducerOperation producerOperation, - Object[] args) throws Exception; -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/InvocationContextProcessor.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/InvocationContextProcessor.java index c995a9330d2..13e93b23dc6 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/InvocationContextProcessor.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/InvocationContextProcessor.java @@ -17,20 +17,14 @@ package org.apache.servicecomb.swagger.invocation.generator; -import org.apache.servicecomb.swagger.extend.parameter.InvocationContextParameter; -import org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor; -import org.apache.servicecomb.swagger.generator.core.OperationGenerator; +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.SwaggerContextRegister; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -public class InvocationContextProcessor implements CommonParameterTypeProcessor { +public class InvocationContextProcessor implements SwaggerContextRegister { @Override - public Class getParameterType() { + public Type getContextType() { return InvocationContext.class; } - - @Override - public void process(OperationGenerator operationGenerator, int paramIdx) { - InvocationContextParameter parameter = new InvocationContextParameter(); - operationGenerator.addProviderParameter(parameter); - } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/ScbResponseProcessor.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/ScbResponseProcessor.java new file mode 100644 index 00000000000..f77062d4add --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/generator/ScbResponseProcessor.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.generator; + +import java.lang.reflect.Type; + +import org.apache.servicecomb.swagger.generator.OperationGenerator; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.processor.response.DefaultResponseTypeProcessor; +import org.apache.servicecomb.swagger.invocation.Response; + +public class ScbResponseProcessor extends DefaultResponseTypeProcessor { + @Override + public Class getProcessType() { + return Response.class; + } + + @Override + public Type extractResponseType(SwaggerGenerator swaggerGenerator, OperationGenerator operationGenerator, + Type genericResponseType) { + return null; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactories.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactories.java new file mode 100644 index 00000000000..761149ae24e --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactories.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response; + +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; + +public class ResponseMapperFactories { + private final List> factories; + + @SuppressWarnings("unchecked") + public ResponseMapperFactories(Class> factoryCls) { + factories = (List>) SPIServiceUtils.getSortedService(factoryCls); + } + + public MAPPER createResponseMapper(Type providerType) { + for (ResponseMapperFactory factory : factories) { + if (!factory.isMatch(providerType)) { + continue; + } + + return factory.createResponseMapper(this, providerType); + } + + throw new IllegalStateException( + String.format("can not find response mapper for %s, this should never happened.", + providerType.getTypeName())); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java index 70d8871c08c..917a3a835b9 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactory.java @@ -18,18 +18,12 @@ import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; - public interface ResponseMapperFactory { default int getOrder() { return 0; } - default void setConverterMgr(ConverterMgr converterMgr) { - } - - boolean isMatch(Type swaggerType, Type providerType); + boolean isMatch(Type providerType); - MAPPER createResponseMapper(ResponseMapperFactorys factorys, Type swaggerType, - Type providerType); + MAPPER createResponseMapper(ResponseMapperFactories factories, Type providerType); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java deleted file mode 100644 index 92e95c6d924..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMapperFactorys.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response; - -import java.lang.reflect.Type; -import java.util.List; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; - -public class ResponseMapperFactorys { - private List> factorys; - - public ResponseMapperFactorys(Class> factoryCls, ConverterMgr converterMgr) { - this(factoryCls); - this.setConverterMgr(converterMgr); - } - - @SuppressWarnings("unchecked") - public ResponseMapperFactorys(Class> factoryCls) { - factorys = (List>) SPIServiceUtils.getSortedService(factoryCls); - } - - public void setConverterMgr(ConverterMgr converterMgr) { - factorys.forEach(factory -> factory.setConverterMgr(converterMgr)); - } - - public MAPPER createResponseMapper(Type swaggerType, Type providerType) { - for (ResponseMapperFactory factory : factorys) { - if (!factory.isMatch(swaggerType, providerType)) { - continue; - } - - return factory.createResponseMapper(this, swaggerType, providerType); - } - - throw new IllegalStateException( - String.format("can not find response mapper for %s and %s, this should never happened.", - swaggerType.getTypeName(), - providerType.getTypeName())); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java deleted file mode 100644 index 4a35879a3d3..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMeta.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; - -import com.fasterxml.jackson.databind.JavaType; - -import io.swagger.models.Response; -import io.swagger.models.properties.Property; - -public class ResponseMeta { - /** - * swagger中定义的statusCode与java类型的映射,方便consumer端transport将码流转换为具体的类型 - */ - private JavaType javaType; - - private Map headers = new HashMap<>(); - - public void init(SwaggerToClassGenerator swaggerToClassGenerator, Response response) { - if (javaType == null) { - javaType = swaggerToClassGenerator.convert(response.getSchema()); - } - - if (response.getHeaders() == null) { - return; - } - for (Entry entry : response.getHeaders().entrySet()) { - JavaType headerJavaType = swaggerToClassGenerator.convert(entry.getValue()); - headers.put(entry.getKey(), headerJavaType); - } - } - - public JavaType getJavaType() { - return javaType; - } - - public void setJavaType(JavaType javaType) { - this.javaType = javaType; - } - - public Map getHeaders() { - return headers; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java index e3577114fed..8de01afe630 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java @@ -19,10 +19,12 @@ import java.util.Map; +import com.fasterxml.jackson.databind.JavaType; + public interface ResponseMetaMapper { default int getOrder() { return 0; } - Map getMapper(); + Map getMapper(); } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java index 881cb812f6c..aa9e75796c4 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java @@ -16,26 +16,51 @@ */ package org.apache.servicecomb.swagger.invocation.response; -import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.converter.ConverterMgr; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.SimpleType; -import com.fasterxml.jackson.databind.type.TypeFactory; - -import io.swagger.models.Operation; -import io.swagger.models.Response; +import io.swagger.v3.core.util.ReflectionUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.responses.ApiResponse; +import jakarta.ws.rs.core.Response.Status; + +/** + *
+ * two Scenes:
+ * 1.consumer interface + swagger
+ *   interface declare success response type
+ *   and can declare exceptions response type by annotations
+ *   consumer interface meta never changed and has high priority
+ *
+ *   so, merge them to be one ResponsesMeta
+ *
+ * 2.restTemplate + swagger
+ *   can only declare success response type
+ *   and not stable
+ *
+ *   so, will wrap swagger meta
+ *
+ *   note:
+ *   old version support: List<User> users = restTemplate.postForObject(...., List.class)
+ *     in fact, in this time, type is determined by swagger meta
+ *   new version:
+ *     1) if request response type is List/Set/Map, and there is element type defined, then use swagger type,
+ *     2) other times use request response type
+ *     3) compare to old version, add support of ParameterizedTypeReference
+ * 
+ */ public class ResponsesMeta { private static final JavaType COMMON_EXCEPTION_JAVA_TYPE = SimpleType.constructUnsafe(CommonExceptionData.class); @@ -44,65 +69,68 @@ public class ResponsesMeta { private static final ResponseMetaMapper GLOBAL_DEFAULT_MAPPER = SPIServiceUtils .getPriorityHighestService(ResponseMetaMapper.class); - private Map responseMap = new HashMap<>(); + private final Map responseMap = new HashMap<>(); - private ResponseMeta defaultResponse; + private JavaType defaultResponse; - // 最后一个参数returnType用于兼容场景 - // 历史版本中swagger中定义的return可能没定义class名,此时consumer与swagger接口是一致的 - // 如果不传return类型进来,完全以swagger为标准,会导致生成的class不等于return - public void init(SwaggerToClassGenerator swaggerToClassGenerator, Operation operation, Type returnType) { - initSuccessResponse(returnType); - initGlobalDefaultMapper(); + public void init(OpenAPI swagger, Operation operation) { + if (responseMap.isEmpty()) { + responseMap.put(Status.OK.getStatusCode(), OBJECT_JAVA_TYPE); + initGlobalDefaultMapper(); + } + + for (Entry entry : operation.getResponses().entrySet()) { + if (entry.getValue().getContent() == null || entry.getValue().getContent().size() == 0) { + continue; + } + + String mediaType = entry.getValue().getContent().keySet().iterator().next(); + + JavaType javaType = ConverterMgr.findJavaType(swagger, + SwaggerUtils.getSchema(swagger, + entry.getValue().getContent().get(mediaType).getSchema())); - for (Entry entry : operation.getResponses().entrySet()) { if ("default".equals(entry.getKey())) { - defaultResponse = new ResponseMeta(); - defaultResponse.init(swaggerToClassGenerator, entry.getValue()); + defaultResponse = javaType; continue; } Integer statusCode = Integer.parseInt(entry.getKey()); - ResponseMeta responseMeta = responseMap.computeIfAbsent(statusCode, k -> new ResponseMeta()); - responseMeta.init(swaggerToClassGenerator, entry.getValue()); + JavaType existing = responseMap.get(statusCode); + if (existing == null || !ReflectionUtils.isVoid(javaType)) { + responseMap.put(statusCode, javaType); + } } - initInternalErrorResponse(); + responseMap.putIfAbsent(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, COMMON_EXCEPTION_JAVA_TYPE); + responseMap.putIfAbsent(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, COMMON_EXCEPTION_JAVA_TYPE); + responseMap.putIfAbsent(Status.TOO_MANY_REQUESTS.getStatusCode(), COMMON_EXCEPTION_JAVA_TYPE); + responseMap.putIfAbsent(Status.REQUEST_TIMEOUT.getStatusCode(), COMMON_EXCEPTION_JAVA_TYPE); + responseMap.putIfAbsent(Status.SERVICE_UNAVAILABLE.getStatusCode(), COMMON_EXCEPTION_JAVA_TYPE); if (defaultResponse == null) { // swagger中没有定义default,加上default专用于处理exception - ResponseMeta responseMeta = new ResponseMeta(); - responseMeta.setJavaType(OBJECT_JAVA_TYPE); - - defaultResponse = responseMeta; + defaultResponse = OBJECT_JAVA_TYPE; } } - protected void initSuccessResponse(Type returnType) { - ResponseMeta successResponse = new ResponseMeta(); - successResponse.setJavaType(TypeFactory.defaultInstance().constructType(returnType)); - responseMap.put(Status.OK.getStatusCode(), successResponse); - } - - protected void initInternalErrorResponse() { - ResponseMeta internalErrorResponse = new ResponseMeta(); - internalErrorResponse.setJavaType(COMMON_EXCEPTION_JAVA_TYPE); - responseMap.putIfAbsent(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, internalErrorResponse); - responseMap.putIfAbsent(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, internalErrorResponse); + public void cloneTo(ResponsesMeta target) { + target.defaultResponse = defaultResponse; + target.responseMap.putAll(responseMap); } protected void initGlobalDefaultMapper() { if (GLOBAL_DEFAULT_MAPPER != null) { - Map mappers = GLOBAL_DEFAULT_MAPPER.getMapper(); + Map mappers = GLOBAL_DEFAULT_MAPPER.getMapper(); if (mappers != null) { responseMap.putAll(mappers); } } } - public ResponseMeta findResponseMeta(int statusCode) { - ResponseMeta responseMeta = responseMap.get(statusCode); - if (responseMeta == null) { + public JavaType findResponseType(int statusCode) { + JavaType responseType = responseMap.get(statusCode); + if (responseType == null) { if (HttpStatus.isSuccess(statusCode)) { return responseMap.get(Status.OK.getStatusCode()); } @@ -110,6 +138,10 @@ public ResponseMeta findResponseMeta(int statusCode) { return defaultResponse; } - return responseMeta; + return responseType; + } + + public void setResponseType(int statusCode, JavaType javaType) { + this.responseMap.put(statusCode, javaType); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CompletableFutureConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CompletableFutureConsumerResponseMapperFactory.java index 742958d93a6..0a7d5a976ed 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CompletableFutureConsumerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CompletableFutureConsumerResponseMapperFactory.java @@ -20,11 +20,11 @@ import java.lang.reflect.Type; import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class CompletableFutureConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type consumerType) { + public boolean isMatch(Type consumerType) { if (!ParameterizedType.class.isAssignableFrom(consumerType.getClass())) { return false; } @@ -33,9 +33,9 @@ public boolean isMatch(Type swaggerType, Type consumerType) { } @Override - public ConsumerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type consumerType) { + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { Type realConsumerType = ((ParameterizedType) consumerType).getActualTypeArguments()[0]; - return factorys.createResponseMapper(swaggerType, realConsumerType); + return factories.createResponseMapper(realConsumerType); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CseResponseConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CseResponseConsumerResponseMapperFactory.java index 86c294b3a38..76b90185dcd 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CseResponseConsumerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/CseResponseConsumerResponseMapperFactory.java @@ -19,19 +19,19 @@ import java.lang.reflect.Type; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class CseResponseConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { private static final ConsumerResponseMapper SAME = response -> response; @Override - public boolean isMatch(Type swaggerType, Type consumerType) { + public boolean isMatch(Type consumerType) { return Response.class.equals(consumerType); } @Override - public ConsumerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type consumerType) { + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { return SAME; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapper.java index e43e37e3a84..d430050b0ca 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapper.java @@ -17,17 +17,10 @@ package org.apache.servicecomb.swagger.invocation.response.consumer; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; public class DefaultConsumerResponseMapper implements ConsumerResponseMapper { - private Converter converter; - - public DefaultConsumerResponseMapper(Converter converter) { - this.converter = converter; - } - @Override public Object mapResponse(Response response) { - return converter.convert(response.getResult()); + return response.getResult(); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapperFactory.java index bdd96430b3e..e60f05604e0 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/DefaultConsumerResponseMapperFactory.java @@ -18,32 +18,22 @@ import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class DefaultConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { - private ConverterMgr converterMgr; - - @Override - public void setConverterMgr(ConverterMgr converterMgr) { - this.converterMgr = converterMgr; - } - @Override public int getOrder() { return Integer.MAX_VALUE; } @Override - public boolean isMatch(Type swaggerType, Type consumerType) { + public boolean isMatch(Type consumerType) { return true; } @Override - public ConsumerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type consumerType) { - Converter converter = converterMgr.findConverter(swaggerType, consumerType); - return new DefaultConsumerResponseMapper(converter); + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { + return new DefaultConsumerResponseMapper(); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapper.java new file mode 100644 index 00000000000..d90be2d52a0 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapper.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.consumer; + +import java.util.Optional; + +import org.apache.servicecomb.swagger.invocation.Response; + +public class OptionalConsumerResponseMapper implements ConsumerResponseMapper { + private final ConsumerResponseMapper realMapper; + + public OptionalConsumerResponseMapper(ConsumerResponseMapper realMapper) { + this.realMapper = realMapper; + } + + @Override + public Object mapResponse(Response response) { + Object realResult = realMapper.mapResponse(response); + return Optional.ofNullable(realResult); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapperFactory.java new file mode 100644 index 00000000000..eddd30e407a --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/consumer/OptionalConsumerResponseMapperFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.consumer; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Optional; + +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; + +public class OptionalConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { + @Override + public boolean isMatch(Type consumerType) { + if (!ParameterizedType.class.isAssignableFrom(consumerType.getClass())) { + return false; + } + + return ((ParameterizedType) consumerType).getRawType().equals(Optional.class); + } + + @Override + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { + Type realConsumerType = ((ParameterizedType) consumerType).getActualTypeArguments()[0]; + ConsumerResponseMapper realMapper = factories.createResponseMapper(realConsumerType); + return new OptionalConsumerResponseMapper(realMapper); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CompletableFutureProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CompletableFutureProducerResponseMapperFactory.java index 21916084afa..fc87f5728b7 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CompletableFutureProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CompletableFutureProducerResponseMapperFactory.java @@ -20,11 +20,11 @@ import java.lang.reflect.Type; import java.util.concurrent.CompletableFuture; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class CompletableFutureProducerResponseMapperFactory implements ProducerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type producerType) { + public boolean isMatch(Type producerType) { if (!ParameterizedType.class.isAssignableFrom(producerType.getClass())) { return false; } @@ -33,9 +33,9 @@ public boolean isMatch(Type swaggerType, Type producerType) { } @Override - public ProducerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type producerType) { + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { Type realProducerType = ((ParameterizedType) producerType).getActualTypeArguments()[0]; - return factorys.createResponseMapper(swaggerType, realProducerType); + return factories.createResponseMapper(realProducerType); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CseResponseProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CseResponseProducerResponseMapperFactory.java index b7365229306..02f840cbb59 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CseResponseProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/CseResponseProducerResponseMapperFactory.java @@ -19,19 +19,19 @@ import java.lang.reflect.Type; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class CseResponseProducerResponseMapperFactory implements ProducerResponseMapperFactory { private static final ProducerResponseMapper SAME = (status, response) -> (Response) response; @Override - public boolean isMatch(Type swaggerType, Type producerType) { + public boolean isMatch(Type producerType) { return producerType.equals(Response.class); } @Override - public ProducerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type producerType) { + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { return SAME; } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapper.java index 2d35e7c0709..aa12dad9be9 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapper.java @@ -16,21 +16,13 @@ */ package org.apache.servicecomb.swagger.invocation.response.producer; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; public class DefaultProducerResponseMapper implements ProducerResponseMapper { - private Converter converter; - - public DefaultProducerResponseMapper(Converter converter) { - this.converter = converter; - } - @Override public Response mapResponse(StatusType status, Object response) { - Object swaggerResult = converter.convert(response); - return Response.create(status, swaggerResult); + return Response.create(status, response); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapperFactory.java index 5e282047629..1b58d6cbb08 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/DefaultProducerResponseMapperFactory.java @@ -18,32 +18,22 @@ import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; public class DefaultProducerResponseMapperFactory implements ProducerResponseMapperFactory { - private ConverterMgr converterMgr; - - @Override - public void setConverterMgr(ConverterMgr converterMgr) { - this.converterMgr = converterMgr; - } - @Override public int getOrder() { return Integer.MAX_VALUE; } @Override - public boolean isMatch(Type swaggerType, Type producerType) { + public boolean isMatch(Type producerType) { return true; } @Override - public ProducerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type producerType) { - Converter converter = converterMgr.findConverter(producerType, swaggerType); - return new DefaultProducerResponseMapper(converter); + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { + return new DefaultProducerResponseMapper(); } } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapper.java new file mode 100644 index 00000000000..1e63a537140 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapper.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.producer; + +import java.util.Optional; + +import jakarta.ws.rs.core.Response.StatusType; + +import org.apache.servicecomb.swagger.invocation.Response; + +public class OptionalProducerResponseMapper implements ProducerResponseMapper { + private final ProducerResponseMapper realMapper; + + public OptionalProducerResponseMapper(ProducerResponseMapper realMapper) { + this.realMapper = realMapper; + } + + @Override + public Response mapResponse(StatusType status, Object response) { + @SuppressWarnings("unchecked") + Optional optional = (Optional) response; + return realMapper.mapResponse(status, optional.orElse(null)); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapperFactory.java new file mode 100644 index 00000000000..39d46b8b777 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/OptionalProducerResponseMapperFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.producer; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Optional; + +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; + +public class OptionalProducerResponseMapperFactory implements ProducerResponseMapperFactory { + @Override + public boolean isMatch(Type producerType) { + if (!ParameterizedType.class.isAssignableFrom(producerType.getClass())) { + return false; + } + + return ((ParameterizedType) producerType).getRawType().equals(Optional.class); + } + + @Override + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { + Type realProducerType = ((ParameterizedType) producerType).getActualTypeArguments()[0]; + ProducerResponseMapper realMapper = factories.createResponseMapper(realProducerType); + return new OptionalProducerResponseMapper(realMapper); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/ProducerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/ProducerResponseMapper.java index 4347d8b45ba..68617b87c1d 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/ProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/producer/ProducerResponseMapper.java @@ -16,7 +16,7 @@ */ package org.apache.servicecomb.swagger.invocation.response.producer; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.Response; diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor new file mode 100644 index 00000000000..f1f15cdd7a0 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.ResponseTypeProcessor @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.invocation.generator.ScbResponseProcessor diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister similarity index 100% rename from swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.core.CommonParameterTypeProcessor rename to swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.generator.SwaggerContextRegister diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory new file mode 100644 index 00000000000..66a48f5a85c --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerContextArgumentMapperFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerInvocationContextMapperFactory diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory new file mode 100644 index 00000000000..fa524012dc5 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerContextArgumentMapperFactory @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerInvocationContextMapperFactory diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter new file mode 100644 index 00000000000..c91943b26bc --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.invocation.converter.impl.part.InputStreamToPartConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.BytesToPartConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.FileToPartConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.PartToPartConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.PartListToPartArrayConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.PartListToPartListConverter diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter deleted file mode 100644 index f7315d67ce1..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.invocation.exception.InvocationExceptionToProducerResponseConverter -org.apache.servicecomb.swagger.invocation.exception.DefaultExceptionToProducerResponseConverter diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory index bd061f71464..0474058a9e3 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory @@ -17,4 +17,5 @@ org.apache.servicecomb.swagger.invocation.response.consumer.CseResponseConsumerResponseMapperFactory org.apache.servicecomb.swagger.invocation.response.consumer.CompletableFutureConsumerResponseMapperFactory -org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapperFactory +org.apache.servicecomb.swagger.invocation.response.consumer.OptionalConsumerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory index 1cbfe9e65f5..dac2a90e393 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-core/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory @@ -17,4 +17,5 @@ org.apache.servicecomb.swagger.invocation.response.producer.CseResponseProducerResponseMapperFactory org.apache.servicecomb.swagger.invocation.response.producer.CompletableFutureProducerResponseMapperFactory -org.apache.servicecomb.swagger.invocation.response.producer.DefaultProducerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.response.producer.DefaultProducerResponseMapperFactory +org.apache.servicecomb.swagger.invocation.response.producer.OptionalProducerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestException.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestException.java index 97028614e03..743b77f8acd 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestException.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestException.java @@ -18,52 +18,52 @@ import java.lang.reflect.InvocationTargetException; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestException { @Test public void testCommonExceptionData() { CommonExceptionData oData = new CommonExceptionData(); oData.setMessage("this is Common exception message"); - Assert.assertEquals("this is Common exception message", oData.getMessage()); + Assertions.assertEquals("this is Common exception message", oData.getMessage()); oData = new CommonExceptionData("this is a test"); - Assert.assertEquals("this is a test", oData.getMessage()); - Assert.assertEquals("CommonExceptionData [message=this is a test]", oData.toString()); + Assertions.assertEquals("this is a test", oData.getMessage()); + Assertions.assertEquals("CommonExceptionData [message=this is a test]", oData.toString()); } @Test public void testInvocationException() { InvocationException oExceptionIn = new InvocationException(Status.OK, "I am gone now"); oExceptionIn = ExceptionFactory.convertConsumerException(new Throwable()); - Assert.assertEquals(490, oExceptionIn.getStatusCode()); + Assertions.assertEquals(490, oExceptionIn.getStatusCode()); oExceptionIn = ExceptionFactory.convertConsumerException(new Throwable(), "abc"); - Assert.assertEquals(490, oExceptionIn.getStatusCode()); - Assert.assertEquals("abc", ((CommonExceptionData) oExceptionIn.getErrorData()).getMessage()); + Assertions.assertEquals(490, oExceptionIn.getStatusCode()); + Assertions.assertEquals("abc", ((CommonExceptionData) oExceptionIn.getErrorData()).getMessage()); oExceptionIn = ExceptionFactory.convertProducerException(new Throwable()); - Assert.assertEquals(590, oExceptionIn.getStatusCode()); + Assertions.assertEquals(590, oExceptionIn.getStatusCode()); oExceptionIn = ExceptionFactory.convertProducerException(new Throwable(), "abcd"); - Assert.assertEquals(590, oExceptionIn.getStatusCode()); - Assert.assertEquals("abcd", ((CommonExceptionData) oExceptionIn.getErrorData()).getMessage()); + Assertions.assertEquals(590, oExceptionIn.getStatusCode()); + Assertions.assertEquals("abcd", ((CommonExceptionData) oExceptionIn.getErrorData()).getMessage()); oExceptionIn = ExceptionFactory.convertConsumerException(new InvocationException(Status.OK, new String("fake-object"))); - Assert.assertEquals(200, oExceptionIn.getStatusCode()); + Assertions.assertEquals(200, oExceptionIn.getStatusCode()); oExceptionIn = ExceptionFactory.convertConsumerException(new InvocationTargetException(new Throwable())); - Assert.assertNotEquals("java.lang.Throwable", oExceptionIn.getMessage()); + Assertions.assertNotEquals("java.lang.Throwable", oExceptionIn.getMessage()); InvocationException oTemp = new InvocationException(Status.OK, new CommonExceptionData("testObject")); - Assert.assertEquals("OK", oTemp.getReasonPhrase()); - Assert.assertEquals("CommonExceptionData [message=testObject]", (oTemp.getErrorData().toString())); + Assertions.assertEquals("OK", oTemp.getReasonPhrase()); + Assertions.assertEquals("CommonExceptionData [message=testObject]", (oTemp.getErrorData().toString())); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestResponse.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestResponse.java index 38b3158a6c5..1eaa0dfcc09 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestResponse.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/core/TestResponse.java @@ -16,16 +16,17 @@ */ package org.apache.servicecomb.core; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestResponse { Response response; @@ -40,89 +41,89 @@ public void handle(Response resp) { @Test public void testAr() { ar.success(Status.ACCEPTED, 1); - Assert.assertEquals(true, response.isSuccessed()); - Assert.assertEquals(false, response.isFailed()); - Assert.assertEquals(1, (int) response.getResult()); - Assert.assertEquals(Status.ACCEPTED.getStatusCode(), response.getStatusCode()); - Assert.assertEquals(Status.ACCEPTED.getReasonPhrase(), response.getReasonPhrase()); - Assert.assertEquals(Status.ACCEPTED, response.getStatus()); + Assertions.assertTrue(response.isSucceed()); + Assertions.assertFalse(response.isFailed()); + Assertions.assertEquals(1, (int) response.getResult()); + Assertions.assertEquals(Status.ACCEPTED.getStatusCode(), response.getStatusCode()); + Assertions.assertEquals(Status.ACCEPTED.getReasonPhrase(), response.getReasonPhrase()); + Assertions.assertEquals(Status.ACCEPTED, response.getStatus()); ar.success(2); - Assert.assertEquals(2, (int) response.getResult()); - Assert.assertEquals(Status.OK.getStatusCode(), response.getStatusCode()); + Assertions.assertEquals(2, (int) response.getResult()); + Assertions.assertEquals(Status.OK.getStatusCode(), response.getStatusCode()); Response r = Response.succResp(3); ar.complete(r); - Assert.assertEquals(r, response); + Assertions.assertEquals(r, response); - ar.consumerFail(new Error("abc")); + ar.consumerFail(new RuntimeExceptionWithoutStackTrace("abc")); CommonExceptionData data = (CommonExceptionData) ((InvocationException) response.getResult()).getErrorData(); - Assert.assertEquals("Cse Internal Bad Request", data.getMessage()); - Assert.assertEquals(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, response.getStatusCode()); + Assertions.assertEquals("Unexpected consumer error, please check logs for details", data.getMessage()); + Assertions.assertEquals(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, response.getStatusCode()); - ar.fail(InvocationType.CONSUMER, new Error("abc")); + ar.fail(InvocationType.CONSUMER, new RuntimeExceptionWithoutStackTrace("abc")); data = (CommonExceptionData) ((InvocationException) response.getResult()).getErrorData(); - Assert.assertEquals("Cse Internal Bad Request", data.getMessage()); - Assert.assertEquals(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, response.getStatusCode()); + Assertions.assertEquals("Unexpected consumer error, please check logs for details", data.getMessage()); + Assertions.assertEquals(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, response.getStatusCode()); InvocationException consumerException = new InvocationException(300, "abc", "def"); ar.consumerFail(consumerException); - Assert.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); - Assert.assertEquals(300, response.getStatusCode()); + Assertions.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); + Assertions.assertEquals(300, response.getStatusCode()); ar.fail(InvocationType.CONSUMER, consumerException); - Assert.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); - Assert.assertEquals(300, response.getStatusCode()); + Assertions.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); + Assertions.assertEquals(300, response.getStatusCode()); - ar.producerFail(new Error("abc")); + ar.producerFail(new RuntimeExceptionWithoutStackTrace("abc")); data = (CommonExceptionData) ((InvocationException) response.getResult()).getErrorData(); - Assert.assertEquals("Cse Internal Server Error", data.getMessage()); - Assert.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, response.getStatusCode()); + Assertions.assertEquals("Unexpected producer error, please check logs for details", data.getMessage()); + Assertions.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, response.getStatusCode()); - ar.fail(InvocationType.PRODUCER, new Error("abc")); + ar.fail(InvocationType.PROVIDER, new RuntimeExceptionWithoutStackTrace("abc")); data = (CommonExceptionData) ((InvocationException) response.getResult()).getErrorData(); - Assert.assertEquals("Cse Internal Server Error", data.getMessage()); - Assert.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, response.getStatusCode()); + Assertions.assertEquals("Unexpected producer error, please check logs for details", data.getMessage()); + Assertions.assertEquals(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, response.getStatusCode()); InvocationException producerException = new InvocationException(500, "abc", "def"); ar.producerFail(producerException); - Assert.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); - Assert.assertEquals(500, response.getStatusCode()); + Assertions.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); + Assertions.assertEquals(500, response.getStatusCode()); - ar.fail(InvocationType.PRODUCER, producerException); - Assert.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); - Assert.assertEquals(500, response.getStatusCode()); + ar.fail(InvocationType.PROVIDER, producerException); + Assertions.assertEquals("def", ((InvocationException) response.getResult()).getErrorData()); + Assertions.assertEquals(500, response.getStatusCode()); } @Test public void test() { Response r = Response.create(200, "200", 2); - Assert.assertEquals(200, r.getStatusCode()); - Assert.assertEquals(2, (int) r.getResult()); + Assertions.assertEquals(200, r.getStatusCode()); + Assertions.assertEquals(2, (int) r.getResult()); Response r1 = r.build(); - Assert.assertEquals(r, r1); + Assertions.assertEquals(r, r1); r = Response.create(300, "300", 3); - Assert.assertEquals(300, r.getStatusCode()); - Assert.assertEquals("300", r.getReasonPhrase()); - Assert.assertEquals(3, ((InvocationException) r.getResult()).getErrorData()); + Assertions.assertEquals(300, r.getStatusCode()); + Assertions.assertEquals("300", r.getReasonPhrase()); + Assertions.assertEquals(3, ((InvocationException) r.getResult()).getErrorData()); r = Response.createSuccess(Status.OK, 2); - Assert.assertEquals(200, r.getStatusCode()); - Assert.assertEquals(2, (int) r.getResult()); + Assertions.assertEquals(200, r.getStatusCode()); + Assertions.assertEquals(2, (int) r.getResult()); r = Response.success(2, Status.OK); - Assert.assertEquals(200, r.getStatusCode()); - Assert.assertEquals(2, (int) r.getResult()); + Assertions.assertEquals(200, r.getStatusCode()); + Assertions.assertEquals(2, (int) r.getResult()); r = Response.createFail(InvocationType.CONSUMER, "abc"); - Assert.assertEquals("CommonExceptionData [message=abc]", + Assertions.assertEquals("CommonExceptionData [message=abc]", ((InvocationException) r.getResult()).getErrorData().toString()); - Assert.assertEquals(490, r.getStatusCode()); + Assertions.assertEquals(490, r.getStatusCode()); - r = Response.createFail(InvocationType.PRODUCER, "def"); - Assert.assertEquals("CommonExceptionData [message=def]", + r = Response.createFail(InvocationType.PROVIDER, "def"); + Assertions.assertEquals("CommonExceptionData [message=def]", ((InvocationException) r.getResult()).getErrorData().toString()); - Assert.assertEquals(590, r.getStatusCode()); + Assertions.assertEquals(590, r.getStatusCode()); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java deleted file mode 100644 index b2c6d006c10..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.engine; - -import java.util.LinkedHashMap; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; -import org.apache.servicecomb.swagger.engine.SwaggerProducer; -import org.apache.servicecomb.swagger.engine.bootstrap.BootstrapNormal; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; - -import io.swagger.models.Swagger; - -public class SwaggerEnvironmentForTest { - private SwaggerEnvironment swaggerEnvironment = new BootstrapNormal().boot(); - - private ClassLoader classLoader = new ClassLoader() { - }; - - public ClassLoader getClassLoader() { - return classLoader; - } - - public SwaggerEnvironment getSwaggerEnvironment() { - return swaggerEnvironment; - } - - public SwaggerProducer createProducer(Object producerInstance) { - Class producerCls = BeanUtils.getImplClassFromBean(producerInstance); - SwaggerGenerator producerGenerator = UnitTestSwaggerUtils.generateSwagger(classLoader, producerCls); - Swagger swagger = producerGenerator.getSwagger(); - - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(classLoader, swagger, - producerInstance.getClass().getPackage().getName()); - return swaggerEnvironment.createProducer(producerInstance, swaggerToClassGenerator.convert(), - new LinkedHashMap<>()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerEnvironment.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerEnvironment.java index 0a888cce4b9..0393af06ddb 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerEnvironment.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerEnvironment.java @@ -20,62 +20,34 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.engine.SwaggerEnvironmentForTest; -import org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.producer.JaxRSProducerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory; -import org.apache.servicecomb.swagger.invocation.arguments.producer.SpringMVCProducerArgumentsMapperFactory; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.apache.servicecomb.swagger.invocation.models.ProducerImpl; -import org.junit.AfterClass; -import org.junit.Assert; +import org.hamcrest.MatcherAssert; import org.junit.BeforeClass; import org.junit.Test; -import mockit.Deencapsulation; +import io.swagger.v3.oas.models.OpenAPI; +import org.junit.jupiter.api.Assertions; public class TestSwaggerEnvironment { - private static SwaggerEnvironmentForTest env = new SwaggerEnvironmentForTest(); + private static final SwaggerEnvironment env = new SwaggerEnvironment(); private static SwaggerProducer producer; - private static ProducerArgumentsMapperFactory defaultProducerArgumentsMapperFactory; - @BeforeClass public static void init() { - producer = env.createProducer(new ProducerImpl()); - defaultProducerArgumentsMapperFactory = new ProducerArgumentsMapperFactory(); - List producerArgumentsMapperFactoryList = new ArrayList<>(); - producerArgumentsMapperFactoryList.add(new JaxRSProducerArgumentsMapperFactory()); - producerArgumentsMapperFactoryList.add(new SpringMVCProducerArgumentsMapperFactory()); - producerArgumentsMapperFactoryList.add(new ProducerArgumentsMapperFactory()); - - Deencapsulation.setField( - env.getSwaggerEnvironment(), "producerArgumentsFactory", defaultProducerArgumentsMapperFactory); - Deencapsulation.setField( - env.getSwaggerEnvironment(), "producerArgumentsMapperFactoryList", producerArgumentsMapperFactoryList); - } - - @AfterClass - public static void tearDown() { - JavassistUtils.clearByClassLoader(env.getClassLoader()); + producer = env.createProducer(new ProducerImpl(), null); } @Test public void ableToFindVisibleMethod() { - assertThat(producer.findOperation("visibleMethod"), is(notNullValue())); + MatcherAssert.assertThat(producer.findOperation("visibleMethod"), is(notNullValue())); } @Test public void unableToFindHiddenMethod() { - assertThat(producer.findOperation("hiddenMethod"), is(nullValue())); + MatcherAssert.assertThat(producer.findOperation("hiddenMethod"), is(nullValue())); } interface ConsumerIntf { @@ -90,32 +62,10 @@ interface ContractIntf { @Test public void createConsumer_consumerMethodSetBigger() { - SwaggerConsumer swaggerConsumer = env.getSwaggerEnvironment() - .createConsumer(ConsumerIntf.class, ContractIntf.class); - - Assert.assertNotNull(swaggerConsumer.findOperation("exist")); - Assert.assertNull(swaggerConsumer.findOperation("notExist")); - } - - @Test - public void selectProducerArgumentsMapperFactory() { - final ArgumentsMapperConfig config = new ArgumentsMapperConfig(); - config.setSwaggerGeneratorContext(new JaxrsSwaggerGeneratorContext()); - - final ProducerArgumentsMapperFactory producerArgumentsMapperFactory = env.getSwaggerEnvironment() - .selectProducerArgumentsMapperFactory(config); - - Assert.assertEquals(JaxRSProducerArgumentsMapperFactory.class, producerArgumentsMapperFactory.getClass()); - } - - @Test - public void selectProducerArgumentsMapperFactoryOnReturnDefault() { - final ArgumentsMapperConfig config = new ArgumentsMapperConfig(); - config.setSwaggerGeneratorContext(new PojoSwaggerGeneratorContext()); - - final ProducerArgumentsMapperFactory producerArgumentsMapperFactory = env.getSwaggerEnvironment() - .selectProducerArgumentsMapperFactory(config); + OpenAPI swagger = SwaggerGenerator.generate(ContractIntf.class); + SwaggerConsumer swaggerConsumer = env.createConsumer(ConsumerIntf.class, swagger); - Assert.assertSame(defaultProducerArgumentsMapperFactory, producerArgumentsMapperFactory); + Assertions.assertNotNull(swaggerConsumer.findOperation("exist")); + Assertions.assertNull(swaggerConsumer.findOperation("notExist")); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerProducerOperation.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerProducerOperation.java index 3ea0bf18cf7..8f4d557bc67 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerProducerOperation.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/engine/TestSwaggerProducerOperation.java @@ -14,38 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.swagger.engine; - -import java.lang.reflect.InvocationTargetException; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.junit.Assert; -import org.junit.Test; +package org.apache.servicecomb.swagger.engine; -import mockit.Mocked; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.invocation.models.PojoImpl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestSwaggerProducerOperation { - SwaggerProducerOperation swaggerProducerOperation = new SwaggerProducerOperation(); + private static final SwaggerEnvironment env = new SwaggerEnvironment(); - @Test - public void processException_normal(@Mocked SwaggerInvocation invocation) { - Error error = new Error("abc"); - - Response response = swaggerProducerOperation.processException(invocation, error); - Assert.assertSame(Status.OK, response.getStatus()); - Assert.assertEquals("response from error: abc", response.getResult()); - } + private static SwaggerProducer producer; @Test - public void processException_InvocationTargetException(@Mocked SwaggerInvocation invocation) { - Error error = new Error("abc"); - InvocationTargetException targetException = new InvocationTargetException(error); - - Response response = swaggerProducerOperation.processException(invocation, targetException); - Assert.assertSame(Status.OK, response.getStatus()); - Assert.assertEquals("response from error: abc", response.getResult()); + public void testGetParameterType() { + PojoImpl pojo = new PojoImpl(); + producer = env.createProducer(pojo, null); + + SwaggerProducerOperation swaggerProducerOperation = producer.findOperation("testBytes"); + Assertions.assertEquals(true, + swaggerProducerOperation.getSwaggerOperation().getOperation().getRequestBody() != null); + Assertions.assertEquals(null, swaggerProducerOperation.getSwaggerParameterType("bytes")); + + swaggerProducerOperation = producer.findOperation("testSimple"); + Assertions.assertEquals(true, + swaggerProducerOperation.getSwaggerOperation().getOperation().getRequestBody() != null); + Assertions.assertEquals(Object.class, swaggerProducerOperation.getSwaggerParameterType( + (String) swaggerProducerOperation.getSwaggerOperation().getOperation().getRequestBody().getExtensions() + .get(SwaggerConst.EXT_BODY_NAME))); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/TestSwaggerInvocation.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/TestSwaggerInvocation.java index 835adc63a72..d5533d84cca 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/TestSwaggerInvocation.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/TestSwaggerInvocation.java @@ -18,8 +18,8 @@ import org.apache.servicecomb.swagger.invocation.context.ContextUtils; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestSwaggerInvocation { @Test @@ -31,9 +31,9 @@ public void construct_withContext() { try { SwaggerInvocation invocation = new SwaggerInvocation(); - Assert.assertSame(parentContext, invocation.getParentContext()); - Assert.assertEquals("v", invocation.getContext("k")); - Assert.assertEquals(1, (int) invocation.getLocalContext("k")); + Assertions.assertSame(parentContext, invocation.getParentContext()); + Assertions.assertEquals("v", invocation.getContext("k")); + Assertions.assertEquals(1, (int) invocation.getLocalContext("k")); } finally { ContextUtils.removeInvocationContext(); } @@ -42,6 +42,6 @@ public void construct_withContext() { @Test public void construct_noContext() { SwaggerInvocation invocation = new SwaggerInvocation(); - Assert.assertNull(invocation.getParentContext()); + Assertions.assertNull(invocation.getParentContext()); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualProducer.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualProducer.java deleted file mode 100644 index ec2ce3f035a..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualProducer.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.engine.SwaggerEnvironmentForTest; -import org.apache.servicecomb.swagger.engine.SwaggerConsumer; -import org.apache.servicecomb.swagger.engine.SwaggerProducer; -import org.apache.servicecomb.swagger.engine.unittest.LocalProducerInvoker; -import org.apache.servicecomb.swagger.invocation.arguments.utils.Utils; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.models.Person; -import org.apache.servicecomb.swagger.invocation.models.PojoConsumerIntf; -import org.apache.servicecomb.swagger.invocation.models.PojoImpl; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestPojoConsumerEqualProducer { - private static SwaggerEnvironmentForTest env = new SwaggerEnvironmentForTest(); - - private static SwaggerProducer producer; - - private static SwaggerConsumer consumer; - - private static LocalProducerInvoker invoker; - - private static PojoConsumerIntf proxy; - - @BeforeClass - public static void init() { - producer = env.createProducer(new PojoImpl()); - consumer = env.getSwaggerEnvironment().createConsumer(PojoConsumerIntf.class, producer.getSwaggerIntf()); - invoker = new LocalProducerInvoker(consumer, producer); - proxy = invoker.getProxy(); - } - - @AfterClass - public static void tearDown() { - JavassistUtils.clearByClassLoader(env.getClassLoader()); - } - - @Test - public void testSimple() { - int result = proxy.testSimple(1, 2, 3); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(1, Utils.getFieldValue(body, "a")); - Assert.assertEquals(2, Utils.getFieldValue(body, "b")); - Assert.assertEquals(3, Utils.getFieldValue(body, "c")); - - Assert.assertEquals(-4, result); - } - - @Test - public void testObject() { - Person person = new Person(); - person.setName("abc"); - - Person result = proxy.testObject(person); - - Person swaggerPerson = invoker.getSwaggerArgument(0); - Assert.assertEquals(person, swaggerPerson); - - Assert.assertEquals("hello abc", result.getName()); - } - - @Test - public void testObjectAsync() throws Exception { - Person person = new Person(); - person.setName("abc"); - - CompletableFuture future = proxy.testObjectAsync(person); - Person result = future.get(); - - Person swaggerPerson = invoker.getSwaggerArgument(0); - Assert.assertEquals(person, swaggerPerson); - - Assert.assertEquals("hello abc", result.getName()); - } - - @Test - public void testSimpleAndObject() { - Person person = new Person(); - person.setName("abc"); - - String result = proxy.testSimpleAndObject("prefix", person); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals("prefix", Utils.getFieldValue(body, "prefix")); - Assert.assertEquals(person, Utils.getFieldValue(body, "user")); - - Assert.assertEquals("prefix abc", result); - } - - @Test - public void testContext() { - InvocationContext threadContext = new InvocationContext(); - threadContext.addContext("ta", "tvalue"); - ContextUtils.setInvocationContext(threadContext); - - InvocationContext context = new InvocationContext(); - context.addContext("a", "value"); - - String result = proxy.testContext(context, "name"); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(3, invoker.getInvocation().getContext().size()); - Assert.assertEquals("tvalue", invoker.getContext("ta")); - Assert.assertEquals("value", invoker.getContext("a")); - Assert.assertEquals("name", invoker.getContext("name")); - Assert.assertEquals("name", Utils.getFieldValue(body, "name")); - - Assert.assertEquals("name sayhi", result); - } - - @Test - public void testBytes() { - byte[] bytes = new byte[] {1, 2}; - - byte[] result = proxy.testBytes(bytes); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(bytes, Utils.getFieldValue(body, "bytes")); - - Assert.assertArrayEquals(bytes, result); - } - - @Test - public void testListBytes() { - List bytes = Arrays.asList(new byte[] {1, 2}); - - List result = proxy.testListBytes(bytes); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(bytes, Utils.getFieldValue(body, "bytes")); - - Assert.assertEquals(bytes, result); - } - - @Test - public void testArrayArray() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - - String[] result = proxy.testArrayArray(array); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(list, Utils.getFieldValue(body, "s")); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testArrayList() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - List result = proxy.testArrayList(array); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(list, Utils.getFieldValue(body, "s")); - - Assert.assertEquals(list, result); - } - - @Test - public void testListArray() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - - String[] result = proxy.testListArray(list); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(list, Utils.getFieldValue(body, "s")); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testListList() { - List list = Arrays.asList("a", "b"); - - List result = proxy.testListList(list); - - Object body = invoker.getSwaggerArgument(0); - Assert.assertEquals(list, Utils.getFieldValue(body, "s")); - - Assert.assertEquals(list, result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualSwagger.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualSwagger.java deleted file mode 100644 index f4c39872a67..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/TestPojoConsumerEqualSwagger.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments; - -import java.util.Arrays; -import java.util.List; - -import org.apache.servicecomb.common.javassist.JavassistUtils; -import org.apache.servicecomb.engine.SwaggerEnvironmentForTest; -import org.apache.servicecomb.swagger.engine.SwaggerConsumer; -import org.apache.servicecomb.swagger.engine.SwaggerProducer; -import org.apache.servicecomb.swagger.engine.unittest.LocalProducerInvoker; -import org.apache.servicecomb.swagger.invocation.context.ContextUtils; -import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import org.apache.servicecomb.swagger.invocation.models.JaxrsImpl; -import org.apache.servicecomb.swagger.invocation.models.Person; -import org.apache.servicecomb.swagger.invocation.models.PojoConsumerIntf; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestPojoConsumerEqualSwagger { - private static SwaggerEnvironmentForTest env = new SwaggerEnvironmentForTest(); - - private static SwaggerProducer producer; - - private static SwaggerConsumer consumer; - - private static LocalProducerInvoker invoker; - - private static PojoConsumerIntf proxy; - - @BeforeClass - public static void init() { - producer = env.createProducer(new JaxrsImpl()); - consumer = env.getSwaggerEnvironment().createConsumer(PojoConsumerIntf.class, producer.getSwaggerIntf()); - invoker = new LocalProducerInvoker(consumer, producer); - proxy = invoker.getProxy(); - } - - @AfterClass - public static void tearDown() { - JavassistUtils.clearByClassLoader(env.getClassLoader()); - } - - @Test - public void testSimple() { - int result = proxy.testSimple(1, 2, 3); - - Assert.assertEquals(1, (int) invoker.getSwaggerArgument(0)); - Assert.assertEquals(2, (int) invoker.getSwaggerArgument(1)); - Assert.assertEquals(3, (int) invoker.getSwaggerArgument(2)); - - Assert.assertEquals(-4, result); - } - - @Test - public void testObject() { - Person person = new Person(); - person.setName("abc"); - - Person result = proxy.testObject(person); - - Person swaggerPerson = invoker.getSwaggerArgument(0); - Assert.assertEquals(person.getName(), swaggerPerson.getName()); - - Assert.assertEquals("hello abc", result.getName()); - } - - @Test - public void testSimpleAndObject() { - Person person = new Person(); - person.setName("abc"); - - String result = proxy.testSimpleAndObject("prefix", person); - - Assert.assertEquals("prefix", (String) invoker.getSwaggerArgument(0)); - Assert.assertEquals(person.getName(), ((Person) invoker.getSwaggerArgument(1)).getName()); - - Assert.assertEquals("prefix abc", result); - } - - @Test - public void testContext() { - InvocationContext threadContext = new InvocationContext(); - threadContext.addContext("ta", "tvalue"); - ContextUtils.setInvocationContext(threadContext); - - InvocationContext context = new InvocationContext(); - context.addContext("a", "value"); - - String result = proxy.testContext(context, "name"); - - Assert.assertEquals(3, invoker.getInvocation().getContext().size()); - Assert.assertEquals("tvalue", invoker.getContext("ta")); - Assert.assertEquals("value", invoker.getContext("a")); - Assert.assertEquals("name", invoker.getContext("name")); - Assert.assertEquals("name", (String) invoker.getSwaggerArgument(0)); - - Assert.assertEquals("name sayhi", result); - } - - @Test - public void testBytes() { - byte[] bytes = new byte[] {1, 2}; - - byte[] result = proxy.testBytes(bytes); - - Assert.assertEquals(bytes, invoker.getSwaggerArgument(0)); - - Assert.assertArrayEquals(bytes, result); - } - - @Test - public void testListBytes() { - List bytes = Arrays.asList(new byte[] {1, 2}); - - List result = proxy.testListBytes(bytes); - - Assert.assertEquals(bytes, invoker.getSwaggerArgument(0)); - Assert.assertEquals(bytes, result); - } - - @Test - public void testArrayArray() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - - String[] result = proxy.testArrayArray(array); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testArrayList() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - List result = proxy.testArrayList(array); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertEquals(list, result); - } - - @Test - public void testListArray() { - String[] array = new String[] {"a", "b"}; - List list = Arrays.asList(array); - - String[] result = proxy.testListArray(list); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testListList() { - List list = Arrays.asList("a", "b"); - - List result = proxy.testListList(list); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertEquals(list, result); - } - - @Test - public void testObjectArrayArray() { - Person[] array = new Person[] {new Person("a"), new Person("b")}; - List list = Arrays.asList(array); - - Person[] result = proxy.testObjectArrayArray(array); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testObjectArrayList() { - Person[] array = new Person[] {new Person("a"), new Person("b")}; - List list = Arrays.asList(array); - List result = proxy.testObjectArrayList(array); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertEquals(list, result); - } - - @Test - public void testObjectListArray() { - Person[] array = new Person[] {new Person("a"), new Person("b")}; - List list = Arrays.asList(array); - - Person[] result = proxy.testObjectListArray(list); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - Assert.assertEquals(list, invoker.getProducerResponse().getResult()); - - Assert.assertArrayEquals(array, result); - } - - @Test - public void testObjectListList() { - Person[] array = new Person[] {new Person("a"), new Person("b")}; - List list = Arrays.asList(array); - - List result = proxy.testObjectListList(list); - - Assert.assertEquals(list, invoker.getSwaggerArgument(0)); - - Assert.assertEquals(list, result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSameTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSameTest.java deleted file mode 100644 index 1af5cd8ac1b..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentSameTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.consumer; - -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.junit.Test; -import org.mockito.Mockito; - -public class ConsumerArgumentSameTest { - - private Converter mockConverter = Mockito.mock(Converter.class); - - private ConsumerArgumentSame consumerArgumentSame = new ConsumerArgumentSame(0, 0, mockConverter); - - @Test - public void testMapArgumentOnArgument() { - SwaggerInvocation swaggerInvocation = Mockito.mock(SwaggerInvocation.class); - String[] args = {"testArg"}; - - Mockito.when(mockConverter.convert(args[0])).thenReturn(args[0]); - - consumerArgumentSame.mapArgument(swaggerInvocation, args); - - Mockito.verify(mockConverter, Mockito.times(1)).convert(args[0]); - Mockito.verify(swaggerInvocation, Mockito.times(1)).setSwaggerArgument(0, args[0]); - } - - @Test - public void testMapArgumentOnArgumentIsNull() { - SwaggerInvocation swaggerInvocation = Mockito.mock(SwaggerInvocation.class); - - consumerArgumentSame.mapArgument(swaggerInvocation, new Object[1]); - - Mockito.verify(mockConverter, Mockito.never()).convert(Mockito.anyObject()); - Mockito.verify(swaggerInvocation, Mockito.never()).setSwaggerArgument(Mockito.anyInt(), Mockito.anyObject()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V1.java new file mode 100644 index 00000000000..a330f59beb7 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V1.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBeanParamV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestJaxrsV1V1 { + @Test + public void should_mapper_consumer_multi_args_to_swagger_multi_args() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + interface ConsumerAddV1_diff_order { + int add(int y, int x); + } + + @Test + public void should_mapper_consumer_multi_args_to_swagger_multi_args_with_diff_order() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1_diff_order.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void should_mapper_consumer_multi_args_to_swagger_multi_args_gen_by_BeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void should_mapper_consumer_multi_args_to_swagger_body() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void should_mapper_consumer_wrapped_body_to_swagger_multi_args() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void should_mapper_consumer_wrapped_body_to_swagger_multi_args_gen_by_BeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void should_mapper_consumer_body_to_swagger_body() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV1.class); + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V2.java new file mode 100644 index 00000000000..f1800371ef1 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV1V2.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBeanParamV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestJaxrsV1V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void add_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV2.class); + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V1.java new file mode 100644 index 00000000000..d344be6a193 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V1.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBeanParamV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestJaxrsV2V1 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV1.class); + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V2.java new file mode 100644 index 00000000000..44f16497a27 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestJaxrsV2V2.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBeanParamV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestJaxrsV2V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void add_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_addBeanParam() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBeanParamV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(JaxrsAddBodyV2.class); + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoOneArg.java new file mode 100644 index 00000000000..35ebc5ccaa9 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoOneArg.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerOneArg; +import org.apache.servicecomb.swagger.invocation.schemas.PojoOneArg; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestPojoOneArg { + @Test + public void should_mapper_consumer_simple_to_swagger_body() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoOneArg.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerOneArg.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("simple").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("name", "name"); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("simpleBody"); + Assertions.assertEquals(1, result.size()); + Assertions.assertEquals("name", result.get("name")); + } + + @Test + public void should_mapper_consumer_bean_to_swagger_body() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoOneArg.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerOneArg.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("bean").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("user", new User()); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + Assertions.assertSame(arguments.get("user"), result.get("user")); + } + + @Test + public void should_mapper_consumer_enum_to_swagger_body_field() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoOneArg.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerOneArg.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("enumBody").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("color", Color.BLUE); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("enumBodyBody"); + Assertions.assertEquals(1, result.size()); + Assertions.assertEquals(Color.BLUE, result.get("color")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V1.java new file mode 100644 index 00000000000..ca716ec2cdb --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V1.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddWithContext; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestPojoV1V1 { + @Test + public void add_add_class() { + add_add(PojoAddV1.class); + } + + @Test + public void add_add_interface() { + add_add(ConsumerAddV1.class); + } + + public void add_add(Class clazz) { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(clazz); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV1.class); + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + AddWrapperV1 wrapperV1 = (AddWrapperV1) result.get("addBody"); + Assertions.assertEquals(1, wrapperV1.getX()); + Assertions.assertEquals(2, wrapperV1.y); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } + + @Test + public void addWithContext_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddWithContext.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + InvocationContext invocationContext = new InvocationContext(); + invocationContext.addContext("k1", "v1"); + invocationContext.addContext("k2", "v2"); + invocationContext.addLocalContext("k3", "v3"); + invocationContext.addLocalContext("k4", "v4"); + + Map arguments = new HashMap<>(); + arguments.put("context", invocationContext); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, result.get("x")); + Assertions.assertEquals(2, result.get("y")); + + Assertions.assertEquals(2, invocation.getContext().size()); + Assertions.assertEquals("v1", invocation.getContext().get("k1")); + Assertions.assertEquals("v2", invocation.getContext().get("k2")); + + Assertions.assertEquals(2, invocation.getLocalContext().size()); + Assertions.assertEquals("v3", invocation.getLocalContext().get("k3")); + Assertions.assertEquals("v4", invocation.getLocalContext().get("k4")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V2.java new file mode 100644 index 00000000000..ab7f3a0bd36 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV1V2.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestPojoV1V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V1.java new file mode 100644 index 00000000000..6eb38a81679 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V1.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestPojoV2V1 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V2.java new file mode 100644 index 00000000000..3e85c77c035 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestPojoV2V2.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestPojoV2V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(PojoAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(arguments.get("addBody"), result.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V1.java new file mode 100644 index 00000000000..b2f905b3090 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V1.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddWrapperV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; + +import io.swagger.v3.oas.models.OpenAPI; +import org.junit.jupiter.api.Assertions; + +@SuppressWarnings("unchecked") +public class TestSpringmvcV1V1 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V2.java new file mode 100644 index 00000000000..e81c1f70424 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV1V2.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddWrapperV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.Test; + +import io.swagger.v3.oas.models.OpenAPI; +import org.junit.jupiter.api.Assertions; + +@SuppressWarnings("unchecked") +public class TestSpringmvcV1V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void add_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertNull(result.get("x-z")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV1.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV1(1, 2)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V1.java new file mode 100644 index 00000000000..65e3475fb39 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V1.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddWrapperV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.Test; + +import io.swagger.v3.oas.models.OpenAPI; +import org.junit.jupiter.api.Assertions; + +@SuppressWarnings("unchecked") +public class TestSpringmvcV2V1 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("x-z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV1.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V2.java new file mode 100644 index 00000000000..0e5fcb440f6 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/TestSpringmvcV2V2.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.consumer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapper; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.ConsumerAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddBodyV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddV2; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddWrapperV2; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.models.OpenAPI; + +@SuppressWarnings("unchecked") +public class TestSpringmvcV2V2 { + @Test + public void add_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void add_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void add_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + arguments.put("z", 3); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + result = (Map) result.get("addBody"); + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_add() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_addWrapper() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddWrapperV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + Assertions.assertEquals(3, (int) result.get("x-z")); + } + + @Test + public void addBody_addBody() { + SwaggerEnvironment environment = new SwaggerEnvironment(); + OpenAPI swagger = SwaggerGenerator.generate(SpringmvcAddBodyV2.class); + + SwaggerConsumer swaggerConsumer = environment.createConsumer(ConsumerAddBodyV2.class, swagger); + ArgumentsMapper mapper = swaggerConsumer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("addBody", new AddWrapperV2(1, 2, 3)); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.invocationArgumentToSwaggerArguments(invocation, arguments); + + Assertions.assertSame(result.get("addBody"), arguments.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactoryTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactoryTest.java deleted file mode 100644 index 751920378b4..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/JaxRSProducerArgumentsMapperFactoryTest.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.servlet.http.Part; -import javax.ws.rs.BeanParam; -import javax.ws.rs.CookieParam; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.FormParam; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; - -import org.apache.servicecomb.swagger.generator.jaxrs.JaxrsSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig; -import org.apache.servicecomb.swagger.invocation.arguments.ProviderParameter; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory.ParamWrapper; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -import io.swagger.models.parameters.CookieParameter; -import io.swagger.models.parameters.FormParameter; -import io.swagger.models.parameters.HeaderParameter; -import io.swagger.models.parameters.Parameter; -import io.swagger.models.parameters.PathParameter; -import io.swagger.models.parameters.QueryParameter; -import mockit.Deencapsulation; - -public class JaxRSProducerArgumentsMapperFactoryTest { - - private final JaxRSProducerArgumentsMapperFactory producerArgumentsMapperFactory = new JaxRSProducerArgumentsMapperFactory(); - - @Test - public void canProcess() { - ArgumentsMapperConfig argumentsMapperConfig = new ArgumentsMapperConfig(); - - argumentsMapperConfig.setSwaggerGeneratorContext(new JaxrsSwaggerGeneratorContext()); - Assert.assertTrue(producerArgumentsMapperFactory.canProcess(argumentsMapperConfig)); - - argumentsMapperConfig.setSwaggerGeneratorContext(new PojoSwaggerGeneratorContext()); - Assert.assertFalse(producerArgumentsMapperFactory.canProcess(argumentsMapperConfig)); - } - - @Test - public void findAggregatedParamNames() throws NoSuchMethodException { - Map providerParamMap = new HashMap<>(); - providerParamMap.put("qqq", new ProviderParameter(1, String.class, "qqq")); - Method aggregatedTestParamMethod = AggregatedParamProvider.class - .getMethod("aggregatedParamTest", AggregatedTestParam.class); - Annotation beanParamAnnotation = aggregatedTestParamMethod.getParameterAnnotations()[0][0]; - providerParamMap.put("aggregatedTestParam", - new ProviderParameter(0, AggregatedTestParam.class, "aggregatedTestParam") - .setAnnotations(new Annotation[] {beanParamAnnotation})); - - Map> swaggerParamMap = new HashMap<>(); - Parameter swaggerParam = new PathParameter().name("pathSwaggerParam"); - swaggerParamMap.put("pathSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(0)); - swaggerParam = new HeaderParameter().name("headerSwaggerParam"); - swaggerParamMap.put("headerSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(1)); - swaggerParam = new CookieParameter().name("intSwaggerVal"); - swaggerParamMap.put("intSwaggerVal", new ParamWrapper<>(swaggerParam).setIndex(2)); - swaggerParam = new FormParameter().name("longSwaggerVal"); - swaggerParamMap.put("longSwaggerVal", new ParamWrapper<>(swaggerParam).setIndex(3)); - swaggerParam = new QueryParameter().name("querySwaggerParam"); - swaggerParamMap.put("querySwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(4)); - swaggerParam = new FormParameter().name("uploadSwaggerParam"); - swaggerParamMap.put("uploadSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(5)); - swaggerParam = new QueryParameter().name("qqq"); - swaggerParamMap.put("qqq", new ParamWrapper<>(swaggerParam).setIndex(6)); - - Set aggregatedParamNames = producerArgumentsMapperFactory - .findAggregatedParamNames(providerParamMap, swaggerParamMap); - Assert.assertThat(aggregatedParamNames, Matchers.contains("aggregatedTestParam")); - } - - @Test - public void generateAggregatedParamMapper() throws NoSuchMethodException { - Map providerParamMap = new HashMap<>(); - providerParamMap.put("qqq", new ProviderParameter(1, String.class, "qqq")); - Method aggregatedTestParamMethod = AggregatedParamProvider.class - .getMethod("aggregatedParamTest", AggregatedTestParam.class); - Annotation beanParamAnnotation = aggregatedTestParamMethod.getParameterAnnotations()[0][0]; - providerParamMap.put("aggregatedTestParam", - new ProviderParameter(0, AggregatedTestParam.class, "aggregatedTestParam") - .setAnnotations(new Annotation[] {beanParamAnnotation})); - - Map> swaggerParamMap = new HashMap<>(); - Parameter swaggerParam = new PathParameter().name("pathSwaggerParam"); - swaggerParamMap.put("pathSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(0)); - swaggerParam = new HeaderParameter().name("headerSwaggerParam"); - swaggerParamMap.put("headerSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(1)); - swaggerParam = new CookieParameter().name("intSwaggerVal"); - swaggerParamMap.put("intSwaggerVal", new ParamWrapper<>(swaggerParam).setIndex(2)); - swaggerParam = new FormParameter().name("longSwaggerVal"); - swaggerParamMap.put("longSwaggerVal", new ParamWrapper<>(swaggerParam).setIndex(3)); - swaggerParam = new QueryParameter().name("querySwaggerParam"); - swaggerParamMap.put("querySwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(4)); - swaggerParam = new FormParameter().name("uploadSwaggerParam"); - swaggerParamMap.put("uploadSwaggerParam", new ParamWrapper<>(swaggerParam).setIndex(5)); - swaggerParam = new QueryParameter().name("qqq"); - swaggerParamMap.put("qqq", new ParamWrapper<>(swaggerParam).setIndex(6)); - - Set aggregatedParamNames = new HashSet<>(); - aggregatedParamNames.add("aggregatedTestParam"); - ArgumentsMapperConfig argumentsMapperConfig = new ArgumentsMapperConfig(); - producerArgumentsMapperFactory.generateAggregatedParamMapper( - argumentsMapperConfig, providerParamMap, swaggerParamMap, aggregatedParamNames); - - Assert.assertEquals(1, argumentsMapperConfig.getArgumentMapperList().size()); - Assert.assertEquals(ProducerBeanParamMapper.class, argumentsMapperConfig.getArgumentMapperList().get(0).getClass()); - ProducerBeanParamMapper producerBeanParamMapper = - (ProducerBeanParamMapper) argumentsMapperConfig.getArgumentMapperList().get(0); - Assert.assertEquals(Integer.valueOf(0), Deencapsulation.getField(producerBeanParamMapper, "producerIdx")); - Map swaggerParamIndexMap = - Deencapsulation.getField(producerBeanParamMapper, "swaggerParamIndexMap"); - Assert.assertEquals(Integer.valueOf(0), swaggerParamIndexMap.get("pathParam")); - Assert.assertEquals(Integer.valueOf(1), swaggerParamIndexMap.get("headerParam")); - Assert.assertEquals(Integer.valueOf(2), swaggerParamIndexMap.get("intVal")); - Assert.assertEquals(Integer.valueOf(3), swaggerParamIndexMap.get("longVal")); - Assert.assertEquals(Integer.valueOf(4), swaggerParamIndexMap.get("q")); - Assert.assertEquals(Integer.valueOf(5), swaggerParamIndexMap.get("uploaded")); - } - - static class AggregatedParamProvider { - public String aggregatedParamTest(@BeanParam AggregatedTestParam aggregatedTestParam) { - return null; - } - } - - static class AggregatedTestParam { - @PathParam("pathSwaggerParam") - private String pathParam; - - private String queryParam; - - @DefaultValue("defaultHeader") - @HeaderParam(value = "headerSwaggerParam") - private String headerParam; - - @CookieParam("intSwaggerVal") - private int intVal; - - @FormParam("longSwaggerVal") - private long longVal; - - private Part uploaded; - - public String getPathParam() { - return pathParam; - } - - public AggregatedTestParam setPathParam(String pathParam) { - this.pathParam = pathParam; - return this; - } - - public String getQ() { - return queryParam; - } - - @DefaultValue("defaultQuery") - @QueryParam(value = "querySwaggerParam") - public AggregatedTestParam setQ(String queryParam) { - this.queryParam = queryParam; - return this; - } - - public String getHeaderParam() { - return headerParam; - } - - public AggregatedTestParam setHeaderParam(String headerParam) { - this.headerParam = headerParam; - return this; - } - - public int getIntVal() { - return intVal; - } - - public AggregatedTestParam setIntVal(int intVal) { - this.intVal = intVal; - return this; - } - - public long getLongVal() { - return longVal; - } - - public AggregatedTestParam setLongVal(long longVal) { - this.longVal = longVal; - return this; - } - - public Part getUploaded() { - return uploaded; - } - - @FormParam("uploadSwaggerParam") - public AggregatedTestParam setUploaded(Part uploaded) { - this.uploaded = uploaded; - return this; - } - } -} \ No newline at end of file diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java deleted file mode 100644 index 81c8d35bd07..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.util.Date; -import java.util.HashMap; -import java.util.Objects; - -import javax.servlet.http.Part; - -import org.apache.servicecomb.foundation.common.part.AbstractPart; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerSpringMVCQueryObjectMapperTest.RecursiveParam; -import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerSpringMVCQueryObjectMapperTest.TestParam; -import org.junit.Assert; -import org.junit.Test; - -public class ProducerBeanParamMapperTest { - - @Test - public void mapArgument() { - final HashMap producerNameToSwaggerIndexMap = new HashMap<>(); - producerNameToSwaggerIndexMap.put("name", 2); - producerNameToSwaggerIndexMap.put("age", 0); - ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 0, TestParam.class); - SwaggerInvocation swaggerInvocation = new SwaggerInvocation(); - swaggerInvocation.setSwaggerArguments(new Object[] {22, "abc", "nameTest"}); - - final Object[] producerArguments = new Object[1]; - argumentMapper.mapArgument(swaggerInvocation, producerArguments); - Assert.assertEquals(producerArguments[0], new TestParam().setName("nameTest").setAge(22)); - } - - @Test - public void mapArgumentOnRecursiveParam() { - final HashMap producerNameToSwaggerIndexMap = new HashMap<>(); - producerNameToSwaggerIndexMap.put("num", 0); - producerNameToSwaggerIndexMap.put("str", 1); - producerNameToSwaggerIndexMap.put("date", 2); - ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 1, - RecursiveParam.class); - SwaggerInvocation swaggerInvocation = new SwaggerInvocation(); - final Date testDate = new Date(); - swaggerInvocation.setSwaggerArguments(new Object[] {2, "str0_0", testDate}); - - final Object[] producerArguments = new Object[2]; - argumentMapper.mapArgument(swaggerInvocation, producerArguments); - Assert.assertNull(producerArguments[0]); - Assert.assertEquals(producerArguments[1], new RecursiveParam().setNum(2).setStr("str0_0").setDate(testDate)); - } - - @Test - public void mapArgumentWithPart() { - final HashMap producerNameToSwaggerIndexMap = new HashMap<>(); - producerNameToSwaggerIndexMap.put("up", 0); - producerNameToSwaggerIndexMap.put("str", 2); - producerNameToSwaggerIndexMap.put("longValue", 3); - ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 0, - TestParamWithPart.class); - SwaggerInvocation swaggerInvocation = new SwaggerInvocation(); - final AbstractPart uploadedFile = new AbstractPart(); - swaggerInvocation.setSwaggerArguments(new Object[] {uploadedFile, 123L, "testString", 12L}); - - final Object[] producerArguments = new Object[2]; - argumentMapper.mapArgument(swaggerInvocation, producerArguments); - Assert.assertEquals(producerArguments[0], new TestParamWithPart("testString", 12L, uploadedFile)); - Assert.assertSame(((TestParamWithPart) producerArguments[0]).getUp(), uploadedFile); - Assert.assertNull(producerArguments[1]); - } - - static class TestParamWithPart { - private String str; - - private long longValue; - - private Part uploaded; - - public TestParamWithPart() { - } - - public TestParamWithPart(String str, long longValue, Part uploaded) { - this.str = str; - this.longValue = longValue; - this.uploaded = uploaded; - } - - public String getStr() { - return str; - } - - public void setStr(String str) { - this.str = str; - } - - public long getLongValue() { - return longValue; - } - - public void setLongValue(long longValue) { - this.longValue = longValue; - } - - public Part getUp() { - return uploaded; - } - - public void setUp(Part uploaded) { - this.uploaded = uploaded; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TestParamWithPart that = (TestParamWithPart) o; - return longValue == that.longValue && - Objects.equals(str, that.str) && - Objects.equals(uploaded, that.uploaded); - } - - @Override - public int hashCode() { - return Objects.hash(str, longValue, uploaded); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java deleted file mode 100644 index fea80f258a4..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.producer; - -import java.util.Date; -import java.util.HashMap; -import java.util.Objects; - -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; -import org.junit.Assert; -import org.junit.Test; - -public class ProducerSpringMVCQueryObjectMapperTest { - - @Test - public void mapArgument() { - final HashMap swaggerParamIndexMap = new HashMap<>(); - swaggerParamIndexMap.put("name", 0); - swaggerParamIndexMap.put("age", 1); - ArgumentMapper argumentMapper = new ProducerSpringMVCQueryObjectMapper(swaggerParamIndexMap, 0, TestParam.class); - SwaggerInvocation swaggerInvocation = new SwaggerInvocation(); - swaggerInvocation.setSwaggerArguments(new Object[] {"nameTest", 22}); - - final Object[] producerArguments = new Object[1]; - argumentMapper.mapArgument(swaggerInvocation, producerArguments); - Assert.assertEquals(producerArguments[0], new TestParam().setName("nameTest").setAge(22)); - } - - @Test - public void mapArgumentOnRecursiveParam() { - final HashMap swaggerParamIndexMap = new HashMap<>(); - swaggerParamIndexMap.put("num", 0); - swaggerParamIndexMap.put("str", 1); - swaggerParamIndexMap.put("date", 2); - ArgumentMapper argumentMapper = new ProducerSpringMVCQueryObjectMapper(swaggerParamIndexMap, 1, - RecursiveParam.class); - SwaggerInvocation swaggerInvocation = new SwaggerInvocation(); - final Date testDate = new Date(); - swaggerInvocation.setSwaggerArguments(new Object[] {2, "str0_0", testDate}); - - final Object[] producerArguments = new Object[2]; - argumentMapper.mapArgument(swaggerInvocation, producerArguments); - Assert.assertNull(producerArguments[0]); - Assert.assertEquals(producerArguments[1], new RecursiveParam().setNum(2).setStr("str0_0").setDate(testDate)); - } - - static class TestParam { - private String name; - - private int age; - - public String getName() { - return name; - } - - public TestParam setName(String name) { - this.name = name; - return this; - } - - public int getAge() { - return age; - } - - public TestParam setAge(int age) { - this.age = age; - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TestParam testParam = (TestParam) o; - return age == testParam.age && - Objects.equals(name, testParam.name); - } - - @Override - public int hashCode() { - return Objects.hash(name, age); - } - } - - static class RecursiveParam { - - private int num; - - private String str; - - private Date date; - - private RecursiveParam recursiveParam; - - public int getNum() { - return num; - } - - public RecursiveParam setNum(int num) { - this.num = num; - return this; - } - - public String getStr() { - return str; - } - - public RecursiveParam setStr(String str) { - this.str = str; - return this; - } - - public Date getDate() { - return date; - } - - public RecursiveParam setDate(Date date) { - this.date = date; - return this; - } - - public RecursiveParam getRecursiveParam() { - return recursiveParam; - } - - public RecursiveParam setRecursiveParam( - RecursiveParam recursiveParam) { - this.recursiveParam = recursiveParam; - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("RecursiveParam{"); - sb.append("num=").append(num); - sb.append(", str='").append(str).append('\''); - sb.append(", date=").append(date); - sb.append(", recursiveParam=").append(recursiveParam); - sb.append('}'); - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RecursiveParam that = (RecursiveParam) o; - return num == that.num && - Objects.equals(str, that.str) && - Objects.equals(date, that.date) && - Objects.equals(recursiveParam, that.recursiveParam); - } - - @Override - public int hashCode() { - return Objects.hash(num, str, date, recursiveParam); - } - } -} \ No newline at end of file diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestJaxrs.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestJaxrs.java new file mode 100644 index 00000000000..fa9739866b8 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestJaxrs.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBeanParamV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.JaxrsAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddBeanParamV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestJaxrs { + @Test + public void add() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new JaxrsAddV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBeanParam() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new JaxrsAddBeanParamV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + AddBeanParamV1 paramV1 = (AddBeanParamV1) result.get("wrapper"); + Assertions.assertEquals(1, paramV1.getX()); + Assertions.assertEquals(2, paramV1.y); + } + + @Test + public void addBody() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new JaxrsAddBodyV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + AddWrapperV1 addBody = new AddWrapperV1(); + Map arguments = new HashMap<>(); + arguments.put("addBody", addBody); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + Assertions.assertSame(addBody, result.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojo.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojo.java new file mode 100644 index 00000000000..a42a58c8388 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojo.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.PojoAddWithContextV1; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class TestPojo { + static Map addBody = new HashMap<>(); + + static { + addBody.put("x", 1); + addBody.put("y", 2); + } + + @Test + public void add() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new PojoAddV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map arguments = new HashMap<>(); + arguments.put("addBody", addBody); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addBody() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new PojoAddBodyV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map arguments = new HashMap<>(); + arguments.put("addBody", addBody); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + Assertions.assertSame(addBody, result.get("addBody")); + } + + @Test + public void addWithContext_add() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new PojoAddWithContextV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map arguments = new HashMap<>(); + arguments.put("addBody", addBody); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(3, result.size()); + Assertions.assertSame(invocation, result.get("context")); + Assertions.assertEquals(1, result.get("x")); + Assertions.assertEquals(2, result.get("y")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.java new file mode 100644 index 00000000000..cd01c6a6bba --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.generator.SwaggerConst; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.schemas.PojoOneArg; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class TestPojoOneArg { + @Test + public void should_mapper_swagger_wrapped_body_field_to_producer_enum() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new PojoOneArg(), null); + SwaggerProducerOperation swaggerProducerOperation = swaggerProducer.findOperation("enumBody"); + Assertions.assertEquals("enumBodyBody", + swaggerProducerOperation.getSwaggerOperation().getOperation().getRequestBody().getExtensions().get(SwaggerConst.EXT_BODY_NAME)); + + ProducerArgumentsMapper mapper = swaggerProducerOperation.getArgumentsMapper(); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map swaggerArguments = new HashMap<>(); + Map arguments = new HashMap<>(); + arguments.put("color", "BLUE"); + swaggerArguments.put("enumBodyBody", arguments); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, swaggerArguments); + + Assertions.assertEquals(1, result.size()); + Assertions.assertSame(Color.BLUE, result.get("color")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestSpringmvc.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestSpringmvc.java new file mode 100644 index 00000000000..cc4119aa480 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestSpringmvc.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.arguments.producer; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddBodyV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddV1; +import org.apache.servicecomb.swagger.invocation.schemas.SpringmvcAddWrapperV1; +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestSpringmvc { + @Test + public void add() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new SpringmvcAddV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(2, result.size()); + Assertions.assertEquals(1, (int) result.get("x")); + Assertions.assertEquals(2, (int) result.get("y")); + } + + @Test + public void addWrapper() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new SpringmvcAddWrapperV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + Map arguments = new HashMap<>(); + arguments.put("x", 1); + arguments.put("y", 2); + SwaggerInvocation invocation = new SwaggerInvocation(); + + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + AddWrapperV1 paramV1 = (AddWrapperV1) result.get("wrapper"); + Assertions.assertEquals(1, paramV1.getX()); + Assertions.assertEquals(2, paramV1.y); + } + + @Test + public void addBody() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new SpringmvcAddBodyV1(), null); + ProducerArgumentsMapper mapper = swaggerProducer.findOperation("add").getArgumentsMapper(); + + AddWrapperV1 addBody = new AddWrapperV1(); + Map arguments = new HashMap<>(); + arguments.put("addBody", addBody); + + SwaggerInvocation invocation = new SwaggerInvocation(); + Map result = mapper.swaggerArgumentToInvocationArguments(invocation, arguments); + + Assertions.assertEquals(1, result.size()); + Assertions.assertSame(addBody, result.get("addBody")); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/utils/Utils.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/utils/Utils.java deleted file mode 100644 index 3a831cbdd95..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/utils/Utils.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.arguments.utils; - -import org.springframework.util.ReflectionUtils; - -public class Utils { - public static Object getFieldValue(Object instance, String fieldName) { - try { - return ReflectionUtils.findField(instance.getClass(), fieldName).get(instance); - } catch (Exception e) { - throw new Error(e); - } - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestContextUtils.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestContextUtils.java index c84b4dcde99..725114cf5eb 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestContextUtils.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestContextUtils.java @@ -18,16 +18,16 @@ import java.util.concurrent.CompletableFuture; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestContextUtils { @Test public void getFromCompletableFuture() { - Assert.assertNull(ContextUtils.getFromCompletableFuture(new CompletableFuture<>())); + Assertions.assertNull(ContextUtils.getFromCompletableFuture(new CompletableFuture<>())); InvocationContext context = new InvocationContext(); - Assert - .assertSame(context, ContextUtils.getFromCompletableFuture(new InvocationContextCompletableFuture<>(context))); + Assertions + .assertSame(context, ContextUtils.getFromCompletableFuture(new InvocationContextCompletableFuture<>(context))); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestInvocationContext.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestInvocationContext.java index 189b1af4ffd..b52a3054056 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestInvocationContext.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/context/TestInvocationContext.java @@ -19,31 +19,31 @@ import java.util.HashMap; import java.util.Map; -import javax.ws.rs.core.Response.Status.Family; +import jakarta.ws.rs.core.Response.Status.Family; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestInvocationContext { @Test public void addContext() { InvocationContext invocationContext = new InvocationContext(); invocationContext.addContext("key1", "value1"); - Assert.assertEquals(1, invocationContext.getContext().size()); - Assert.assertEquals("value1", invocationContext.getContext("key1")); + Assertions.assertEquals(1, invocationContext.getContext().size()); + Assertions.assertEquals("value1", invocationContext.getContext("key1")); Map otherContext = new HashMap<>(); otherContext.put("key2", "value2"); invocationContext.addContext(otherContext); - Assert.assertEquals(2, invocationContext.getContext().size()); - Assert.assertEquals("value2", invocationContext.getContext("key2")); + Assertions.assertEquals(2, invocationContext.getContext().size()); + Assertions.assertEquals("value2", invocationContext.getContext("key2")); InvocationContext invocationContext2 = new InvocationContext(); Map otherContext2 = new HashMap<>(); otherContext2.put("key3", "value3"); - invocationContext2.context = otherContext2; + invocationContext2.setContext(otherContext2); invocationContext.addContext(invocationContext2); - Assert.assertEquals(3, invocationContext.getContext().size()); + Assertions.assertEquals(3, invocationContext.getContext().size()); } @Test @@ -53,14 +53,14 @@ public void mergeMapContext() { otherContext.put("key1", "value1"); //otherContext's size is large than old. invocationContext.mergeContext(otherContext); - Assert.assertEquals(1, invocationContext.getContext().size()); - Assert.assertEquals("value1", invocationContext.getContext("key1")); + Assertions.assertEquals(1, invocationContext.getContext().size()); + Assertions.assertEquals("value1", invocationContext.getContext("key1")); otherContext.put("key1", "value2"); //otherContext's size is not large than old. invocationContext.mergeContext(otherContext); - Assert.assertEquals(1, invocationContext.getContext().size()); - Assert.assertEquals("value2", invocationContext.getContext("key1")); + Assertions.assertEquals(1, invocationContext.getContext().size()); + Assertions.assertEquals("value2", invocationContext.getContext("key1")); } @Test @@ -69,24 +69,24 @@ public void mergeInvocationContext() { Map otherContext = new HashMap<>(); otherContext.put("key1", "value1"); InvocationContext context2 = new InvocationContext(); - context2.context = otherContext; + context2.setContext(otherContext); invocationContext.mergeContext(context2); - Assert.assertEquals(1, invocationContext.getContext().size()); - Assert.assertEquals("value1", invocationContext.getContext("key1")); + Assertions.assertEquals(1, invocationContext.getContext().size()); + Assertions.assertEquals("value1", invocationContext.getContext("key1")); } @Test public void addLocalContext() { InvocationContext invocationContext = new InvocationContext(); invocationContext.addLocalContext("key1", "value1"); - Assert.assertEquals(1, invocationContext.getLocalContext().size()); - Assert.assertEquals("value1", invocationContext.getLocalContext("key1")); + Assertions.assertEquals(1, invocationContext.getLocalContext().size()); + Assertions.assertEquals("value1", invocationContext.getLocalContext("key1")); Map otherContext = new HashMap<>(); otherContext.put("key2", "value2"); invocationContext.addLocalContext(otherContext); - Assert.assertEquals(2, invocationContext.getLocalContext().size()); - Assert.assertEquals("value2", invocationContext.getLocalContext("key2")); + Assertions.assertEquals(2, invocationContext.getLocalContext().size()); + Assertions.assertEquals("value2", invocationContext.getLocalContext("key2")); } @Test @@ -94,13 +94,13 @@ public void setStatus() { InvocationContext invocationContext = new InvocationContext(); invocationContext.setStatus(200); System.out.println(invocationContext.getStatus().getFamily()); - Assert.assertEquals(200, invocationContext.getStatus().getStatusCode()); - Assert.assertEquals("OK", invocationContext.getStatus().getReasonPhrase()); - Assert.assertEquals(Family.SUCCESSFUL, invocationContext.getStatus().getFamily()); + Assertions.assertEquals(200, invocationContext.getStatus().getStatusCode()); + Assertions.assertEquals("OK", invocationContext.getStatus().getReasonPhrase()); + Assertions.assertEquals(Family.SUCCESSFUL, invocationContext.getStatus().getFamily()); invocationContext.setStatus(200, "TEST"); - Assert.assertEquals(200, invocationContext.getStatus().getStatusCode()); - Assert.assertEquals("TEST", invocationContext.getStatus().getReasonPhrase()); - Assert.assertEquals(Family.SUCCESSFUL, invocationContext.getStatus().getFamily()); + Assertions.assertEquals(200, invocationContext.getStatus().getStatusCode()); + Assertions.assertEquals("TEST", invocationContext.getStatus().getReasonPhrase()); + Assertions.assertEquals(Family.SUCCESSFUL, invocationContext.getStatus().getFamily()); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgrTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgrTest.java deleted file mode 100644 index b19fa964735..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/ConverterMgrTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.converter; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -public class ConverterMgrTest { - @Test - public void isAssignable() { - ConverterMgr converterMgr = new ConverterMgr(); - // simple type - Assert.assertTrue(converterMgr.isAssignable(String.class, String.class)); - Assert.assertTrue(converterMgr.isAssignable(int.class, Integer.class)); - Assert.assertTrue(converterMgr.isAssignable(long.class, Long.class)); - Assert.assertTrue(converterMgr.isAssignable(void.class, Void.class)); - // simple type reverse - Assert.assertTrue(converterMgr.isAssignable(String.class, String.class)); - Assert.assertTrue(converterMgr.isAssignable(Integer.class, int.class)); - Assert.assertTrue(converterMgr.isAssignable(Long.class, long.class)); - Assert.assertTrue(converterMgr.isAssignable(Void.class, void.class)); - // Object type - Assert.assertTrue(converterMgr.isAssignable(ArrayList.class, List.class)); - Assert.assertFalse(converterMgr.isAssignable(List.class, ArrayList.class)); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverterTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverterTest.java new file mode 100644 index 00000000000..908d6ece56a --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartArrayConverterTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import java.util.Arrays; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.foundation.common.part.FilePart; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class PartListToPartArrayConverterTest { + PartListToPartArrayConverter converter = new PartListToPartArrayConverter(); + + @Test + public void getSrcType() { + Assertions.assertEquals("java.util.List", converter.getSrcType().getTypeName()); + } + + @Test + public void getTargetType() { + Assertions.assertEquals(Part[].class.getCanonicalName(), converter.getTargetType().getTypeName()); + } + + @Test + public void convert() { + Object parts = converter.convert(Arrays.asList(new FilePart("name", "file"))); + MatcherAssert.assertThat(parts, Matchers.instanceOf(Part[].class)); + } + + @Test + public void should_got_null_when_convert_null() { + Assertions.assertNull(converter.convert(null)); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverterTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverterTest.java new file mode 100644 index 00000000000..33f96ba9e25 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartListToPartListConverterTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import java.util.Arrays; +import java.util.List; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.foundation.common.part.FilePart; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PartListToPartListConverterTest { + PartListToPartListConverter converter = new PartListToPartListConverter(); + + @Test + public void getSrcType() { + Assertions.assertEquals("java.util.List", converter.getSrcType().getTypeName()); + } + + @Test + public void getTargetType() { + Assertions.assertEquals("java.util.List", converter.getTargetType().getTypeName()); + } + + @Test + public void convert() { + List parts = Arrays.asList(new FilePart("name", "file")); + Assertions.assertSame(parts, converter.convert(parts)); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverterTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverterTest.java new file mode 100644 index 00000000000..02e20c5f94a --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/PartToPartConverterTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter.impl.part; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.foundation.common.part.FilePart; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +public class PartToPartConverterTest { + PartToPartConverter converter = new PartToPartConverter(); + + @Test + public void getSrcType() { + Assertions.assertEquals(Part.class.getName(), converter.getSrcType().getTypeName()); + } + + @Test + public void getTargetType() { + Assertions.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); + } + + @Test + public void convert() { + Part part = new FilePart("name", "file"); + Assertions.assertSame(part, converter.convert(part)); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestBytesToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestBytesToPartConverter.java index 19fcfa256cb..409e53e2d3c 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestBytesToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestBytesToPartConverter.java @@ -16,28 +16,29 @@ */ package org.apache.servicecomb.swagger.invocation.converter.impl.part; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestBytesToPartConverter { BytesToPartConverter converter = new BytesToPartConverter(); @Test public void getSrcType() { - Assert.assertSame(byte[].class, converter.getSrcType()); + Assertions.assertSame(byte[].class, converter.getSrcType()); } @Test public void getTargetType() { - Assert.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); + Assertions.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); } @Test public void convert() { Object part = converter.convert(new byte[] {}); - Assert.assertThat(part, Matchers.instanceOf(Part.class)); + MatcherAssert.assertThat(part, Matchers.instanceOf(Part.class)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestFileToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestFileToPartConverter.java index 0cf1516f825..38b2378ab59 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestFileToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestFileToPartConverter.java @@ -19,29 +19,30 @@ import java.io.File; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestFileToPartConverter { FileToPartConverter converter = new FileToPartConverter(); @Test public void getSrcType() { - Assert.assertEquals(File.class.getName(), converter.getSrcType().getTypeName()); + Assertions.assertEquals(File.class.getName(), converter.getSrcType().getTypeName()); } @Test public void getTargetType() { - Assert.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); + Assertions.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); } @Test public void convert() { File file = new File("abc"); Object part = converter.convert(file); - Assert.assertThat(part, Matchers.instanceOf(Part.class)); + MatcherAssert.assertThat(part, Matchers.instanceOf(Part.class)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestInputStreamToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestInputStreamToPartConverter.java index 74fe2b05c87..a846900eeb2 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestInputStreamToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestInputStreamToPartConverter.java @@ -20,28 +20,29 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestInputStreamToPartConverter { InputStreamToPartConverter converter = new InputStreamToPartConverter(); @Test public void getSrcType() { - Assert.assertEquals(InputStream.class.getName(), converter.getSrcType().getTypeName()); + Assertions.assertEquals(InputStream.class.getName(), converter.getSrcType().getTypeName()); } @Test public void getTargetType() { - Assert.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); + Assertions.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); } @Test public void convert() { Object part = converter.convert(new ByteArrayInputStream(new byte[] {})); - Assert.assertThat(part, Matchers.instanceOf(Part.class)); + MatcherAssert.assertThat(part, Matchers.instanceOf(Part.class)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestResourceToPartConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestResourceToPartConverter.java index 54c72c09dd1..20dd2a757ee 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestResourceToPartConverter.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/converter/impl/part/TestResourceToPartConverter.java @@ -19,11 +19,12 @@ import java.io.ByteArrayInputStream; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; @@ -32,17 +33,17 @@ public class TestResourceToPartConverter { @Test public void getSrcType() { - Assert.assertEquals(Resource.class.getName(), converter.getSrcType().getTypeName()); + Assertions.assertEquals(Resource.class.getName(), converter.getSrcType().getTypeName()); } @Test public void getTargetType() { - Assert.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); + Assertions.assertEquals(Part.class.getName(), converter.getTargetType().getTypeName()); } @Test public void convert() { Object part = converter.convert(new InputStreamResource(new ByteArrayInputStream(new byte[] {}))); - Assert.assertThat(part, Matchers.instanceOf(Part.class)); + MatcherAssert.assertThat(part, Matchers.instanceOf(Part.class)); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionDataTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionDataTest.java new file mode 100644 index 00000000000..c12f149b825 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/CommonExceptionDataTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.exception; + +import static com.google.common.collect.ImmutableMap.of; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import io.vertx.core.json.Json; + +class CommonExceptionDataTest { + @Test + void should_not_include_code_in_json_when_code_is_null() { + CommonExceptionData data = new CommonExceptionData("msg"); + + assertThat(Json.encode(data)).isEqualTo("{\"message\":\"msg\"}"); + } + + @Test + void should_include_code_in_json_when_code_is_not_null() { + CommonExceptionData data = new CommonExceptionData("code", "msg"); + + String json = Json.encode(data); + @SuppressWarnings("unchecked") + Map obj = Json.decodeValue(json, Map.class); + + assertThat(obj).containsEntry("code", "code").containsEntry("message", "msg").hasSize(2); + } + + @Test + void should_include_dynamic_field_in_json() { + CommonExceptionData data = new CommonExceptionData("msg"); + data.putDynamic("k", "v"); + + assertThat(Json.encode(data)).isEqualTo("{\"message\":\"msg\",\"k\":\"v\"}"); + } + + @Test + void should_decode_dynamic_field_from_json() { + String json = "{\"message\":\"msg\",\"k\":\"v\"}"; + CommonExceptionData data = Json.decodeValue(json, CommonExceptionData.class); + + assertThat(data.getMessage()).isEqualTo("msg"); + assertThat(data.getDynamic()).isEqualTo(of("k", "v")); + assertThat(Json.encode(data)).isEqualTo(json); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/ErrorToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/ErrorToProducerResponseConverter.java deleted file mode 100644 index 87eaae408a5..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/ErrorToProducerResponseConverter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; - -public class ErrorToProducerResponseConverter implements ExceptionToProducerResponseConverter { - @Override - public Class getExceptionClass() { - return Error.class; - } - - @Override - public Response convert(SwaggerInvocation swaggerInvocation, Error e) { - return Response.create(Status.OK, "response from error: " + e.getMessage()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestDefaultExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestDefaultExceptionToProducerResponseConverter.java deleted file mode 100644 index c90d5e7e3a5..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestDefaultExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mocked; - -public class TestDefaultExceptionToProducerResponseConverter { - DefaultExceptionToProducerResponseConverter converter = new DefaultExceptionToProducerResponseConverter(); - - @Test - public void getExceptionClass() { - Assert.assertNull(converter.getExceptionClass()); - } - - @Test - public void convert(@Mocked SwaggerInvocation swaggerInvocation, @Mocked Error e) { - Response response = converter.convert(swaggerInvocation, e); - Assert.assertSame(e, ((InvocationException) response.getResult()).getCause()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionFactory.java deleted file mode 100644 index 76f5458f1a2..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -public class TestExceptionFactory { - @Test - public void convertExceptionToResponse() { - Error error = new Error("test"); - Response response = ExceptionFactory.convertExceptionToResponse(null, error); - - Assert.assertSame(Status.OK, response.getStatus()); - Assert.assertEquals("response from error: test", response.getResult()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionToProducerResponseConverters.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionToProducerResponseConverters.java deleted file mode 100644 index 319e411537d..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestExceptionToProducerResponseConverters.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import java.io.IOException; -import java.util.Arrays; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -public class TestExceptionToProducerResponseConverters { - @Test - public void convertExceptionToResponse( - @Mocked ExceptionToProducerResponseConverter c1, - @Mocked Response r1, - @Mocked ExceptionToProducerResponseConverter c2, - @Mocked Response r2, - @Mocked ExceptionToProducerResponseConverter cDef) { - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(ExceptionToProducerResponseConverter.class); - result = Arrays.asList(c1, c2, cDef); - - c1.getExceptionClass(); - result = Throwable.class; - c1.convert((SwaggerInvocation) any, (Throwable) any); - result = r1; - - c2.getExceptionClass(); - result = Exception.class; - c2.convert((SwaggerInvocation) any, (Throwable) any); - result = r2; - - cDef.getExceptionClass(); - result = null; - } - }; - - ExceptionToProducerResponseConverters exceptionToProducerResponseConverters = new ExceptionToProducerResponseConverters(); - - Assert.assertSame(r1, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new Throwable())); - Assert.assertSame(r2, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new Exception())); - Assert.assertSame(r2, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, - new IllegalStateException())); - } - - @Test - public void convertExceptionToResponse_checkDefaultConverterPriority( - @Mocked ExceptionToProducerResponseConverter c1, - @Mocked Response r1, - @Mocked ExceptionToProducerResponseConverter c2, - @Mocked Response r2, - @Mocked ExceptionToProducerResponseConverter cDef, - @Mocked Response rDef, - @Mocked ExceptionToProducerResponseConverter cDef2) { - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(ExceptionToProducerResponseConverter.class); - result = Arrays.asList(c1, c2, cDef, cDef2); - - c1.getExceptionClass(); - result = RuntimeException.class; - c1.convert((SwaggerInvocation) any, (Throwable) any); - result = r1; - - c2.getExceptionClass(); - result = InvocationException.class; - c2.convert((SwaggerInvocation) any, (Throwable) any); - result = r2; - - cDef.getExceptionClass(); - result = null; - cDef.convert((SwaggerInvocation) any, (Throwable) any); - result = rDef; - - cDef2.getExceptionClass(); - result = null; - } - }; - - ExceptionToProducerResponseConverters exceptionToProducerResponseConverters = new ExceptionToProducerResponseConverters(); - - Assert.assertSame(r2, - exceptionToProducerResponseConverters - .convertExceptionToResponse(null, new InvocationException(Status.UNAUTHORIZED, ""))); - Assert.assertSame(r1, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new RuntimeException())); - Assert.assertSame(rDef, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, - new IOException())); - } - - @Test - public void convertExceptionToResponse_CheckCommonConvertPriority( - @Mocked ExceptionToProducerResponseConverter cR0, - @Mocked ExceptionToProducerResponseConverter cR0_LowPriority, - @Mocked ExceptionToProducerResponseConverter cR1, - @Mocked ExceptionToProducerResponseConverter cR, - @Mocked ExceptionToProducerResponseConverter cT, - @Mocked ExceptionToProducerResponseConverter cDef, - @Mocked Response rR0, - @Mocked Response rR1, - @Mocked Response rR, - @Mocked Response rT) { - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(ExceptionToProducerResponseConverter.class); - result = Arrays.asList(cR, cR0, cR0_LowPriority, cR1, cDef, cT); - - cR0.getExceptionClass(); - result = RuntimeException0.class; - cR0.convert((SwaggerInvocation) any, (RuntimeException0) any); - result = rR0; - - cR0_LowPriority.getExceptionClass(); - result = RuntimeException0.class; - - cR1.getExceptionClass(); - result = RuntimeException1.class; - cR1.convert((SwaggerInvocation) any, (RuntimeException1) any); - result = rR1; - - cR.getExceptionClass(); - result = RuntimeException.class; - cR.convert((SwaggerInvocation) any, (RuntimeException) any); - result = rR; - - cT.getExceptionClass(); - result = Throwable.class; - cT.convert((SwaggerInvocation) any, (Throwable) any); - result = rT; - - cDef.getExceptionClass(); - result = null; - } - }; - - ExceptionToProducerResponseConverters exceptionToProducerResponseConverters = new ExceptionToProducerResponseConverters(); - - Assert.assertSame(rR0, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new RuntimeException0_0())); - Assert.assertSame(rR0, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new RuntimeException0())); - Assert.assertSame(rR1, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new RuntimeException1())); - Assert.assertSame(rR, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new RuntimeException())); - // Actually, a Throwable exception converter will act like a default converter, as our implementation expects. - Assert.assertSame(rT, - exceptionToProducerResponseConverters.convertExceptionToResponse(null, new IOException())); - } - - static class RuntimeException0 extends RuntimeException { - private static final long serialVersionUID = -5151948381107463505L; - } - - static class RuntimeException1 extends RuntimeException { - private static final long serialVersionUID = 1752513688353075486L; - } - - static class RuntimeException0_0 extends RuntimeException0 { - private static final long serialVersionUID = -6645187961518504765L; - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestInvocationExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestInvocationExceptionToProducerResponseConverter.java deleted file mode 100644 index 49dbd59eae6..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/exception/TestInvocationExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.exception; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Mocked; - -public class TestInvocationExceptionToProducerResponseConverter { - InvocationExceptionToProducerResponseConverter converter = new InvocationExceptionToProducerResponseConverter(); - - @Test - public void getExceptionClass() { - Assert.assertEquals(InvocationException.class, converter.getExceptionClass()); - } - - @Test - public void convert(@Mocked SwaggerInvocation swaggerInvocation, @Mocked InvocationException e) { - Response response = converter.convert(swaggerInvocation, e); - Assert.assertSame(e, response.getResult()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/JaxrsImpl.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/JaxrsImpl.java index fe02aa2d82f..c1e9bd23f7b 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/JaxrsImpl.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/JaxrsImpl.java @@ -20,16 +20,16 @@ import java.util.Arrays; import java.util.List; -import javax.ws.rs.CookieParam; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.swagger.invocation.context.InvocationContext; @@ -89,7 +89,7 @@ public List testArrayList(String[] s) { @Path("/testListArray") @POST public String[] testListArray(List s) { - return s.toArray(new String[s.size()]); + return s.toArray(new String[0]); } @Path("/testListList") @@ -113,7 +113,7 @@ public List testObjectArrayList(Person[] s) { @Path("/testObjectListArray") @POST public Person[] testObjectListArray(List s) { - return s.toArray(new Person[s.size()]); + return s.toArray(new Person[0]); } @Path("/testObjectListList") diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoConsumerIntf.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoConsumerIntf.java index be2dc07ae52..c7a4f8f3877 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoConsumerIntf.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoConsumerIntf.java @@ -22,14 +22,14 @@ import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; public interface PojoConsumerIntf { int testSimple(int a, int b, int c); Person testObject(Person user); - @ApiOperation(nickname = "testObject", value = "") + @Operation(operationId = "testObject", summary = "") CompletableFuture testObjectAsync(Person user); String testSimpleAndObject(String prefix, Person user); diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoImpl.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoImpl.java index 611a5c77098..ba0760d21bb 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoImpl.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/PojoImpl.java @@ -23,7 +23,7 @@ import org.apache.servicecomb.swagger.invocation.context.InvocationContext; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; public class PojoImpl { public int testSimple(int a, int b, int c) { @@ -35,7 +35,7 @@ public Person testObject(Person user) { return user; } - @ApiOperation(nickname = "testSimpleAndObject", value = "") + @Operation(operationId = "testSimpleAndObject", summary = "") public CompletableFuture testSimpleAndObjectAsync(String prefix, Person user) { CompletableFuture future = new CompletableFuture<>(); future.complete(prefix + " " + user.getName()); @@ -64,7 +64,7 @@ public List testArrayList(String[] s) { } public String[] testListArray(List s) { - return s.toArray(new String[s.size()]); + return s.toArray(new String[0]); } public List testListList(List s) { @@ -80,7 +80,7 @@ public List testObjectArrayList(Person[] s) { } public Person[] testObjectListArray(List s) { - return s.toArray(new Person[s.size()]); + return s.toArray(new Person[0]); } public List testObjectListList(List s) { diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/ProducerImpl.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/ProducerImpl.java index c993b91a54e..3461d823376 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/ProducerImpl.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/models/ProducerImpl.java @@ -17,15 +17,16 @@ package org.apache.servicecomb.swagger.invocation.models; -import io.swagger.annotations.ApiOperation; + +import io.swagger.v3.oas.annotations.Operation; public class ProducerImpl { - @ApiOperation(value = "", hidden = true) + @Operation(summary = "", hidden = true) public int hiddenMethod(int a) { return a; } - @ApiOperation(value = "") + @Operation(summary = "") public int visibleMethod(int a) { return a; } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestHeaders.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestHeaders.java deleted file mode 100644 index f248661165a..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestHeaders.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestHeaders { - @Test - public void test1() { - Headers headers = new Headers(); - Assert.assertEquals(null, headers.getFirst("h1")); - Assert.assertEquals(null, headers.getHeader("h1")); - - Map> headerMap = new HashMap<>(); - List h1Value = Arrays.asList("h1v1", "h1v2"); - headerMap.put("h1", h1Value); - headerMap.put("h2", null); - headerMap.put("h3", Arrays.asList()); - headers.setHeaderMap(headerMap); - - Assert.assertEquals(headerMap, headers.getHeaderMap()); - Assert.assertEquals("h1v1", headers.getFirst("h1")); - Assert.assertEquals(null, headers.getFirst("h2")); - Assert.assertEquals(null, headers.getFirst("h3")); - Assert.assertEquals(h1Value, headers.getHeader("h1")); - } - - @Test - public void test2() { - Headers headers = new Headers(); - headers.addHeader("h1", "h1v1"); - headers.addHeader("h1", "h1v2"); - - Assert.assertEquals("h1v1", headers.getFirst("h1")); - } - - @Test - public void addHeader_list() { - Headers headers = new Headers(); - headers.addHeader("h", Arrays.asList("v1", "v2")); - headers.addHeader("h", Arrays.asList("v3")); - - Assert.assertThat(headers.getHeader("h"), Matchers.contains("v1", "v2", "v3")); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java deleted file mode 100644 index 394e7f42270..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponseMapperFactorys.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response; - -import java.util.List; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterSame; -import org.apache.servicecomb.swagger.invocation.response.consumer.CompletableFutureConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.CseResponseConsumerResponseMapperFactory; -import org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapper; -import org.apache.servicecomb.swagger.invocation.response.consumer.DefaultConsumerResponseMapperFactory; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Deencapsulation; - -public class TestResponseMapperFactorys { - ResponseMapperFactorys consumerResponseMapperFactorys = - new ResponseMapperFactorys<>(ConsumerResponseMapperFactory.class); - - List> factorys = - Deencapsulation.getField(consumerResponseMapperFactorys, "factorys"); - - ConverterMgr converterMgr = new ConverterMgr(); - - @Before - public void setup() { - consumerResponseMapperFactorys.setConverterMgr(converterMgr); - } - - @SuppressWarnings("unchecked") - @Test - public void construct() { - Assert.assertThat(factorys, - Matchers.contains(Matchers.instanceOf(CseResponseConsumerResponseMapperFactory.class), - Matchers.instanceOf(CompletableFutureConsumerResponseMapperFactory.class), - Matchers.instanceOf(DefaultConsumerResponseMapperFactory.class))); - } - - @Test - public void setConverterMgr() { - Assert.assertSame(converterMgr, Deencapsulation.getField(factorys.get(2), "converterMgr")); - } - - @Test - public void createResponseMapper_default() { - ConsumerResponseMapper mapper = consumerResponseMapperFactorys.createResponseMapper(String.class, String.class); - Assert.assertThat(mapper, Matchers.instanceOf(DefaultConsumerResponseMapper.class)); - - Converter converter = Deencapsulation.getField(mapper, "converter"); - Assert.assertSame(ConverterSame.getInstance(), converter); - } - - @Test - public void createResponseMapper_cseResponse() { - ConsumerResponseMapper mapper = consumerResponseMapperFactorys.createResponseMapper(String.class, Response.class); - - Response response = Response.ok(null); - Object result = mapper.mapResponse(response); - Assert.assertSame(response, result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java index f6077ced8e7..972ce6d7edd 100644 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java @@ -16,26 +16,27 @@ */ package org.apache.servicecomb.swagger.invocation.response; -import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator; -import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; -import org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils; -import org.junit.Assert; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.junit.Test; +import org.junit.jupiter.api.Assertions; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ResponseHeader; -import io.swagger.models.Operation; -import io.swagger.models.Swagger; +import com.fasterxml.jackson.databind.JavaType; + +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; public class TestResponsesMeta { - class ResponseMetaImpl { - @ApiResponses({@ApiResponse(code = 400, response = String.class, message = ""), - @ApiResponse( - code = 401, - response = long.class, - message = "", - responseHeaders = {@ResponseHeader(name = "h1", response = int.class)}) + static class ResponseMetaImpl { + @ApiResponses({@ApiResponse(responseCode = "400", description = "", + content = {@Content(schema = @Schema(implementation = String.class))}), + @ApiResponse(responseCode = "401", description = "", + content = {@Content(schema = @Schema(implementation = String.class))}, + headers = {@Header(name = "h1", schema = @Schema(implementation = String.class))}) }) public int add(int x, int y) { return x + y; @@ -44,33 +45,26 @@ public int add(int x, int y) { @Test public void test() { - SwaggerGenerator generator = UnitTestSwaggerUtils.generateSwagger(ResponseMetaImpl.class); - Swagger swagger = generator.getSwagger(); - Operation operation = swagger.getPath("/add").getPost(); + OpenAPI swagger = SwaggerGenerator.generate(ResponseMetaImpl.class); + Operation operation = swagger.getPaths().get("/add").getPost(); - SwaggerToClassGenerator swaggerToClassGenerator = new SwaggerToClassGenerator(new ClassLoader() { - }, swagger, "ms.sid"); ResponsesMeta meta = new ResponsesMeta(); - meta.init(swaggerToClassGenerator, operation, int.class); + meta.init(swagger, operation); - ResponseMeta resp = meta.findResponseMeta(200); - // Response currently is based on return type not swagger type - Assert.assertEquals(int.class, resp.getJavaType().getRawClass()); + JavaType resp = meta.findResponseType(200); + Assertions.assertEquals(Integer.class, resp.getRawClass()); - resp = meta.findResponseMeta(201); - // Response currently is based on return type not swagger type. For this test case there is one problem need to discuss. - // If SUCCESS family, do we should use OK response type? - Assert.assertEquals(int.class, resp.getJavaType().getRawClass()); + resp = meta.findResponseType(201); + Assertions.assertEquals(Integer.class, resp.getRawClass()); - resp = meta.findResponseMeta(400); - Assert.assertEquals(String.class, resp.getJavaType().getRawClass()); + resp = meta.findResponseType(400); + Assertions.assertEquals(String.class, resp.getRawClass()); - resp = meta.findResponseMeta(401); - Assert.assertEquals(Long.class, resp.getJavaType().getRawClass()); - Assert.assertEquals(Integer.class, resp.getHeaders().get("h1").getRawClass()); + resp = meta.findResponseType(401); + Assertions.assertEquals(String.class, resp.getRawClass()); - resp = meta.findResponseMeta(500); + resp = meta.findResponseType(500); // changed to Object for new version to keep user defined error data not lose and can be parsed. - Assert.assertEquals(Object.class, resp.getJavaType().getRawClass()); + Assertions.assertEquals(Object.class, resp.getRawClass()); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCompletableFutureConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCompletableFutureConsumerResponseMapperFactory.java deleted file mode 100644 index ea4cc4917d6..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCompletableFutureConsumerResponseMapperFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.consumer; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestCompletableFutureConsumerResponseMapperFactory { - CompletableFutureConsumerResponseMapperFactory factory = new CompletableFutureConsumerResponseMapperFactory(); - - ConverterMgr converterMgr = new ConverterMgr(); - - ResponseMapperFactorys factorys = - new ResponseMapperFactorys<>(ConsumerResponseMapperFactory.class, converterMgr); - - public CompletableFuture consumer() { - return null; - } - - public List swagger() { - return null; - } - - @Test - public void isMatch_true() { - Method method = ReflectUtils.findMethod(this.getClass(), "consumer"); - Assert.assertTrue(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_Parameterized_false() { - Method method = ReflectUtils.findMethod(this.getClass(), "swagger"); - Assert.assertFalse(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); - } - - @Test - public void completableFuture() { - Method consumerMethod = ReflectUtils.findMethod(this.getClass(), "consumer"); - Method swaggerMethod = ReflectUtils.findMethod(this.getClass(), "swagger"); - ConsumerResponseMapper mapper = factory - .createResponseMapper(factorys, swaggerMethod.getGenericReturnType(), consumerMethod.getGenericReturnType()); - - Response response = Response.ok(Arrays.asList("a", "b")); - String[] arr = (String[]) mapper.mapResponse(response); - Assert.assertThat(arr, Matchers.arrayContaining("a", "b")); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestConsumerResponseMapperFactories.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestConsumerResponseMapperFactories.java new file mode 100644 index 00000000000..6a198088e4d --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestConsumerResponseMapperFactories.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.consumer; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.models.OpenAPI; + +public class TestConsumerResponseMapperFactories { + interface ConsumerResponseForTest { + String normal(); + + CompletableFuture async(); + + @ApiResponse(responseCode = "200", description = "", content = + {@Content(schema = @Schema(implementation = String.class))}) + Response scbResponse(); + + @ApiResponse(responseCode = "200", description = "", content = + {@Content(schema = @Schema(implementation = String.class))}) + jakarta.ws.rs.core.Response jaxrsResponse(); + + Optional optional(); + } + + SwaggerEnvironment environment = new SwaggerEnvironment(); + + SwaggerConsumer swaggerConsumer; + + String result = "abc"; + + Response response = Response.ok(result); + + @Before + public void setup() { + OpenAPI swagger = SwaggerGenerator.generate(ConsumerResponseForTest.class); + swaggerConsumer = environment.createConsumer(ConsumerResponseForTest.class, swagger); + } + + @Test + public void should_mapper_to_normal_string() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("normal"); + assertThat(operation.getResponseMapper()).isInstanceOf(DefaultConsumerResponseMapper.class); + Assertions.assertEquals(result, operation.getResponseMapper().mapResponse(response)); + } + + @Test + public void should_mapper_to_completableFuture_element_string() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("async"); + assertThat(operation.getResponseMapper()).isInstanceOf(DefaultConsumerResponseMapper.class); + Assertions.assertEquals(result, operation.getResponseMapper().mapResponse(response)); + } + + @Test + public void should_mapper_to_scbResponse_string() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("scbResponse"); + assertThat(operation.getResponseMapper().getClass().getName()) + .startsWith(CseResponseConsumerResponseMapperFactory.class.getName()); + Response scbResponse = (Response) operation.getResponseMapper().mapResponse(response); + Assertions.assertEquals(result, scbResponse.getResult()); + } + + @Test + public void should_mapper_to_optional_string() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("optional"); + assertThat(operation.getResponseMapper()).isInstanceOf(OptionalConsumerResponseMapper.class); + @SuppressWarnings("unchecked") + Optional optional = (Optional) operation.getResponseMapper().mapResponse(response); + Assertions.assertEquals(result, optional.get()); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCseResponseConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCseResponseConsumerResponseMapperFactory.java deleted file mode 100644 index 423862897f2..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestCseResponseConsumerResponseMapperFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.consumer; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -public class TestCseResponseConsumerResponseMapperFactory { - CseResponseConsumerResponseMapperFactory factory = new CseResponseConsumerResponseMapperFactory(); - - @Test - public void isMatch_true() { - Assert.assertTrue(factory.isMatch(String.class, Response.class)); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(String.class, String.class)); - } - - @Test - public void createResponseMapper() { - ConsumerResponseMapper mapper = factory.createResponseMapper(null, null, Response.class); - Response response = Response.ok(null); - - Assert.assertSame(response, mapper.mapResponse(response)); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapper.java deleted file mode 100644 index d88be491364..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.consumer; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.junit.Assert; -import org.junit.Test; - -public class TestDefaultConsumerResponseMapper { - ConverterMgr mgr = new ConverterMgr(); - - Converter converter = mgr.findConverter(Integer.class, String.class); - - DefaultConsumerResponseMapper mapper = new DefaultConsumerResponseMapper(converter); - - @Test - public void mapResponse() { - Object result = mapper.mapResponse(Response.ok(1)); - Assert.assertEquals("1", result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapperFactory.java deleted file mode 100644 index 18991d93d3e..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/consumer/TestDefaultConsumerResponseMapperFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.consumer; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestDefaultConsumerResponseMapperFactory { - static ConverterMgr mgr = new ConverterMgr(); - - static DefaultConsumerResponseMapperFactory factory = new DefaultConsumerResponseMapperFactory(); - - @BeforeClass - public static void setup() { - factory.setConverterMgr(mgr); - } - - @Test - public void getOrder() { - Assert.assertEquals(Integer.MAX_VALUE, factory.getOrder()); - } - - @Test - public void isMatch() { - Assert.assertTrue(factory.isMatch(null, null)); - } - - @Test - public void createResponseMapper() { - ConsumerResponseMapper mapper = factory.createResponseMapper(null, Integer.class, String.class); - Object result = mapper.mapResponse(Response.ok(1)); - Assert.assertEquals("1", result); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCompletableFutureProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCompletableFutureProducerResponseMapperFactory.java deleted file mode 100644 index a1c8c47deb2..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCompletableFutureProducerResponseMapperFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.producer; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestCompletableFutureProducerResponseMapperFactory { - CompletableFutureProducerResponseMapperFactory factory = new CompletableFutureProducerResponseMapperFactory(); - - ConverterMgr converterMgr = new ConverterMgr(); - - ResponseMapperFactorys factorys = - new ResponseMapperFactorys<>(ProducerResponseMapperFactory.class, converterMgr); - - public CompletableFuture producer() { - return null; - } - - public List swagger() { - return null; - } - - @Test - public void isMatch_true() { - Method method = ReflectUtils.findMethod(this.getClass(), "producer"); - Assert.assertTrue(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_Parameterized_false() { - Method method = ReflectUtils.findMethod(this.getClass(), "swagger"); - Assert.assertFalse(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); - } - - @Test - public void completableFuture() { - Method producerMethod = ReflectUtils.findMethod(this.getClass(), "producer"); - Method swaggerMethod = ReflectUtils.findMethod(this.getClass(), "swagger"); - ProducerResponseMapper mapper = factory - .createResponseMapper(factorys, swaggerMethod.getGenericReturnType(), producerMethod.getGenericReturnType()); - - Response response = mapper.mapResponse(Status.OK, new String[] {"a", "b"}); - Assert.assertThat(response.getResult(), Matchers.contains("a", "b")); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCseResponseProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCseResponseProducerResponseMapperFactory.java deleted file mode 100644 index 22f2ddc6109..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestCseResponseProducerResponseMapperFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.producer; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.junit.Assert; -import org.junit.Test; - -public class TestCseResponseProducerResponseMapperFactory { - CseResponseProducerResponseMapperFactory factory = new CseResponseProducerResponseMapperFactory(); - - @Test - public void isMatch_true() { - Assert.assertTrue(factory.isMatch(String.class, Response.class)); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(String.class, String.class)); - } - - @Test - public void createResponseMapper() { - ProducerResponseMapper mapper = factory.createResponseMapper(null, null, Response.class); - Response response = Response.ok(null); - - Assert.assertSame(response, mapper.mapResponse(Status.OK, response)); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapper.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapper.java deleted file mode 100644 index c9e980ba620..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapper.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.producer; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.Converter; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.junit.Assert; -import org.junit.Test; - -public class TestDefaultProducerResponseMapper { - ConverterMgr mgr = new ConverterMgr(); - - Converter converter = mgr.findConverter(Integer.class, String.class); - - DefaultProducerResponseMapper mapper = new DefaultProducerResponseMapper(converter); - - @Test - public void mapResponse() { - Response result = mapper.mapResponse(Status.OK, 1); - Assert.assertSame(Status.OK, result.getStatus()); - Assert.assertEquals("1", result.getResult()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapperFactory.java deleted file mode 100644 index 42aaac90f23..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestDefaultProducerResponseMapperFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.response.producer; - -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class TestDefaultProducerResponseMapperFactory { - static ConverterMgr mgr = new ConverterMgr(); - - static DefaultProducerResponseMapperFactory factory = new DefaultProducerResponseMapperFactory(); - - @BeforeClass - public static void setup() { - factory.setConverterMgr(mgr); - } - - @Test - public void getOrder() { - Assert.assertEquals(Integer.MAX_VALUE, factory.getOrder()); - } - - @Test - public void isMatch() { - Assert.assertTrue(factory.isMatch(null, null)); - } - - @Test - public void createResponseMapper() { - ProducerResponseMapper mapper = factory.createResponseMapper(null, String.class, Integer.class); - Response result = mapper.mapResponse(Status.OK, 1); - - Assert.assertSame(Status.OK, result.getStatus()); - Assert.assertEquals("1", result.getResult()); - } -} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestProducerResponseMapperFactories.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestProducerResponseMapperFactories.java new file mode 100644 index 00000000000..fd0fec59387 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/producer/TestProducerResponseMapperFactories.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.response.producer; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.Response; +import org.junit.BeforeClass; +import org.junit.Test; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.ws.rs.core.Response.Status; + +public class TestProducerResponseMapperFactories { + static class ResponseForTest { + public String normal() { + return "normal"; + } + + public CompletableFuture async() { + return CompletableFuture.completedFuture("async"); + } + + @ApiResponse(responseCode = "200", description = "", + content = {@Content(schema = @Schema(implementation = String.class))}) + public Response scbResponse() { + return Response.ok("scb"); + } + + @ApiResponse(responseCode = "200", description = "", + content = {@Content(schema = @Schema(implementation = String.class))}) + public jakarta.ws.rs.core.Response jaxrsResponse() { + return jakarta.ws.rs.core.Response.ok("jaxrs").build(); + } + + public Optional optional() { + return Optional.of("optional"); + } + } + + static SwaggerEnvironment environment = new SwaggerEnvironment(); + + static SwaggerProducer swaggerProducer; + + static ResponseForTest instance = new ResponseForTest(); + + static String result = "abc"; + + static Response response = Response.ok(result); + + @BeforeClass + public static void setup() { + swaggerProducer = environment.createProducer(instance); + } + + @Test + public void should_mapper_to_normal_string() { + SwaggerProducerOperation operation = swaggerProducer.findOperation("normal"); + assertThat(operation.getResponseMapper()).isInstanceOf(DefaultProducerResponseMapper.class); + assertThat((String) operation.getResponseMapper().mapResponse(Status.OK, instance.normal()).getResult()) + .isEqualTo("normal"); + } + + @Test + public void should_mapper_to_completableFuture_element_string() throws ExecutionException, InterruptedException { + SwaggerProducerOperation operation = swaggerProducer.findOperation("async"); + assertThat(operation.getResponseMapper()).isInstanceOf(DefaultProducerResponseMapper.class); + assertThat((String) operation.getResponseMapper().mapResponse(Status.OK, instance.async().get()).getResult()) + .isEqualTo("async"); + } + + @Test + public void should_mapper_to_scbResponse_string() { + SwaggerProducerOperation operation = swaggerProducer.findOperation("scbResponse"); + assertThat(operation.getResponseMapper().getClass().getName()) + .startsWith(CseResponseProducerResponseMapperFactory.class.getName()); + assertThat((String) operation.getResponseMapper().mapResponse(Status.OK, instance.scbResponse()).getResult()) + .isEqualTo("scb"); + } + + @Test + public void should_mapper_to_optional_string() { + SwaggerProducerOperation operation = swaggerProducer.findOperation("optional"); + assertThat(operation.getResponseMapper()).isInstanceOf(OptionalProducerResponseMapper.class); + assertThat((String) operation.getResponseMapper().mapResponse(Status.OK, instance.optional()).getResult()) + .isEqualTo("optional"); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV1.java new file mode 100644 index 00000000000..05b433d124c --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV1.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; + +public interface ConsumerAddBodyV1 { + int add(AddWrapperV1 addBody); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV2.java new file mode 100644 index 00000000000..fa9f4d93594 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddBodyV2.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; + +public interface ConsumerAddBodyV2 { + int add(AddWrapperV2 addBody); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV1.java new file mode 100644 index 00000000000..202bbfc39a3 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV1.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +public interface ConsumerAddV1 { + int add(int x, int y); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV2.java new file mode 100644 index 00000000000..9a86119ef2d --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddV2.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + + +import io.swagger.v3.oas.annotations.Parameter; + +public interface ConsumerAddV2 { + int add(int x, int y, @Parameter(name = "x-z") int z); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddWithContext.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddWithContext.java new file mode 100644 index 00000000000..a797ec0b42b --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerAddWithContext.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; + +public interface ConsumerAddWithContext { + int add(InvocationContext context, int x, int y); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.java new file mode 100644 index 00000000000..876b952d481 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public interface ConsumerOneArg { + void simple(String name); + + void bean(User user); + + void enumBody(Color color); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV1.java new file mode 100644 index 00000000000..440fa289a98 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV1.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddBeanParamV1; + +@Path("/") +public class JaxrsAddBeanParamV1 { + @Path("/add") + @GET + public int add(@BeanParam AddBeanParamV1 wrapper) { + return wrapper.getX() + wrapper.y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV2.java new file mode 100644 index 00000000000..94a677a276e --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBeanParamV2.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddBeanParamV2; + +@Path("/") +public interface JaxrsAddBeanParamV2 { + @Path("/add") + @GET + int add(@BeanParam AddBeanParamV2 wrapper); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV1.java new file mode 100644 index 00000000000..274f3846bed --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV1.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; + +@Path("/") +public class JaxrsAddBodyV1 { + @Path("/add") + @POST + public int add(AddWrapperV1 addBody) { + return addBody.getX() + addBody.y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV2.java new file mode 100644 index 00000000000..a1dc40c9b57 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddBodyV2.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; + +@Path("/") +public interface JaxrsAddBodyV2 { + @Path("/add") + @POST + int add(AddWrapperV2 addBody); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV1.java new file mode 100644 index 00000000000..4051f5551c4 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV1.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +@Path("/") +public class JaxrsAddV1 { + @Path("/add") + @GET + public int add(@QueryParam("x") int x, @QueryParam("y") int y) { + return x + y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV2.java new file mode 100644 index 00000000000..661dd749113 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/JaxrsAddV2.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +@Path("/") +public interface JaxrsAddV2 { + @Path("/add") + @GET + int add(@QueryParam("x") int x, @QueryParam("y") int y, @HeaderParam("x-z") int z); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV1.java new file mode 100644 index 00000000000..c3c3907ce36 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV1.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; + +public class PojoAddBodyV1 { + public int add(AddWrapperV1 addBody) { + return addBody.getX() + addBody.y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV2.java new file mode 100644 index 00000000000..aa0531dd126 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddBodyV2.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; + +public interface PojoAddBodyV2 { + int add(AddWrapperV2 addBody); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV1.java new file mode 100644 index 00000000000..32916c2a541 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV1.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +public class PojoAddV1 { + public int add(int x, int y) { + return x + y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV2.java new file mode 100644 index 00000000000..4dba4abfa6e --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddV2.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import io.swagger.v3.oas.annotations.Parameter; + +public interface PojoAddV2 { + int add(int x, int y, @Parameter(name = "x-z") int z); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddWithContextV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddWithContextV1.java new file mode 100644 index 00000000000..26694feb425 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoAddWithContextV1.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; + +public class PojoAddWithContextV1 { + public int add(InvocationContext context, int x, int y) { + return x + y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.java new file mode 100644 index 00000000000..6172f47083b --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public class PojoOneArg { + public void simple(String name) { + + } + + public void bean(User user) { + + } + + public void enumBody(Color color) { + + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV1.java new file mode 100644 index 00000000000..de34aff2d79 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV1.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public class SpringmvcAddBodyV1 { + @PostMapping(path = "/add") + public int add(@RequestBody AddWrapperV1 addBody) { + return addBody.getX() + addBody.y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV2.java new file mode 100644 index 00000000000..a67a2e00da5 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddBodyV2.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public interface SpringmvcAddBodyV2 { + @PostMapping(path = "/add") + int add(@RequestBody AddWrapperV2 addBody); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV1.java new file mode 100644 index 00000000000..c1e1d15b5b4 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV1.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public class SpringmvcAddV1 { + @GetMapping(path = "/add") + public int add(int x, int y) { + return x + y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV2.java new file mode 100644 index 00000000000..5934af56f1a --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddV2.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public interface SpringmvcAddV2 { + @GetMapping(path = "/add") + int add(int x, int y, @RequestHeader(name = "x-z") int z); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV1.java new file mode 100644 index 00000000000..76c435a311b --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV1.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV1; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public class SpringmvcAddWrapperV1 { + @GetMapping(path = "/add") + public int add(AddWrapperV1 wrapper) { + return wrapper.getX() + wrapper.y; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV2.java new file mode 100644 index 00000000000..8d2de4b48cb --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/SpringmvcAddWrapperV2.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas; + +import org.apache.servicecomb.swagger.invocation.schemas.models.AddWrapperV2; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@RequestMapping +public interface SpringmvcAddWrapperV2 { + @GetMapping(path = "/add") + int add(AddWrapperV2 wrapper); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV1.java new file mode 100644 index 00000000000..130e00ba79a --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV1.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas.models; + +import jakarta.ws.rs.QueryParam; + +public class AddBeanParamV1 { + @QueryParam("x") + private int x; + + @QueryParam("y") + public int y; + + public AddBeanParamV1() { + } + + public AddBeanParamV1(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV2.java new file mode 100644 index 00000000000..42d64834631 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddBeanParamV2.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas.models; + +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.QueryParam; + +public class AddBeanParamV2 { + @QueryParam("x") + private int x; + + @QueryParam("y") + public int y; + + @HeaderParam("x-z") + public int z; + + public AddBeanParamV2(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV1.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV1.java new file mode 100644 index 00000000000..5bd078b20e1 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV1.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas.models; + +public class AddWrapperV1 { + private int x; + + public int y; + + public AddWrapperV1() { + } + + public AddWrapperV1(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV2.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV2.java new file mode 100644 index 00000000000..1a2b3608665 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/models/AddWrapperV2.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.schemas.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class AddWrapperV2 { + private int x; + + public int y; + + @JsonProperty(value = "x-z") + public int z; + + public AddWrapperV2(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/swagger/swagger-invocation/invocation-core/src/test/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter deleted file mode 100644 index a3afa7714b3..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.invocation.exception.ErrorToProducerResponseConverter \ No newline at end of file diff --git a/swagger/swagger-invocation/invocation-core/src/test/resources/log4j.properties b/swagger/swagger-invocation/invocation-core/src/test/resources/log4j.properties deleted file mode 100644 index 30e31c322be..00000000000 --- a/swagger/swagger-invocation/invocation-core/src/test/resources/log4j.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - diff --git a/swagger/swagger-invocation/invocation-jaxrs/pom.xml b/swagger/swagger-invocation/invocation-jaxrs/pom.xml index 9bd2547adef..50d12dd243f 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/pom.xml +++ b/swagger/swagger-invocation/invocation-jaxrs/pom.xml @@ -21,16 +21,30 @@ org.apache.servicecomb swagger-invocation - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-invocation-jaxrs Java Chassis::Swagger::Invocation::JAXRS - org.apache.servicecomb swagger-invocation-core + + org.apache.servicecomb + swagger-generator-jaxrs + + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.glassfish.jersey.core + jersey-client + test + diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapper.java index f499b7bb9fd..549f4fc7151 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapper.java @@ -16,26 +16,28 @@ */ package org.apache.servicecomb.swagger.invocation.jaxrs.response; -import java.util.List; -import java.util.Map; import java.util.Map.Entry; -import javax.ws.rs.core.Response.ResponseBuilder; +import jakarta.ws.rs.core.Response.ResponseBuilder; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; +import io.vertx.core.MultiMap; + public class JaxrsConsumerResponseMapper implements ConsumerResponseMapper { @Override public Object mapResponse(Response response) { ResponseBuilder responseBuilder = - javax.ws.rs.core.Response.status(response.getStatus()).entity(response.getResult()); + jakarta.ws.rs.core.Response.status(response.getStatus()).entity(response.getResult()); + + MultiMap headers = response.getHeaders(); + if (headers == null) { + return responseBuilder.build(); + } - Map> headers = response.getHeaders().getHeaderMap(); - if (headers != null) { - for (Entry> entry : headers.entrySet()) { - responseBuilder.header(entry.getKey(), entry.getValue()); - } + for (Entry entry : headers.entries()) { + responseBuilder.header(entry.getKey(), entry.getValue()); } return responseBuilder.build(); diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapperFactory.java index abf491e905e..307cdb26c20 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsConsumerResponseMapperFactory.java @@ -18,21 +18,21 @@ import java.lang.reflect.Type; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.core.Response; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; public class JaxrsConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type consumerType) { + public boolean isMatch(Type consumerType) { return Response.class.equals(consumerType); } @Override - public ConsumerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type consumerType) { + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { return new JaxrsConsumerResponseMapper(); } } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapper.java b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapper.java index f563e7af65f..e1625da79d0 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapper.java @@ -19,8 +19,8 @@ import java.util.List; import java.util.Map.Entry; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; @@ -28,16 +28,21 @@ public class JaxrsProducerResponseMapper implements ProducerResponseMapper { @Override public Response mapResponse(StatusType status, Object response) { - javax.ws.rs.core.Response jaxrsResponse = (javax.ws.rs.core.Response) response; + jakarta.ws.rs.core.Response jaxrsResponse = (jakarta.ws.rs.core.Response) response; Response cseResponse = Response.status(jaxrsResponse.getStatusInfo()).entity(jaxrsResponse.getEntity()); MultivaluedMap headers = jaxrsResponse.getHeaders(); for (Entry> entry : headers.entrySet()) { - if (entry.getValue() == null || entry.getValue().isEmpty()) { + if (entry.getValue() == null) { continue; } - cseResponse.getHeaders().addHeader(entry.getKey(), entry.getValue()); + for (Object value : entry.getValue()) { + if (value == null) { + continue; + } + cseResponse.addHeader(entry.getKey(), value.toString()); + } } return cseResponse; } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapperFactory.java index 14a0ff64d49..a8e1e064fdd 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/JaxrsProducerResponseMapperFactory.java @@ -18,21 +18,21 @@ import java.lang.reflect.Type; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.core.Response; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory; public class JaxrsProducerResponseMapperFactory implements ProducerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type producerType) { + public boolean isMatch(Type producerType) { return Response.class.equals(producerType); } @Override - public ProducerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type producerType) { + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { return new JaxrsProducerResponseMapper(); } } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory b/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory index 764b9d711d7..b15dde97c09 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.swagger.invocation.jaxrs.response.JaxrsConsumerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.jaxrs.response.JaxrsConsumerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory b/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory index 24087486ab9..2598b38b3d6 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-jaxrs/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.swagger.invocation.jaxrs.response.JaxrsProducerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.jaxrs.response.JaxrsProducerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapper.java index b35a4e9a6b0..44f4f3cf7ed 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapper.java @@ -16,89 +16,68 @@ */ package org.apache.servicecomb.swagger.invocation.jaxrs.response; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.Response.ResponseBuilder; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.ext.RuntimeDelegate; - -import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.models.OpenAPI; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; public class TestJaxrsConsumerResponseMapper { - JaxrsConsumerResponseMapper mapper = new JaxrsConsumerResponseMapper(); - - int status; + @Path("/") + interface ConsumerResponseForTest { + @ApiResponse(responseCode = "200", description = "", content = @Content(schema = + @Schema(implementation = String.class))) + @Path("/jaxrsResponse") + @GET + jakarta.ws.rs.core.Response jaxrsResponse(); + } - Object entity; + SwaggerEnvironment environment = new SwaggerEnvironment(); - Map headers = new LinkedHashMap<>(); + SwaggerConsumer swaggerConsumer; - ResponseBuilder responseBuilder; + String result = "abc"; - @Mocked - RuntimeDelegate runtimeDelegate; + org.apache.servicecomb.swagger.invocation.Response response = org.apache.servicecomb.swagger.invocation.Response + .ok(result); - @Before + @BeforeEach public void setup() { - responseBuilder = new MockUp() { - @Mock - ResponseBuilder status(int status) { - TestJaxrsConsumerResponseMapper.this.status = status; - return responseBuilder; - } - - @Mock - ResponseBuilder entity(Object entity) { - TestJaxrsConsumerResponseMapper.this.entity = entity; - return responseBuilder; - } - - @Mock - ResponseBuilder header(String name, Object value) { - headers.put(name, value); - return responseBuilder; - } - }.getMockInstance(); - - new Expectations() { - { - runtimeDelegate.createResponseBuilder(); - result = responseBuilder; - } - }; + OpenAPI swagger = SwaggerGenerator.generate(ConsumerResponseForTest.class); + swaggerConsumer = environment.createConsumer(ConsumerResponseForTest.class, swagger); } @SuppressWarnings("unchecked") @Test - public void mapResponse_withHeaders() { - Response response = Response.create(Status.OK, "ret"); - response.getHeaders().addHeader("h", "v"); - mapper.mapResponse(response); + public void jaxrsResponse() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("jaxrsResponse"); - Assert.assertEquals(Status.OK.getStatusCode(), status); - Assert.assertEquals("ret", entity); - Assert.assertEquals(1, headers.size()); - Assert.assertThat((List) headers.get("h"), Matchers.contains("v")); + Response jaxrsResponse = (Response) operation.getResponseMapper().mapResponse(response); + Assertions.assertEquals(result, jaxrsResponse.getEntity()); + Assertions.assertTrue(jaxrsResponse.getHeaders().isEmpty()); } @Test - public void mapResponse_withoutHeaders() { - Response response = Response.create(Status.OK, "ret"); - mapper.mapResponse(response); - - Assert.assertEquals(Status.OK.getStatusCode(), status); - Assert.assertEquals("ret", entity); - Assert.assertEquals(0, headers.size()); + public void jaxrsResponseWithHeaders() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("jaxrsResponse"); + response.addHeader("h", "v1").addHeader("h", "v2").addHeader("h", null); + response.addHeader("h1", null); + + Response jaxrsResponse = (Response) operation.getResponseMapper().mapResponse(response); + Assertions.assertEquals(result, jaxrsResponse.getEntity()); + Assertions.assertEquals(1, jaxrsResponse.getHeaders().size()); + MatcherAssert.assertThat(jaxrsResponse.getHeaders().get("h"), Matchers.contains("v1", "v2")); } } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapperFactory.java deleted file mode 100644 index f57149dff53..00000000000 --- a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsConsumerResponseMapperFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.jaxrs.response; - -import javax.ws.rs.core.Response; - -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class TestJaxrsConsumerResponseMapperFactory { - JaxrsConsumerResponseMapperFactory factory = new JaxrsConsumerResponseMapperFactory(); - - @Test - public void isMatch_true() { - Assert.assertTrue(factory.isMatch(null, Response.class)); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); - } - - @Test - public void createResponseMapper() { - Assert.assertThat(factory.createResponseMapper(null, null, null), - Matchers.instanceOf(JaxrsConsumerResponseMapper.class)); - } -} diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapper.java b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapper.java index adbda3a57dd..6b60db54852 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapper.java @@ -16,59 +16,48 @@ */ package org.apache.servicecomb.swagger.invocation.jaxrs.response; -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response.Status; import org.apache.servicecomb.swagger.invocation.Response; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import mockit.Expectations; -import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class TestJaxrsProducerResponseMapper { JaxrsProducerResponseMapper mapper = new JaxrsProducerResponseMapper(); - @Mocked - javax.ws.rs.core.Response jaxrsResponse; - @Test public void mapResponse_withoutHeaders() { - new Expectations() { - { - jaxrsResponse.getStatusInfo(); - result = Status.OK; - jaxrsResponse.getEntity(); - result = "result"; - } - }; + jakarta.ws.rs.core.Response jaxrsResponse = Mockito.mock(jakarta.ws.rs.core.Response.class); + Mockito.when(jaxrsResponse.getStatusInfo()).thenReturn(Status.OK); + Mockito.when(jaxrsResponse.getEntity()).thenReturn("result"); + Mockito.when(jaxrsResponse.getHeaders()).thenReturn(new MultivaluedHashMap<>()); + Response response = mapper.mapResponse(null, jaxrsResponse); - Assert.assertEquals(Status.OK, response.getStatus()); - Assert.assertEquals("result", response.getResult()); - Assert.assertNull(response.getHeaders().getHeaderMap()); + Assertions.assertEquals(Status.OK, response.getStatus()); + Assertions.assertEquals("result", response.getResult()); + Assertions.assertNull(response.getHeaders()); } @Test public void mapResponse_withHeaders() { + jakarta.ws.rs.core.Response jaxrsResponse = Mockito.mock(jakarta.ws.rs.core.Response.class); + Mockito.when(jaxrsResponse.getStatusInfo()).thenReturn(Status.OK); + Mockito.when(jaxrsResponse.getEntity()).thenReturn("result"); + MultivaluedMap headers = new MultivaluedHashMap<>(); headers.add("h", "v"); + Mockito.when(jaxrsResponse.getHeaders()).thenReturn(headers); - new Expectations() { - { - jaxrsResponse.getStatusInfo(); - result = Status.OK; - jaxrsResponse.getEntity(); - result = "result"; - jaxrsResponse.getHeaders(); - result = headers; - } - }; Response response = mapper.mapResponse(null, jaxrsResponse); - Assert.assertEquals(Status.OK, response.getStatus()); - Assert.assertEquals("result", response.getResult()); - Assert.assertEquals(1, response.getHeaders().getHeaderMap().size()); - Assert.assertThat(response.getHeaders().getHeader("h"), Matchers.contains("v")); + Assertions.assertEquals(Status.OK, response.getStatus()); + Assertions.assertEquals("result", response.getResult()); + Assertions.assertEquals(1, response.getHeaders().size()); + MatcherAssert.assertThat(response.getHeaders("h"), Matchers.contains("v")); } } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapperFactory.java index 179def7a2dc..0a72f648b27 100644 --- a/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-jaxrs/src/test/java/org/apache/servicecomb/swagger/invocation/jaxrs/response/TestJaxrsProducerResponseMapperFactory.java @@ -16,28 +16,29 @@ */ package org.apache.servicecomb.swagger.invocation.jaxrs.response; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.core.Response; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestJaxrsProducerResponseMapperFactory { JaxrsProducerResponseMapperFactory factory = new JaxrsProducerResponseMapperFactory(); @Test public void isMatch_true() { - Assert.assertTrue(factory.isMatch(null, Response.class)); + Assertions.assertTrue(factory.isMatch(Response.class)); } @Test public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); + Assertions.assertFalse(factory.isMatch(String.class)); } @Test public void createResponseMapper() { - Assert.assertThat(factory.createResponseMapper(null, null, null), + MatcherAssert.assertThat(factory.createResponseMapper(null, null), Matchers.instanceOf(JaxrsProducerResponseMapper.class)); } } diff --git a/swagger/swagger-invocation/invocation-jaxrs/src/test/resources/log4j2.xml b/swagger/swagger-invocation/invocation-jaxrs/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/swagger/swagger-invocation/invocation-jaxrs/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/swagger/swagger-invocation/invocation-springmvc/pom.xml b/swagger/swagger-invocation/invocation-springmvc/pom.xml index 6cd333dbccd..5ae28883576 100644 --- a/swagger/swagger-invocation/invocation-springmvc/pom.xml +++ b/swagger/swagger-invocation/invocation-springmvc/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger-invocation - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-invocation-springmvc Java Chassis::Swagger::Invocation::Spring MVC @@ -36,5 +36,15 @@ org.springframework spring-webmvc + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.jmockit + jmockit + test + diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartArrayConverter.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartArrayConverter.java new file mode 100644 index 00000000000..d9b0901df6c --- /dev/null +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartArrayConverter.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter; + +import java.lang.reflect.Type; +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.servlet.http.Part; + +public class PartListToMultipartArrayConverter implements Converter { + @Override + public Type getSrcType() { + return ParameterizedTypeUtil.make(List.class, Part.class); + } + + @Override + public Type getTargetType() { + return MultipartFile[].class; + } + + @Override + public Object convert(Object value) { + if (value == null) { + return null; + } + @SuppressWarnings("unchecked") + List partList = (List) value; + PartToMultipartFile[] partArray = new PartToMultipartFile[partList.size()]; + for (int i = 0; i < partArray.length; i++) { + partArray[i] = new PartToMultipartFile(partList.get(i)); + } + return partArray; + } +} diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartListConverter.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartListConverter.java new file mode 100644 index 00000000000..4d7d50725cd --- /dev/null +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartListToMultipartListConverter.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.swagger.invocation.converter; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.foundation.common.ParameterizedTypeUtil; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.servlet.http.Part; + +public class PartListToMultipartListConverter implements Converter { + @Override + public Type getSrcType() { + return ParameterizedTypeUtil.make(List.class, Part.class); + } + + @Override + public Type getTargetType() { + return ParameterizedTypeUtil.make(List.class, MultipartFile.class); + } + + @Override + public Object convert(Object value) { + if (value == null) { + return null; + } + @SuppressWarnings("unchecked") + List partList = (List) value; + List fileList = new ArrayList<>(); + partList.forEach(part -> fileList.add(new PartToMultipartFile(part))); + return fileList; + } +} diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartConverter.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartConverter.java new file mode 100644 index 00000000000..ea65af5b121 --- /dev/null +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartConverter.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.swagger.invocation.converter; + +import java.lang.reflect.Type; + +import jakarta.servlet.http.Part; + +import org.springframework.web.multipart.MultipartFile; + +public class PartToMultipartConverter implements Converter { + @Override + public Type getSrcType() { + return Part.class; + } + + @Override + public Type getTargetType() { + return MultipartFile.class; + } + + @Override + public Object convert(Object value) { + if (value == null) { + return null; + } + + return new PartToMultipartFile((Part) value); + } +} diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartFile.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartFile.java index fc87cfdb167..8dd03dd3c86 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartFile.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/PartToMultipartFile.java @@ -21,13 +21,13 @@ import java.io.IOException; import java.io.InputStream; -import javax.servlet.http.Part; +import jakarta.servlet.http.Part; import org.apache.commons.io.IOUtils; import org.springframework.web.multipart.MultipartFile; public class PartToMultipartFile implements MultipartFile { - private Part part; + private final Part part; public PartToMultipartFile(Part part) { this.part = part; diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/SpringMultipartConverter.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/SpringMultipartConverter.java deleted file mode 100644 index f465a736280..00000000000 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/converter/SpringMultipartConverter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.swagger.invocation.converter; - -import java.lang.reflect.Type; - -import javax.servlet.http.Part; - -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - -@Component -class SpringMultipartConverter implements CustomizedConverter { - @Override - public Type getSrcType() { - return Part.class; - } - - @Override - public Type getTargetType() { - return MultipartFile.class; - } - - @Override - public Object convert(Object value) { - if (value == null) { - return null; - } - - return new PartToMultipartFile((Part) value); - } -} diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapper.java index 92e439bea3e..cba05cbb0c4 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapper.java @@ -16,8 +16,6 @@ */ package org.apache.servicecomb.swagger.invocation.springmvc.response; -import java.util.List; -import java.util.Map; import java.util.Map.Entry; import org.apache.servicecomb.swagger.invocation.Response; @@ -26,8 +24,10 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import io.vertx.core.MultiMap; + public class SpringmvcConsumerResponseMapper implements ConsumerResponseMapper { - private ConsumerResponseMapper realMapper; + private final ConsumerResponseMapper realMapper; public SpringmvcConsumerResponseMapper(ConsumerResponseMapper realMapper) { this.realMapper = realMapper; @@ -37,15 +37,15 @@ public SpringmvcConsumerResponseMapper(ConsumerResponseMapper realMapper) { public Object mapResponse(Response response) { HttpStatus status = HttpStatus.valueOf(response.getStatusCode()); - HttpHeaders httpHeaders = null; - Map> headers = response.getHeaders().getHeaderMap(); - if (headers != null) { - httpHeaders = new HttpHeaders(); - for (Entry> entry : headers.entrySet()) { - for (Object value : entry.getValue()) { - httpHeaders.add(entry.getKey(), String.valueOf(value)); - } - } + MultiMap headers = response.getHeaders(); + if (headers == null) { + Object realResult = realMapper.mapResponse(response); + return new ResponseEntity<>(realResult, null, status); + } + + HttpHeaders httpHeaders = new HttpHeaders(); + for (Entry entry : headers.entries()) { + httpHeaders.add(entry.getKey(), entry.getValue()); } Object realResult = realMapper.mapResponse(response); diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapperFactory.java index 3887e4a52b9..0e22da39176 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcConsumerResponseMapperFactory.java @@ -19,14 +19,14 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; import org.springframework.http.ResponseEntity; public class SpringmvcConsumerResponseMapperFactory implements ConsumerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type consumerType) { + public boolean isMatch(Type consumerType) { if (!ParameterizedType.class.isAssignableFrom(consumerType.getClass())) { return false; } @@ -35,10 +35,10 @@ public boolean isMatch(Type swaggerType, Type consumerType) { } @Override - public ConsumerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type consumerType) { + public ConsumerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type consumerType) { Type realConsumerType = ((ParameterizedType) consumerType).getActualTypeArguments()[0]; - ConsumerResponseMapper realMapper = factorys.createResponseMapper(swaggerType, realConsumerType); + ConsumerResponseMapper realMapper = factories.createResponseMapper(realConsumerType); return new SpringmvcConsumerResponseMapper(realMapper); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapper.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapper.java index 8f898e110e4..2838d4558a0 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapper.java @@ -19,17 +19,16 @@ import java.util.List; import java.util.Map.Entry; -import javax.ws.rs.core.Response.StatusType; - import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.context.HttpStatus; -import org.apache.servicecomb.swagger.invocation.response.Headers; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import jakarta.ws.rs.core.Response.StatusType; + public class SpringmvcProducerResponseMapper implements ProducerResponseMapper { - private ProducerResponseMapper realMapper; + private final ProducerResponseMapper realMapper; public SpringmvcProducerResponseMapper(ProducerResponseMapper realMapper) { this.realMapper = realMapper; @@ -40,8 +39,8 @@ public SpringmvcProducerResponseMapper(ProducerResponseMapper realMapper) { public Response mapResponse(StatusType status, Object response) { ResponseEntity springmvcResponse = (ResponseEntity) response; - StatusType responseStatus = new HttpStatus(springmvcResponse.getStatusCode().value(), - springmvcResponse.getStatusCode().getReasonPhrase()); + // TODO: maybe can use swagger HttpStatus instead of customized one + StatusType responseStatus = new HttpStatus(springmvcResponse.getStatusCode().value(), ""); Response cseResponse = null; if (HttpStatus.isSuccess(responseStatus)) { @@ -52,14 +51,13 @@ public Response mapResponse(StatusType status, Object response) { } HttpHeaders headers = springmvcResponse.getHeaders(); - Headers cseHeaders = cseResponse.getHeaders(); for (Entry> entry : headers.entrySet()) { - if (entry.getValue() == null || entry.getValue().isEmpty()) { + if (entry.getValue() == null) { continue; } for (String value : entry.getValue()) { - cseHeaders.addHeader(entry.getKey(), value); + cseResponse.addHeader(entry.getKey(), value); } } return cseResponse; diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapperFactory.java index d01a93dd85c..cfb43f5c3b2 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/java/org/apache/servicecomb/swagger/invocation/springmvc/response/SpringmvcProducerResponseMapperFactory.java @@ -19,14 +19,14 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory; import org.springframework.http.ResponseEntity; public class SpringmvcProducerResponseMapperFactory implements ProducerResponseMapperFactory { @Override - public boolean isMatch(Type swaggerType, Type producerType) { + public boolean isMatch(Type producerType) { if (!ParameterizedType.class.isAssignableFrom(producerType.getClass())) { return false; } @@ -35,10 +35,10 @@ public boolean isMatch(Type swaggerType, Type producerType) { } @Override - public ProducerResponseMapper createResponseMapper(ResponseMapperFactorys factorys, - Type swaggerType, Type producerType) { + public ProducerResponseMapper createResponseMapper(ResponseMapperFactories factories, + Type producerType) { Type realProducerType = ((ParameterizedType) producerType).getActualTypeArguments()[0]; - ProducerResponseMapper realMapper = factorys.createResponseMapper(swaggerType, realProducerType); + ProducerResponseMapper realMapper = factories.createResponseMapper(realProducerType); return new SpringmvcProducerResponseMapper(realMapper); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter new file mode 100644 index 00000000000..2222af91fe7 --- /dev/null +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.converter.Converter @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.swagger.invocation.converter.PartListToMultipartArrayConverter +org.apache.servicecomb.swagger.invocation.converter.PartToMultipartConverter +org.apache.servicecomb.swagger.invocation.converter.PartListToMultipartListConverter +org.apache.servicecomb.swagger.invocation.converter.impl.part.ResourceToPartConverter diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory index 80c4778dc57..26ddc8af9fa 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.swagger.invocation.springmvc.response.SpringmvcConsumerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.springmvc.response.SpringmvcConsumerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory index 7c5459b7609..5550f33368c 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory +++ b/swagger/swagger-invocation/invocation-springmvc/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.swagger.invocation.springmvc.response.SpringmvcProducerResponseMapperFactory \ No newline at end of file +org.apache.servicecomb.swagger.invocation.springmvc.response.SpringmvcProducerResponseMapperFactory diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/converter/TestPartToMultipartFile.java b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/converter/TestPartToMultipartFile.java index 55362550883..7bf2bda9836 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/converter/TestPartToMultipartFile.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/converter/TestPartToMultipartFile.java @@ -21,15 +21,12 @@ import java.io.File; import java.io.IOException; -import javax.servlet.http.Part; -import javax.xml.ws.Holder; +import jakarta.servlet.http.Part; -import org.hamcrest.Matchers; -import org.junit.Assert; +import org.apache.servicecomb.foundation.common.Holder; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Assertions; import mockit.Expectations; import mockit.Mock; @@ -42,9 +39,6 @@ public class TestPartToMultipartFile { PartToMultipartFile multipartFile; - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Before public void setup() { multipartFile = new PartToMultipartFile(part); @@ -60,7 +54,7 @@ public void getName() { } }; - Assert.assertEquals(name, multipartFile.getName()); + Assertions.assertEquals(name, multipartFile.getName()); } @Test @@ -73,7 +67,7 @@ public void getOriginalFilename() { } }; - Assert.assertEquals(submittedFileName, multipartFile.getOriginalFilename()); + Assertions.assertEquals(submittedFileName, multipartFile.getOriginalFilename()); } @Test @@ -86,7 +80,7 @@ public void getContentType() { } }; - Assert.assertEquals(contentType, multipartFile.getContentType()); + Assertions.assertEquals(contentType, multipartFile.getContentType()); } @Test @@ -98,7 +92,7 @@ public void isEmptyTrue() { } }; - Assert.assertTrue(multipartFile.isEmpty()); + Assertions.assertTrue(multipartFile.isEmpty()); } @Test @@ -110,7 +104,7 @@ public void isEmptyFalse() { } }; - Assert.assertFalse(multipartFile.isEmpty()); + Assertions.assertFalse(multipartFile.isEmpty()); } @Test @@ -123,10 +117,10 @@ public void getSize() { } }; - Assert.assertEquals(size, multipartFile.getSize()); + Assertions.assertEquals(size, multipartFile.getSize()); } - class ByteArrayInputStreamForTest extends ByteArrayInputStream { + static class ByteArrayInputStreamForTest extends ByteArrayInputStream { boolean closed; public ByteArrayInputStreamForTest(byte[] buf) { @@ -150,8 +144,8 @@ public void getBytes_normal() throws IOException { } }; - Assert.assertArrayEquals(bytes, multipartFile.getBytes()); - Assert.assertTrue(is.closed); + Assertions.assertArrayEquals(bytes, multipartFile.getBytes()); + Assertions.assertTrue(is.closed); } @Test @@ -163,10 +157,9 @@ public void getBytes_exception() throws IOException { } }; - expectedException.expect(IOException.class); - expectedException.expectMessage(Matchers.is("open stream failed")); - - multipartFile.getBytes(); + IOException exception = Assertions.assertThrows(IOException.class, + () -> multipartFile.getBytes()); + Assertions.assertEquals("open stream failed", exception.getMessage()); } @Test @@ -181,6 +174,6 @@ void write(String fileName) throws IOException { }; multipartFile.transferTo(dest); - Assert.assertEquals(dest.getPath(), destName.value); + Assertions.assertEquals(dest.getPath(), destName.value); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapper.java b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapper.java index 357d163032a..eb95d441576 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapper.java @@ -16,53 +16,89 @@ */ package org.apache.servicecomb.swagger.invocation.springmvc.response; -import javax.ws.rs.core.Response.Status; +import java.util.concurrent.CompletableFuture; +import org.apache.servicecomb.swagger.engine.SwaggerConsumer; +import org.apache.servicecomb.swagger.engine.SwaggerConsumerOperation; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.generator.SwaggerGenerator; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.springframework.http.ResponseEntity; -import mockit.Expectations; -import mockit.Mocked; +import io.swagger.v3.oas.models.OpenAPI; public class TestSpringmvcConsumerResponseMapper { - @Mocked - ConsumerResponseMapper realMapper; + interface ConsumerResponseForTest { + ResponseEntity responseEntity(); - SpringmvcConsumerResponseMapper mapper; + CompletableFuture> asyncResponseEntity(); + } + + SwaggerEnvironment environment = new SwaggerEnvironment(); + + SwaggerConsumer swaggerConsumer; + + String result = "abc"; - Response response = Response.ok("1"); + Response response = Response.ok(result); @Before public void setup() { - mapper = new SpringmvcConsumerResponseMapper(realMapper); - - new Expectations() { - { - realMapper.mapResponse(response); - result = 1; - } - }; + OpenAPI swagger = SwaggerGenerator.generate(ConsumerResponseForTest.class); + swaggerConsumer = environment.createConsumer(ConsumerResponseForTest.class, swagger); } @Test - public void mapResponse_withoutHeader() { + public void responseEntity() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("responseEntity"); + + @SuppressWarnings("unchecked") + ResponseEntity responseEntity = (ResponseEntity) operation.getResponseMapper() + .mapResponse(response); + Assertions.assertEquals(result, responseEntity.getBody()); + Assertions.assertTrue(responseEntity.getHeaders().isEmpty()); + } + + @Test + public void responseEntityWithHeader() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("responseEntity"); + response.addHeader("h", "v"); + + @SuppressWarnings("unchecked") + ResponseEntity responseEntity = (ResponseEntity) operation.getResponseMapper() + .mapResponse(response); + Assertions.assertEquals(result, responseEntity.getBody()); + Assertions.assertEquals(1, responseEntity.getHeaders().size()); + MatcherAssert.assertThat(responseEntity.getHeaders().get("h"), Matchers.contains("v")); + } + + @Test + public void asyncResponseEntity() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("asyncResponseEntity"); + @SuppressWarnings("unchecked") - ResponseEntity responseEntity = (ResponseEntity) mapper.mapResponse(response); - Assert.assertEquals((Integer) 1, responseEntity.getBody()); - Assert.assertEquals(Status.OK.getStatusCode(), responseEntity.getStatusCodeValue()); + ResponseEntity responseEntity = (ResponseEntity) operation.getResponseMapper() + .mapResponse(response); + Assertions.assertEquals(result, responseEntity.getBody()); + Assertions.assertTrue(responseEntity.getHeaders().isEmpty()); } @Test - public void mapResponse_withHeader() { - response.getHeaders().addHeader("h", "v"); + public void asyncResponseEntityWithHeader() { + SwaggerConsumerOperation operation = swaggerConsumer.findOperation("asyncResponseEntity"); + response.addHeader("h", "v1").addHeader("h", "v2"); + response.addHeader("h1", null); @SuppressWarnings("unchecked") - ResponseEntity responseEntity = (ResponseEntity) mapper.mapResponse(response); - Assert.assertThat(responseEntity.getHeaders().get("h"), Matchers.contains("v")); + ResponseEntity responseEntity = (ResponseEntity) operation.getResponseMapper() + .mapResponse(response); + Assertions.assertEquals(result, responseEntity.getBody()); + Assertions.assertEquals(1, responseEntity.getHeaders().size()); + MatcherAssert.assertThat(responseEntity.getHeaders().get("h"), Matchers.contains("v1", "v2")); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapperFactory.java deleted file mode 100644 index 769443bfde9..00000000000 --- a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcConsumerResponseMapperFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.springmvc.response; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapper; -import org.apache.servicecomb.swagger.invocation.response.consumer.ConsumerResponseMapperFactory; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.http.ResponseEntity; - -public class TestSpringmvcConsumerResponseMapperFactory { - SpringmvcConsumerResponseMapperFactory factory = new SpringmvcConsumerResponseMapperFactory(); - - ConverterMgr converterMgr = new ConverterMgr(); - - ResponseMapperFactorys factorys = - new ResponseMapperFactorys<>(ConsumerResponseMapperFactory.class, converterMgr); - - public CompletableFuture> asyncResponseEntityMethod() { - return null; - } - - public ResponseEntity responseEntity() { - return null; - } - - public List list() { - return null; - } - - @Test - public void isMatch_true() { - Method method = ReflectUtils.findMethod(this.getClass(), "responseEntity"); - Assert.assertTrue(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_Parameterized_false() { - Method method = ReflectUtils.findMethod(this.getClass(), "list"); - Assert.assertFalse(factory.isMatch(null, method.getGenericReturnType())); - } - - @Test - public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); - } - - @Test - public void createResponseMapper() { - Method responseEntityMethod = ReflectUtils.findMethod(this.getClass(), "responseEntity"); - Method listMethod = ReflectUtils.findMethod(this.getClass(), "list"); - - ConsumerResponseMapper mapper = factory - .createResponseMapper(factorys, listMethod.getGenericReturnType(), responseEntityMethod.getGenericReturnType()); - Assert.assertThat(mapper, Matchers.instanceOf(SpringmvcConsumerResponseMapper.class)); - - Response response = Response.ok(Arrays.asList("a", "b")); - @SuppressWarnings("unchecked") - ResponseEntity responseEntity = (ResponseEntity) mapper.mapResponse(response); - Assert.assertThat(responseEntity.getBody(), Matchers.arrayContaining("a", "b")); - } - - @Test - public void asyncResponseEntity() { - Method responseEntityMethod = ReflectUtils.findMethod(this.getClass(), "asyncResponseEntityMethod"); - Method listMethod = ReflectUtils.findMethod(this.getClass(), "list"); - - ConsumerResponseMapper mapper = factorys - .createResponseMapper(listMethod.getGenericReturnType(), responseEntityMethod.getGenericReturnType()); - Assert.assertThat(mapper, Matchers.instanceOf(SpringmvcConsumerResponseMapper.class)); - - Response response = Response.ok(Arrays.asList("a", "b")); - @SuppressWarnings("unchecked") - ResponseEntity responseEntity = (ResponseEntity) mapper.mapResponse(response); - Assert.assertThat(responseEntity.getBody(), Matchers.arrayContaining("a", "b")); - } -} diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapper.java b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapper.java index 4a397d15d8c..c48fc62be8c 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapper.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapper.java @@ -19,16 +19,17 @@ import java.util.Arrays; import java.util.List; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.StatusType; import org.apache.servicecomb.foundation.common.http.HttpStatus; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; @@ -62,12 +63,12 @@ Response mapResponse(StatusType status, Object response) { @SuppressWarnings("unchecked") @Test - public void mapResponse_withoutHeader_sucess() { + public void mapResponse_withoutHeader_success() { ResponseEntity responseEntity = new ResponseEntity<>(arrResult, org.springframework.http.HttpStatus.OK); Response response = mapper.mapResponse(null, responseEntity); - Assert.assertThat((List) response.getResult(), Matchers.contains("a", "b")); - Assert.assertEquals(Status.OK, response.getStatus()); + MatcherAssert.assertThat((List) response.getResult(), Matchers.contains("a", "b")); + Assertions.assertEquals(Status.OK, response.getStatus()); } @Test @@ -75,8 +76,8 @@ public void mapResponse_withoutHeader_fail() { ResponseEntity responseEntity = new ResponseEntity<>(arrResult, org.springframework.http.HttpStatus.BAD_REQUEST); Response response = mapper.mapResponse(null, responseEntity); - Assert.assertSame(arrResult, response.getResult()); - Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus().getStatusCode()); + Assertions.assertSame(arrResult, response.getResult()); + Assertions.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus().getStatusCode()); } @Test @@ -88,7 +89,7 @@ public void mapResponse_withHeader() { new ResponseEntity<>(arrResult, headers, org.springframework.http.HttpStatus.OK); Response response = mapper.mapResponse(null, responseEntity); - List hv = response.getHeaders().getHeader("h"); - Assert.assertThat(hv, Matchers.contains("v")); + List hv = response.getHeaders("h"); + MatcherAssert.assertThat(hv, Matchers.contains("v")); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapperFactory.java b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapperFactory.java index cd0668e1fb6..35c84db148f 100644 --- a/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapperFactory.java +++ b/swagger/swagger-invocation/invocation-springmvc/src/test/java/org/apache/servicecomb/swagger/invocation/springmvc/response/TestSpringmvcProducerResponseMapperFactory.java @@ -21,23 +21,21 @@ import org.apache.servicecomb.foundation.common.utils.ReflectUtils; import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr; -import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactorys; +import org.apache.servicecomb.swagger.invocation.response.ResponseMapperFactories; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapper; import org.apache.servicecomb.swagger.invocation.response.producer.ProducerResponseMapperFactory; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; public class TestSpringmvcProducerResponseMapperFactory { SpringmvcProducerResponseMapperFactory factory = new SpringmvcProducerResponseMapperFactory(); - ConverterMgr converterMgr = new ConverterMgr(); - - ResponseMapperFactorys factorys = - new ResponseMapperFactorys<>(ProducerResponseMapperFactory.class, converterMgr); + ResponseMapperFactories factories = new ResponseMapperFactories<>( + ProducerResponseMapperFactory.class); public ResponseEntity responseEntity() { return null; @@ -50,31 +48,30 @@ public List list() { @Test public void isMatch_true() { Method method = ReflectUtils.findMethod(this.getClass(), "responseEntity"); - Assert.assertTrue(factory.isMatch(null, method.getGenericReturnType())); + Assertions.assertTrue(factory.isMatch(method.getGenericReturnType())); } @Test public void isMatch_Parameterized_false() { Method method = ReflectUtils.findMethod(this.getClass(), "list"); - Assert.assertFalse(factory.isMatch(null, method.getGenericReturnType())); + Assertions.assertFalse(factory.isMatch(method.getGenericReturnType())); } @Test public void isMatch_false() { - Assert.assertFalse(factory.isMatch(null, String.class)); + Assertions.assertFalse(factory.isMatch(String.class)); } @Test public void createResponseMapper() { Method responseEntityMethod = ReflectUtils.findMethod(this.getClass(), "responseEntity"); - Method listMethod = ReflectUtils.findMethod(this.getClass(), "list"); ProducerResponseMapper mapper = factory - .createResponseMapper(factorys, listMethod.getGenericReturnType(), responseEntityMethod.getGenericReturnType()); - Assert.assertThat(mapper, Matchers.instanceOf(SpringmvcProducerResponseMapper.class)); + .createResponseMapper(factories, responseEntityMethod.getGenericReturnType()); + MatcherAssert.assertThat(mapper, Matchers.instanceOf(SpringmvcProducerResponseMapper.class)); - ResponseEntity responseEntity = new ResponseEntity(new String[] {"a", "b"}, HttpStatus.OK); + ResponseEntity responseEntity = new ResponseEntity<>(new String[] {"a", "b"}, HttpStatus.OK); Response response = mapper.mapResponse(null, responseEntity); - Assert.assertThat(response.getResult(), Matchers.contains("a", "b")); + MatcherAssert.assertThat(response.getResult(), Matchers.arrayContaining("a", "b")); } } diff --git a/swagger/swagger-invocation/invocation-springmvc/src/test/resources/log4j2.xml b/swagger/swagger-invocation/invocation-springmvc/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/swagger/swagger-invocation/invocation-springmvc/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/swagger/swagger-invocation/invocation-validator/pom.xml b/swagger/swagger-invocation/invocation-validator/pom.xml index 76e34c4afa6..cf0f46c7f4f 100644 --- a/swagger/swagger-invocation/invocation-validator/pom.xml +++ b/swagger/swagger-invocation/invocation-validator/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger-invocation - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-invocation-validator Java Chassis::Swagger::Invocation::Validator @@ -31,22 +31,18 @@ swagger-invocation-core - org.hibernate + org.hibernate.validator hibernate-validator - org.glassfish - javax.el - - - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test - \ No newline at end of file + diff --git a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ConstraintViolationExceptionToProducerResponseConverter.java b/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ConstraintViolationExceptionToProducerResponseConverter.java deleted file mode 100644 index 58e3e4e0cfc..00000000000 --- a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ConstraintViolationExceptionToProducerResponseConverter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.validator; - -import javax.validation.ConstraintViolationException; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; - -public class ConstraintViolationExceptionToProducerResponseConverter - implements ExceptionToProducerResponseConverter { - @Override - public Class getExceptionClass() { - return ConstraintViolationException.class; - } - - @Override - public Response convert(SwaggerInvocation swaggerInvocation, ConstraintViolationException e) { - return Response.createFail(new InvocationException(Status.BAD_REQUEST, e.getConstraintViolations().toString())); - } - - @Override - public int getOrder() { - return -100; - } -} diff --git a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/DefaultParameterNameProvider.java b/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/DefaultParameterNameProvider.java index 0188b674229..e1a30725b45 100644 --- a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/DefaultParameterNameProvider.java +++ b/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/DefaultParameterNameProvider.java @@ -20,15 +20,15 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import javax.validation.ParameterNameProvider; -import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils; +import jakarta.validation.ParameterNameProvider; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; public class DefaultParameterNameProvider implements ParameterNameProvider { private final Map> methodCache = new ConcurrentHashMapEx<>(); @@ -44,11 +44,12 @@ public List getParameterNames(Method method) { } private List getParameterNamesEx(Executable methodOrConstructor) { - int parameterCount = methodOrConstructor.getParameterCount(); - List parameterNames = new ArrayList<>(parameterCount); - - for (int i = 0; i < parameterCount; i++) { - parameterNames.add(ParamUtils.getParameterName(methodOrConstructor, i)); + Parameter[] parameters = methodOrConstructor.getParameters(); + List parameterNames = new ArrayList<>(parameters.length); + for (int idx = 0; idx < parameters.length; idx++) { + Parameter parameter = parameters[idx]; + String parameterName = parameter.isNamePresent() ? parameter.getName() : "arg" + idx; + parameterNames.add(parameterName); } return Collections.unmodifiableList(parameterNames); } diff --git a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ParameterValidator.java b/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ParameterValidator.java deleted file mode 100644 index 8a645e0d020..00000000000 --- a/swagger/swagger-invocation/invocation-validator/src/main/java/org/apache/servicecomb/swagger/invocation/validator/ParameterValidator.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.swagger.invocation.validator; - -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.ValidatorFactory; -import javax.validation.executable.ExecutableValidator; -import javax.validation.groups.Default; - -import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; -import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; -import org.apache.servicecomb.swagger.invocation.extension.ProducerInvokeExtension; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ParameterValidator implements ProducerInvokeExtension { - - private static final Logger LOGGER = LoggerFactory.getLogger(ParameterValidator.class); - - private static ExecutableValidator executableValidator; - - @Override - public void beforeMethodInvoke(SwaggerInvocation invocation, SwaggerProducerOperation producerOperation, - Object[] args) - throws ConstraintViolationException { - - if (null == executableValidator) { - ValidatorFactory factory = - Validation.byDefaultProvider() - .configure() - .parameterNameProvider(new DefaultParameterNameProvider()) - .buildValidatorFactory(); - executableValidator = factory.getValidator().forExecutables(); - } - Set> violations = - executableValidator.validateParameters(producerOperation.getProducerInstance(), - producerOperation.getProducerMethod(), - args, - Default.class); - if (violations.size() > 0) { - LOGGER.warn("Parameter validation failed : " + violations.toString()); - throw new ConstraintViolationException(violations); - } - } - - @Override - public int getOrder() { - return 100; - } -} diff --git a/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter deleted file mode 100644 index f6d6fd90616..00000000000 --- a/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.invocation.validator.ConstraintViolationExceptionToProducerResponseConverter \ No newline at end of file diff --git a/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.extension.ProducerInvokeExtension b/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.extension.ProducerInvokeExtension deleted file mode 100644 index 215fc569235..00000000000 --- a/swagger/swagger-invocation/invocation-validator/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.extension.ProducerInvokeExtension +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.swagger.invocation.validator.ParameterValidator diff --git a/swagger/swagger-invocation/invocation-validator/src/test/java/org/apache/servicecomb/swagger/invocation/validator/TestDefaultParameterNameProvider.java b/swagger/swagger-invocation/invocation-validator/src/test/java/org/apache/servicecomb/swagger/invocation/validator/TestDefaultParameterNameProvider.java index fcb228fe22b..b655231874d 100644 --- a/swagger/swagger-invocation/invocation-validator/src/test/java/org/apache/servicecomb/swagger/invocation/validator/TestDefaultParameterNameProvider.java +++ b/swagger/swagger-invocation/invocation-validator/src/test/java/org/apache/servicecomb/swagger/invocation/validator/TestDefaultParameterNameProvider.java @@ -18,9 +18,11 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; + +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestDefaultParameterNameProvider { static class ValidatorForTest { @@ -91,25 +93,25 @@ public void setNumber(int number) { @Test public void testMethod() throws NoSuchMethodException { Method method = validatorForTest.getMethod("add", int.class, int.class); - Assert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("a", "b")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("a", "b")); method = validatorForTest.getMethod("sayHi", String.class); - Assert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("hi")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("hi")); method = validatorForTest.getMethod("sayHello", ValidatorForTest.Student.class); - Assert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("student")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("student")); method = validatorForTest.getMethod("setTest", String.class); - Assert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("grade")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("grade")); method = validatorForTest.getMethod("getNumber"); - Assert.assertTrue(parameterNameProvider.getParameterNames(method).isEmpty()); + Assertions.assertTrue(parameterNameProvider.getParameterNames(method).isEmpty()); method = validatorForTest.getMethod("setNumber", int.class); - Assert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("number")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(method), Matchers.contains("number")); } @Test public void testConstructor() throws NoSuchMethodException { Constructor constructor = validatorForTest.getConstructor(String.class, int.class); - Assert.assertThat(parameterNameProvider.getParameterNames(constructor), Matchers.contains("grade", "number")); + MatcherAssert.assertThat(parameterNameProvider.getParameterNames(constructor), Matchers.contains("grade", "number")); constructor = validatorForTest.getConstructor(); - Assert.assertTrue(parameterNameProvider.getParameterNames(constructor).isEmpty()); + Assertions.assertTrue(parameterNameProvider.getParameterNames(constructor).isEmpty()); } } diff --git a/swagger/swagger-invocation/pom.xml b/swagger/swagger-invocation/pom.xml index f3f0e12de54..00f83a03fc4 100644 --- a/swagger/swagger-invocation/pom.xml +++ b/swagger/swagger-invocation/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb swagger - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT swagger-invocation Java Chassis::Swagger::Invocation diff --git a/tracing/README.md b/tracing/README.md index fdb82a49114..7ffbb400bcc 100644 --- a/tracing/README.md +++ b/tracing/README.md @@ -11,6 +11,14 @@ interest. ``` 2. Enable tracing with annotation `@EnableZipkinTracing` on your application entry or configuration + +Import `tracing.zipkin.EnableZipkinTracing` package + +``` +import org.apache.servicecomb.tracing.zipkin.EnableZipkinTracing; +``` +Add annotation `@EnableZipkinTracing` + ``` @SpringBootApplication @EnableZipkinTracing @@ -21,6 +29,14 @@ public class ZipkinSpanTestApplication { } ``` 3. Add new span to the point of interest with annotation `@Span` + +Import `tracing.Span` package + +``` +import org.apache.servicecomb.tracing.Span; +``` +Add annotation `@Span` + ``` @Component public class SlowRepoImpl implements SlowRepo { diff --git a/tracing/pom.xml b/tracing/pom.xml index dddeac8cda5..7ffde2fbc3a 100644 --- a/tracing/pom.xml +++ b/tracing/pom.xml @@ -22,8 +22,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default 4.0.0 @@ -39,6 +39,12 @@ org.springframework.boot spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-logging + + diff --git a/tracing/tracing-common/pom.xml b/tracing/tracing-common/pom.xml index 235c598c1c2..f03ecbb2b04 100644 --- a/tracing/tracing-common/pom.xml +++ b/tracing/tracing-common/pom.xml @@ -22,7 +22,7 @@ tracing org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 diff --git a/tracing/tracing-zipkin/pom.xml b/tracing/tracing-zipkin/pom.xml index a8fb4655dc9..e5755729748 100644 --- a/tracing/tracing-zipkin/pom.xml +++ b/tracing/tracing-zipkin/pom.xml @@ -22,7 +22,7 @@ tracing org.apache.servicecomb - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT 4.0.0 @@ -30,6 +30,14 @@ Java Chassis::Tracing::Zipkin + + org.apache.servicecomb + foundation-common + + + org.apache.servicecomb + handler-tracing-zipkin + org.apache.servicecomb tracing-common @@ -42,23 +50,17 @@ io.zipkin.brave brave - - io.zipkin.reporter2 - zipkin-sender-okhttp3 - io.zipkin.brave - brave-context-log4j12 + brave-context-slf4j - com.google.code.findbugs - jsr305 + io.zipkin.reporter2 + zipkin-sender-okhttp3 - - org.springframework.boot - spring-boot-starter-test - test + io.zipkin.reporter2 + zipkin-reporter-brave diff --git a/tracing/tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviser.java b/tracing/tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviser.java index 42ec0bb3874..b2bcf1c2423 100644 --- a/tracing/tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviser.java +++ b/tracing/tracing-zipkin/src/main/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviser.java @@ -17,6 +17,9 @@ package org.apache.servicecomb.tracing.zipkin; +import org.apache.servicecomb.swagger.invocation.context.ContextUtils; +import org.apache.servicecomb.swagger.invocation.context.InvocationContext; + import brave.Span; import brave.Tracer; import brave.Tracer.SpanInScope; @@ -45,7 +48,14 @@ T invoke(String spanName, String path, ThrowableSupplier supplier) throws } private Span createSpan(String spanName, String path) { - Span currentSpan = tracer.currentSpan(); + InvocationContext context = ContextUtils.getInvocationContext(); + Span currentSpan = null; + if (context != null) { + currentSpan = context.getLocalContext(ZipkinTracingFilter.CONTEXT_TRACE_SPAN); + } + if (currentSpan == null) { + currentSpan = tracer.currentSpan(); + } if (currentSpan != null) { return tracer.newChild(currentSpan.context()).name(spanName).tag(CALL_PATH, path).start(); } diff --git a/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinSpanAspectTest.java b/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinSpanAspectTest.java index d0b6cfa62b9..4eee935137d 100644 --- a/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinSpanAspectTest.java +++ b/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinSpanAspectTest.java @@ -22,9 +22,9 @@ import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.stream.Collectors; @@ -33,36 +33,55 @@ import org.apache.servicecomb.tracing.zipkin.app.ZipkinSpanTestApplication; import org.apache.servicecomb.tracing.zipkin.app.ZipkinSpanTestApplication.CustomSpanTask; import org.apache.servicecomb.tracing.zipkin.app.ZipkinSpanTestApplication.SomeSlowTask; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.context.annotation.Primary; import brave.Tracing; -import brave.propagation.StrictCurrentTraceContext; +import brave.propagation.StrictScopeDecorator; +import brave.propagation.ThreadLocalCurrentTraceContext; import zipkin2.Span; +import zipkin2.reporter.brave.ZipkinSpanHandler; -@RunWith(SpringRunner.class) @SpringBootTest(classes = {ZipkinSpanTestApplication.class, TracingConfig.class}) public class ZipkinSpanAspectTest { + private Queue spans; + + private SomeSlowTask someSlowTask; + + private CustomSpanTask customSpanTask; + + private Tracing tracing; @Autowired - private Queue spans; + public void setSpans(Queue spans) { + this.spans = spans; + } @Autowired - private SomeSlowTask someSlowTask; + public void setSomeSlowTask(SomeSlowTask someSlowTask) { + this.someSlowTask = someSlowTask; + } @Autowired - private CustomSpanTask customSpanTask; + public void setCustomSpanTask(CustomSpanTask customSpanTask) { + this.customSpanTask = customSpanTask; + } @Autowired - private Tracing tracing; + public void setTracing(Tracing tracing) { + this.tracing = tracing; + } + + public ZipkinSpanAspectTest() { + } - @After + @AfterEach public void tearDown() throws Exception { tracing.close(); } @@ -74,25 +93,25 @@ public void reportedSpanContainsAnnotatedMethodInfo() throws Exception { await().atMost(2, SECONDS).until(() -> !spans.isEmpty()); zipkin2.Span span = spans.poll(); - assertThat(span.name(), is("crawl")); - assertThat(tracedValues(span), contains(SomeSlowTask.class.getMethod("crawl").toString())); + MatcherAssert.assertThat(span.name(), is("crawl")); + MatcherAssert.assertThat(tracedValues(span), contains(SomeSlowTask.class.getMethod("crawl").toString())); } @Test - public void reportCustomSpanInfomation() throws Exception { + public void reportCustomSpanInformation() { customSpanTask.invoke(); await().atMost(2, SECONDS).until(() -> !spans.isEmpty()); zipkin2.Span span = spans.poll(); - assertThat(span.name(), is("transaction1")); - assertThat(tracedValues(span), contains("startA")); + MatcherAssert.assertThat(span.name(), is("transaction1")); + MatcherAssert.assertThat(tracedValues(span), contains("startA")); } private List tracedValues(zipkin2.Span spans) { return spans.tags().entrySet().stream() .filter(span -> CALL_PATH.equals(span.getKey()) || "error".equals(span.getKey())) .filter(span -> span.getValue() != null) - .map(annotation -> new String(annotation.getValue())) + .map(Map.Entry::getValue) .distinct() .collect(Collectors.toList()); } @@ -105,10 +124,12 @@ Queue spans() { } @Bean - Tracing tracing(Queue spans) { + @Primary + Tracing zipkinTracing(Queue spans) { return Tracing.newBuilder() - .currentTraceContext(new StrictCurrentTraceContext()) - .spanReporter(spans::add) + .currentTraceContext( + ThreadLocalCurrentTraceContext.newBuilder().addScopeDecorator(StrictScopeDecorator.create()).build()) + .addSpanHandler(ZipkinSpanHandler.create(spans::add)) .build(); } } diff --git a/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviserTest.java b/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviserTest.java index e6416fbf0c9..60df34100ed 100644 --- a/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviserTest.java +++ b/tracing/tracing-zipkin/src/test/java/org/apache/servicecomb/tracing/zipkin/ZipkinTracingAdviserTest.java @@ -24,8 +24,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; import java.lang.reflect.Array; import java.util.List; @@ -40,13 +38,19 @@ import java.util.stream.Collectors; import org.apache.servicecomb.tracing.zipkin.ZipkinTracingAdviser.ThrowableSupplier; -import org.junit.After; -import org.junit.Test; +import org.hamcrest.MatcherAssert; import brave.Span; import brave.Tracer.SpanInScope; import brave.Tracing; -import brave.propagation.StrictCurrentTraceContext; +import brave.propagation.StrictScopeDecorator; +import brave.propagation.ThreadLocalCurrentTraceContext; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import zipkin2.reporter.brave.ZipkinSpanHandler; public class ZipkinTracingAdviserTest { private static final int nThreads = 10; @@ -64,13 +68,15 @@ public class ZipkinTracingAdviserTest { private final Map> traces = new ConcurrentHashMap<>(); private final Tracing tracing = Tracing.newBuilder() - .currentTraceContext(new StrictCurrentTraceContext()) - .spanReporter(e -> traces.computeIfAbsent(e.traceId(), id -> new ConcurrentLinkedDeque<>()).add(e)) + .currentTraceContext( + ThreadLocalCurrentTraceContext.newBuilder().addScopeDecorator(StrictScopeDecorator.create()).build()) + .addSpanHandler(ZipkinSpanHandler.create( + e -> traces.computeIfAbsent(e.traceId(), id -> new ConcurrentLinkedDeque<>()).add(e))) .build(); private final ZipkinTracingAdviser tracingAdviser = new ZipkinTracingAdviser(tracing.tracer()); - @After + @AfterEach public void tearDown() throws Exception { tracing.close(); } @@ -79,12 +85,12 @@ public void tearDown() throws Exception { public void startsNewRootSpan() throws Throwable { String result = tracingAdviser.invoke(spanName, path, supplier); - assertThat(result, is(expected)); + MatcherAssert.assertThat(result, is(expected)); await().atMost(2, SECONDS).until(() -> !traces.isEmpty()); zipkin2.Span span = traces.values().iterator().next().poll(); - assertThat(span.name(), is(spanName)); - assertThat(tracedValues(span), contains(this.getClass().getCanonicalName())); + MatcherAssert.assertThat(span.name(), is(spanName)); + MatcherAssert.assertThat(tracedValues(span), contains(this.getClass().getCanonicalName())); } @Test @@ -101,8 +107,9 @@ public void includesExceptionInTags() throws Throwable { await().atMost(2, SECONDS).until(() -> !traces.isEmpty()); zipkin2.Span span = traces.values().iterator().next().poll(); - assertThat(span.name(), is(spanName)); - assertThat(tracedValues(span), containsInAnyOrder(this.getClass().getCanonicalName(), "RuntimeException: oops")); + Assertions.assertEquals(spanName, span.name()); + MatcherAssert.assertThat(tracedValues(span), + containsInAnyOrder(this.getClass().getCanonicalName(), "RuntimeException: oops")); } @SuppressWarnings({"unused", "try"}) @@ -118,9 +125,9 @@ public void startsNewChildSpan() { waitTillAllAreReady(cyclicBarrier); try (SpanInScope spanInScope = tracing.tracer().withSpanInScope(currentSpan)) { - assertThat(tracingAdviser.invoke(spanName, path, supplier), is(expected)); + MatcherAssert.assertThat(tracingAdviser.invoke(spanName, path, supplier), is(expected)); } catch (Throwable throwable) { - fail(throwable.getMessage()); + Assertions.fail(throwable.getMessage()); } finally { currentSpan.finish(); } @@ -129,16 +136,16 @@ public void startsNewChildSpan() { CompletableFuture.allOf(futures).join(); - assertThat(traces.size(), is(nThreads)); + MatcherAssert.assertThat(traces.size(), is(nThreads)); for (Queue queue : traces.values()) { zipkin2.Span child = queue.poll(); - assertThat(child.name(), is(spanName)); + MatcherAssert.assertThat(child.name(), is(spanName)); zipkin2.Span parent = queue.poll(); - assertThat(child.parentId(), is(parent.id())); - assertThat(child.traceId(), is(parent.traceId())); - assertThat(tracedValues(child), contains(this.getClass().getCanonicalName())); + MatcherAssert.assertThat(child.parentId(), is(parent.id())); + MatcherAssert.assertThat(child.traceId(), is(parent.traceId())); + MatcherAssert.assertThat(tracedValues(child), contains(this.getClass().getCanonicalName())); } } @@ -154,7 +161,7 @@ private List tracedValues(zipkin2.Span spans) { return spans.tags().entrySet().stream() .filter(span -> CALL_PATH.equals(span.getKey()) || "error".equals(span.getKey())) .filter(span -> span.getValue() != null) - .map(annotation -> new String(annotation.getValue())) + .map(Map.Entry::getValue) .distinct() .collect(Collectors.toList()); } diff --git a/transports/pom.xml b/transports/pom.xml index 362ebf9bf3b..13439c0ffdc 100644 --- a/transports/pom.xml +++ b/transports/pom.xml @@ -21,8 +21,8 @@ org.apache.servicecomb java-chassis-parent - 1.2.0-SNAPSHOT - ../parent + 3.4.0-SNAPSHOT + ../parents/default transports Java Chassis::Transports @@ -30,5 +30,6 @@ transport-highway transport-rest + transport-common diff --git a/transports/transport-common/pom.xml b/transports/transport-common/pom.xml new file mode 100644 index 00000000000..00c1ae33c73 --- /dev/null +++ b/transports/transport-common/pom.xml @@ -0,0 +1,57 @@ + + + + + transports + org.apache.servicecomb + 3.4.0-SNAPSHOT + + 4.0.0 + + transport-common + Java Chassis::Transports::common + + + + org.apache.servicecomb + foundation-config + + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.jmockit + jmockit + test + + + diff --git a/transports/transport-common/src/main/java/org/apache/servicecomb/transport/common/TransportConfigUtils.java b/transports/transport-common/src/main/java/org/apache/servicecomb/transport/common/TransportConfigUtils.java new file mode 100644 index 00000000000..672475e592c --- /dev/null +++ b/transports/transport-common/src/main/java/org/apache/servicecomb/transport/common/TransportConfigUtils.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.common; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class TransportConfigUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(TransportConfigUtils.class); + + private TransportConfigUtils() { + } + + // old verticle count key is ambiguous + // suggest to use new name + public static int readVerticleCount(String key, String deprecatedKey) { + int count = LegacyPropertyFactory.getIntProperty(key, -1); + if (count > 0) { + return count; + } + + count = LegacyPropertyFactory.getIntProperty(deprecatedKey, -1); + if (count > 0) { + LOGGER.warn("{} is ambiguous, and deprecated, recommended to use {}.", deprecatedKey, key); + return count; + } + + // default value + count = Math.min(Runtime.getRuntime().availableProcessors(), 8); + LOGGER.info("{} not defined, set to {}.", key, count); + return count; + } +} diff --git a/transports/transport-common/src/test/java/org/apache/servicecomb/transport/common/TestTransportConfigUtils.java b/transports/transport-common/src/test/java/org/apache/servicecomb/transport/common/TestTransportConfigUtils.java new file mode 100644 index 00000000000..05351e62351 --- /dev/null +++ b/transports/transport-common/src/test/java/org/apache/servicecomb/transport/common/TestTransportConfigUtils.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.common; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import mockit.Mock; +import mockit.MockUp; + +public class TestTransportConfigUtils { + Environment environment = Mockito.mock(Environment.class); + + @BeforeEach + public void setup() { + LegacyPropertyFactory.setEnvironment(environment); + } + + @AfterAll + public static void teardown() { + } + + static String key = "verticle-count"; + + static String deprecatedKey = "thread-count"; + + @Test + public void readVerticleCount_new_exist() { + Mockito.when(environment.getProperty("verticle-count", int.class, -1)).thenReturn(10); + Assertions.assertEquals(10, TransportConfigUtils.readVerticleCount(key, deprecatedKey)); + } + + @Test + public void readVerticleCount_old_exist() { + Mockito.when(environment.getProperty("verticle-count", int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty("thread-count", int.class, -1)).thenReturn(10); + LogCollector collector = new LogCollector(); + Assertions.assertEquals(10, TransportConfigUtils.readVerticleCount(key, deprecatedKey)); + Assertions.assertEquals("thread-count is ambiguous, and deprecated, recommended to use verticle-count.", + collector.getEvent(0).getMessage().getFormattedMessage()); + collector.tearDown(); + } + + @Test + public void readVerticleCount_default_smallCpu() { + Mockito.when(environment.getProperty("verticle-count", int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty("thread-count", int.class, -1)).thenReturn(-1); + + new MockUp() { + @Mock + int availableProcessors() { + return 7; + } + }; + + LogCollector collector = new LogCollector(); + Assertions.assertEquals(7, TransportConfigUtils.readVerticleCount(key, deprecatedKey)); + Assertions.assertEquals("verticle-count not defined, set to 7.", + collector.getLastEvents().getMessage().getFormattedMessage()); + collector.tearDown(); + } + + @Test + public void readVerticleCount_default_bigCpu() { + Mockito.when(environment.getProperty("verticle-count", int.class, -1)).thenReturn(-1); + Mockito.when(environment.getProperty("thread-count", int.class, -1)).thenReturn(-1); + + AtomicInteger count = new AtomicInteger(8); + new MockUp() { + @Mock + int availableProcessors() { + return count.get(); + } + }; + + LogCollector collector = new LogCollector(); + Assertions.assertEquals(8, TransportConfigUtils.readVerticleCount(key, deprecatedKey)); + Assertions.assertEquals("verticle-count not defined, set to 8.", + collector.getLastEvents().getMessage().getFormattedMessage()); + + count.set(9); + collector.clear(); + Assertions.assertEquals(8, TransportConfigUtils.readVerticleCount(key, deprecatedKey)); + Assertions.assertEquals("verticle-count not defined, set to 8.", + collector.getLastEvents().getMessage().getFormattedMessage()); + + collector.tearDown(); + } +} diff --git a/transports/transport-common/src/test/resources/log4j2.xml b/transports/transport-common/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/transports/transport-common/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/transports/transport-highway/pom.xml b/transports/transport-highway/pom.xml index cf8dce722de..d722eb7aa23 100644 --- a/transports/transport-highway/pom.xml +++ b/transports/transport-highway/pom.xml @@ -21,7 +21,7 @@ org.apache.servicecomb transports - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT transport-highway Java Chassis::Transports::Hightway @@ -30,13 +30,25 @@ org.apache.servicecomb java-chassis-core + + org.apache.servicecomb + common-protobuf + org.apache.servicecomb foundation-vertx org.apache.servicecomb - common-protobuf + foundation-metrics + + + org.apache.servicecomb + foundation-test-scaffolding + + + org.apache.servicecomb + transport-common @@ -44,24 +56,21 @@ vertx-codegen provided - + - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test - org.apache.servicecomb - foundation-metrics - - - org.apache.servicecomb - foundation-test-scaffolding + org.jmockit + jmockit + test diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClient.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClient.java index 730a29c99bf..681bfbd3874 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClient.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClient.java @@ -17,11 +17,11 @@ package org.apache.servicecomb.transport.highway; +import java.util.Map; + import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.transport.AbstractTransport; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.ssl.SSLCustom; import org.apache.servicecomb.foundation.ssl.SSLOption; import org.apache.servicecomb.foundation.ssl.SSLOptionFactory; @@ -30,17 +30,13 @@ import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConfig; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; import io.vertx.core.DeploymentOptions; import io.vertx.core.Vertx; public class HighwayClient { - private static final Logger LOGGER = LoggerFactory.getLogger(HighwayClient.class); - private static final String SSL_KEY = "highway.consumer"; private ClientPoolManager clientMgr; @@ -56,77 +52,45 @@ public void init(Vertx vertx) throws Exception { DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(clientMgr, HighwayConfig.getClientThreadCount()); - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); + Map result = VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); + if (!(boolean) result.get("code")) { + throw new IllegalStateException((String) result.get("message")); + } } - private TcpClientConfig createTcpClientConfig() { + @VisibleForTesting + TcpClientConfig createTcpClientConfig() { TcpClientConfig tcpClientConfig = new TcpClientConfig(); + // global request timeout to be login timeout + tcpClientConfig.setMsLoginTimeout( + LegacyPropertyFactory.getLongProperty("servicecomb.request.timeout", TcpClientConfig.DEFAULT_LOGIN_TIMEOUT)); SSLOptionFactory factory = - SSLOptionFactory.createSSLOptionFactory(SSL_KEY, null); + SSLOptionFactory.createSSLOptionFactory(SSL_KEY, LegacyPropertyFactory.getEnvironment()); SSLOption sslOption; if (factory == null) { - sslOption = SSLOption.buildFromYaml(SSL_KEY); + sslOption = SSLOption.build(SSL_KEY, LegacyPropertyFactory.getEnvironment()); } else { sslOption = factory.createSSLOption(); } SSLCustom sslCustom = SSLCustom.createSSLCustom(sslOption.getSslCustomClass()); VertxTLSBuilder.buildClientOptionsBase(sslOption, sslCustom, tcpClientConfig); + if (!sslOption.isCheckCNHost()) { + tcpClientConfig.setHostnameVerificationAlgorithm(""); + } else { + tcpClientConfig.setHostnameVerificationAlgorithm("HTTPS"); + } return tcpClientConfig; } - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - invocation.getInvocationStageTrace().startClientFiltersRequest(); - invocation.getInvocationStageTrace().startSend(); - - HighwayClientConnectionPool tcpClientPool = clientMgr.findClientPool(invocation.isSync()); - - OperationMeta operationMeta = invocation.getOperationMeta(); - OperationProtobuf operationProtobuf = ProtobufManager.getOrCreateOperation(operationMeta); - - HighwayClientConnection tcpClient = - tcpClientPool.findOrCreateClient(invocation.getEndpoint().getEndpoint()); - - invocation.getInvocationStageTrace().finishGetConnection(System.nanoTime()); - - //set the timeout based on priority. the priority is follows. - //high priotiry: 1) operational level 2)schema level 3) service level 4) global level : low priotiry. - TcpClientConfig tcpClientConfig = tcpClient.getClientConfig(); - tcpClientConfig.setRequestTimeoutMillis(AbstractTransport.getReqTimeout(invocation.getOperationName(), - invocation.getSchemaId(), - invocation.getMicroserviceName())); - HighwayClientPackage clientPackage = new HighwayClientPackage(invocation, operationProtobuf, tcpClient); - - LOGGER.debug("Sending request by highway, qualifiedName={}, endpoint={}.", - invocation.getMicroserviceQualifiedName(), - invocation.getEndpoint().getEndpoint()); - tcpClient.send(clientPackage, ar -> { - invocation.getInvocationStageTrace().finishWriteToBuffer(clientPackage.getFinishWriteToBuffer()); - invocation.getInvocationStageTrace().finishReceiveResponse(); - // 此时是在网络线程中,转换线程 - invocation.getResponseExecutor().execute(() -> { - invocation.getInvocationStageTrace().startClientFiltersResponse(); - if (ar.failed()) { - // 只会是本地异常 - invocation.getInvocationStageTrace().finishClientFiltersResponse(); - asyncResp.consumerFail(ar.cause()); - return; - } - - // 处理应答 - try { - Response response = - HighwayCodec.decodeResponse(invocation, - operationProtobuf, - ar.result()); - invocation.getInvocationStageTrace().finishClientFiltersResponse(); - asyncResp.complete(response); - } catch (Throwable e) { - invocation.getInvocationStageTrace().finishClientFiltersResponse(); - asyncResp.consumerFail(e); - } - }); - }); + public HighwayClientPackage createClientPackage(Invocation invocation, OperationProtobuf operationProtobuf) { + long msRequestTimeout = invocation.getOperationMeta().getConfig().getMsRequestTimeout(); + return new HighwayClientPackage(invocation, operationProtobuf, msRequestTimeout); + } + + public HighwayClientConnection findClientPool(Invocation invocation) { + return clientMgr.findClientPool(invocation.isSync()) + .findOrCreateClient(invocation.getEndpoint().getEndpoint()); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientConnection.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientConnection.java index 6a642912fe2..77d6fcfcc22 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientConnection.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientConnection.java @@ -16,7 +16,7 @@ */ package org.apache.servicecomb.transport.highway; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.foundation.vertx.client.tcp.AbstractTcpClientPackage; import org.apache.servicecomb.foundation.vertx.client.tcp.NetClientWrapper; import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConnection; @@ -45,10 +45,10 @@ protected TcpOutputStream createLogin() { header.setMsgType(MsgType.LOGIN); LoginRequest login = new LoginRequest(); - login.setProtocol(Const.HIGHWAY); + login.setProtocol(CoreConst.HIGHWAY); HighwayOutputStream os = new HighwayOutputStream(AbstractTcpClientPackage.getAndIncRequestId()); - os.write(header, LoginRequest.getLoginRequestSchema(), login); + os.write(header, LoginRequest.getRootSerializer(), login); return os; } catch (Throwable e) { throw new Error("impossible.", e); @@ -58,7 +58,7 @@ protected TcpOutputStream createLogin() { @Override protected boolean onLoginResponse(Buffer bodyBuffer) { try { - LoginResponse response = LoginResponse.readObject(bodyBuffer); + LoginResponse.readObject(bodyBuffer); return true; } catch (Throwable e) { LOGGER.error("decode login response failed.", e); diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java new file mode 100644 index 00000000000..3d657bb9d53 --- /dev/null +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientFilter.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.foundation.vertx.client.tcp.TcpData; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HighwayClientFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(HighwayClientFilter.class); + + public static final String NAME = "highway-client"; + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.HIGHWAY.equals(transport); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 2000; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + LOGGER.debug("Sending request by highway, operation={}, endpoint={}.", + invocation.getMicroserviceQualifiedName(), + invocation.getEndpoint().getEndpoint()); + + OperationProtobuf operationProtobuf = ProtobufManager.getOrCreateOperation(invocation); + return send(invocation, operationProtobuf) + .thenApply(tcpData -> convertToResponse(invocation, operationProtobuf, tcpData)) + .thenApply(this::convertFailedResponseToException); + } + + protected CompletableFuture send(Invocation invocation, OperationProtobuf operationProtobuf) { + invocation.getInvocationStageTrace().startConsumerConnection(); + HighwayClient highwayClient = ((HighwayTransport) invocation.getTransport()).getHighwayClient(); + HighwayClientPackage clientPackage = highwayClient.createClientPackage(invocation, operationProtobuf); + HighwayClientConnection clientConnection = highwayClient.findClientPool(invocation); + invocation.getInvocationStageTrace().finishConsumerConnection(); + invocation.onStartSendRequest(); + invocation.getInvocationStageTrace().startConsumerSendRequest(); + CompletableFuture sendFuture = clientConnection + .send(clientPackage).whenComplete((r, e) -> invocation.getInvocationStageTrace().finishWaitResponse()); + invocation.getInvocationStageTrace().finishConsumerSendRequest(); + invocation.getInvocationStageTrace().startWaitResponse(); + return invocation.optimizeSyncConsumerThread(sendFuture); + } + + protected Response convertToResponse(Invocation invocation, OperationProtobuf operationProtobuf, TcpData tcpData) { + try { + invocation.getInvocationStageTrace().startConsumerDecodeResponse(); + Response result = HighwayCodec.decodeResponse(invocation, operationProtobuf, tcpData); + invocation.getInvocationStageTrace().finishConsumerDecodeResponse(); + return result; + } catch (Exception e) { + throw AsyncUtils.rethrow(e); + } + } + + protected Response convertFailedResponseToException(Response response) { + if (response.isFailed()) { + Object errorData = response.getResult(); + if (errorData instanceof InvocationException) { + errorData = ((InvocationException) errorData).getErrorData(); + } + throw Exceptions.create(response.getStatus(), errorData); + } + + return response; + } +} diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientPackage.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientPackage.java index e97875790fd..db1c58dd14f 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientPackage.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayClientPackage.java @@ -20,19 +20,20 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.vertx.client.tcp.AbstractTcpClientPackage; import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class HighwayClientPackage extends AbstractTcpClientPackage { - private Invocation invocation; + private static final Logger LOGGER = LoggerFactory.getLogger(HighwayClientPackage.class); - private OperationProtobuf operationProtobuf; + private final Invocation invocation; - private HighwayClientConnection tcpClient; + private final OperationProtobuf operationProtobuf; - public HighwayClientPackage(Invocation invocation, OperationProtobuf operationProtobuf, - HighwayClientConnection tcpClient) { + public HighwayClientPackage(Invocation invocation, OperationProtobuf operationProtobuf, long msRequestTimeout) { this.invocation = invocation; this.operationProtobuf = operationProtobuf; - this.tcpClient = tcpClient; + this.setMsRequestTimeout(msRequestTimeout); } @Override @@ -43,6 +44,7 @@ public TcpOutputStream createStream() { String msg = String.format("encode request failed. appid=%s, qualifiedName=%s", invocation.getAppId(), invocation.getOperationMeta().getMicroserviceQualifiedName()); + LOGGER.error(msg, e); throw new Error(msg, e); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java index 5d7395d1d88..ca2f24e0a8e 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayCodec.java @@ -17,17 +17,32 @@ package org.apache.servicecomb.transport.highway; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootDeserializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.vertx.client.tcp.TcpData; import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; +import org.apache.servicecomb.swagger.generator.SwaggerConst; import org.apache.servicecomb.swagger.invocation.Response; import org.apache.servicecomb.transport.highway.message.RequestHeader; import org.apache.servicecomb.transport.highway.message.ResponseHeader; +import com.fasterxml.jackson.databind.JavaType; +import com.google.common.base.Defaults; + +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; import io.vertx.core.buffer.Buffer; +@SuppressWarnings("rawtypes") public final class HighwayCodec { private HighwayCodec() { } @@ -44,24 +59,59 @@ public static TcpOutputStream encodeRequest(long msgId, Invocation invocation, header.setContext(invocation.getContext()); HighwayOutputStream os = new HighwayOutputStream(msgId); - os.write(header, operationProtobuf.getRequestSchema(), invocation.getArgs()); + os.write(header, operationProtobuf.getRequestRootSerializer(), invocation.getSwaggerArguments()); return os; } + // Proto buffer never serialize default values, put it back in provider. + // Or will get IllegalArgumentsException for primitive types. + private static Map addPrimitiveTypeDefaultValues(Invocation invocation, + Map swaggerArguments) { + if (invocation.getOperationMeta().getSwaggerProducerOperation() != null && !invocation.isEdge()) { + List swaggerParameters = invocation.getOperationMeta().getSwaggerOperation() + .getParameters(); + if (swaggerParameters != null) { + for (Parameter parameter : swaggerParameters) { + if (swaggerArguments.get(parameter.getName()) == null) { + Type type = invocation.getOperationMeta().getSwaggerProducerOperation() + .getSwaggerParameterType(parameter.getName()); + swaggerArguments.put(parameter.getName(), defaultPrimitiveValue(null, type)); + } + } + } + + RequestBody requestBody = invocation.getOperationMeta().getSwaggerOperation().getRequestBody(); + if (requestBody != null && requestBody.getContent() != null + && requestBody.getContent().get(SwaggerConst.FORM_MEDIA_TYPE) != null + && requestBody.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema() != null + && requestBody.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties() != null) { + for (Object entry : + requestBody.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().getProperties().entrySet()) { + Entry types = (Entry) entry; + if (swaggerArguments.get(types.getKey()) == null) { + Type type = invocation.getOperationMeta().getSwaggerProducerOperation() + .getSwaggerParameterType(types.getKey()); + swaggerArguments.put(types.getKey(), defaultPrimitiveValue(null, type)); + } + } + } + } + return swaggerArguments; + } + public static void decodeRequest(Invocation invocation, RequestHeader header, OperationProtobuf operationProtobuf, Buffer bodyBuffer) throws Exception { - WrapSchema schema = operationProtobuf.getRequestSchema(); - Object[] args = schema.readObject(bodyBuffer); - - invocation.setSwaggerArguments(args); - invocation.mergeContext(header.getContext()); + RequestRootDeserializer requestDeserializer = operationProtobuf.getRequestRootDeserializer(); + Map swaggerArguments = requestDeserializer.deserialize(bodyBuffer.getBytes()); + addPrimitiveTypeDefaultValues(invocation, swaggerArguments); + invocation.setSwaggerArguments(swaggerArguments); } public static RequestHeader readRequestHeader(Buffer headerBuffer) throws Exception { return RequestHeader.readObject(headerBuffer); } - public static Buffer encodeResponse(long msgId, ResponseHeader header, WrapSchema bodySchema, + public static Buffer encodeResponse(long msgId, ResponseHeader header, ResponseRootSerializer bodySchema, Object body) throws Exception { try (HighwayOutputStream os = new HighwayOutputStream(msgId)) { os.write(header, bodySchema, body); @@ -76,12 +126,28 @@ public static Response decodeResponse(Invocation invocation, OperationProtobuf o invocation.getContext().putAll(header.getContext()); } - WrapSchema bodySchema = operationProtobuf.findResponseSchema(header.getStatusCode()); - Object body = bodySchema.readObject(tcpData.getBodyBuffer()); + ResponseRootDeserializer bodySchema = operationProtobuf + .findResponseRootDeserializer(header.getStatusCode()); + JavaType type = invocation.findResponseType(header.getStatusCode()); + Object body = bodySchema + .deserialize(tcpData.getBodyBuffer().getBytes(), type); - Response response = Response.create(header.getStatusCode(), header.getReasonPhrase(), body); - response.setHeaders(header.getHeaders()); + Response response = Response.create(header.getStatusCode(), header.getReasonPhrase() + , defaultPrimitiveValue(body, type)); + response.setHeaders(header.toMultiMap()); return response; } + + private static Object defaultPrimitiveValue(Object body, Type type) { + if (body == null) { + if (type instanceof Class && ((Class) type).isPrimitive()) { + return Defaults.defaultValue((Class) type); + } + if (type instanceof JavaType && ((JavaType) type).isPrimitive()) { + return Defaults.defaultValue(((JavaType) type).getRawClass()); + } + } + return body; + } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayConfig.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayConfig.java index 35ea257b438..4ddf9c47f11 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayConfig.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayConfig.java @@ -17,42 +17,26 @@ package org.apache.servicecomb.transport.highway; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicLongProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.transport.common.TransportConfigUtils; public final class HighwayConfig { private HighwayConfig() { } - public static final String KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT = "servicecomb.highway.server.requestWaitInPoolTimeout"; - - public static final long DEFAULT_REQUEST_WAIT_IN_POOL_TIMEOUT = 30000; - - private static final DynamicLongProperty requestWaitInPoolTimeoutProperty = - DynamicPropertyFactory.getInstance().getLongProperty(KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT, - DEFAULT_REQUEST_WAIT_IN_POOL_TIMEOUT); - - public static long getRequestWaitInPoolTimeout() { - return requestWaitInPoolTimeoutProperty.get(); - } - public static String getAddress() { - DynamicStringProperty address = - DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.highway.address", null); - return address.get(); + return LegacyPropertyFactory.getStringProperty("servicecomb.highway.address", null); } public static int getServerThreadCount() { - DynamicIntProperty address = - DynamicPropertyFactory.getInstance().getIntProperty("servicecomb.highway.server.thread-count", 1); - return address.get(); + return TransportConfigUtils.readVerticleCount( + "servicecomb.highway.server.verticle-count", + "servicecomb.highway.server.thread-count"); } public static int getClientThreadCount() { - DynamicIntProperty address = - DynamicPropertyFactory.getInstance().getIntProperty("servicecomb.highway.client.thread-count", 1); - return address.get(); + return TransportConfigUtils.readVerticleCount( + "servicecomb.highway.client.verticle-count", + "servicecomb.highway.client.thread-count"); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayOutputStream.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayOutputStream.java index 90e13414c9e..b0eb3e8158e 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayOutputStream.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayOutputStream.java @@ -16,45 +16,67 @@ */ package org.apache.servicecomb.transport.highway; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootSerializer; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; import org.apache.servicecomb.transport.highway.message.RequestHeader; import org.apache.servicecomb.transport.highway.message.ResponseHeader; -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; - public class HighwayOutputStream extends TcpOutputStream { public HighwayOutputStream(long msgId) { super(msgId); } - public void write(RequestHeader header, WrapSchema bodySchema, Object body) throws Exception { - write(RequestHeader.getRequestHeaderSchema(), header, bodySchema, body); + public void write(RequestHeader header, RequestRootSerializer requestRootSerializer, Object body) throws Exception { + write(RequestHeader.getRootSerializer().serialize(header), requestRootSerializer.serialize(body)); + } + + public void write(ResponseHeader header, ResponseRootSerializer responseRootSerializer, Object body) + throws Exception { + write(ResponseHeader.getRootSerializer().serialize(header), responseRootSerializer.serialize(body)); + } + + public void write(RequestHeader header, RootSerializer bodySerializer, Object body) throws Exception { + write(RequestHeader.getRootSerializer(), header, bodySerializer, body); + } + + public void write(ResponseHeader header, RootSerializer bodySerializer, Object body) throws Exception { + write(ResponseHeader.getRootSerializer(), header, bodySerializer, body); } - public void write(ResponseHeader header, WrapSchema bodySchema, Object body) throws Exception { - write(ResponseHeader.getResponseHeaderSchema(), header, bodySchema, body); + public void write(RootSerializer headerSerializer, Object header, RootSerializer bodySerializer, Object body) + throws Exception { + byte[] headerBytes = new byte[0]; + byte[] bodyBytes = new byte[0]; + + if (headerSerializer != null) { + headerBytes = headerSerializer.serialize(header); + } + + if (bodySerializer != null) { + bodyBytes = bodySerializer.serialize(body); + } + + write(headerBytes, bodyBytes); } - public void write(WrapSchema headerSchema, Object header, WrapSchema bodySchema, Object body) throws Exception { - // 写protobuf数据 - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); + private void write(byte[] headerBytes, byte[] bodyBytes) + throws Exception { + int headerLength = 0; + int totalLength = 0; - // 写header - if (headerSchema != null) { - headerSchema.writeObject(output, header); + if (headerBytes != null) { + headerLength = headerBytes.length; + totalLength = totalLength + headerLength; } - int headerSize = output.getSize(); - // 写body - // void时bodySchema为null - if (bodySchema != null) { - bodySchema.writeObject(output, body); + if (bodyBytes != null) { + totalLength = totalLength + bodyBytes.length; } - writeLength(output.getSize(), headerSize); - LinkedBuffer.writeTo(this, linkedBuffer); + this.writeLength(totalLength, headerLength); + this.write(headerBytes); + this.write(bodyBytes); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayProducerInvocationFlow.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayProducerInvocationFlow.java new file mode 100644 index 00000000000..3f38fd760d3 --- /dev/null +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayProducerInvocationFlow.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.ProducerInvocationFlow; +import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; +import org.apache.servicecomb.foundation.vertx.tcp.TcpConnection; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HighwayProducerInvocationFlow extends ProducerInvocationFlow { + private static final Logger LOGGER = LoggerFactory.getLogger(HighwayProducerInvocationFlow.class); + + private final TcpConnection connection; + + private final long msgId; + + public HighwayProducerInvocationFlow(InvocationCreator invocationCreator, TcpConnection connection, long msgId) { + super(invocationCreator); + this.connection = connection; + this.msgId = msgId; + } + + @Override + protected Invocation sendCreateInvocationException(Throwable throwable) { + logException(throwable); + return null; + } + + private void logException(Throwable throwable) { + if (Exceptions.isPrintInvocationStackTrace()) { + LOGGER.error("Failed to prepare invocation, msgId={}.", msgId, throwable); + return; + } + + LOGGER.error("Failed to prepare invocation, msgId={}, message={}.", msgId, + ExceptionUtils.getExceptionMessageWithoutTrace(throwable)); + } + + @Override + protected void endResponse(Invocation invocation, Response response) { + HighwayTransportContext transportContext = invocation.getTransportContext(); + connection.write(transportContext.getResponseBuffer()); + } +} diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServer.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServer.java index 57a5a09a19e..2a76d0b8919 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServer.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServer.java @@ -17,15 +17,14 @@ package org.apache.servicecomb.transport.highway; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; import org.apache.servicecomb.foundation.vertx.server.TcpServer; import org.apache.servicecomb.foundation.vertx.server.TcpServerConnection; -import com.netflix.config.DynamicPropertyFactory; - public class HighwayServer extends TcpServer { - private Endpoint endpoint; + private final Endpoint endpoint; public HighwayServer(Endpoint endpoint) { super((URIEndpointObject) endpoint.getAddress()); @@ -39,7 +38,6 @@ protected TcpServerConnection createTcpServerConnection() { @Override protected int getConnectionLimit() { - return DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.highway.server.connection-limit", Integer.MAX_VALUE).get(); + return LegacyPropertyFactory.getIntProperty("servicecomb.highway.server.connection-limit", Integer.MAX_VALUE); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java new file mode 100644 index 00000000000..1f165f9227c --- /dev/null +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilter.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway; + +import static org.apache.servicecomb.core.exception.Exceptions.toProducerResponse; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.codec.protobuf.definition.ResponseRootSerializer; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.filter.ProviderFilter; +import org.apache.servicecomb.foundation.common.utils.AsyncUtils; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.apache.servicecomb.transport.highway.message.ResponseHeader; + +import io.vertx.core.buffer.Buffer; + +public class HighwayServerCodecFilter extends AbstractFilter implements ProviderFilter { + public static final String NAME = "highway-server-codec"; + + @Override + public String getName() { + return NAME; + } + + @Override + public int getOrder() { + // almost time, should be the first filter. + return Filter.PROVIDER_SCHEDULE_FILTER_ORDER - 2000; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.HIGHWAY.equals(transport); + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + return CompletableFuture.completedFuture(invocation) + .thenCompose(this::decodeRequest) + .thenCompose(nextNode::onFilter) + .exceptionally(exception -> toProducerResponse(invocation, exception)) + .thenCompose(response -> encodeResponse(invocation, response)); + } + + protected CompletableFuture decodeRequest(Invocation invocation) { + HighwayTransportContext transportContext = invocation.getTransportContext(); + try { + invocation.getInvocationStageTrace().startProviderDecodeRequest(); + HighwayCodec.decodeRequest(invocation, + transportContext.getHeader(), + transportContext.getOperationProtobuf(), + transportContext.getBodyBuffer()); + invocation.getInvocationStageTrace().finishProviderDecodeRequest(); + return CompletableFuture.completedFuture(invocation); + } catch (Exception e) { + return AsyncUtils.completeExceptionally(e); + } + } + + protected CompletableFuture encodeResponse(Invocation invocation, Response response) { + invocation.onEncodeResponseStart(response); + + ResponseHeader header = new ResponseHeader(); + header.setStatusCode(response.getStatusCode()); + header.setReasonPhrase(response.getReasonPhrase()); + header.setContext(invocation.getContext()); + header.fromMultiMap(response.getHeaders()); + + HighwayTransportContext transportContext = invocation.getTransportContext(); + long msgId = transportContext.getMsgId(); + OperationProtobuf operationProtobuf = transportContext.getOperationProtobuf(); + ResponseRootSerializer bodySchema = operationProtobuf.findResponseRootSerializer(response.getStatusCode()); + + try { + boolean failed = response.getResult() instanceof InvocationException; + Buffer respBuffer; + if (failed) { + respBuffer = HighwayCodec.encodeResponse( + msgId, header, bodySchema, ((InvocationException) response.getResult()).getErrorData()); + } else { + respBuffer = HighwayCodec.encodeResponse( + msgId, header, bodySchema, response.getResult()); + } + transportContext.setResponseBuffer(respBuffer); + + invocation.onEncodeResponseFinish(); + return CompletableFuture.completedFuture(response); + } catch (Exception e) { + // keep highway performance and simple, this encoding/decoding error not need handle by client + String msg = String.format("encode response failed, msgId=%d", msgId); + return AsyncUtils.completeExceptionally(new IllegalStateException(msg, e)); + } + } +} diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerConnection.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerConnection.java index 5641992a618..b1c97704c5e 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerConnection.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerConnection.java @@ -16,9 +16,20 @@ */ package org.apache.servicecomb.transport.highway; -import javax.ws.rs.core.Response.Status; +import java.util.concurrent.CompletableFuture; +import jakarta.ws.rs.core.Response.Status; + +import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.InvocationFactory; import org.apache.servicecomb.foundation.vertx.server.TcpBufferHandler; import org.apache.servicecomb.foundation.vertx.server.TcpParser; import org.apache.servicecomb.foundation.vertx.server.TcpServerConnection; @@ -35,7 +46,7 @@ public class HighwayServerConnection extends TcpServerConnection implements TcpBufferHandler { private static final Logger LOGGER = LoggerFactory.getLogger(HighwayServerConnection.class); - private Endpoint endpoint; + private final Endpoint endpoint; public HighwayServerConnection(Endpoint endpoint) { this.endpoint = endpoint; @@ -68,9 +79,8 @@ public void handle(long msgId, Buffer headerBuffer, Buffer bodyBuffer) { } protected RequestHeader decodeRequestHeader(long msgId, Buffer headerBuffer) { - RequestHeader requestHeader = null; try { - requestHeader = HighwayCodec.readRequestHeader(headerBuffer); + return HighwayCodec.readRequestHeader(headerBuffer); } catch (Exception e) { String msg = String.format("decode request header error, msgId=%d", msgId); @@ -79,12 +89,10 @@ protected RequestHeader decodeRequestHeader(long msgId, Buffer headerBuffer) { netSocket.close(); return null; } - - return requestHeader; } protected void onLogin(long msgId, RequestHeader header, Buffer bodyBuffer) { - LoginRequest request = null; + LoginRequest request; try { request = LoginRequest.readObject(bodyBuffer); } catch (Exception e) { @@ -106,9 +114,9 @@ protected void onLogin(long msgId, RequestHeader header, Buffer bodyBuffer) { LoginResponse response = new LoginResponse(); - os.write(ResponseHeader.getResponseHeaderSchema(), + os.write(ResponseHeader.getRootSerializer(), responseHeader, - LoginResponse.getLoginResponseSchema(), + LoginResponse.getRootSerializer(), response); netSocket.write(os.getBuffer()); } catch (Exception e) { @@ -117,9 +125,31 @@ protected void onLogin(long msgId, RequestHeader header, Buffer bodyBuffer) { } protected void onRequest(long msgId, RequestHeader header, Buffer bodyBuffer) { - HighwayServerInvoke invoke = new HighwayServerInvoke(endpoint); - if (invoke.init(this, msgId, header, bodyBuffer)) { - invoke.execute(); - } + InvocationCreator creator = () -> createInvocation(msgId, header, bodyBuffer); + new HighwayProducerInvocationFlow(creator, this, msgId) + .run(); + } + + public CompletableFuture createInvocation(long msgId, RequestHeader header, Buffer bodyBuffer) { + MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); + SchemaMeta schemaMeta = microserviceMeta.ensureFindSchemaMeta(header.getSchemaId()); + OperationMeta operationMeta = schemaMeta.ensureFindOperation(header.getOperationName()); + + Invocation invocation = InvocationFactory.forProvider(endpoint, + operationMeta, + null); + invocation.getHandlerContext().put(CoreConst.REMOTE_ADDRESS, netSocket.remoteAddress()); + + HighwayTransportContext transportContext = new HighwayTransportContext() + .setConnection(this) + .setMsgId(msgId) + .setHeader(header) + .setBodyBuffer(bodyBuffer) + .setOperationProtobuf(ProtobufManager.getOrCreateOperation(invocation)); + invocation.setTransportContext(transportContext); + + invocation.mergeContext(header.getContext()); + + return CompletableFuture.completedFuture(invocation); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java deleted file mode 100644 index 32bfb67b913..00000000000 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.highway; - -import java.util.Map; - -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.invocation.InvocationFactory; -import org.apache.servicecomb.foundation.vertx.tcp.TcpConnection; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.transport.highway.message.RequestHeader; -import org.apache.servicecomb.transport.highway.message.ResponseHeader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.buffer.Buffer; - -public class HighwayServerInvoke { - private static final Logger LOGGER = LoggerFactory.getLogger(HighwayServerInvoke.class); - - private RequestHeader header; - - private OperationMeta operationMeta; - - private OperationProtobuf operationProtobuf; - - private TcpConnection connection; - - private long msgId; - - private Buffer bodyBuffer; - - private Endpoint endpoint; - - Invocation invocation; - - protected long start; - - public HighwayServerInvoke() { - this(null); - } - - public HighwayServerInvoke(Endpoint endpoint) { - this.start = System.nanoTime(); - this.endpoint = endpoint; - } - - public boolean init(TcpConnection connection, long msgId, - RequestHeader header, Buffer bodyBuffer) { - try { - doInit(connection, msgId, header, bodyBuffer); - return true; - } catch (Throwable e) { - String microserviceQualifiedName = "unknown"; - if (operationMeta != null) { - microserviceQualifiedName = operationMeta.getMicroserviceQualifiedName(); - } - String msg = String.format("decode request error, microserviceQualifiedName=%s, msgId=%d", - microserviceQualifiedName, - msgId); - LOGGER.error(msg, e); - - return false; - } - } - - private void doInit(TcpConnection connection, long msgId, RequestHeader header, - Buffer bodyBuffer) throws Exception { - this.connection = connection; - this.msgId = msgId; - this.header = header; - - MicroserviceMeta microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); - SchemaMeta schemaMeta = microserviceMeta.ensureFindSchemaMeta(header.getSchemaId()); - this.operationMeta = schemaMeta.ensureFindOperation(header.getOperationName()); - this.operationProtobuf = ProtobufManager.getOrCreateOperation(operationMeta); - - this.bodyBuffer = bodyBuffer; - } - - private void runInExecutor() { - try { - if (isInQueueTimeout()) { - throw new InvocationException(Status.INTERNAL_SERVER_ERROR, "Timeout when processing the request."); - } - doRunInExecutor(); - } catch (Throwable e) { - String msg = String.format("handle request error, %s, msgId=%d", - operationMeta.getMicroserviceQualifiedName(), - msgId); - LOGGER.error(msg, e); - - sendResponse(header.getContext(), Response.providerFailResp(e)); - } - } - - private boolean isInQueueTimeout() { - return System.nanoTime() - invocation.getInvocationStageTrace().getStart() > - HighwayConfig.getRequestWaitInPoolTimeout() * 1_000_000; - } - - private void doRunInExecutor() throws Exception { - invocation.onExecuteStart(); - - invocation.getInvocationStageTrace().startServerFiltersRequest(); - HighwayCodec.decodeRequest(invocation, header, operationProtobuf, bodyBuffer); - invocation.getHandlerContext().put(Const.REMOTE_ADDRESS, this.connection.getNetSocket().remoteAddress()); - - invocation.getInvocationStageTrace().startHandlersRequest(); - invocation.next(response -> { - sendResponse(invocation.getContext(), response); - }); - } - - private void sendResponse(Map context, Response response) { - invocation.getInvocationStageTrace().finishHandlersResponse(); - - ResponseHeader header = new ResponseHeader(); - header.setStatusCode(response.getStatusCode()); - header.setReasonPhrase(response.getReasonPhrase()); - header.setContext(context); - header.setHeaders(response.getHeaders()); - - WrapSchema bodySchema = operationProtobuf.findResponseSchema(response.getStatusCode()); - Object body = response.getResult(); - if (response.isFailed()) { - body = ((InvocationException) body).getErrorData(); - } - - try { - Buffer respBuffer = HighwayCodec.encodeResponse(msgId, header, bodySchema, body); - invocation.getInvocationStageTrace().finishServerFiltersResponse(); - connection.write(respBuffer.getByteBuf()); - } catch (Exception e) { - // 没招了,直接打日志 - String msg = String.format("encode response failed, %s, msgId=%d", - operationProtobuf.getOperationMeta().getMicroserviceQualifiedName(), - msgId); - LOGGER.error(msg, e); - } finally { - if (invocation != null) { - invocation.onFinish(response); - } - } - } - - /** - * start time in queue. - */ - public void execute() { - try { - invocation = InvocationFactory.forProvider(endpoint, - operationProtobuf.getOperationMeta(), - null); - invocation.onStart(null, start); - invocation.getInvocationStageTrace().startSchedule(); - - // copied from HighwayCodec#decodeRequest() - // for temporary qps enhance purpose, we'll remove it when handler mechanism is refactored - invocation.mergeContext(header.getContext()); - - Holder qpsFlowControlReject = checkQpsFlowControl(operationMeta); - if (qpsFlowControlReject.value) { - return; - } - - operationMeta.getExecutor().execute(this::runInExecutor); - } catch (IllegalStateException e) { - sendResponse(header.getContext(), Response.providerFailResp(e)); - } - } - - private Holder checkQpsFlowControl(OperationMeta operationMeta) { - Holder qpsFlowControlReject = new Holder<>(false); - @SuppressWarnings("deprecation") - Handler providerQpsFlowControlHandler = operationMeta.getProviderQpsFlowControlHandler(); - if (null != providerQpsFlowControlHandler) { - try { - providerQpsFlowControlHandler.handle(invocation, response -> { - qpsFlowControlReject.value = true; - sendResponse(header.getContext(), response); - }); - } catch (Exception e) { - LOGGER.error("failed to execute ProviderQpsFlowControlHandler", e); - qpsFlowControlReject.value = true; - sendResponse(header.getContext(), Response.providerFailResp(e)); - } - } - return qpsFlowControlReject; - } -} diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerVerticle.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerVerticle.java index 3d6efc4cf39..9b89ae32f2d 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerVerticle.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerVerticle.java @@ -19,7 +19,7 @@ import java.net.InetSocketAddress; -import org.apache.servicecomb.core.Const; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.transport.AbstractTransport; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; @@ -28,7 +28,7 @@ import io.vertx.core.AbstractVerticle; import io.vertx.core.Context; -import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.Vertx; public class HighwayServerVerticle extends AbstractVerticle { @@ -48,10 +48,10 @@ public void init(Vertx vertx, Context context) { } @Override - public void start(Future startFuture) throws Exception { + public void start(Promise startPromise) throws Exception { try { super.start(); - startListen(startFuture); + startListen(startPromise); } catch (Throwable e) { // vert.x got some states that not print error and execute call back in VertexUtils.blockDeploy, we add a log our self. LOGGER.error("", e); @@ -59,11 +59,11 @@ public void start(Future startFuture) throws Exception { } } - protected void startListen(Future startFuture) { - // 如果本地未配置地址,则表示不必监听,只需要作为客户端使用即可 + protected void startListen(Promise startPromise) { + // if listen address is not provided, do not fail and maybe a consumer service. if (endpointObject == null) { LOGGER.warn("highway listen address is not configured, will not listen."); - startFuture.complete(); + startPromise.complete(); return; } @@ -74,12 +74,12 @@ protected void startListen(Future startFuture) { LOGGER.info("highway listen success. address={}:{}", socketAddress.getHostString(), socketAddress.getPort()); - startFuture.complete(); + startPromise.complete(); return; } - LOGGER.error(Const.HIGHWAY, ar.cause()); - startFuture.fail(ar.cause()); + LOGGER.error(CoreConst.HIGHWAY, ar.cause()); + startPromise.fail(ar.cause()); }); } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransport.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransport.java index f4bbcd164be..2d5d4fa5683 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransport.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransport.java @@ -18,28 +18,25 @@ package org.apache.servicecomb.transport.highway; import java.util.Collections; +import java.util.Map; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.transport.AbstractTransport; import org.apache.servicecomb.foundation.vertx.SimpleJsonObject; import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.foundation.vertx.tcp.TcpConst; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.springframework.stereotype.Component; import io.vertx.core.DeploymentOptions; -@Component public class HighwayTransport extends AbstractTransport { - - private HighwayClient highwayClient = new HighwayClient(); + private final HighwayClient highwayClient = new HighwayClient(); @Override public String getName() { - return Const.HIGHWAY; + return CoreConst.HIGHWAY; } + @Override public boolean init() throws Exception { highwayClient.init(transportVertx); @@ -48,11 +45,16 @@ public boolean init() throws Exception { SimpleJsonObject json = new SimpleJsonObject(); json.put(ENDPOINT_KEY, getEndpoint()); deployOptions.setConfig(json); - return VertxUtils.blockDeploy(transportVertx, HighwayServerVerticle.class, deployOptions); + deployOptions.setWorkerPoolName("pool-worker-transport-highway"); + Map result = VertxUtils.blockDeploy(transportVertx, HighwayServerVerticle.class, deployOptions); + if ((boolean) result.get("code")) { + return true; + } else { + throw new IllegalStateException((String) result.get("message")); + } } - @Override - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - highwayClient.send(invocation, asyncResp); + public HighwayClient getHighwayClient() { + return highwayClient; } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransportContext.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransportContext.java new file mode 100644 index 00000000000..bf4b699d35d --- /dev/null +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayTransportContext.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.foundation.vertx.tcp.TcpConnection; +import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext; +import org.apache.servicecomb.transport.highway.message.RequestHeader; + +import io.vertx.core.Context; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; + +public class HighwayTransportContext implements VertxTransportContext { + private final Context vertxContext; + + private TcpConnection connection; + + private long msgId; + + private RequestHeader header; + + private Buffer bodyBuffer; + + private OperationProtobuf operationProtobuf; + + private Buffer responseBuffer; + + public HighwayTransportContext() { + this.vertxContext = Vertx.currentContext(); + } + + @Override + public Context getVertxContext() { + return vertxContext; + } + + public TcpConnection getConnection() { + return connection; + } + + public HighwayTransportContext setConnection(TcpConnection connection) { + this.connection = connection; + return this; + } + + public long getMsgId() { + return msgId; + } + + public HighwayTransportContext setMsgId(long msgId) { + this.msgId = msgId; + return this; + } + + public RequestHeader getHeader() { + return header; + } + + public HighwayTransportContext setHeader(RequestHeader header) { + this.header = header; + return this; + } + + public Buffer getBodyBuffer() { + return bodyBuffer; + } + + public HighwayTransportContext setBodyBuffer(Buffer bodyBuffer) { + this.bodyBuffer = bodyBuffer; + return this; + } + + public OperationProtobuf getOperationProtobuf() { + return operationProtobuf; + } + + public HighwayTransportContext setOperationProtobuf( + OperationProtobuf operationProtobuf) { + this.operationProtobuf = operationProtobuf; + return this; + } + + public Buffer getResponseBuffer() { + return responseBuffer; + } + + public HighwayTransportContext setResponseBuffer(Buffer responseBuffer) { + this.responseBuffer = responseBuffer; + return this; + } +} diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/TransportHighwayConfiguration.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/TransportHighwayConfiguration.java new file mode 100644 index 00000000000..b029d643814 --- /dev/null +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/TransportHighwayConfiguration.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TransportHighwayConfiguration { + @Bean + public HighwayServerCodecFilter highwayServerCodecFilter() { + return new HighwayServerCodecFilter(); + } + + @Bean + public HighwayClientFilter highwayClientFilter() { + return new HighwayClientFilter(); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/Headers.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/Headers.java similarity index 97% rename from swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/Headers.java rename to transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/Headers.java index acdba5f3270..6dfe8c146de 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/Headers.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/Headers.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.swagger.invocation.response; +package org.apache.servicecomb.transport.highway.message; import java.util.ArrayList; import java.util.HashMap; diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginRequest.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginRequest.java index 11545661861..6c678e52cf6 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginRequest.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginRequest.java @@ -16,39 +16,35 @@ */ package org.apache.servicecomb.transport.highway.message; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Tag; import io.vertx.core.buffer.Buffer; public class LoginRequest { - private static WrapSchema loginRequestSchema = ProtobufManager.getDefaultScopedProtobufSchemaManager() - .getOrCreateSchema(LoginRequest.class); + private static final ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); - public static WrapSchema getLoginRequestSchema() { - return loginRequestSchema; + private static final RootDeserializer rootDeserializer = protoMapperFactory + .createFromName("LoginRequest.proto") + .createRootDeserializer("LoginRequest", LoginRequest.class); + + private static final RootSerializer rootSerializer = protoMapperFactory.createFromName("LoginRequest.proto") + .createRootSerializer("LoginRequest", LoginRequest.class); + + public static RootSerializer getRootSerializer() { + return rootSerializer; } public static LoginRequest readObject(Buffer bodyBuffer) throws Exception { - return loginRequestSchema.readObject(bodyBuffer); + return rootDeserializer.deserialize(bodyBuffer.getBytes()); } - @Tag(1) private String protocol; // 压缩算法名字 - @Tag(2) private String zipName; - // no need this flag any more, but tag(3) should be reserved - // 历史版本中的protoStuff实现的protobuf的map编码与标准的protobuf不兼容 - // 为保持highway的兼容,旧的不兼容编码也要保留 - // 只有LoginRequest/LoginResponse同时为true时,才使用标准protobuf编码 - //@Tag(3) - //private boolean useProtobufMapCodec; - public String getProtocol() { return protocol; } @@ -64,8 +60,4 @@ public String getZipName() { public void setZipName(String zipName) { this.zipName = zipName; } - - public void writeObject(ProtobufOutput output) throws Exception { - loginRequestSchema.writeObject(output, this); - } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginResponse.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginResponse.java index 3e5d48230ca..d8cc0414463 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginResponse.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/LoginResponse.java @@ -16,39 +16,35 @@ */ package org.apache.servicecomb.transport.highway.message; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Tag; import io.vertx.core.buffer.Buffer; public class LoginResponse { - private static WrapSchema loginResponseSchema = ProtobufManager.getDefaultScopedProtobufSchemaManager() - .getOrCreateSchema(LoginResponse.class); + private static final ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); - public static WrapSchema getLoginResponseSchema() { - return loginResponseSchema; + private static final RootDeserializer rootDeserializer = protoMapperFactory + .createFromName("LoginResponse.proto") + .createRootDeserializer("LoginResponse", LoginResponse.class); + + private static final RootSerializer rootSerializer = protoMapperFactory.createFromName("LoginResponse.proto") + .createRootSerializer("LoginResponse", LoginResponse.class); + + public static RootSerializer getRootSerializer() { + return rootSerializer; } public static LoginResponse readObject(Buffer bodyBuffer) throws Exception { - return loginResponseSchema.readObject(bodyBuffer); + return rootDeserializer.deserialize(bodyBuffer.getBytes()); } - @Tag(1) private String protocol; // 压缩算法名字 - @Tag(2) private String zipName; - // no need this flag any more, but tag(3) should be reserved - // 历史版本中的protoStuff实现的protobuf的map编码与标准的protobuf不兼容 - // 为保持highway的兼容,旧的不兼容编码也要保留 - // 只有LoginRequest/LoginResponse同时为true时,才使用标准protobuf编码 - //@Tag(3) - //private boolean useProtobufMapCodec; - public String getProtocol() { return protocol; } @@ -64,8 +60,4 @@ public String getZipName() { public void setZipName(String zipName) { this.zipName = zipName; } - - public void writeObject(ProtobufOutput output) throws Exception { - loginResponseSchema.writeObject(output, this); - } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/RequestHeader.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/RequestHeader.java index 41e11140544..4009a7fb89c 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/RequestHeader.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/RequestHeader.java @@ -19,56 +19,49 @@ import java.util.Map; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Tag; import io.vertx.core.buffer.Buffer; -/** - * tag的缺失、乱序,是因为要兼容历史版本 - * 1.tag(4),是历史版本中的压缩算法名,转移到login消息中传递 - */ public class RequestHeader { - private static WrapSchema requestHeaderSchema = ProtobufManager.getDefaultScopedProtobufSchemaManager() - .getOrCreateSchema(RequestHeader.class); + private static final ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); + + private static final RootDeserializer rootDeserializer = protoMapperFactory + .createFromName("RequestHeader.proto") + .createRootDeserializer("RequestHeader", RequestHeader.class); + + private static final RootSerializer rootSerializer = protoMapperFactory.createFromName("RequestHeader.proto") + .createRootSerializer("RequestHeader", RequestHeader.class); - public static WrapSchema getRequestHeaderSchema() { - return requestHeaderSchema; + public static RootSerializer getRootSerializer() { + return rootSerializer; } public static RequestHeader readObject(Buffer bodyBuffer) throws Exception { - return requestHeaderSchema.readObject(bodyBuffer); + return rootDeserializer.deserialize(bodyBuffer.getBytes()); } - //CHECKSTYLE:OFF: magicnumber - @Tag(2) - private byte msgType; + private int msgType; // 运行时必须的数据,比如body是否压缩 // 预留特性选项 - @Tag(3) private int flags; - @Tag(1) private String destMicroservice; - @Tag(5) private String schemaId; - @Tag(6) private String operationName; - @Tag(7) private Map context; - //CHECKSTYLE:ON - public byte getMsgType() { + public int getMsgType() { return msgType; } - public void setMsgType(byte msgType) { + public void setMsgType(int msgType) { this.msgType = msgType; } @@ -111,8 +104,4 @@ public Map getContext() { public void setContext(Map context) { this.context = context; } - - public void writeObject(ProtobufOutput output) throws Exception { - requestHeaderSchema.writeObject(output, this); - } } diff --git a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/ResponseHeader.java b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/ResponseHeader.java index 92003855a00..2a50efd0365 100644 --- a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/ResponseHeader.java +++ b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/message/ResponseHeader.java @@ -17,47 +17,55 @@ package org.apache.servicecomb.transport.highway.message; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.swagger.invocation.response.Headers; +import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory; +import org.apache.servicecomb.foundation.protobuf.RootDeserializer; +import org.apache.servicecomb.foundation.protobuf.RootSerializer; -import io.protostuff.ProtobufOutput; -import io.protostuff.Tag; +import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; public class ResponseHeader { - private static WrapSchema responseHeaderSchema = ProtobufManager.getDefaultScopedProtobufSchemaManager() - .getOrCreateSchema(ResponseHeader.class); + private static final ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory(); - public static WrapSchema getResponseHeaderSchema() { - return responseHeaderSchema; + private static final RootDeserializer rootDeserializer = protoMapperFactory + .createFromName("ResponseHeader.proto") + .createRootDeserializer("ResponseHeader", ResponseHeader.class); + + private static final RootSerializer rootSerializer = protoMapperFactory.createFromName("ResponseHeader.proto") + .createRootSerializer("ResponseHeader", ResponseHeader.class); + + public static RootSerializer getRootSerializer() { + return rootSerializer; } public static ResponseHeader readObject(Buffer bodyBuffer) throws Exception { - return responseHeaderSchema.readObject(bodyBuffer); + return rootDeserializer.deserialize(bodyBuffer.getBytes()); } // 运行时必须的数据,比如body是否压缩 // 预留特性选项 - //CHECKSTYLE:OFF: magicnumber - @Tag(5) private int flags; - @Tag(1) private int statusCode; - @Tag(2) - private String reason; + private String reasonPhrase; - @Tag(3) private Map context; - @Tag(4) private Headers headers = new Headers(); - //CHECKSTYLE:ON: magicnumber + public int getFlags() { + return flags; + } + + public void setFlags(int flags) { + this.flags = flags; + } + public int getStatusCode() { return statusCode; } @@ -67,11 +75,11 @@ public void setStatusCode(int statusCode) { } public String getReasonPhrase() { - return reason; + return reasonPhrase; } public void setReasonPhrase(String reason) { - this.reason = reason; + this.reasonPhrase = reason; } public Map getContext() { @@ -90,7 +98,29 @@ public void setHeaders(Headers headers) { this.headers = headers; } - public void writeObject(ProtobufOutput output) throws Exception { - responseHeaderSchema.writeObject(output, this); + public void fromMultiMap(MultiMap multiMap) { + if (multiMap == null) { + return; + } + + for (Entry entry : multiMap.entries()) { + headers.addHeader(entry.getKey(), entry.getValue()); + } + } + + public MultiMap toMultiMap() { + MultiMap multiMap = MultiMap.caseInsensitiveMultiMap(); + Map> headerMap = headers.getHeaderMap(); + if (headerMap == null) { + return multiMap; + } + + for (Entry> entry : headerMap.entrySet()) { + String key = entry.getKey(); + for (Object value : entry.getValue()) { + multiMap.add(key, value.toString()); + } + } + return multiMap; } } diff --git a/transports/transport-highway/src/main/resources/LoginRequest.proto b/transports/transport-highway/src/main/resources/LoginRequest.proto new file mode 100644 index 00000000000..cc402fb06bb --- /dev/null +++ b/transports/transport-highway/src/main/resources/LoginRequest.proto @@ -0,0 +1,24 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; +package org.apache.servicecomb.transport.highway.message; + +message LoginRequest { + string protocol = 1; + string zipName = 2; +} diff --git a/transports/transport-highway/src/main/resources/LoginResponse.proto b/transports/transport-highway/src/main/resources/LoginResponse.proto new file mode 100644 index 00000000000..2931e792ceb --- /dev/null +++ b/transports/transport-highway/src/main/resources/LoginResponse.proto @@ -0,0 +1,24 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; +package org.apache.servicecomb.transport.highway.message; + +message LoginResponse { + string protocol = 1; + string zipName = 2; +} diff --git a/transports/transport-highway/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport b/transports/transport-highway/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport new file mode 100644 index 00000000000..25f1bb25976 --- /dev/null +++ b/transports/transport-highway/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.transport.highway.HighwayTransport diff --git a/transports/transport-highway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/transports/transport-highway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..46a50fbf311 --- /dev/null +++ b/transports/transport-highway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.transport.highway.TransportHighwayConfiguration diff --git a/transports/transport-highway/src/main/resources/RequestHeader.proto b/transports/transport-highway/src/main/resources/RequestHeader.proto new file mode 100644 index 00000000000..1ccf235f842 --- /dev/null +++ b/transports/transport-highway/src/main/resources/RequestHeader.proto @@ -0,0 +1,28 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; +package org.apache.servicecomb.transport.highway.message; + +message RequestHeader { + string destMicroservice = 1; + int32 msgType = 2; + int32 flags = 3; + string schemaId = 4; + string operationName = 5; + map context = 6; +} diff --git a/transports/transport-highway/src/main/resources/ResponseHeader.proto b/transports/transport-highway/src/main/resources/ResponseHeader.proto new file mode 100644 index 00000000000..c92bf71e94a --- /dev/null +++ b/transports/transport-highway/src/main/resources/ResponseHeader.proto @@ -0,0 +1,37 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +syntax = "proto3"; +import "google/protobuf/any.proto"; +package org.apache.servicecomb.transport.highway.message; + +message ResponseHeader { + int32 flags = 1; + int32 statusCode = 2; + string reasonPhrase = 3; + map context = 4; + Headers headers = 5; +} + +message Headers { + map headerMap = 1; +} + +//@WrapProperty +message ListGoogle_protobuf_Any { + repeated google.protobuf.Any value = 1; +} diff --git a/transports/transport-highway/src/main/resources/microservice.yaml b/transports/transport-highway/src/main/resources/microservice.yaml new file mode 100644 index 00000000000..4b37228f3f6 --- /dev/null +++ b/transports/transport-highway/src/main/resources/microservice.yaml @@ -0,0 +1,25 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +servicecomb-config-order: -500 +servicecomb: + filter-chains: + transport: + scb-consumer-transport: + highway: highway-client + scb-producer-transport: + highway: highway-server-codec diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/common/MockUtil.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/common/MockUtil.java index 07d87c9dd50..385ba6d4b8a 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/common/MockUtil.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/common/MockUtil.java @@ -30,7 +30,7 @@ public class MockUtil { - private static MockUtil instance = new MockUtil(); + private static final MockUtil instance = new MockUtil(); private MockUtil() { diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilterTest.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilterTest.java new file mode 100644 index 00000000000..46352690c95 --- /dev/null +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/HighwayServerCodecFilterTest.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.highway; + +import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static org.apache.servicecomb.core.SCBEngine.CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC; +import static org.apache.servicecomb.core.SCBEngine.DEFAULT_TURN_DOWN_STATUS_WAIT_SEC; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.SCBStatus; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.core.invocation.InvocationFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.apache.servicecomb.transport.highway.message.RequestHeader; +import org.apache.servicecomb.transport.highway.message.ResponseHeader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.core.env.Environment; + +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.impl.SysProps; +import io.vertx.core.json.Json; +import mockit.Expectations; +import mockit.Mocked; +import mockit.Verifications; + +public class HighwayServerCodecFilterTest { + HighwayServerCodecFilter codecFilter = new HighwayServerCodecFilter(); + + Invocation invocation; + + @Mocked + Endpoint endpoint; + + @Mocked + OperationMeta operationMeta; + + @Mocked + HighwayTransportContext transportContext; + + MultiMap headers = MultiMap.caseInsensitiveMultiMap(); + + FilterNode nextNode = new FilterNode(new AbstractFilter() { + @Override + public String getName() { + return "test"; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + Response response = Response.ok("ok"); + response.setHeaders(headers); + return CompletableFuture.completedFuture(response); + } + }); + + static SCBEngine engine; + + Environment environment = Mockito.mock(Environment.class); + + @Before + public void setUp() { + Mockito.when(environment.getProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, + long.class, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)).thenReturn(DEFAULT_TURN_DOWN_STATUS_WAIT_SEC); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + + engine = SCBBootstrap.createSCBEngineForTest(environment); + engine.setStatus(SCBStatus.UP); + invocation = InvocationFactory.forProvider(endpoint, operationMeta, null); + } + + @After + public void tearDown() { + engine.destroy(); + } + + private void mockDecodeRequestFail() throws Exception { + new Expectations(invocation) { + { + invocation.getTransportContext(); + result = transportContext; + } + }; + new Expectations(HighwayCodec.class) { + { + HighwayCodec.decodeRequest(invocation, (RequestHeader) any, (OperationProtobuf) any, (Buffer) any); + result = new RuntimeExceptionWithoutStackTrace("encode request failed"); + } + }; + } + + @Test + public void should_not_invoke_filter_when_decode_request_failed(@Mocked FilterNode nextNode) throws Exception { + mockDecodeRequestFail(); + + codecFilter.onFilter(invocation, nextNode); + + new Verifications() { + { + nextNode.onFilter(invocation); + times = 0; + } + }; + } + + @Test + public void should_convert_exception_to_response_when_decode_request_failed() + throws Exception { + mockDecodeRequestFail(); + + Response response = codecFilter.onFilter(invocation, nextNode).get(); + + assertThat(response.getStatus()).isEqualTo(INTERNAL_SERVER_ERROR); + + JSONAssert.assertEquals(Json.encode(((InvocationException) response.getResult()).getErrorData()), + "{\"code\":\"SCB.50000000\",\"message\":\"Unexpected " + + "exception when processing null. encode request failed\"}", false); + } + + private void success_invocation() throws InterruptedException, ExecutionException { + new Expectations(invocation) { + { + invocation.getTransportContext(); + result = transportContext; + } + }; + + codecFilter.onFilter(invocation, nextNode).get(); + } + + @Test + public void should_encode_response_header(@Mocked ResponseHeader responseHeader) + throws ExecutionException, InterruptedException { + success_invocation(); + + new Verifications() { + { + MultiMap captureHeaders; + responseHeader.fromMultiMap(captureHeaders = withCapture()); + assertThat(captureHeaders).isSameAs(headers); + } + }; + } + + @Test + public void should_encode_response() throws ExecutionException, InterruptedException { + success_invocation(); + + new Verifications() { + { + Buffer captureBuffer; + transportContext.setResponseBuffer(captureBuffer = withCapture()); + assertThat(captureBuffer).isNotNull(); + } + }; + } +} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayClient.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayClient.java index f8d23fc20c0..d7a29f0f86e 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayClient.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayClient.java @@ -17,45 +17,24 @@ package org.apache.servicecomb.transport.highway; -import javax.ws.rs.core.Response.Status; -import javax.xml.ws.Holder; +import java.util.HashMap; +import java.util.Map; -import org.apache.commons.configuration.AbstractConfiguration; -import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.config.ConfigUtil; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.core.transport.AbstractTransport; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.tcp.AbstractTcpClientPackage; -import org.apache.servicecomb.foundation.vertx.client.tcp.NetClientWrapper; -import org.apache.servicecomb.foundation.vertx.client.tcp.TcpData; -import org.apache.servicecomb.foundation.vertx.client.tcp.TcpResponseCallback; -import org.apache.servicecomb.foundation.vertx.server.TcpParser; -import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.transport.highway.message.LoginRequest; -import org.apache.servicecomb.transport.highway.message.RequestHeader; -import org.junit.Assert; +import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConfig; +import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; +import org.springframework.core.env.Environment; -import com.netflix.config.DynamicPropertyFactory; - -import io.netty.buffer.ByteBuf; -import io.protostuff.runtime.ProtobufCompatibleUtils; import io.vertx.core.AbstractVerticle; import io.vertx.core.DeploymentOptions; import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; import mockit.Deencapsulation; import mockit.Mock; import mockit.MockUp; @@ -66,25 +45,12 @@ public class TestHighwayClient { HighwayClient client = new HighwayClient(); - Invocation invocation = Mockito.mock(Invocation.class); - - InvocationStageTrace invocationStageTrace = new InvocationStageTrace(invocation); - - OperationProtobuf operationProtobuf = Mockito.mock(OperationProtobuf.class); - - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - - Endpoint endpoint = Mockito.mock(Endpoint.class); + Environment environment = Mockito.mock(Environment.class); static long nanoTime = 123; @BeforeClass - public static void beforeCls() { - ConfigUtil.installDynamicConfig(); - AbstractConfiguration configuration = - (AbstractConfiguration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.addProperty(REQUEST_TIMEOUT_KEY, 2000); - + public static void setup() { new MockUp() { @Mock long nanoTime() { @@ -93,188 +59,48 @@ long nanoTime() { }; } + @AfterClass + public static void teardown() { + + } + + @Before + public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty(REQUEST_TIMEOUT_KEY, long.class, (long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT)) + .thenReturn((long) 2000); + Mockito.when(environment.getProperty("servicecomb.highway.client.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.client.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.server.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.server.thread-count", int.class, -1)) + .thenReturn(-1); + } + @Test - public void testRequestTimeout() { - Assert.assertEquals(AbstractTransport.getReqTimeout("sayHi", "hello", "test"), 2000); + public void testLoginTimeout(@Mocked Vertx vertx) { + TcpClientConfig tcpClientConfig = client.createTcpClientConfig(); + Assertions.assertEquals(2000, tcpClientConfig.getMsLoginTimeout()); } @Test public void testHighwayClientSSL(@Mocked Vertx vertx) throws Exception { new MockUp() { @Mock - boolean blockDeploy(Vertx vertx, + Map blockDeploy(Vertx vertx, Class cls, DeploymentOptions options) { - return true; + Map result = new HashMap<>(); + result.put("code", true); + return result; } }; client.init(vertx); ClientPoolManager clientMgr = Deencapsulation.getField(client, "clientMgr"); - Assert.assertSame(vertx, Deencapsulation.getField(clientMgr, "vertx")); - } - - private Object doTestSend(Vertx vertx, HighwayClientConnectionPool pool, HighwayClientConnection tcpClient, - Object decodedResponse) throws Exception { - new MockUp() { - @Mock - boolean blockDeploy(Vertx vertx, - Class cls, - DeploymentOptions options) { - return true; - } - }; - - new MockUp>() { - @Mock - public HighwayClientConnectionPool findClientPool(boolean sync) { - return pool; - } - }; - - new MockUp() { - @Mock - public OperationProtobuf getOrCreateOperation(OperationMeta operationMeta) { - return operationProtobuf; - } - }; - - new MockUp() { - @Mock - HighwayClientConnection findOrCreateClient(String endpoint) { - return tcpClient; - } - }; - - new MockUp() { - @Mock - public Buffer encodeRequest(Invocation invocation, OperationProtobuf operationProtobuf, - long msgId) { - return null; - } - - @Mock - Response decodeResponse(Invocation invocation, OperationProtobuf operationProtobuf, TcpData tcpData) - throws Throwable { - if (decodedResponse instanceof Response) { - return (Response) decodedResponse; - } - - throw (Throwable) decodedResponse; - } - }; - - client.init(vertx); - - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(invocation.getEndpoint()).thenReturn(endpoint); - Mockito.when(invocation.getEndpoint().getEndpoint()).thenReturn("endpoint"); - Mockito.when(invocation.getResponseExecutor()).thenReturn(new ReactiveExecutor()); - Mockito.when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); - - Holder result = new Holder<>(); - client.send(invocation, ar -> { - result.value = ar.getResult(); - }); - - return result.value; - } - - @Test - public void testSend_success(@Mocked Vertx vertx, @Mocked HighwayClientConnectionPool pool, - @Mocked HighwayClientConnection tcpClient) throws Exception { - new MockUp() { - @Mock - void send(AbstractTcpClientPackage tcpClientPackage, TcpResponseCallback callback) { - callback.success(null); - } - }; - new MockUp() { - @Mock - public long getFinishWriteToBuffer() { - return nanoTime; - } - }; - Object result = doTestSend(vertx, pool, tcpClient, Response.ok("ok")); - - Assert.assertEquals("ok", result); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishClientFiltersResponse()); - - Assert.assertEquals(nanoTime, invocationStageTrace.getStartSend()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishGetConnection()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishWriteToBuffer()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishReceiveResponse()); - } - - @Test - public void testSend_success_decode_failed(@Mocked Vertx vertx, @Mocked HighwayClientConnectionPool pool, - @Mocked HighwayClientConnection tcpClient) throws Exception { - new MockUp() { - @Mock - void send(AbstractTcpClientPackage tcpClientPackage, TcpResponseCallback callback) { - callback.success(null); - } - }; - - Object result = doTestSend(vertx, pool, tcpClient, new InvocationException(Status.BAD_REQUEST, (Object) "failed")); - - Assert.assertEquals("failed", ((InvocationException) result).getErrorData()); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishClientFiltersResponse()); - } - - @Test - public void testSend_failed(@Mocked Vertx vertx, @Mocked HighwayClientConnectionPool pool, - @Mocked HighwayClientConnection tcpClient) throws Exception { - new MockUp() { - @Mock - void send(AbstractTcpClientPackage tcpClientPackage, TcpResponseCallback callback) { - callback.fail(new InvocationException(Status.BAD_REQUEST, (Object) "failed")); - } - }; - - Object result = doTestSend(vertx, - pool, - tcpClient, - null); - - Assert.assertEquals("failed", ((InvocationException) result).getErrorData()); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocationStageTrace.getStartClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocationStageTrace.getFinishClientFiltersResponse()); - } - - @Test - public void testCreateLogin(@Mocked NetClientWrapper netClientWrapper) throws Exception { - ProtobufCompatibleUtils.init(); - - HighwayClientConnection connection = - new HighwayClientConnection(null, netClientWrapper, "highway://127.0.0.1:7890"); - TcpOutputStream os = connection.createLogin(); - ByteBuf buf = os.getBuffer().getByteBuf(); - - byte[] magic = new byte[TcpParser.TCP_MAGIC.length]; - buf.readBytes(magic); - Assert.assertArrayEquals(TcpParser.TCP_MAGIC, magic); - Assert.assertEquals(os.getMsgId(), buf.readLong()); - - int start = TcpParser.TCP_HEADER_LENGTH; - int totalLen = buf.readInt(); - int headerLen = buf.readInt(); - Buffer headerBuffer = - os.getBuffer().slice(start, start + headerLen); - int end = start + totalLen; - start += headerLen; - Buffer bodyBuffer = os.getBuffer().slice(start, end); - - RequestHeader header = RequestHeader.readObject(headerBuffer); - Assert.assertEquals(MsgType.LOGIN, header.getMsgType()); - - LoginRequest login = LoginRequest.readObject(bodyBuffer); - Assert.assertEquals(Const.HIGHWAY, login.getProtocol()); + Assertions.assertSame(vertx, Deencapsulation.getField(clientMgr, "vertx")); } } diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayCodec.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayCodec.java deleted file mode 100644 index ad3feddc808..00000000000 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayCodec.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.highway; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.codec.protobuf.utils.schema.NotWrapSchema; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.vertx.client.tcp.TcpData; -import org.apache.servicecomb.foundation.vertx.server.TcpParser; -import org.apache.servicecomb.foundation.vertx.tcp.TcpOutputStream; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.transport.highway.message.RequestHeader; -import org.apache.servicecomb.transport.highway.message.ResponseHeader; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import io.netty.buffer.ByteBuf; -import io.protostuff.Input; -import io.protostuff.runtime.ProtobufCompatibleUtils; -import io.vertx.core.buffer.Buffer; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestHighwayCodec { - - private RequestHeader header = null; - - private OperationProtobuf operationProtobuf = null; - - private Buffer bodyBuffer = null; - - private WrapSchema schema = null; - - private SchemaMeta schemaMeta = null; - - private OperationMeta operationMeta = null; - - private ByteBuf lByteBuf = null; - - private ByteBuffer nioBuffer = null; - - private Invocation invocation = null; - - @BeforeClass - public static void setupClass() { - ProtobufCompatibleUtils.init(); - } - - @Before - public void setUp() { - ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); - serviceRegistry.init(); - RegistryUtils.setServiceRegistry(serviceRegistry); - - header = Mockito.mock(RequestHeader.class); - - operationProtobuf = Mockito.mock(OperationProtobuf.class); - - bodyBuffer = Mockito.mock(Buffer.class); - - schema = Mockito.mock(WrapSchema.class); - - schemaMeta = Mockito.mock(SchemaMeta.class); - - operationMeta = Mockito.mock(OperationMeta.class); - - lByteBuf = Mockito.mock(ByteBuf.class); - - nioBuffer = Mockito.mock(ByteBuffer.class); - - invocation = Mockito.mock(Invocation.class); - } - - @After - public void tearDown() { - - header = null; - - operationProtobuf = null; - - bodyBuffer = null; - - schema = null; - - schemaMeta = null; - - operationMeta = null; - - lByteBuf = null; - - nioBuffer = null; - - invocation = null; - } - - @Test - public void testDecodeRequest(@Mocked Endpoint endpoint) throws Exception { - commonMock(); - Mockito.when(schemaMeta.getProviderHandlerChain()).thenReturn(Collections.emptyList()); - Object[] args = new Object[] {}; - Mockito.when(schema.readObject(bodyBuffer)).thenReturn(args); - - Invocation invocation = new Invocation(endpoint, operationMeta, null); - - HighwayCodec.decodeRequest(invocation, header, operationProtobuf, bodyBuffer); - - Assert.assertSame(args, invocation.getSwaggerArguments()); - } - - @Test - public void testDecodeResponse() throws Exception { - Invocation invocation = Mockito.mock(Invocation.class); - Mockito.when(operationProtobuf.findResponseSchema(200)).thenReturn(Mockito.mock(WrapSchema.class)); - - Map context = new HashMap<>(); - Mockito.when(invocation.getContext()).thenReturn(context); - - TcpData tcpData = Mockito.mock(TcpData.class); - - Mockito.when(tcpData.getHeaderBuffer()).thenReturn(bodyBuffer); - commonMock(); - - ResponseHeader header = new ResponseHeader(); - header.setStatusCode(200); - header.setContext(new HashMap<>()); - header.getContext().put("a", "10"); - Buffer responseBuf = HighwayCodec.encodeResponse(0, header, null, null); - - TcpData tcp = new TcpData(responseBuf.slice(23, responseBuf.length()), null); - Response response = HighwayCodec.decodeResponse(invocation, operationProtobuf, tcp); - Assert.assertEquals("10", invocation.getContext().get("a")); - Assert.assertEquals(200, response.getStatusCode()); - } - - @Test - public void testDecodeRequestTraceId(@Mocked Endpoint endpoint) throws Exception { - commonMock(); - - Invocation invocation = new Invocation(endpoint, operationMeta, null); - - invocation.addContext("X-B3-traceId", "test1"); - Assert.assertEquals("test1", invocation.getContext("X-B3-traceId")); - - RequestHeader headers = new RequestHeader(); - Map context = new HashMap<>(); - headers.setContext(context); - HighwayCodec.decodeRequest(invocation, headers, operationProtobuf, bodyBuffer); - Assert.assertEquals("test1", invocation.getContext("X-B3-traceId")); - - context.put("X-B3-traceId", "test2"); - HighwayCodec.decodeRequest(invocation, headers, operationProtobuf, bodyBuffer); - Assert.assertEquals("test2", invocation.getContext("X-B3-traceId")); - } - - @Test - public void testEncodeResponse() { - boolean status = true; - WrapSchema bodySchema = Mockito.mock(WrapSchema.class); - try { - commonMock(); - HighwayCodec.encodeResponse(23432142, null, bodySchema, new Object()); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testEncodeRequest() { - boolean status = true; - try { - commonMock(); - TcpOutputStream os = HighwayCodec.encodeRequest(0, invocation, operationProtobuf); - Assert.assertNotNull(os); - Assert.assertArrayEquals(TcpParser.TCP_MAGIC, os.getBuffer().getBytes(0, 7)); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - @Test - public void testReadRequestHeader() { - boolean status = true; - try { - new MockUp() { - @Mock - public Object readObject(Input input) throws IOException { - return new RequestHeader(); - } - }; - bodyBuffer = Buffer.buffer("\"abc\""); - RequestHeader requestHeader = HighwayCodec.readRequestHeader(bodyBuffer); - Assert.assertNotNull(requestHeader); - Assert.assertEquals(0, requestHeader.getFlags()); - } catch (Exception e) { - status = false; - } - Assert.assertTrue(status); - } - - private void commonMock() { - Mockito.when(operationProtobuf.getRequestSchema()).thenReturn(schema); - Mockito.when(bodyBuffer.getByteBuf()).thenReturn(lByteBuf); - Mockito.when(lByteBuf.nioBuffer()).thenReturn(nioBuffer); - Mockito.when(operationProtobuf.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); - } -} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayConfig.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayConfig.java deleted file mode 100644 index 31889e5bced..00000000000 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.highway; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - -public class TestHighwayConfig { - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); - } - @Test - public void getServerThreadCount() { - Assert.assertEquals(HighwayConfig.getServerThreadCount(), 1); - } - - @Test - public void getClientThreadCount() { - Assert.assertEquals(HighwayConfig.getClientThreadCount(), 1); - } - - @Test - public void getAddress() { - Assert.assertEquals(HighwayConfig.getAddress(), null); - } - - @Test - public void testTimeoutConfig() { - Assert.assertEquals(HighwayConfig.getRequestWaitInPoolTimeout(), 30000); - ArchaiusUtils.setProperty(HighwayConfig.KEY_SERVICECOMB_REQUEST_WAIT_IN_POOL_TIMEOUT, 50000); - Assert.assertEquals(HighwayConfig.getRequestWaitInPoolTimeout(), 50000); - } -} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerConnection.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerConnection.java deleted file mode 100644 index 5375b0a46d1..00000000000 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerConnection.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.transport.highway; - -import java.net.InetSocketAddress; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.codec.protobuf.definition.ProtobufManager; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.definition.MicroserviceMeta; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream; -import org.apache.servicecomb.transport.highway.message.LoginRequest; -import org.apache.servicecomb.transport.highway.message.RequestHeader; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufOutput; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.net.NetSocket; -import io.vertx.core.net.impl.NetSocketImpl; -import io.vertx.core.net.impl.SocketAddressImpl; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestHighwayServerConnection { - private static WrapSchema requestHeaderSchema = - ProtobufManager.getDefaultScopedProtobufSchemaManager().getOrCreateSchema(RequestHeader.class); - - private static WrapSchema setParameterRequestSchema = - ProtobufManager.getDefaultScopedProtobufSchemaManager().getOrCreateSchema(LoginRequest.class); - - HighwayServerConnection connection; - - @Mocked - Endpoint endpoint; - - @Mocked - NetSocketImpl netSocket; - - RequestHeader header = new RequestHeader(); - - @Before - public void init() { - new Expectations(CseContext.getInstance()) { - { - netSocket.remoteAddress(); - result = new SocketAddressImpl(new InetSocketAddress("127.0.0.1", 80)); - } - }; - connection = new HighwayServerConnection(endpoint); - connection.init(netSocket); - - header = new RequestHeader(); - } - - @Test - public void testInvalidMsgType() throws Exception { - header.setMsgType((byte) 100); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - try { - connection.handle(0, headerBuffer, null); - throw new Error("must error"); - } catch (Throwable e) { - Assert.assertEquals("Unknown tcp msgType 100", e.getMessage()); - } - } - - @Test - public void testReqeustHeaderError() throws Exception { - header.setMsgType(MsgType.LOGIN); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - headerBuffer.setByte(0, (byte) 100); - - connection.handle(0, headerBuffer, null); - - Assert.assertEquals(null, connection.getProtocol()); - Assert.assertEquals(null, connection.getZipName()); - } - - @Test - public void testSetParameterNormal() throws Exception { - header.setMsgType(MsgType.LOGIN); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - LoginRequest body = new LoginRequest(); - body.setProtocol("p"); - body.setZipName("z"); - Buffer bodyBuffer = createBuffer(setParameterRequestSchema, body); - - connection.handle(0, headerBuffer, bodyBuffer); - - Assert.assertEquals("p", connection.getProtocol()); - Assert.assertEquals("z", connection.getZipName()); - } - - @Test - public void testSetParameterError() throws Exception { - header.setMsgType(MsgType.LOGIN); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - LoginRequest body = new LoginRequest(); - body.setProtocol("p"); - body.setZipName("z"); - Buffer bodyBuffer = createBuffer(setParameterRequestSchema, body); - bodyBuffer.setByte(0, (byte) 100); - - connection.handle(0, headerBuffer, bodyBuffer); - - Assert.assertEquals(null, connection.getProtocol()); - Assert.assertEquals(null, connection.getZipName()); - } - - @Test - public void testRequestNormal(@Mocked MicroserviceMeta microserviceMeta, @Mocked OperationMeta operationMeta, - @Mocked SchemaMeta schemaMeta) throws Exception { - header.setMsgType(MsgType.REQUEST); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - Buffer bodyBuffer = Buffer.buffer(); - new Expectations(SCBEngine.class) { - { - SCBEngine.getInstance().getProducerMicroserviceMeta(); - result = microserviceMeta; - } - }; - new Expectations(CseContext.getInstance()) { - { - microserviceMeta.ensureFindSchemaMeta(header.getSchemaId()); - result = schemaMeta; - } - }; - - new Expectations(ProtobufManager.class) { - { - ProtobufManager.getOrCreateOperation(operationMeta); - result = null; - } - }; - - Holder holder = new Holder<>(); - new MockUp() { - @Mock - public boolean init(NetSocket netSocket, long msgId, - RequestHeader header, Buffer bodyBuffer) { - return true; - } - - @Mock - public void execute() { - holder.value = true; - } - }; - - connection.handle(0, headerBuffer, bodyBuffer); - - Assert.assertEquals(null, connection.getProtocol()); - Assert.assertEquals(null, connection.getZipName()); - Assert.assertEquals(true, holder.value); - } - - @Test - public void testRequestError() throws Exception { - header.setMsgType(MsgType.REQUEST); - Buffer headerBuffer = createBuffer(requestHeaderSchema, header); - - Buffer bodyBuffer = Buffer.buffer(); - - Holder holder = new Holder<>(false); - new MockUp() { - @Mock - public boolean init(NetSocket netSocket, long msgId, - RequestHeader header, Buffer bodyBuffer) { - return false; - } - }; - - connection.handle(0, headerBuffer, bodyBuffer); - - Assert.assertEquals(null, connection.getProtocol()); - Assert.assertEquals(null, connection.getZipName()); - Assert.assertEquals(false, holder.value); - } - - protected Buffer createBuffer(WrapSchema schema, Object value) throws Exception { - Buffer headerBuffer; - LinkedBuffer linkedBuffer = LinkedBuffer.allocate(); - ProtobufOutput output = new ProtobufOutput(linkedBuffer); - schema.writeObject(output, value); - try (BufferOutputStream os = new BufferOutputStream()) { - LinkedBuffer.writeTo(os, linkedBuffer); - - headerBuffer = os.getBuffer(); - } - return headerBuffer; - } -} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerInvoke.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerInvoke.java deleted file mode 100644 index b4e202b95ac..00000000000 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayServerInvoke.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.highway; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.Handler; -import org.apache.servicecomb.core.SCBEngine; -import org.apache.servicecomb.core.SCBStatus; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.apache.servicecomb.core.event.InvocationFinishEvent; -import org.apache.servicecomb.core.event.InvocationStartEvent; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.apache.servicecomb.core.unittest.UnitTestMeta; -import org.apache.servicecomb.foundation.common.event.EventManager; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.foundation.vertx.tcp.TcpConnection; -import org.apache.servicecomb.swagger.invocation.context.HttpStatus; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.transport.common.MockUtil; -import org.apache.servicecomb.transport.highway.message.RequestHeader; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; - -import io.netty.buffer.ByteBuf; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.net.NetSocket; -import io.vertx.core.net.SocketAddress; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class TestHighwayServerInvoke { - class Impl { - public int add(int x, int y) { - return x + y; - } - } - - private static UnitTestMeta unitTestMeta; - - private ByteBuf netSocketBuffer; - - private TcpConnection connection; - - private NetSocket netSocket; - - private SocketAddress socketAddress; - - static long nanoTime = 1; - - @BeforeClass - public static void classSetup() { - EventManager.eventBus = new EventBus(); - SCBEngine.getInstance().setStatus(SCBStatus.UP); - unitTestMeta = new UnitTestMeta(); - - new MockUp() { - @Mock - long nanoTime() { - return nanoTime; - } - }; - } - - @AfterClass - public static void classTeardown() { - EventManager.eventBus = new EventBus(); - SCBEngine.getInstance().setStatus(SCBStatus.DOWN); - } - - @Before - public void setup() { - socketAddress = new MockUp() { - @Mock - public String host() { - return "127.0.0.1"; - } - - @Mock - public int port() { - return 8080; - } - }.getMockInstance(); - netSocket = new MockUp() { - @Mock - public SocketAddress remoteAddress() { - return socketAddress; - } - }.getMockInstance(); - connection = new MockUp() { - @Mock - public void write(ByteBuf data) { - netSocketBuffer = data; - } - - @Mock - public NetSocket getNetSocket() { - return netSocket; - } - }.getMockInstance(); - } - - @Test - public void test() { - Holder startHolder = new Holder<>(); - Holder finishHolder = new Holder<>(); - Object subscriber = new Object() { - @Subscribe - public void onStart(InvocationStartEvent event) { - startHolder.value = event; - } - - @Subscribe - public void onFinish(InvocationFinishEvent event) { - finishHolder.value = event; - } - }; - EventManager.register(subscriber); - - MockUtil.getInstance().mockHighwayCodec(); - - SchemaMeta schemaMeta = unitTestMeta.getOrCreateSchemaMeta(Impl.class); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("add"); - operationMeta.setExecutor(new ReactiveExecutor()); - - HighwayServerInvoke highwayServerInvoke = new HighwayServerInvoke(); - - RequestHeader requestHeader = MockUtil.getInstance().requestHeader; - - // 初始化失败 - requestHeader.setDestMicroservice(null); - Assert.assertFalse(highwayServerInvoke.init(connection, 0, null, null)); - - // 初始化成功 - requestHeader.setDestMicroservice(schemaMeta.getMicroserviceName()); - requestHeader.setSchemaId(schemaMeta.getSchemaId()); - requestHeader.setOperationName(operationMeta.getOperationId()); - assertTrue(highwayServerInvoke.init(connection, 0, requestHeader, null)); - - // exe失败 - MockUtil.getInstance().decodeRequestSucc = false; - highwayServerInvoke.execute(); - EventManager.unregister(subscriber); - - assertTrue(Buffer.buffer(netSocketBuffer).toString().startsWith("CSE.TCP")); - assertSame(highwayServerInvoke.invocation, startHolder.value.getInvocation()); - assertSame(highwayServerInvoke.invocation, finishHolder.value.getInvocation()); - assertTrue(highwayServerInvoke.invocation.getInvocationStageTrace().getStartExecution() != 0); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getStart()); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getStartHandlersRequest()); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getFinishHandlersResponse()); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getStartSchedule()); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getStartHandlersRequest()); - assertEquals(1, highwayServerInvoke.invocation.getInvocationStageTrace().getFinishHandlersResponse()); - } - - @Test - public void testFlowControlQps() { - MockUtil.getInstance().mockHighwayCodec(); - SchemaMeta schemaMeta = unitTestMeta.getOrCreateSchemaMeta(Impl.class); - OperationMeta operationMeta = schemaMeta.ensureFindOperation("add"); - operationMeta.setExecutor(new ReactiveExecutor()); - Deencapsulation.setField(operationMeta, "providerQpsFlowControlHandlerSearched", true); - Deencapsulation.setField(operationMeta, "providerQpsFlowControlHandler", - (Handler) (invocation, asyncResp) -> asyncResp.producerFail(new InvocationException( - new HttpStatus(429, "Too Many Requests"), - new CommonExceptionData("rejected by qps flowcontrol")))); - - RequestHeader requestHeader = MockUtil.getInstance().requestHeader; - requestHeader.setDestMicroservice(schemaMeta.getMicroserviceName()); - requestHeader.setSchemaId(schemaMeta.getSchemaId()); - requestHeader.setOperationName(operationMeta.getOperationId()); - - HighwayServerInvoke highwayServerInvoke = new HighwayServerInvoke(); - - assertTrue(highwayServerInvoke.init(connection, 0, requestHeader, null)); - MockUtil.getInstance().decodeRequestSucc = true; - - ArchaiusUtils.setProperty("servicecomb.flowcontrol.Provider.qps.enabled", "true"); - ArchaiusUtils.setProperty("servicecomb.flowcontrol.Provider.qps.global.limit", "1"); - - highwayServerInvoke.execute(); - String bodyString = Buffer.buffer(netSocketBuffer).toString(); - assertTrue(bodyString.contains("Too Many Requests")); - assertTrue(bodyString.contains("rejected by qps flowcontrol")); - - ArchaiusUtils.resetConfig(); - } -} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayTransport.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayTransport.java index 8805379e3be..18d674f00f0 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayTransport.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayTransport.java @@ -17,64 +17,91 @@ package org.apache.servicecomb.transport.highway; -import javax.xml.ws.Holder; - import org.apache.servicecomb.codec.protobuf.definition.OperationProtobuf; -import org.apache.servicecomb.codec.protobuf.utils.WrapSchema; +import org.apache.servicecomb.codec.protobuf.definition.RequestRootSerializer; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.Assert; +import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConfig; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; -import mockit.Mock; -import mockit.MockUp; +import io.vertx.core.impl.SysProps; public class TestHighwayTransport { + private static final Logger LOGGER = LoggerFactory.getLogger(TestHighwayTransport.class); + + Environment environment = Mockito.mock(Environment.class); + + @BeforeClass + public static void setup() { + VertxUtils.blockCloseVertxByName("transport"); + Thread.getAllStackTraces().keySet().forEach(t -> LOGGER.info("before: {}", t.getName())); + } + + @AfterClass + public static void teardown() { + VertxUtils.blockCloseVertxByName("transport"); + Thread.getAllStackTraces().keySet().forEach(t -> LOGGER.info("after: {}", t.getName())); + } - private HighwayTransport transport = new HighwayTransport(); + @Before + public void setUp() { + Mockito.when(environment.getProperty( + "servicecomb.request.timeout", long.class, (long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT)) + .thenReturn((long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT); + Mockito.when(environment.getProperty("servicecomb.highway.client.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.client.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.server.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.highway.server.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + } @Test public void testGetInstance() { - Assert.assertNotNull(transport); + HighwayTransport transport = new HighwayTransport(); + Assertions.assertNotNull(transport); } @Test public void testInit() { + HighwayTransport transport = new HighwayTransport(); + transport.setEnvironment(environment); boolean status = true; try { transport.init(); } catch (Exception e) { + e.printStackTrace(); status = false; } - Assert.assertTrue(status); - } - - @Test - public void testSendException() throws Exception { - Invocation invocation = Mockito.mock(Invocation.class); - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - commonHighwayMock(invocation); - Holder sended = new Holder<>(false); - new MockUp() { - @Mock - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - sended.value = true; - } - }; - transport.send(invocation, asyncResp); - Assert.assertTrue(sended.value); + Assertions.assertTrue(status); } @Test public void testHighway() { + HighwayTransport transport = new HighwayTransport(); Invocation invocation = Mockito.mock(Invocation.class); commonHighwayMock(invocation); - Assert.assertEquals("highway", transport.getName()); + Assertions.assertEquals("highway", transport.getName()); } private void commonHighwayMock(Invocation invocation) { @@ -84,8 +111,8 @@ private void commonHighwayMock(Invocation invocation) { Mockito.when(operationMeta.getExtData("protobuf")).thenReturn(operationProtobuf); Endpoint lEndpoint = Mockito.mock(Endpoint.class); Mockito.when(invocation.getEndpoint()).thenReturn(lEndpoint); - WrapSchema lWrapSchema = Mockito.mock(WrapSchema.class); - Mockito.when(operationProtobuf.getRequestSchema()).thenReturn(lWrapSchema); + RequestRootSerializer lWrapSchema = Mockito.mock(RequestRootSerializer.class); + Mockito.when(operationProtobuf.getRequestRootSerializer()).thenReturn(lWrapSchema); URIEndpointObject ep = Mockito.mock(URIEndpointObject.class); Mockito.when(lEndpoint.getAddress()).thenReturn(ep); Mockito.when(ep.getHostOrIp()).thenReturn("127.0.0.1"); diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayVerticle.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayVerticle.java index f2ac8d6a1dd..e17ec8348f0 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayVerticle.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/TestHighwayVerticle.java @@ -17,18 +17,16 @@ package org.apache.servicecomb.transport.highway; -import static org.junit.Assert.assertTrue; - import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; import org.apache.servicecomb.transport.common.MockUtil; -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; import io.vertx.core.Context; -import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import mockit.Expectations; @@ -36,14 +34,14 @@ public class TestHighwayVerticle { @Test - public void testHighwayVerticle(@Mocked Transport transport, @Mocked Vertx vertx, @Mocked Context context, - @Mocked JsonObject json) { - HighwayServerVerticle highwayVerticle = new HighwayServerVerticle(); - URIEndpointObject endpiontObject = new URIEndpointObject("highway://127.0.0.1:9090"); + public void testHighwayVehicle(@Mocked Transport transport, @Mocked Vertx vertx, @Mocked Context context, + @Mocked JsonObject json) { + HighwayServerVerticle highwayVehicle = new HighwayServerVerticle(); + URIEndpointObject endpointObject = new URIEndpointObject("highway://127.0.0.1:9090"); new Expectations() { { transport.parseAddress(anyString); - result = endpiontObject; + result = endpointObject; } }; @@ -58,16 +56,16 @@ public void testHighwayVerticle(@Mocked Transport transport, @Mocked Vertx vertx } }; - highwayVerticle.init(vertx, context); + highwayVehicle.init(vertx, context); @SuppressWarnings("unchecked") - Future startFuture = Mockito.mock(Future.class); - highwayVerticle.startListen(startFuture); + Promise startPromise = Mockito.mock(Promise.class); + highwayVehicle.startListen(startPromise); MockUtil.getInstance().mockHighwayConfig(); try { - highwayVerticle.startListen(startFuture); - assertTrue(true); + highwayVehicle.startListen(startPromise); + Assertions.assertTrue(true); } catch (Exception e) { - Assert.fail(); + Assertions.fail(); } } } diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestHeaders.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestHeaders.java new file mode 100644 index 00000000000..d51100bae04 --- /dev/null +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestHeaders.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.highway.message; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestHeaders { + @Test + public void test1() { + Headers headers = new Headers(); + Assertions.assertNull(headers.getFirst("h1")); + Assertions.assertNull(headers.getHeader("h1")); + + Map> headerMap = new HashMap<>(); + List h1Value = Arrays.asList("h1v1", "h1v2"); + headerMap.put("h1", h1Value); + headerMap.put("h2", null); + headerMap.put("h3", Arrays.asList()); + headers.setHeaderMap(headerMap); + + Assertions.assertEquals(headerMap, headers.getHeaderMap()); + Assertions.assertEquals("h1v1", headers.getFirst("h1")); + Assertions.assertNull(headers.getFirst("h2")); + Assertions.assertNull(headers.getFirst("h3")); + Assertions.assertEquals(h1Value, headers.getHeader("h1")); + } + + @Test + public void test2() { + Headers headers = new Headers(); + headers.addHeader("h1", "h1v1"); + headers.addHeader("h1", "h1v2"); + + Assertions.assertEquals("h1v1", headers.getFirst("h1")); + } + + @Test + public void addHeader_list() { + Headers headers = new Headers(); + headers.addHeader("h", Arrays.asList("v1", "v2")); + headers.addHeader("h", Arrays.asList("v3")); + + MatcherAssert.assertThat(headers.getHeader("h"), Matchers.contains("v1", "v2", "v3")); + } +} diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginRequest.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginRequest.java index 48f690d7066..13b12900005 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginRequest.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginRequest.java @@ -16,8 +16,8 @@ */ package org.apache.servicecomb.transport.highway.message; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestLoginRequest { @Test @@ -26,7 +26,7 @@ public void test() { req.setProtocol("p"); req.setZipName("z"); - Assert.assertEquals("p", req.getProtocol()); - Assert.assertEquals("z", req.getZipName()); + Assertions.assertEquals("p", req.getProtocol()); + Assertions.assertEquals("z", req.getZipName()); } } diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginResponse.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginResponse.java index 464b819585d..45132c4dc8c 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginResponse.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestLoginResponse.java @@ -16,8 +16,8 @@ */ package org.apache.servicecomb.transport.highway.message; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class TestLoginResponse { @Test @@ -26,7 +26,7 @@ public void test() { resp.setProtocol("p"); resp.setZipName("z"); - Assert.assertEquals("p", resp.getProtocol()); - Assert.assertEquals("z", resp.getZipName()); + Assertions.assertEquals("p", resp.getProtocol()); + Assertions.assertEquals("z", resp.getZipName()); } } diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestRequestHeader.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestRequestHeader.java index 5b5633919dd..01be0df7943 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestRequestHeader.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestRequestHeader.java @@ -20,9 +20,9 @@ import java.util.Map; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestRequestHeader { @@ -43,33 +43,33 @@ public void testContext() { Map context = null; requestHeader.setContext(context); - Assert.assertNull(requestHeader.getContext()); + Assertions.assertNull(requestHeader.getContext()); } @Test public void testDestMicroservice() { requestHeader.setDestMicroservice("test"); - Assert.assertEquals("test", requestHeader.getDestMicroservice()); + Assertions.assertEquals("test", requestHeader.getDestMicroservice()); } @Test public void testFlags() { requestHeader.setFlags(1); - Assert.assertEquals(1, requestHeader.getFlags()); + Assertions.assertEquals(1, requestHeader.getFlags()); } @Test public void testOperationName() { requestHeader.setOperationName("cse"); - Assert.assertEquals("cse", requestHeader.getOperationName()); + Assertions.assertEquals("cse", requestHeader.getOperationName()); } @Test public void testSchemaId() { requestHeader.setSchemaId("id"); - Assert.assertEquals("id", requestHeader.getSchemaId()); + Assertions.assertEquals("id", requestHeader.getSchemaId()); } } diff --git a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestResponseHeader.java b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestResponseHeader.java index 9d9ac5155d7..f5a6ffef9c9 100644 --- a/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestResponseHeader.java +++ b/transports/transport-highway/src/test/java/org/apache/servicecomb/transport/highway/message/TestResponseHeader.java @@ -21,9 +21,9 @@ import java.util.Map; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; public class TestResponseHeader { @@ -45,7 +45,7 @@ public void tearDown() throws Exception { public void testSetContext() { context.put("key1", "v1"); responseHeader.setContext(context); - Assert.assertNotNull(responseHeader.getContext()); - Assert.assertEquals("v1", responseHeader.getContext().get("key1")); + Assertions.assertNotNull(responseHeader.getContext()); + Assertions.assertEquals("v1", responseHeader.getContext().get("key1")); } } diff --git a/transports/transport-highway/src/test/resources/log4j.properties b/transports/transport-highway/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/transports/transport-highway/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/transports/transport-rest/pom.xml b/transports/transport-rest/pom.xml index 6c7651664a0..933e7c8858c 100644 --- a/transports/transport-rest/pom.xml +++ b/transports/transport-rest/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb transports - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT transport-rest Java Chassis::Transports::Rest diff --git a/transports/transport-rest/transport-rest-client/pom.xml b/transports/transport-rest/transport-rest-client/pom.xml index 8fda177b692..49175b2140a 100644 --- a/transports/transport-rest/transport-rest-client/pom.xml +++ b/transports/transport-rest/transport-rest-client/pom.xml @@ -22,16 +22,24 @@ org.apache.servicecomb transport-rest - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT transport-rest-client Java Chassis::Transports::Rest::Client + + io.vertx + vertx-rx-java3 + org.apache.servicecomb foundation-vertx + + org.apache.servicecomb + transport-common + org.apache.servicecomb common-rest @@ -42,15 +50,15 @@ vertx-codegen provided - + - org.slf4j - slf4j-log4j12 + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test @@ -58,5 +66,25 @@ foundation-test-scaffolding test + + org.apache.servicecomb + registry-local + test + + + org.apache.servicecomb + swagger-generator-jaxrs + test + + + org.apache.commons + commons-text + test + + + org.jmockit + jmockit + test + diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java new file mode 100644 index 00000000000..d50193b4aba --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/BoundaryFactory.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +public interface BoundaryFactory { + String BOUNDARY_PREFIX = "boundary-" + UUID.randomUUID() + "-"; + + AtomicLong BOUNDARY_INDEX = new AtomicLong(); + + BoundaryFactory DEFAULT = () -> BOUNDARY_PREFIX + BOUNDARY_INDEX.getAndIncrement(); + + String create(); +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/Http2TransportHttpClientOptionsSPI.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/Http2TransportHttpClientOptionsSPI.java new file mode 100644 index 00000000000..cfa6e9356be --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/Http2TransportHttpClientOptionsSPI.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.client; + +import io.vertx.core.http.HttpVersion; + +public class Http2TransportHttpClientOptionsSPI extends HttpTransportHttpClientOptionsSPI { + public static final String CLIENT_NAME = "http2-transport-client"; + + @Override + public String clientName() { + return CLIENT_NAME; + } + + @Override + public int getOrder() { + return super.getOrder() + 1; + } + + @Override + public boolean enabled() { + return TransportClientConfig.isHttp2TransportClientEnabled(); + } + + @Override + public HttpVersion getHttpVersion() { + return HttpVersion.HTTP_2; + } + + @Override + public String getWorkerPoolName() { + return "pool-worker-transport-client-http2"; + } + + @Override + public boolean isUseAlpn() { + return TransportClientConfig.getUseAlpn(); + } + + @Override + public int getHttp2MultiplexingLimit() { + return TransportClientConfig.getHttp2MultiplexingLimit(); + } + + @Override + public int getHttp2MaxPoolSize() { + return TransportClientConfig.getHttp2ConnectionMaxPoolSize(); + } + + @Override + public int getIdleTimeoutInSeconds() { + return TransportClientConfig.getHttp2ConnectionIdleTimeoutInSeconds(); + } + + @Override + public int getKeepAliveTimeout() { + return TransportClientConfig.getHttp2ConnectionKeepAliveTimeoutInSeconds(); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpClientRequestFactory.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpClientRequestFactory.java new file mode 100644 index 00000000000..8b2f3afc136 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpClientRequestFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import org.apache.servicecomb.core.Invocation; + +import io.vertx.core.Future; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.RequestOptions; + +/** + * some service has special domain name rule, eg: k8s
+ * assume k8s domain name is https://k8s.com:1234, and clusterId is my-id
+ * then must send request to https://my-id.k8s.com:1234
+ *
+ * this interface allowed to modify host by invocation argument, eg:
+ *
+ * {@code
+ *  Future create(Invocation invocation, HttpClient httpClient, HttpMethod method, RequestOptions options) {
+ *    if ("k8s".equals(invocation.getMicroserviceName())) {
+ *      options.setHost(invocation.getSwaggerArgument("clusterId") + "." + options.getHost());
+ *    }
+ *
+ *    return httpClient.request(options);
+ *  }
+ * }
+ * 
+ */ +public interface HttpClientRequestFactory { + HttpClientRequestFactory DEFAULT = (invocation, httpClient, options) -> httpClient.request(options); + + Future create(Invocation invocation, HttpClient httpClient, RequestOptions options) + throws Throwable; +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpTransportHttpClientOptionsSPI.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpTransportHttpClientOptionsSPI.java new file mode 100644 index 00000000000..1091167ceed --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/HttpTransportHttpClientOptionsSPI.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.client; + +import org.apache.servicecomb.foundation.vertx.client.http.HttpClientOptionsSPI; + +import io.vertx.core.VertxOptions; +import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.HttpVersion; +import io.vertx.core.http.PoolOptions; + +public class HttpTransportHttpClientOptionsSPI implements HttpClientOptionsSPI { + public static final String CLIENT_NAME = "http-transport-client"; + + public static final String CLIENT_TAG = "rest.consumer"; + + @Override + public String clientName() { + return CLIENT_NAME; + } + + @Override + public int getOrder() { + return 100; + } + + @Override + public boolean enabled() { + return TransportClientConfig.isHttpTransportClientEnabled(); + } + + @Override + public String getConfigTag() { + return CLIENT_TAG; + } + + @Override + public int getEventLoopPoolSize() { + // not reading this, using shared transport vert.x + return -1; + } + + @Override + public boolean useSharedVertx() { + return true; + } + + @Override + public int getInstanceCount() { + return TransportClientConfig.getThreadCount(); + } + + @Override + public boolean isWorker() { + return false; + } + + @Override + public String getWorkerPoolName() { + return "pool-worker-transport-client-http"; + } + + @Override + public int getWorkerPoolSize() { + return VertxOptions.DEFAULT_WORKER_POOL_SIZE; + } + + @Override + public HttpVersion getHttpVersion() { + return HttpVersion.HTTP_1_1; + } + + @Override + public int getConnectTimeoutInMillis() { + return TransportClientConfig.getConnectionTimeoutInMillis(); + } + + @Override + public int getIdleTimeoutInSeconds() { + return TransportClientConfig.getConnectionIdleTimeoutInSeconds(); + } + + @Override + public boolean isTryUseCompression() { + return TransportClientConfig.getConnectionCompression(); + } + + @Override + public int getMaxWaitQueueSize() { + return TransportClientConfig.getMaxWaitQueueSize(); + } + + @Override + public int getMaxPoolSize() { + return TransportClientConfig.getConnectionMaxPoolSize(); + } + + @Override + public boolean isKeepAlive() { + return TransportClientConfig.getConnectionKeepAlive(); + } + + @Override + public int getMaxHeaderSize() { + return TransportClientConfig.getMaxHeaderSize(); + } + + @Override + public int getKeepAliveTimeout() { + return TransportClientConfig.getConnectionKeepAliveTimeoutInSeconds(); + } + + @Override + public boolean enableLogActivity() { + return TransportClientConfig.enableLogActivity(); + } + + @Override + public int getHttp2MultiplexingLimit() { + return HttpClientOptions.DEFAULT_HTTP2_MULTIPLEXING_LIMIT; + } + + @Override + public int getHttp2MaxPoolSize() { + return PoolOptions.DEFAULT_HTTP2_MAX_POOL_SIZE; + } + + @Override + public boolean isUseAlpn() { + return !HttpClientOptions.DEFAULT_ALPN_VERSIONS.isEmpty(); + } + + @Override + public boolean isProxyEnable() { + // now transport proxy not implemented + return false; + } + + @Override + public String getProxyHost() { + return null; + } + + @Override + public int getProxyPort() { + return 0; + } + + @Override + public String getProxyUsername() { + return null; + } + + @Override + public String getProxyPassword() { + return null; + } + + @Override + public boolean isSsl() { + return true; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java new file mode 100644 index 00000000000..72ff3f00e85 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; +import org.springframework.beans.factory.annotation.Autowired; + +import io.vertx.core.http.HttpClientRequest; + +public class RestClientCodecFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + public static final String NAME = "rest-client-codec"; + + protected RestClientTransportContextFactory transportContextFactory; + + protected RestClientEncoder encoder; + + protected RestClientDecoder decoder; + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.RESTFUL.equals(transport); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 1990; + } + + @Autowired + public RestClientCodecFilter setTransportContextFactory(RestClientTransportContextFactory transportContextFactory) { + this.transportContextFactory = transportContextFactory; + return this; + } + + @Autowired + public RestClientCodecFilter setEncoder(RestClientEncoder encoder) { + this.encoder = encoder; + return this; + } + + @Autowired + public RestClientCodecFilter setDecoder(RestClientDecoder decoder) { + this.decoder = decoder; + return this; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + invocation.getInvocationStageTrace().startConsumerConnection(); + CompletionStage createRequest = + transportContextFactory.createHttpClientRequest(invocation).toCompletionStage() + .whenComplete((c, e) -> invocation.getInvocationStageTrace().finishConsumerConnection()); + return CompletableFuture.completedFuture(null) + .thenCompose(v -> createRequest) + .thenAccept(httpClientRequest -> prepareTransportContext(invocation, httpClientRequest)) + .thenAccept(v -> invocation.onStartSendRequest()) + .thenAccept(v -> encoder.encode(invocation)) + .thenCompose(v -> nextNode.onFilter(invocation)) + .thenApply(response -> decoder.decode(invocation, response)); + } + + protected void prepareTransportContext(Invocation invocation, HttpClientRequest httpClientRequest) { + copyExtraHttpHeaders(invocation, httpClientRequest); + + RestClientTransportContext transportContext = transportContextFactory.create(invocation, httpClientRequest); + invocation.setTransportContext(transportContext); + } + + @SuppressWarnings("unchecked") + protected void copyExtraHttpHeaders(Invocation invocation, HttpClientRequest httpClientRequest) { + Map httpHeaders = (Map) invocation.getHandlerContext() + .get(RestConst.CONSUMER_HEADER); + if (httpHeaders == null) { + return; + } + httpHeaders.forEach((key, value) -> { + if ("Content-Length".equalsIgnoreCase(key)) { + return; + } + if (null != value) { + httpClientRequest.putHeader(key, value); + } + }); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java new file mode 100644 index 00000000000..a2534d85450 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import static org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_DECODE_REST_FAIL_RESPONSE; +import static org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_DECODE_REST_SUCCESS_RESPONSE; + +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; +import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.exception.Exceptions; +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JavaType; + +import io.reactivex.rxjava3.core.Flowable; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientRequest; +import jakarta.ws.rs.core.HttpHeaders; + +public class RestClientDecoder { + private static final Logger LOGGER = LoggerFactory.getLogger(RestClientDecoder.class); + + public Response decode(Invocation invocation, Response response) { + invocation.getInvocationStageTrace().startConsumerDecodeResponse(); + if (response.getResult() instanceof Buffer) { + Object result = extractBody(invocation, response, response.getResult()); + response.setResult(result); + + if (response.isFailed()) { + throw Exceptions.create(response.getStatus(), response.getResult()); + } + } + + if (response.getResult() instanceof Flowable) { + Flowable flowable = response.getResult(); + Flowable encoded = flowable.map(buffer -> extractBody(invocation, response, buffer)); + response.setResult(encoded); + } + + invocation.getInvocationStageTrace().finishConsumerDecodeResponse(); + return response; + } + + protected Object extractBody(Invocation invocation, Response response, Buffer buffer) { + ProduceProcessor produceProcessor = safeFindProduceProcessor(invocation, response); + JavaType responseType = invocation.findResponseType(response.getStatusCode()); + + try { + return produceProcessor.decodeResponse(buffer, responseType); + } catch (Exception e) { + throw createDecodeException(invocation, response, e); + } + } + + private ProduceProcessor safeFindProduceProcessor(Invocation invocation, Response response) { + String contentType = extractContentType(response); + ProduceProcessor produceProcessor = + ProduceProcessorManager.INSTANCE.createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(), + contentType, null); + if (produceProcessor != null) { + return produceProcessor; + } + + RestClientTransportContext transportContext = invocation.getTransportContext(); + HttpClientRequest httpClientRequest = transportContext.getHttpClientRequest(); + LOGGER.warn( + "operation={}, method={}, endpoint={}, uri={}, statusCode={}, reasonPhrase={}, response content-type={} is not supported in operation.", + invocation.getMicroserviceQualifiedName(), + httpClientRequest.getMethod(), + invocation.getEndpoint().getEndpoint(), + httpClientRequest.getURI(), + response.getStatusCode(), + response.getReasonPhrase(), + response.getHeader(HttpHeaders.CONTENT_TYPE)); + + // This happens outside the runtime such as Servlet filter response. Here we give a default json parser to it + // and keep user data not get lost. + return ProduceProcessorManager.INSTANCE.findDefaultProcessor(); + } + + protected String extractContentType(Response response) { + String contentType = response.getHeader(HttpHeaders.CONTENT_TYPE); + if (contentType == null) { + return null; + } + + int idx = contentType.indexOf(";"); + return idx == -1 ? contentType : contentType.substring(0, idx); + } + + protected InvocationException createDecodeException(Invocation invocation, Response response, Exception e) { + RestClientTransportContext transportContext = invocation.getTransportContext(); + HttpClientRequest httpClientRequest = transportContext.getHttpClientRequest(); + + LOGGER.warn("failed to decode response body, " + + "operation={}, method={}, endpoint={}, uri={}, " + + "statusCode={}, reasonPhrase={}, content-type={}.", + invocation.getMicroserviceQualifiedName(), + httpClientRequest.getMethod(), + invocation.getEndpoint().getEndpoint(), + httpClientRequest.getURI(), + response.getStatusCode(), + response.getReasonPhrase(), + response.getHeader(HttpHeaders.CONTENT_TYPE)); + + if (response.isSucceed()) { + return Exceptions.consumer(FAILED_TO_DECODE_REST_SUCCESS_RESPONSE, "failed to decode success response body.", e); + } + return Exceptions.consumer(FAILED_TO_DECODE_REST_FAIL_RESPONSE, "failed to decode fail response body.", e); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java new file mode 100644 index 00000000000..cc16c832f08 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java @@ -0,0 +1,243 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import static jakarta.ws.rs.core.HttpHeaders.CONTENT_TYPE; +import static jakarta.ws.rs.core.MediaType.MULTIPART_FORM_DATA; +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_ENCODE_REST_CLIENT_REQUEST; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.servicecomb.common.rest.codec.RestCodec; +import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; +import org.apache.servicecomb.common.rest.codec.query.QueryCodec; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationConfig; +import org.apache.servicecomb.foundation.common.utils.StringBuilderUtils; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientRequest; +import jakarta.servlet.http.Part; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; + +/** + * encode all send data except upload + */ +public class RestClientEncoder { + private static final Logger LOGGER = LoggerFactory.getLogger(RestClientEncoder.class); + + public static final int FORM_BUFFER_SIZE = 1024; + + public void encode(Invocation invocation) { + try { + invocation.getInvocationStageTrace().startConsumerEncodeRequest(); + EncoderSession encoderSession = new EncoderSession(invocation); + encoderSession.doEncode(); + invocation.getInvocationStageTrace().finishConsumerEncodeRequest(); + } catch (Exception e) { + throw new InvocationException(BAD_REQUEST, FAILED_TO_ENCODE_REST_CLIENT_REQUEST, e.getMessage(), e); + } + } + + public static class EncoderSession { + protected final Invocation invocation; + + protected final RestClientTransportContext transportContext; + + protected final RestClientRequestParameters requestParameters; + + protected final HttpClientRequest httpClientRequest; + + public EncoderSession(Invocation invocation) { + this.invocation = invocation; + this.transportContext = invocation.getTransportContext(); + this.requestParameters = this.transportContext.getRequestParameters(); + this.httpClientRequest = this.transportContext.getHttpClientRequest(); + } + + protected void doEncode() throws Exception { + RestClientEncoder.LOGGER.debug("encode rest client request, operation={}, method={}, endpoint={}, uri={}.", + invocation.getMicroserviceQualifiedName(), + httpClientRequest.getMethod(), + invocation.getEndpoint().getEndpoint(), + httpClientRequest.getURI()); + + swaggerArgumentsToRequest(); + + writeCookies(requestParameters.getCookieMap()); + writeScbHeaders(); + writeForm(requestParameters.getFormMap()); + } + + protected void swaggerArgumentsToRequest() throws Exception { + RestCodec.argsToRest(invocation.getSwaggerArguments(), + transportContext.getRestOperationMeta(), requestParameters); + } + + protected void writeCookies(Map cookieMap) { + if (CollectionUtils.isEmpty(cookieMap)) { + return; + } + + StringBuilder builder = new StringBuilder(); + for (Entry entry : cookieMap.entrySet()) { + builder.append(entry.getKey()) + .append('=') + .append(entry.getValue()) + .append("; "); + } + StringBuilderUtils.deleteLast(builder, 2); + httpClientRequest.putHeader(HttpHeaders.COOKIE, builder.toString()); + } + + protected void writeScbHeaders() throws JsonProcessingException { + OperationConfig operationConfig = invocation.getOperationMeta().getConfig(); + if (operationConfig.isClientRequestHeaderFilterEnabled()) { + return; + } + + httpClientRequest.putHeader(CoreConst.TARGET_MICROSERVICE, invocation.getMicroserviceName()); + httpClientRequest.putHeader(CoreConst.CSE_CONTEXT, + RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(invocation.getContext())); + } + + protected void writeForm(Map formMap) throws Exception { + if (requestParameters.getUploads() == null) { + writeUrlEncodedForm(formMap); + return; + } + + writeChunkedForm(formMap); + } + + protected void writeUrlEncodedForm(Map formMap) throws Exception { + if (formMap == null) { + return; + } + + httpClientRequest.putHeader(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); + + Buffer bodyBuffer = genUrlEncodedFormBuffer(formMap); + requestParameters.setBodyBuffer(bodyBuffer); + } + + protected Buffer genUrlEncodedFormBuffer(Map formMap) throws Exception { + Buffer buffer = Buffer.buffer(RestClientEncoder.FORM_BUFFER_SIZE); + for (Entry entry : formMap.entrySet()) { + writeCharSequence(buffer, entry.getKey()); + buffer.appendByte(((byte) '=')); + + String value = QueryCodec.convertToString(entry.getValue()); + String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8); + writeCharSequence(buffer, encodedValue); + + buffer.appendByte(((byte) '&')); + } + + return buffer; + } + + protected void writeChunkedForm(Map formMap) throws Exception { + String boundary = transportContext.getOrCreateBoundary(); + + httpClientRequest.setChunked(true); + httpClientRequest.putHeader(CONTENT_TYPE, MULTIPART_FORM_DATA + "; charset=UTF-8; boundary=" + boundary); + + if (formMap == null) { + return; + } + + Buffer bodyBuffer = genChunkedFormBuffer(formMap, boundary); + requestParameters.setBodyBuffer(bodyBuffer); + } + + protected Buffer genChunkedFormBuffer(Map formMap, String boundary) throws Exception { + Buffer buffer = Buffer.buffer(RestClientEncoder.FORM_BUFFER_SIZE); + for (Entry entry : formMap.entrySet()) { + Object content = entry.getValue(); + if (content instanceof List) { + for (Object item : ((List) content)) { + writeFormData(buffer, boundary, entry.getKey(), item); + } + } else { + writeFormData(buffer, boundary, entry.getKey(), entry.getValue()); + } + } + return buffer; + } + + private void writeFormData(Buffer buffer, String boundary, String key, Object data) throws Exception { + writeCharSequence(buffer, "\r\n--"); + writeCharSequence(buffer, boundary); + writeCharSequence(buffer, "\r\nContent-Disposition: form-data; name=\""); + writeCharSequence(buffer, key); + writeCharSequence(buffer, "\"\r\n\r\n"); + + String value = QueryCodec.convertToString(data); + writeCharSequence(buffer, value); + } + } + + protected static void writeCharSequence(Buffer buffer, String value) { + buffer.appendString(value, "UTF-8"); + } + + public static Buffer genFileBoundaryBuffer(Part part, String name, String boundary) { + Buffer buffer = Buffer.buffer(RestClientEncoder.FORM_BUFFER_SIZE); + + writeCharSequence(buffer, "\r\n--"); + writeCharSequence(buffer, boundary); + writeCharSequence(buffer, "\r\nContent-Disposition: form-data; name=\""); + writeCharSequence(buffer, name); + writeCharSequence(buffer, "\"; filename=\""); + writeCharSequence(buffer, String.valueOf(part.getSubmittedFileName())); + writeCharSequence(buffer, "\"\r\n"); + + writeCharSequence(buffer, "Content-Type: "); + writeCharSequence(buffer, part.getContentType()); + writeCharSequence(buffer, "\r\n"); + + writeCharSequence(buffer, "Content-Transfer-Encoding: binary\r\n"); + + writeCharSequence(buffer, "\r\n"); + + return buffer; + } + + public static Buffer genBoundaryEndBuffer(String boundary) { + Buffer buffer = Buffer.buffer(RestClientEncoder.FORM_BUFFER_SIZE); + + writeCharSequence(buffer, "\r\n--"); + writeCharSequence(buffer, boundary); + writeCharSequence(buffer, "--\r\n"); + + return buffer; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java new file mode 100644 index 00000000000..9c99683f669 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +public interface RestClientExceptionCodes { + String FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT = "scb_rest_client.40000000"; + + String FAILED_TO_ENCODE_REST_CLIENT_REQUEST = "scb_rest_client.40000001"; + + String FAILED_TO_DECODE_REST_SUCCESS_RESPONSE = "scb_rest_client.40000002"; + + String FAILED_TO_DECODE_REST_FAIL_RESPONSE = "scb_rest_client.40000003"; +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java new file mode 100644 index 00000000000..5031250b51f --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParameters.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.Map; + +import jakarta.servlet.http.Part; + +import org.apache.servicecomb.common.rest.codec.RestClientRequest; + +import com.google.common.collect.Multimap; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; + +public interface RestClientRequestParameters extends RestClientRequest { + Map getCookieMap(); + + Map getFormMap(); + + Multimap getUploads(); + + @Override + Buffer getBodyBuffer(); + + void setBodyBuffer(Buffer bodyBuffer); + + @Override + default void write(Buffer bodyBuffer) { + setBodyBuffer(bodyBuffer); + } + + @Override + default Future end() { + throw new UnsupportedOperationException("should not invoke this method"); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java new file mode 100644 index 00000000000..398bde4f402 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.foundation.common.utils.PartUtils; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientRequest; +import jakarta.servlet.http.Part; + +public class RestClientRequestParametersImpl implements RestClientRequestParameters { + protected final HttpClientRequest httpClientRequest; + + protected final MultiMap headers; + + protected Map cookieMap; + + protected Map formMap; + + protected Multimap uploads; + + protected Buffer bodyBuffer; + + public RestClientRequestParametersImpl(HttpClientRequest httpClientRequest) { + this.httpClientRequest = httpClientRequest; + this.headers = this.httpClientRequest.headers(); + } + + @Override + public Map getCookieMap() { + return cookieMap; + } + + @Override + public void addCookie(String name, String value) { + if (cookieMap == null) { + cookieMap = new HashMap<>(); + } + + cookieMap.put(name, value); + } + + @Override + public Map getFormMap() { + return formMap; + } + + @Override + public void addForm(String name, Object value) { + if (formMap == null) { + formMap = new HashMap<>(); + } + + if (value != null) { + formMap.put(name, value); + } + } + + @Override + public MultiMap getHeaders() { + return headers; + } + + @Override + public void putHeader(String name, String value) { + headers.add(name, value); + } + + @Override + public Buffer getBodyBuffer() { + return bodyBuffer; + } + + @Override + public void setBodyBuffer(Buffer bodyBuffer) { + this.bodyBuffer = bodyBuffer; + } + + @Override + public Multimap getUploads() { + return uploads; + } + + @SuppressWarnings("unchecked") + @Override + public void attach(String name, Object partOrList) { + if (uploads == null) { + uploads = ArrayListMultimap.create(); + } + + if (partOrList == null) { + return; + } + + if (partOrList.getClass().isArray()) { + for (Object part : (Object[]) partOrList) { + uploads.put(name, PartUtils.getSinglePart(name, part)); + } + return; + } + + if (partOrList instanceof Collection) { + for (Object part : ((Collection) partOrList)) { + uploads.put(name, PartUtils.getSinglePart(name, part)); + } + return; + } + + uploads.put(name, PartUtils.getSinglePart(name, partOrList)); + } + + @Override + public HttpClientRequest getHttpClientRequest() { + return this.httpClientRequest; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSender.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSender.java new file mode 100644 index 00000000000..b737736c243 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSender.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import static org.apache.servicecomb.transport.rest.client.RestClientEncoder.genBoundaryEndBuffer; +import static org.apache.servicecomb.transport.rest.client.RestClientEncoder.genFileBoundaryBuffer; + +import java.util.Map.Entry; +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.http.HttpStatus; +import org.apache.servicecomb.foundation.vertx.executor.VertxContextExecutor; +import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; +import org.apache.servicecomb.foundation.vertx.stream.PumpFromPart; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Multimap; + +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.Promise; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.rxjava3.FlowableHelper; +import jakarta.servlet.http.Part; + +public class RestClientSender { + private static final Logger LOGGER = LoggerFactory.getLogger(RestClientSender.class); + + protected final Invocation invocation; + + protected final RestClientTransportContext transportContext; + + protected final RestClientRequestParameters requestParameters; + + protected final HttpClientRequest httpClientRequest; + + protected final CompletableFuture future = new CompletableFuture<>(); + + public RestClientSender(Invocation invocation) { + this.invocation = invocation; + this.transportContext = invocation.getTransportContext(); + this.requestParameters = transportContext.getRequestParameters(); + this.httpClientRequest = transportContext.getHttpClientRequest(); + } + + public CompletableFuture send() { + invocation.getInvocationStageTrace().startConsumerSendRequest(); + httpClientRequest.response().compose(this::processResponse).onFailure(future::completeExceptionally); + + CompletableFuture actualFuture = future.whenComplete(this::afterSend); + VertxContextExecutor.create(transportContext.getVertxContext()).execute(this::runInVertxContext); + return actualFuture; + } + + protected void runInVertxContext() { + sendInVertxContext() + .whenComplete((v, e) -> { + if (e != null) { + future.completeExceptionally(e); + } + invocation.getInvocationStageTrace().finishConsumerSendRequest(); + invocation.getInvocationStageTrace().startWaitResponse(); + }); + } + + protected CompletableFuture sendInVertxContext() { + httpClientRequest.idleTimeout(invocation.getOperationMeta().getConfig().getMsRequestTimeout()); + + Multimap uploads = requestParameters.getUploads(); + if (uploads == null) { + if (requestParameters.getBodyBuffer() != null) { + return CompletableFuture.completedFuture(null).thenCompose( + v -> httpClientRequest.end(requestParameters.getBodyBuffer()).toCompletionStage()); + } else { + return CompletableFuture.completedFuture(null).thenCompose( + v -> httpClientRequest.end().toCompletionStage()); + } + } + + if (requestParameters.getBodyBuffer() != null) { + httpClientRequest.write(requestParameters.getBodyBuffer()); + } + return sendFiles(); + } + + protected CompletableFuture sendFiles() { + CompletableFuture sendFileFuture = CompletableFuture.completedFuture(null); + + String boundary = transportContext.getOrCreateBoundary(); + for (Entry entry : requestParameters.getUploads().entries()) { + // do not use part.getName() to get parameter name + // because pojo consumer not easy to set name to part + String name = entry.getKey(); + sendFileFuture = sendFileFuture.thenCompose(v -> sendFile(entry.getValue(), name, boundary)); + } + + return sendFileFuture.thenCompose(v -> httpClientRequest.end(genBoundaryEndBuffer(boundary)).toCompletionStage()); + } + + private CompletableFuture sendFile(Part part, String name, String boundary) { + Buffer fileHeader = genFileBoundaryBuffer(part, name, boundary); + httpClientRequest.write(fileHeader); + + return new PumpFromPart(transportContext.getVertxContext(), part) + .toWriteStream(httpClientRequest, future::completeExceptionally) + .whenComplete((v, e) -> { + if (e != null) { + LOGGER.debug("Failed to send file [{}:{}].", name, part.getSubmittedFileName(), e); + return; + } + + LOGGER.debug("finish send file [{}:{}].", name, part.getSubmittedFileName()); + }); + } + + protected Future processResponse(HttpClientResponse httpClientResponse) { + Promise result = Promise.promise(); + transportContext.setHttpClientResponse(httpClientResponse); + + if (!HttpStatus.isSuccess(httpClientResponse.statusCode())) { + httpClientResponse.body().compose(buffer -> { + future.complete(createResponse(httpClientResponse, buffer)); + result.complete(); + return Future.succeededFuture(); + }); + return result.future(); + } + + if (transportContext.isDownloadFile()) { + ReadStreamPart streamPart = new ReadStreamPart(transportContext.getVertxContext(), httpClientResponse); + future.complete(createResponse(httpClientResponse, streamPart)); + result.complete(); + return result.future(); + } + + if (transportContext.isServerSendEvents()) { + future.complete(createResponse(httpClientResponse, FlowableHelper.toFlowable(httpClientResponse))); + result.complete(); + return result.future(); + } + + httpClientResponse.body().compose(buffer -> { + future.complete(createResponse(httpClientResponse, buffer)); + result.complete(); + return Future.succeededFuture(); + }); + return result.future(); + } + + protected Response createResponse(HttpClientResponse httpClientResponse, Object result) { + // http2's :status header will cause edge forward failed + MultiMap headers = httpClientResponse.headers(); + headers.remove(":status"); + + HttpStatus httpStatus = new HttpStatus(httpClientResponse.statusCode(), httpClientResponse.statusMessage()); + return Response + .status(httpStatus) + .setHeaders(headers) + .entity(result); + } + + protected void afterSend(Response response, Throwable throwable) { + invocation.getInvocationStageTrace().finishWaitResponse(); + + if (throwable != null) { + LOGGER.error("rest client send or receive failed, operation={}, method={}, endpoint={}, uri={}.", + invocation.getMicroserviceQualifiedName(), + httpClientRequest.getMethod(), + invocation.getEndpoint().getEndpoint(), + httpClientRequest.getURI()); + } + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java new file mode 100644 index 00000000000..cf088c764eb --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientSenderFilter.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.concurrent.CompletableFuture; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.swagger.invocation.Response; + +public class RestClientSenderFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + public static final String NAME = "rest-client-sender"; + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.RESTFUL.equals(transport); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 2000; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + CompletableFuture future = new RestClientSender(invocation) + .send(); + + return invocation.optimizeSyncConsumerThread(future); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java new file mode 100644 index 00000000000..5648588a714 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContext.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.util.Optional; + +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext; + +import io.vertx.core.Context; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpClientResponse; +import io.vertx.core.http.HttpConnection; + +public class RestClientTransportContext implements VertxTransportContext { + protected final RestOperationMeta restOperationMeta; + + protected final Context vertxContext; + + protected final HttpClientRequest httpClientRequest; + + protected final RestClientRequestParameters requestParameters; + + protected final BoundaryFactory boundaryFactory; + + protected String boundary; + + protected HttpClientResponse httpClientResponse; + + public RestClientTransportContext(RestOperationMeta restOperationMeta, Context vertxContext, + HttpClientRequest httpClientRequest, BoundaryFactory boundaryFactory) { + this.restOperationMeta = restOperationMeta; + this.vertxContext = vertxContext; + this.httpClientRequest = httpClientRequest; + this.boundaryFactory = boundaryFactory; + this.requestParameters = new RestClientRequestParametersImpl(httpClientRequest); + } + + public RestOperationMeta getRestOperationMeta() { + return restOperationMeta; + } + + public boolean isDownloadFile() { + return restOperationMeta.isDownloadFile(); + } + + public boolean isServerSendEvents() { + return restOperationMeta.isServerSendEvents(); + } + + @Override + public Context getVertxContext() { + return vertxContext; + } + + public HttpClientRequest getHttpClientRequest() { + return httpClientRequest; + } + + public RestClientRequestParameters getRequestParameters() { + return requestParameters; + } + + public String getOrCreateBoundary() { + if (boundary == null) { + boundary = boundaryFactory.create(); + } + + return boundary; + } + + public HttpClientResponse getHttpClientResponse() { + return httpClientResponse; + } + + public RestClientTransportContext setHttpClientResponse(HttpClientResponse httpClientResponse) { + this.httpClientResponse = httpClientResponse; + return this; + } + + public String getLocalAddress() { + return Optional.ofNullable(httpClientRequest.connection()) + .map(HttpConnection::localAddress) + .map(Object::toString) + .orElse("not connected"); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java new file mode 100644 index 00000000000..a4b0fc12dcf --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactory.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; +import static org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.definition.RestMetaUtils; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.beans.factory.annotation.Autowired; + +import io.vertx.core.Future; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.RequestOptions; + +public class RestClientTransportContextFactory { + private BoundaryFactory boundaryFactory = BoundaryFactory.DEFAULT; + + private HttpClientRequestFactory httpClientRequestFactory = HttpClientRequestFactory.DEFAULT; + + @Autowired(required = false) + public RestClientTransportContextFactory setBoundaryFactory(BoundaryFactory boundaryFactory) { + this.boundaryFactory = boundaryFactory; + return this; + } + + @Autowired(required = false) + public RestClientTransportContextFactory setHttpClientRequestFactory(HttpClientRequestFactory factory) { + this.httpClientRequestFactory = factory; + return this; + } + + public RestClientTransportContext create(Invocation invocation, HttpClientRequest httpClientRequest) { + try { + return doCreate(invocation, httpClientRequest); + } catch (Throwable e) { + throw new InvocationException(BAD_REQUEST, FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT, e.getMessage(), e); + } + } + + protected RestClientTransportContext doCreate(Invocation invocation, HttpClientRequest httpClientRequest) + throws Throwable { + RestOperationMeta restOperationMeta = RestMetaUtils.getRestOperationMeta(invocation.getOperationMeta()); + HttpClientWithContext httpClientWithContext = findHttpClientPool(invocation); + RestClientTransportContext context = new RestClientTransportContext(restOperationMeta, + httpClientWithContext.context(), + httpClientRequest, + boundaryFactory); + invocation.getHandlerContext().put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, + context.getRequestParameters()); + return context; + } + + protected HttpClientWithContext findHttpClientPool(Invocation invocation) { + URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); + if (endpoint.isHttp2Enabled()) { + return HttpClients.getClient(Http2TransportHttpClientOptionsSPI.CLIENT_NAME, invocation.isSync()); + } + + return HttpClients.getClient(HttpTransportHttpClientOptionsSPI.CLIENT_NAME, invocation.isSync()); + } + + protected Future createHttpClientRequest(Invocation invocation) { + try { + RestOperationMeta restOperationMeta = RestMetaUtils.getRestOperationMeta(invocation.getOperationMeta()); + HttpClientWithContext httpClientWithContext = findHttpClientPool(invocation); + + URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); + HttpMethod method = HttpMethod.valueOf(restOperationMeta.getHttpMethod()); + RequestOptions requestOptions = new RequestOptions() + .setHost(endpoint.getHostOrIp()) + .setPort(endpoint.getPort()) + .setSsl(endpoint.isSslEnabled()) + .setMethod(method) + .setURI(createRequestPath(invocation, restOperationMeta)); + return httpClientRequestFactory.create(invocation, httpClientWithContext.getHttpClient(), requestOptions); + } catch (Throwable e) { + throw new InvocationException(BAD_REQUEST, FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT, e.getMessage(), e); + } + } + + protected String createRequestPath(Invocation invocation, RestOperationMeta restOperationMeta) throws Exception { + String path = invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH); + if (path == null) { + path = restOperationMeta.getPathBuilder().createRequestPath(invocation.getSwaggerArguments()); + } + + URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); + String urlPrefix = endpoint.getFirst(DefinitionConst.URL_PREFIX); + if (StringUtils.isEmpty(urlPrefix) || path.startsWith(urlPrefix)) { + return path; + } + + return urlPrefix + path; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClient.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClient.java deleted file mode 100644 index 533179a9d52..00000000000 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClient.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client; - -import java.util.List; - -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.vertx.VertxTLSBuilder; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.ClientVerticle; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientPoolFactory; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.transport.rest.client.http.RestClientInvocation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpVersion; - -public class RestTransportClient { - private static final Logger LOGGER = LoggerFactory.getLogger(RestTransportClient.class); - - private static final String SSL_KEY = "rest.consumer"; - - protected ClientPoolManager clientMgr; - - private ClientPoolManager clientMgrHttp2; - - private List httpClientFilters; - - - public ClientPoolManager getClientMgr() { - return clientMgr; - } - - public void init(Vertx vertx) throws Exception { - httpClientFilters = SPIServiceUtils.getSortedService(HttpClientFilter.class); - - HttpClientOptions httpClientOptions = createHttpClientOptions(); - clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions)); - - HttpClientOptions httpClientOptionshttp2 = createHttp2ClientOptions(); - - clientMgrHttp2 = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptionshttp2)); - - DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(clientMgr, - TransportClientConfig.getThreadCount()); - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); - - DeploymentOptions deployOptionshttp2 = VertxUtils.createClientDeployOptions(clientMgrHttp2, - TransportClientConfig.getThreadCount()); - VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptionshttp2); - } - - private static HttpClientOptions createHttpClientOptions() { - HttpClientOptions httpClientOptions = new HttpClientOptions(); - httpClientOptions.setMaxPoolSize(TransportClientConfig.getConnectionMaxPoolSize()); - httpClientOptions.setIdleTimeout(TransportClientConfig.getConnectionIdleTimeoutInSeconds()); - httpClientOptions.setKeepAlive(TransportClientConfig.getConnectionKeepAlive()); - httpClientOptions.setTryUseCompression(TransportClientConfig.getConnectionCompression()); - - VertxTLSBuilder.buildHttpClientOptions(SSL_KEY, httpClientOptions); - return httpClientOptions; - } - - private static HttpClientOptions createHttp2ClientOptions() { - HttpClientOptions httpClientOptions = new HttpClientOptions(); - httpClientOptions.setUseAlpn(TransportClientConfig.getUseAlpn()) - .setHttp2ClearTextUpgrade(false) - .setProtocolVersion(HttpVersion.HTTP_2) - .setIdleTimeout(TransportClientConfig.getHttp2ConnectionIdleTimeoutInSeconds()) - .setHttp2MultiplexingLimit(TransportClientConfig.getHttp2MultiplexingLimit()) - .setHttp2MaxPoolSize(TransportClientConfig.getHttp2ConnectionMaxPoolSize()) - .setTryUseCompression(TransportClientConfig.getConnectionCompression()); - - VertxTLSBuilder.buildHttpClientOptions(SSL_KEY, httpClientOptions); - return httpClientOptions; - } - - public void send(Invocation invocation, AsyncResponse asyncResp) { - URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); - HttpClientWithContext httpClientWithContext; - - if (endpoint.isHttp2Enabled()) { - httpClientWithContext = findHttp2ClientPool(invocation); - } else { - httpClientWithContext = findHttpClientPool(invocation); - } - - RestClientInvocation restClientInvocation = new RestClientInvocation(httpClientWithContext, httpClientFilters); - - try { - restClientInvocation.invoke(invocation, asyncResp); - } catch (Throwable e) { - asyncResp.fail(invocation.getInvocationType(), e); - LOGGER.error("vertx rest transport send error.", e); - } - } - - protected HttpClientWithContext findHttpClientPool(Invocation invocation) { - return clientMgr.findClientPool(invocation.isSync()); - } - - public HttpClientWithContext findHttp2ClientPool(Invocation invocation) { - return clientMgrHttp2.findClientPool(invocation.isSync()); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClientManager.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClientManager.java deleted file mode 100644 index 3dfd785aaca..00000000000 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestTransportClientManager.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client; - -import org.apache.servicecomb.foundation.vertx.VertxUtils; - -import io.vertx.core.Vertx; - -public final class RestTransportClientManager { - public static final RestTransportClientManager INSTANCE = new RestTransportClientManager(); - - // same instance in AbstractTranport. need refactor in future. - private final Vertx transportVertx = VertxUtils.getOrCreateVertxByName("transport", null); - - private RestTransportClient restClient; - - private RestTransportClientManager() { - try { - restClient = TransportClientConfig.getRestTransportClientCls().newInstance(); - restClient.init(transportVertx); - } catch (Exception e) { - throw new IllegalStateException("Failed to init RestTransportClient.", e); - } - } - - public RestTransportClient getRestClient() { - return restClient; - } -} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportClientConfig.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportClientConfig.java index fcc61952d40..e1f2c6042d1 100644 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportClientConfig.java +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportClientConfig.java @@ -17,77 +17,106 @@ package org.apache.servicecomb.transport.rest.client; -import com.netflix.config.DynamicPropertyFactory; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.transport.common.TransportConfigUtils; import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.net.TCPSSLOptions; +import io.vertx.core.http.PoolOptions; public final class TransportClientConfig { - private static Class restTransportClientCls = RestTransportClient.class; + private static final int DEFAULT_IDLE_TIME_OUT = 150; - private TransportClientConfig() { - } - - public static Class getRestTransportClientCls() { - return restTransportClientCls; - } + private static final int DEFAULT_KEEP_ALIVE_TIME_OUT = 60; - public static void setRestTransportClientCls(Class restTransportClientCls) { - TransportClientConfig.restTransportClientCls = restTransportClientCls; + private TransportClientConfig() { } public static int getThreadCount() { - return DynamicPropertyFactory.getInstance().getIntProperty("servicecomb.rest.client.thread-count", 1).get(); + return TransportConfigUtils.readVerticleCount( + "servicecomb.rest.client.verticle-count", + "servicecomb.rest.client.thread-count"); } public static int getHttp2ConnectionMaxPoolSize() { - return DynamicPropertyFactory.getInstance().getIntProperty("servicecomb.rest.client.http2.maxPoolSize", - HttpClientOptions.DEFAULT_HTTP2_MAX_POOL_SIZE) - .get(); + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.client.http2.maxPoolSize", + PoolOptions.DEFAULT_HTTP2_MAX_POOL_SIZE); } public static int getHttp2MultiplexingLimit() { - return DynamicPropertyFactory.getInstance().getIntProperty("servicecomb.rest.client.http2.multiplexingLimit", - HttpClientOptions.DEFAULT_HTTP2_MULTIPLEXING_LIMIT) - .get(); + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.client.http2.multiplexingLimit", + HttpClientOptions.DEFAULT_HTTP2_MULTIPLEXING_LIMIT); } - public static int getHttp2ConnectionIdleTimeoutInSeconds() { - return DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.client.http2.idleTimeoutInSeconds", TCPSSLOptions.DEFAULT_IDLE_TIMEOUT) - .get(); + public static boolean getUseAlpn() { + return LegacyPropertyFactory.getBooleanProperty("servicecomb.rest.client.http2.useAlpnEnabled", true); } - - public static boolean getUseAlpn() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.client.http2.useAlpnEnabled", true) - .get(); + public static boolean isHttp2TransportClientEnabled() { + return LegacyPropertyFactory.getBooleanProperty("servicecomb.rest.client.http2.enabled", + true); } public static int getConnectionMaxPoolSize() { - return DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.client.connection.maxPoolSize", HttpClientOptions.DEFAULT_MAX_POOL_SIZE) - .get(); + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.client.connection.maxPoolSize", + PoolOptions.DEFAULT_MAX_POOL_SIZE); + } + + public static int getHttp2ConnectionIdleTimeoutInSeconds() { + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.client.http2.connection.idleTimeoutInSeconds", + DEFAULT_IDLE_TIME_OUT); } public static int getConnectionIdleTimeoutInSeconds() { - return DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.client.connection.idleTimeoutInSeconds", 30) - .get(); + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.client.connection.idleTimeoutInSeconds", + DEFAULT_IDLE_TIME_OUT); } public static boolean getConnectionKeepAlive() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.client.connection.keepAlive", HttpClientOptions.DEFAULT_KEEP_ALIVE) - .get(); + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.client.connection.keepAlive", HttpClientOptions.DEFAULT_KEEP_ALIVE); } + public static int getConnectionKeepAliveTimeoutInSeconds() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.client.connection.keepAliveTimeoutInSeconds", DEFAULT_KEEP_ALIVE_TIME_OUT); + } + + public static boolean enableLogActivity() { + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.client.enableLogActivity", false); + } + + public static int getHttp2ConnectionKeepAliveTimeoutInSeconds() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.client.http2.connection.keepAliveTimeoutInSeconds", + DEFAULT_KEEP_ALIVE_TIME_OUT); + } public static boolean getConnectionCompression() { - return DynamicPropertyFactory.getInstance() + return LegacyPropertyFactory .getBooleanProperty("servicecomb.rest.client.connection.compression", - HttpClientOptions.DEFAULT_TRY_USE_COMPRESSION) - .get(); + HttpClientOptions.DEFAULT_DECOMPRESSION_SUPPORTED); + } + + public static int getMaxHeaderSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.client.maxHeaderSize", HttpClientOptions.DEFAULT_MAX_HEADER_SIZE); + } + + public static int getMaxWaitQueueSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.client.maxWaitQueueSize", + PoolOptions.DEFAULT_MAX_WAIT_QUEUE_SIZE); + } + + public static boolean isHttpTransportClientEnabled() { + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.client.enabled", + true); + } + + public static int getConnectionTimeoutInMillis() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.client.connection.timeoutInMillis", 60000); } } diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportRestClientConfiguration.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportRestClientConfiguration.java new file mode 100644 index 00000000000..3775744e173 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/TransportRestClientConfiguration.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TransportRestClientConfiguration { + @Bean + public RestClientSenderFilter restClientSenderFilter() { + return new RestClientSenderFilter(); + } + + @Bean + public RestClientCodecFilter restClientCodecFilter() { + return new RestClientCodecFilter(); + } + + @Bean + public WebSocketClientCodecFilter webSocketClientCodecFilter() { + return new WebSocketClientCodecFilter(); + } + + @Bean + public RestClientDecoder restClientDecoder() { + return new RestClientDecoder(); + } + + @Bean + public RestClientTransportContextFactory restClientTransportContextFactory() { + return new RestClientTransportContextFactory(); + } + + @Bean + public RestClientEncoder restClientEncoder() { + return new RestClientEncoder(); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientCodecFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientCodecFilter.java new file mode 100644 index 00000000000..73a38dfe8f2 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientCodecFilter.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.client; + +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.common.rest.WebSocketTransportContext; +import org.apache.servicecomb.common.rest.definition.RestMetaUtils; +import org.apache.servicecomb.common.rest.definition.RestOperationMeta; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.filter.AbstractFilter; +import org.apache.servicecomb.core.filter.ConsumerFilter; +import org.apache.servicecomb.core.filter.EdgeFilter; +import org.apache.servicecomb.core.filter.Filter; +import org.apache.servicecomb.core.filter.FilterNode; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClientOptionsSPI; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClients; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.http.ServerWebSocket; +import io.vertx.core.http.WebSocket; +import io.vertx.core.http.WebSocketClient; + +public class WebSocketClientCodecFilter extends AbstractFilter implements ConsumerFilter, EdgeFilter { + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketClientCodecFilter.class); + + public static final String NAME = "websocket-client"; + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean enabledForTransport(String transport) { + return CoreConst.WEBSOCKET.equals(transport); + } + + @Override + public int getOrder() { + return Filter.CONSUMER_LOAD_BALANCE_ORDER + 2000; + } + + @Override + public CompletableFuture onFilter(Invocation invocation, FilterNode nextNode) { + invocation.getInvocationStageTrace().startConsumerConnection(); + + CompletableFuture createWebSocket = new CompletableFuture<>(); + URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); + HttpClientOptionsSPI optionsSPI; + if (endpoint.isHttp2Enabled()) { + optionsSPI = SPIServiceUtils.getTargetService(HttpClientOptionsSPI.class, + HttpTransportHttpClientOptionsSPI.class); + } else { + optionsSPI = SPIServiceUtils.getTargetService(HttpClientOptionsSPI.class, + Http2TransportHttpClientOptionsSPI.class); + } + WebSocketClient webSocketClient = HttpClients.createWebSocketClient(optionsSPI, endpoint.isSslEnabled()); + + try { + webSocketClient.connect(endpoint.getPort(), endpoint.getHostOrIp(), createRequestPath(invocation, + RestMetaUtils.getRestOperationMeta(invocation.getOperationMeta()))) + .onComplete(asyncResult -> { + invocation.getInvocationStageTrace().finishConsumerConnection(); + if (asyncResult.failed()) { + createWebSocket.completeExceptionally(asyncResult.cause()); + return; + } + if (invocation.isEdge()) { + WebSocketTransportContext parentContext = invocation.getTransportContext(); + ServerWebSocket serverWebSocket = parentContext.getServerWebSocket(); + WebSocket clientWebSocket = asyncResult.result(); + serverWebSocket.closeHandler(v -> { + if (!clientWebSocket.isClosed()) { + clientWebSocket.close(); + } + }); + serverWebSocket.textMessageHandler(clientWebSocket::writeTextMessage); + serverWebSocket.binaryMessageHandler(clientWebSocket::writeBinaryMessage); + serverWebSocket.exceptionHandler(e -> { + LOGGER.warn("consumer exception.", e); + if (!serverWebSocket.isClosed()) { + serverWebSocket.close(); + } + }); + clientWebSocket.closeHandler(v -> { + if (!serverWebSocket.isClosed()) { + serverWebSocket.close(); + } + }); + clientWebSocket.textMessageHandler(serverWebSocket::writeTextMessage); + clientWebSocket.binaryMessageHandler(serverWebSocket::writeBinaryMessage); + clientWebSocket.exceptionHandler(e -> { + LOGGER.warn("producer exception.", e); + if (!clientWebSocket.isClosed()) { + clientWebSocket.close(); + } + }); + } + invocation.setTransportContext(new WebSocketClientTransportContext( + asyncResult.result())); + createWebSocket.complete(Response.createSuccess(asyncResult.result())); + }); + } catch (Exception e) { + createWebSocket.completeExceptionally(e); + } + + return createWebSocket; + } + + protected String createRequestPath(Invocation invocation, RestOperationMeta restOperationMeta) throws Exception { + String path = invocation.getLocalContext(RestConst.REST_CLIENT_REQUEST_PATH); + if (path == null) { + path = restOperationMeta.getPathBuilder().createRequestPath(invocation.getSwaggerArguments()); + } + + URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); + String urlPrefix = endpoint.getFirst(DefinitionConst.URL_PREFIX); + if (StringUtils.isEmpty(urlPrefix) || path.startsWith(urlPrefix)) { + return path; + } + + return urlPrefix + path; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientTransportContext.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientTransportContext.java new file mode 100644 index 00000000000..89d43bcde41 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/WebSocketClientTransportContext.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.client; + +import org.apache.servicecomb.swagger.invocation.context.TransportContext; + +import io.vertx.core.http.WebSocket; + +public class WebSocketClientTransportContext implements TransportContext { + + protected final WebSocket webSocketClient; + + public WebSocketClientTransportContext(WebSocket webSocketClient) { + this.webSocketClient = webSocketClient; + } + + public WebSocket getWebSocketClient() { + return webSocketClient; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java deleted file mode 100644 index 13f91ab514f..00000000000 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client.http; - -import java.util.Collection; - -import javax.ws.rs.core.HttpHeaders; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.context.HttpStatus; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicPropertyFactory; - -public class DefaultHttpClientFilter implements HttpClientFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultHttpClientFilter.class); - - private static final boolean enabled = DynamicPropertyFactory.getInstance().getBooleanProperty - ("servicecomb.http.filter.client.default.enabled", true).get(); - - @Override - public int getOrder() { - return Integer.MAX_VALUE; - } - - @Override - public boolean enabled() { - return enabled; - } - - @Override - public void beforeSendRequest(Invocation invocation, HttpServletRequestEx requestEx) { - - } - - protected ProduceProcessor findProduceProcessor(RestOperationMeta restOperation, - HttpServletResponseEx responseEx) { - String contentType = responseEx.getHeader(HttpHeaders.CONTENT_TYPE); - if (contentType == null) { - return null; - } - - String contentTypeForFind = contentType; - int idx = contentType.indexOf(';'); - if (idx != -1) { - contentTypeForFind = contentType.substring(0, idx); - } - return restOperation.findProduceProcessor(contentTypeForFind); - } - - protected Response extractResponse(Invocation invocation, HttpServletResponseEx responseEx) { - Object result = invocation.getHandlerContext().get(RestConst.READ_STREAM_PART); - if (result != null) { - return Response.create(responseEx.getStatusType(), result); - } - - OperationMeta operationMeta = invocation.getOperationMeta(); - ResponseMeta responseMeta = operationMeta.findResponseMeta(responseEx.getStatus()); - RestOperationMeta swaggerRestOperation = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - ProduceProcessor produceProcessor = findProduceProcessor(swaggerRestOperation, responseEx); - if (produceProcessor == null) { - // This happens outside the runtime such as Servlet filter response. Here we give a default json parser to it - // and keep user data not get lose. - String msg = - String.format("method %s, path %s, statusCode %d, reasonPhrase %s, response content-type %s is not supported", - swaggerRestOperation.getHttpMethod(), - swaggerRestOperation.getAbsolutePath(), - responseEx.getStatus(), - responseEx.getStatusType().getReasonPhrase(), - responseEx.getHeader(HttpHeaders.CONTENT_TYPE)); - LOGGER.warn(msg); - produceProcessor = ProduceProcessorManager.DEFAULT_PROCESSOR; - } - - try { - result = produceProcessor.decodeResponse(responseEx.getBodyBuffer(), responseMeta.getJavaType()); - return Response.create(responseEx.getStatusType(), result); - } catch (Exception e) { - LOGGER.error("failed to decode response body, exception is [{}]", e.getMessage()); - String msg = - String.format("method %s, path %s, statusCode %d, reasonPhrase %s, response content-type %s is not supported", - swaggerRestOperation.getHttpMethod(), - swaggerRestOperation.getAbsolutePath(), - responseEx.getStatus(), - responseEx.getStatusType().getReasonPhrase(), - responseEx.getHeader(HttpHeaders.CONTENT_TYPE)); - if (HttpStatus.isSuccess(responseEx.getStatus())) { - return Response.createConsumerFail( - new InvocationException(400, responseEx.getStatusType().getReasonPhrase(), - new CommonExceptionData(msg), e)); - } - return Response.createConsumerFail( - new InvocationException(responseEx.getStatus(), responseEx.getStatusType().getReasonPhrase(), - new CommonExceptionData(msg), e)); - } - } - - @Override - public Response afterReceiveResponse(Invocation invocation, HttpServletResponseEx responseEx) { - Response response = extractResponse(invocation, responseEx); - - for (String headerName : responseEx.getHeaderNames()) { - Collection headerValues = responseEx.getHeaders(headerName); - for (String headerValue : headerValues) { - response.getHeaders().addHeader(headerName, headerValue); - } - } - - return response; - } -} diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java deleted file mode 100644 index 6b2dd7305da..00000000000 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/RestClientInvocation.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client.http; - -import java.util.List; - -import javax.servlet.http.Part; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.core.transport.AbstractTransport; -import org.apache.servicecomb.foundation.common.http.HttpStatus; -import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; -import org.apache.servicecomb.foundation.vertx.http.VertxClientRequestToHttpServletRequest; -import org.apache.servicecomb.foundation.vertx.http.VertxClientResponseToHttpServletResponse; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; - -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.RequestOptions; -import io.vertx.core.net.impl.ConnectionBase; - -public class RestClientInvocation { - private static final Logger LOGGER = LoggerFactory.getLogger(RestClientInvocation.class); - - private HttpClientWithContext httpClientWithContext; - - private Invocation invocation; - - private AsyncResponse asyncResp; - - private List httpClientFilters; - - private HttpClientRequest clientRequest; - - private HttpClientResponse clientResponse; - - public RestClientInvocation(HttpClientWithContext httpClientWithContext, List httpClientFilters) { - this.httpClientWithContext = httpClientWithContext; - this.httpClientFilters = httpClientFilters; - } - - public void invoke(Invocation invocation, AsyncResponse asyncResp) throws Exception { - this.invocation = invocation; - this.asyncResp = asyncResp; - - OperationMeta operationMeta = invocation.getOperationMeta(); - RestOperationMeta swaggerRestOperation = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - - String path = this.createRequestPath(swaggerRestOperation); - IpPort ipPort = (IpPort) invocation.getEndpoint().getAddress(); - - createRequest(ipPort, path); - clientRequest.putHeader(org.apache.servicecomb.core.Const.TARGET_MICROSERVICE, invocation.getMicroserviceName()); - RestClientRequestImpl restClientRequest = - new RestClientRequestImpl(clientRequest, httpClientWithContext.context(), asyncResp); - invocation.getHandlerContext().put(RestConst.INVOCATION_HANDLER_REQUESTCLIENT, restClientRequest); - - Buffer requestBodyBuffer = restClientRequest.getBodyBuffer(); - HttpServletRequestEx requestEx = new VertxClientRequestToHttpServletRequest(clientRequest, requestBodyBuffer); - invocation.getInvocationStageTrace().startClientFiltersRequest(); - for (HttpClientFilter filter : httpClientFilters) { - if (filter.enabled()) { - filter.beforeSendRequest(invocation, requestEx); - } - } - - clientRequest.exceptionHandler(e -> { - LOGGER.error("Failed to send request to {}.", ipPort.getSocketAddress(), e); - fail(e); - }); - clientRequest.connectionHandler(connection -> { - LOGGER.debug("http connection connected, local:{}, remote:{}.", - connection.localAddress(), - connection.remoteAddress()); - connection.closeHandler(v -> { - LOGGER.debug("http connection closed, local:{}, remote:{}.", - connection.localAddress(), - connection.remoteAddress()); - }); - connection.exceptionHandler(e -> { - LOGGER.info("http connection exception, local:{}, remote:{}.", - connection.localAddress(), - connection.remoteAddress(), - e); - }); - }); - - // 从业务线程转移到网络线程中去发送 - invocation.getInvocationStageTrace().startSend(); - httpClientWithContext.runOnContext(httpClient -> { - this.setCseContext(); - //set the timeout based on priority. the priority is follows. - //high priotiry: 1) operational level 2)schema level 3) service level 4) global level : low priotiry. - clientRequest.setTimeout(AbstractTransport.getReqTimeout(invocation.getOperationName(), - invocation.getSchemaId(), - invocation.getMicroserviceName())); - try { - restClientRequest.end(); - } catch (Throwable e) { - LOGGER.error("send http request failed,", e); - fail(e); - } - }); - } - - private HttpMethod getMethod() { - OperationMeta operationMeta = invocation.getOperationMeta(); - RestOperationMeta swaggerRestOperation = operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - String method = swaggerRestOperation.getHttpMethod(); - return HttpMethod.valueOf(method); - } - - void createRequest(IpPort ipPort, String path) { - URIEndpointObject endpoint = (URIEndpointObject) invocation.getEndpoint().getAddress(); - RequestOptions requestOptions = new RequestOptions(); - requestOptions.setHost(ipPort.getHostOrIp()) - .setPort(ipPort.getPort()) - .setSsl(endpoint.isSslEnabled()) - .setURI(path); - - HttpMethod method = getMethod(); - LOGGER.debug("Sending request by rest, method={}, qualifiedName={}, path={}, endpoint={}.", - method, - invocation.getMicroserviceQualifiedName(), - path, - invocation.getEndpoint().getEndpoint()); - clientRequest = httpClientWithContext.getHttpClient().request(method, requestOptions, this::handleResponse); - } - - protected void handleResponse(HttpClientResponse httpClientResponse) { - this.clientResponse = httpClientResponse; - - if (HttpStatus.isSuccess(clientResponse.statusCode()) - && Part.class.equals(invocation.getOperationMeta().getMethod().getReturnType())) { - ReadStreamPart part = new ReadStreamPart(httpClientWithContext.context(), httpClientResponse); - invocation.getHandlerContext().put(RestConst.READ_STREAM_PART, part); - processResponseBody(null); - return; - } - - httpClientResponse.exceptionHandler(e -> { - LOGGER.error("Failed to receive response from {}.", httpClientResponse.netSocket().remoteAddress(), e); - fail(e); - }); - - clientResponse.bodyHandler(responseBuf -> { - processResponseBody(responseBuf); - }); - } - - /** - * - * @param responseBuf response body buffer, when download, responseBuf is null, because download data by ReadStreamPart - */ - protected void processResponseBody(Buffer responseBuf) { - invocation.getInvocationStageTrace().finishReceiveResponse(); - invocation.getResponseExecutor().execute(() -> { - try { - invocation.getInvocationStageTrace().startClientFiltersResponse(); - HttpServletResponseEx responseEx = - new VertxClientResponseToHttpServletResponse(clientResponse, responseBuf); - for (HttpClientFilter filter : httpClientFilters) { - if (filter.enabled()) { - Response response = filter.afterReceiveResponse(invocation, responseEx); - if (response != null) { - complete(response); - return; - } - } - } - } catch (Throwable e) { - fail(e); - } - }); - } - - protected void complete(Response response) { - DefaultHttpSocketMetric httpSocketMetric = (DefaultHttpSocketMetric) ((ConnectionBase) clientRequest.connection()) - .metric(); - invocation.getInvocationStageTrace().finishGetConnection(httpSocketMetric.getRequestBeginTime()); - invocation.getInvocationStageTrace().finishWriteToBuffer(httpSocketMetric.getRequestEndTime()); - - invocation.getInvocationStageTrace().finishClientFiltersResponse(); - asyncResp.complete(response); - } - - protected void fail(Throwable e) { - if (invocation.isFinished()) { - return; - } - - InvocationStageTrace stageTrace = invocation.getInvocationStageTrace(); - ConnectionBase connection = (ConnectionBase) clientRequest.connection(); - // connection maybe null when exception happens such as ssl handshake failure - if (connection != null) { - DefaultHttpSocketMetric httpSocketMetric = (DefaultHttpSocketMetric) connection.metric(); - stageTrace.finishGetConnection(httpSocketMetric.getRequestBeginTime()); - stageTrace.finishWriteToBuffer(httpSocketMetric.getRequestEndTime()); - } - - // even failed and did not received response, still set time for it - // that will help to know the real timeout time - if (stageTrace.getFinishReceiveResponse() == 0) { - stageTrace.finishReceiveResponse(); - } - if (stageTrace.getStartClientFiltersResponse() == 0) { - stageTrace.startClientFiltersResponse(); - } - - stageTrace.finishClientFiltersResponse(); - //convert exception - asyncResp.handle(ExceptionFactory.convertExceptionToResponse(invocation, e)); - } - - protected void setCseContext() { - try { - String cseContext = JsonUtils.writeValueAsString(invocation.getContext()); - clientRequest.putHeader(org.apache.servicecomb.core.Const.CSE_CONTEXT, cseContext); - } catch (Exception e) { - LOGGER.debug("Failed to encode and set cseContext.", e); - } - } - - protected String createRequestPath(RestOperationMeta swaggerRestOperation) throws Exception { - URIEndpointObject address = (URIEndpointObject) invocation.getEndpoint().getAddress(); - String urlPrefix = address.getFirst(Const.URL_PREFIX); - - String path = (String) invocation.getHandlerContext().get(RestConst.REST_CLIENT_REQUEST_PATH); - if (path == null) { - path = swaggerRestOperation.getPathBuilder().createRequestPath(invocation.getArgs()); - } - - if (StringUtils.isEmpty(urlPrefix) || path.startsWith(urlPrefix)) { - return path; - } - - return urlPrefix + path; - } -} diff --git a/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter b/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter deleted file mode 100644 index 8addf988df9..00000000000 --- a/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.common.rest.filter.HttpClientFilter +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.transport.rest.client.http.DefaultHttpClientFilter diff --git a/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.vertx.client.http.HttpClientOptionsSPI b/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.vertx.client.http.HttpClientOptionsSPI new file mode 100644 index 00000000000..5eb8c592516 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.vertx.client.http.HttpClientOptionsSPI @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.transport.rest.client.HttpTransportHttpClientOptionsSPI +org.apache.servicecomb.transport.rest.client.Http2TransportHttpClientOptionsSPI diff --git a/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..37f7477013c --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +org.apache.servicecomb.transport.rest.client.TransportRestClientConfiguration diff --git a/transports/transport-rest/transport-rest-client/src/test/java/io/vertx/core/http/impl/VertxImplTestUtils.java b/transports/transport-rest/transport-rest-client/src/test/java/io/vertx/core/http/impl/VertxImplTestUtils.java deleted file mode 100644 index 5fb03b151af..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/java/io/vertx/core/http/impl/VertxImplTestUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.vertx.core.http.impl; - -import org.mockito.Mockito; - -public class VertxImplTestUtils { - public static Http1xConnectionBase mockClientConnection() { - return Mockito.mock(Http1xConnectionBase.class); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java new file mode 100644 index 00000000000..50896650aba --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import org.apache.servicecomb.core.transport.AbstractTransport; +import org.apache.servicecomb.foundation.common.net.URIEndpointObject; + +class FakeRestTransport extends AbstractTransport { + @Override + public String getName() { + return null; + } + + @Override + public boolean init() { + return false; + } + + @Override + public Object parseAddress(String address) { + return new URIEndpointObject(address); + } +} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java new file mode 100644 index 00000000000..88127270084 --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.client; + +import java.io.File; +import java.util.List; + +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +@Path("/") +public class RestFeatureController { + public static final String SCHEMA_ID = "rest-feature"; + + @GET + @Path("/query") + public String query(@QueryParam("query") String query) { + return query; + } + + @GET + @Path("/header") + public String header(@HeaderParam("header") String header) { + return header; + } + + @GET + @Path("/cookie") + public String cookie(@CookieParam("cookie1") String cookie1, @CookieParam("cookie2") String cookie2) { + return cookie1 + ":" + cookie2; + } + + @POST + @Path("/form") + public String form(@FormParam("form1") String form1, @FormParam("form2") String form2) { + return form1 + ":" + form2; + } + + @POST + @Path("/formWithUpload") + public String formWithUpload(@FormParam("form1") String form1, @FormParam("form2") File form2) { + return form1 + ":" + form2.getName(); + } + + @POST + @Path("/formWithUploadList") + public String formWithUploadList(@FormParam("files") List files) { + return files.toString(); + } + + @POST + @Path("/body") + public String body(String body) { + return body; + } +} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestRestTransportClient.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestRestTransportClient.java deleted file mode 100644 index d7f71ef4e88..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestRestTransportClient.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client; - -import java.lang.reflect.Field; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.AbstractVerticle; -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.impl.HttpClientImpl; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRestTransportClient { - - private RestTransportClient instance = null; - - Invocation invocation = Mockito.mock(Invocation.class); - - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - - OperationMeta operationMeta = Mockito.mock(OperationMeta.class); - - RestOperationMeta swaggerRestOperation = Mockito.mock(RestOperationMeta.class); - - URIEndpointObject uriEndpointObject = Mockito.mock(URIEndpointObject.class); - - Endpoint endPoint = Mockito.mock(Endpoint.class); - - HttpClientWithContext httpClientWithContext = Mockito.mock(HttpClientWithContext.class); - - HttpClientImpl httpClient = Mockito.mock(HttpClientImpl.class); - - HttpClientOptions httpClientOptions = Mockito.mock(HttpClientOptions.class); - - - @Before - public void setUp() throws Exception { - instance = new RestTransportClient(); - } - - @After - public void tearDown() throws Exception { - instance = null; - } - - @Test - public void testGetInstance() { - Assert.assertNotNull(instance); - } - - @Test - public void init(@Mocked Vertx vertx, @Mocked VertxUtils utils) throws Exception { - new MockUp() { - @Mock - boolean blockDeploy(Vertx vertx, - Class cls, - DeploymentOptions options) throws InterruptedException { - return true; - } - }; - RestTransportClient client = new RestTransportClient(); - client.init(vertx); - - ClientPoolManager clientMgr = Deencapsulation.getField(client, "clientMgr"); - Assert.assertSame(vertx, Deencapsulation.getField(clientMgr, "vertx")); - } - - @Test - public void testRestTransportClientException() { - boolean status = true; - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(operationMeta); - try { - instance.send(invocation, asyncResp); - } catch (Exception e) { - status = false; - } - Assert.assertFalse(status); - } - - - @Test - public void testRestTransportClientHttp2(@Mocked Vertx vertx, @Mocked VertxUtils utils) - throws Exception { - boolean status = true; - Mockito.when(invocation.getEndpoint()).thenReturn(endPoint); - Mockito.when(invocation.isSync()).thenReturn(true); - Mockito.when(endPoint.getAddress()).thenReturn(uriEndpointObject); - Mockito.when(uriEndpointObject.isHttp2Enabled()).thenReturn(true); - Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(operationMeta); - Mockito.when(httpClientWithContext.getHttpClient()).thenReturn(httpClient); - Mockito.when(httpClient.getOptions()).thenReturn(httpClientOptions); - - instance.init(vertx); - Field clientMgrHttp2Field = instance.getClass().getDeclaredField("clientMgrHttp2"); - clientMgrHttp2Field.setAccessible(true); - - ClientPoolManager client = new ClientPoolManager(vertx, null) { - @Mock - public HttpClientWithContext findClientPool(boolean sync) { - return httpClientWithContext; - } - }; - - clientMgrHttp2Field.set(instance, client); - - try { - instance.send(invocation, asyncResp); - } catch (Exception e) { - status = false; - } - - Assert.assertTrue(status); - } - - @Test - public void testCreateHttpClientOptions() { - HttpClientOptions obj = (HttpClientOptions) Deencapsulation.invoke(instance, "createHttpClientOptions"); - Assert.assertNotNull(obj); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestTransportClientConfig.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestTransportClientConfig.java deleted file mode 100644 index d4ebd267a57..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/TestTransportClientConfig.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client; - -import org.junit.Assert; -import org.junit.Test; - -public class TestTransportClientConfig { - @Test - public void getThreadCount() { - Assert.assertEquals(1, TransportClientConfig.getThreadCount()); - } - - @Test - public void getConnectionMaxPoolSize() { - Assert.assertEquals(5, TransportClientConfig.getConnectionMaxPoolSize()); - } - - @Test - public void getConnectionIdleTimeoutInSeconds() { - Assert.assertEquals(30, TransportClientConfig.getConnectionIdleTimeoutInSeconds()); - } - - @Test - public void getHttp2MultiplexingLimit() { - Assert.assertEquals(-1, TransportClientConfig.getHttp2MultiplexingLimit()); - } - - @Test - public void getHttp2ConnectionMaxPoolSize() { - Assert.assertEquals(1, TransportClientConfig.getHttp2ConnectionMaxPoolSize()); - } - - @Test - public void getHttp2ConnectionIdleTimeoutInSeconds() { - Assert.assertEquals(0, TransportClientConfig.getHttp2ConnectionIdleTimeoutInSeconds()); - } - - @Test - public void getUseAplnEnabled() { - Assert.assertTrue(TransportClientConfig.getUseAlpn()); - } - - @Test - public void getConnectionKeepAlive() { - Assert.assertTrue(TransportClientConfig.getConnectionKeepAlive()); - } - - - @Test - public void getConnectionCompression() { - Assert.assertFalse(TransportClientConfig.getConnectionCompression()); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java deleted file mode 100644 index 9c0028b2033..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client.http; - -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response.Status; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor; -import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.utils.JsonUtils; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.swagger.invocation.response.ResponseMeta; -import org.junit.Assert; -import org.junit.Test; - -import com.fasterxml.jackson.databind.type.SimpleType; - -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.buffer.impl.BufferImpl; -import io.vertx.core.http.CaseInsensitiveHeaders; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestDefaultHttpClientFilter { - private DefaultHttpClientFilter filter = new DefaultHttpClientFilter(); - - @Test - public void testOrder() { - Assert.assertEquals(Integer.MAX_VALUE, filter.getOrder()); - } - - @Test - public void testFindProduceProcessorNullContentType(@Mocked RestOperationMeta restOperation, - @Mocked HttpServletResponseEx responseEx) { - new Expectations() { - { - responseEx.getHeader(HttpHeaders.CONTENT_TYPE); - result = null; - } - }; - - Assert.assertNull(filter.findProduceProcessor(restOperation, responseEx)); - } - - @Test - public void testFindProduceProcessorJson(@Mocked RestOperationMeta restOperation, - @Mocked HttpServletResponseEx responseEx, @Mocked ProduceProcessor produceProcessor) { - new Expectations() { - { - responseEx.getHeader(HttpHeaders.CONTENT_TYPE); - result = "json"; - restOperation.findProduceProcessor("json"); - result = produceProcessor; - } - }; - - Assert.assertSame(produceProcessor, filter.findProduceProcessor(restOperation, responseEx)); - } - - @Test - public void testFindProduceProcessorJsonWithCharset(@Mocked RestOperationMeta restOperation, - @Mocked HttpServletResponseEx responseEx, @Mocked ProduceProcessor produceProcessor) { - new Expectations() { - { - responseEx.getHeader(HttpHeaders.CONTENT_TYPE); - result = "json; UTF-8"; - restOperation.findProduceProcessor("json"); - result = produceProcessor; - } - }; - - Assert.assertSame(produceProcessor, filter.findProduceProcessor(restOperation, responseEx)); - } - - @Test - public void extractResult_readStreamPart(@Mocked Invocation invocation, @Mocked ReadStreamPart part, - @Mocked HttpServletResponseEx responseEx) { - Map handlerContext = new HashMap<>(); - handlerContext.put(RestConst.READ_STREAM_PART, part); - new Expectations() { - { - invocation.getHandlerContext(); - result = handlerContext; - responseEx.getStatusType(); - result = Status.OK; - } - }; - - Response response = filter.extractResponse(invocation, responseEx); - Assert.assertSame(part, response.getResult()); - Assert.assertEquals(Status.OK, response.getStatus()); - } - - @Test - public void extractResult_decodeError(@Mocked Invocation invocation, @Mocked ReadStreamPart part, - @Mocked OperationMeta operationMeta, @Mocked ResponseMeta responseMeta, - @Mocked RestOperationMeta swaggerRestOperation, - @Mocked HttpServletResponseEx responseEx) { - Map handlerContext = new HashMap<>(); - new Expectations() { - { - invocation.getHandlerContext(); - result = handlerContext; - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.findResponseMeta(400); - result = responseMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerRestOperation; - responseMeta.getJavaType(); - result = SimpleType.constructUnsafe(Date.class); - responseEx.getStatus(); - result = 400; - responseEx.getBodyBuffer(); - result = new BufferImpl().appendString("abc"); - } - }; - new MockUp() { - @Mock - ProduceProcessor findProduceProcessor(RestOperationMeta restOperation, HttpServletResponseEx responseEx) { - return new ProduceJsonProcessor(); - } - }; - - Response response = filter.extractResponse(invocation, responseEx); - Assert.assertEquals(400, response.getStatusCode()); - Assert.assertEquals(InvocationException.class, response.getResult().getClass()); - InvocationException invocationException = response.getResult(); - Assert.assertEquals( - "InvocationException: code=400;msg=CommonExceptionData [message=method null, path null, statusCode 400, reasonPhrase null, response content-type null is not supported]", - invocationException.getMessage()); - Assert.assertEquals("Unrecognized token 'abc': was expecting ('true', 'false' or 'null')\n" - + " at [Source: (org.apache.servicecomb.foundation.vertx.stream.BufferInputStream); line: 1, column: 7]", - invocationException.getCause().getMessage()); - Assert.assertEquals(CommonExceptionData.class, invocationException.getErrorData().getClass()); - CommonExceptionData commonExceptionData = (CommonExceptionData) invocationException.getErrorData(); - Assert.assertEquals( - "method null, path null, statusCode 400, reasonPhrase null, response content-type null is not supported", - commonExceptionData.getMessage()); - } - - @Test - public void extractResult_decodeError200(@Mocked Invocation invocation, @Mocked ReadStreamPart part, - @Mocked OperationMeta operationMeta, @Mocked ResponseMeta responseMeta, - @Mocked RestOperationMeta swaggerRestOperation, - @Mocked HttpServletResponseEx responseEx) { - Map handlerContext = new HashMap<>(); - new Expectations() { - { - invocation.getHandlerContext(); - result = handlerContext; - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.findResponseMeta(200); - result = responseMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerRestOperation; - responseMeta.getJavaType(); - result = SimpleType.constructUnsafe(Date.class); - responseEx.getStatus(); - result = 200; - responseEx.getBodyBuffer(); - result = new BufferImpl().appendString("abc"); - } - }; - new MockUp() { - @Mock - ProduceProcessor findProduceProcessor(RestOperationMeta restOperation, HttpServletResponseEx responseEx) { - return new ProduceJsonProcessor(); - } - }; - - Response response = filter.extractResponse(invocation, responseEx); - Assert.assertEquals(400, response.getStatusCode()); - Assert.assertEquals(InvocationException.class, response.getResult().getClass()); - InvocationException invocationException = response.getResult(); - Assert.assertEquals( - "InvocationException: code=400;msg=CommonExceptionData [message=method null, path null, statusCode 200, reasonPhrase null, response content-type null is not supported]", - invocationException.getMessage()); - Assert.assertEquals("Unrecognized token 'abc': was expecting ('true', 'false' or 'null')\n" - + " at [Source: (org.apache.servicecomb.foundation.vertx.stream.BufferInputStream); line: 1, column: 7]", - invocationException.getCause().getMessage()); - Assert.assertEquals(CommonExceptionData.class, invocationException.getErrorData().getClass()); - CommonExceptionData commonExceptionData = (CommonExceptionData) invocationException.getErrorData(); - Assert.assertEquals( - "method null, path null, statusCode 200, reasonPhrase null, response content-type null is not supported", - commonExceptionData.getMessage()); - } - - @Test - public void testAfterReceiveResponseNullProduceProcessor(@Mocked Invocation invocation, - @Mocked HttpServletResponseEx responseEx, - @Mocked OperationMeta operationMeta, - @Mocked RestOperationMeta swaggerRestOperation, - @Injectable ResponseMeta responseMeta) throws Exception { - CommonExceptionData data = new CommonExceptionData("abcd"); - new Expectations() { - { - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerRestOperation; - operationMeta.findResponseMeta(403); - result = responseMeta; - responseMeta.getJavaType(); - result = SimpleType.constructUnsafe(CommonExceptionData.class); - responseEx.getStatus(); - result = 403; - responseEx.getStatusType(); - result = Status.FORBIDDEN; - responseEx.getBodyBuffer(); - result = Buffer.buffer(JsonUtils.writeValueAsString(data).getBytes()); - } - }; - - Response response = filter.afterReceiveResponse(invocation, responseEx); - Assert.assertEquals(403, response.getStatusCode()); - Assert.assertEquals("Forbidden", response.getReasonPhrase()); - Assert.assertEquals(InvocationException.class, response.getResult().getClass()); - InvocationException invocationException = response.getResult(); - Assert.assertEquals( - 403, - invocationException.getStatusCode()); - Assert.assertEquals( - "CommonExceptionData [message=abcd]", - invocationException.getErrorData().toString()); - } - - @Test - public void testAfterReceiveResponseNormal(@Mocked Invocation invocation, - @Mocked HttpServletResponseEx responseEx, - @Mocked Buffer bodyBuffer, - @Mocked OperationMeta operationMeta, - @Mocked ResponseMeta responseMeta, - @Mocked RestOperationMeta swaggerRestOperation, - @Mocked ProduceProcessor produceProcessor) throws Exception { - MultiMap responseHeader = new CaseInsensitiveHeaders(); - responseHeader.add("b", "bValue"); - - Object decodedResult = new Object(); - new Expectations() { - { - responseEx.getHeader(HttpHeaders.CONTENT_TYPE); - result = "json"; - responseEx.getHeaderNames(); - result = Arrays.asList("a", "b"); - responseEx.getHeaders("b"); - result = responseHeader.getAll("b"); - swaggerRestOperation.findProduceProcessor("json"); - result = produceProcessor; - produceProcessor.decodeResponse(bodyBuffer, responseMeta.getJavaType()); - result = decodedResult; - - invocation.getOperationMeta(); - result = operationMeta; - operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION); - result = swaggerRestOperation; - - responseEx.getStatusType(); - result = Status.OK; - } - }; - - Response response = filter.afterReceiveResponse(invocation, responseEx); - Assert.assertSame(decodedResult, response.getResult()); - Assert.assertEquals(1, response.getHeaders().getHeaderMap().size()); - Assert.assertEquals(response.getHeaders().getHeader("b"), Arrays.asList("bValue")); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestRestClientInvocation.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestRestClientInvocation.java deleted file mode 100644 index 57a590c420d..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestRestClientInvocation.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.client.http; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.Part; - -import org.apache.log4j.Level; -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder; -import org.apache.servicecomb.common.rest.filter.HttpClientFilter; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.executor.ReactiveExecutor; -import org.apache.servicecomb.core.invocation.InvocationStageTrace; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.common.utils.ReflectUtils; -import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultEndpointMetric; -import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultHttpSocketMetric; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.swagger.invocation.Response; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.Context; -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpClient; -import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.HttpConnection; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.RequestOptions; -import io.vertx.core.http.impl.VertxImplTestUtils; -import io.vertx.core.net.NetSocket; -import io.vertx.core.net.SocketAddress; -import io.vertx.core.net.impl.ConnectionBase; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRestClientInvocation { - Handler exceptionHandler; - - Handler bodyHandler; - - Map headers = new HashMap<>(); - - HttpClientRequest request = mock(HttpClientRequest.class); - - HttpClient httpClient = mock(HttpClient.class); - - Context context = mock(Context.class); - - HttpClientWithContext httpClientWithContext = new HttpClientWithContext(httpClient, context); - - Invocation invocation = mock(Invocation.class); - - InvocationStageTrace invocationStageTrace = new InvocationStageTrace(invocation); - - Response response; - - AsyncResponse asyncResp = resp -> { - response = resp; - }; - - OperationMeta operationMeta = mock(OperationMeta.class); - - Endpoint endpoint = mock(Endpoint.class); - - RestOperationMeta swaggerRestOperation = mock(RestOperationMeta.class); - - URLPathBuilder urlPathBuilder = mock(URLPathBuilder.class); - - URIEndpointObject address = mock(URIEndpointObject.class); - - List httpClientFilters = new ArrayList<>(); - - RestClientInvocation restClientInvocation = new RestClientInvocation(httpClientWithContext, httpClientFilters); - - Map handlerContext = new HashMap<>(); - - static long nanoTime = 123; - - @BeforeClass - public static void classSetup() { - new MockUp() { - @Mock - long nanoTime() { - return nanoTime; - } - }; - } - - @SuppressWarnings("unchecked") - @Before - public void setup() { - Deencapsulation.setField(restClientInvocation, "clientRequest", request); - Deencapsulation.setField(restClientInvocation, "invocation", invocation); - Deencapsulation.setField(restClientInvocation, "asyncResp", asyncResp); - - when(invocation.getOperationMeta()).thenReturn(operationMeta); - when(swaggerRestOperation.getPathBuilder()).thenReturn(urlPathBuilder); - when(swaggerRestOperation.getHttpMethod()).thenReturn("GET"); - when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(swaggerRestOperation); - when(invocation.getEndpoint()).thenReturn(endpoint); - when(endpoint.getAddress()).thenReturn(address); - when(invocation.getHandlerContext()).then(answer -> handlerContext); - when(invocation.getInvocationStageTrace()).thenReturn(invocationStageTrace); - when(httpClient.request((HttpMethod) Mockito.any(), (RequestOptions) Mockito.any(), Mockito.any())) - .thenReturn(request); - - ConnectionBase connectionBase = VertxImplTestUtils.mockClientConnection(); - when(connectionBase.metric()).thenReturn(Mockito.mock(DefaultHttpSocketMetric.class)); - when(request.connection()).thenReturn((HttpConnection) connectionBase); - - DefaultHttpSocketMetric httpSocketMetric = new DefaultHttpSocketMetric(Mockito.mock(DefaultEndpointMetric.class)); - httpSocketMetric.requestBegin(); - httpSocketMetric.requestEnd(); - when(connectionBase.metric()).thenReturn(httpSocketMetric); - - doAnswer(a -> { - exceptionHandler = (Handler) a.getArguments()[0]; - return request; - }).when(request).exceptionHandler(any()); - doAnswer(a -> { - headers.put(a.getArgumentAt(0, String.class), a.getArgumentAt(1, String.class)); - return request; - }).when(request).putHeader((String) any(), (String) any()); - doAnswer(a -> { - ((Handler) a.getArguments()[0]).handle(null); - return null; - }).when(context).runOnContext(any()); - } - - @Test - public void invoke(@Mocked Response resp) throws Exception { - doAnswer(a -> { - asyncResp.complete(resp); - return null; - }).when(request).end(); - restClientInvocation.invoke(invocation, asyncResp); - - Assert.assertSame(resp, response); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartSend()); - } - - @Test - public void invoke_endThrow() throws Exception { - Mockito.doThrow(Error.class).when(request).end(); - restClientInvocation.invoke(invocation, asyncResp); - - Assert.assertThat(((InvocationException) response.getResult()).getCause(), Matchers.instanceOf(Error.class)); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishClientFiltersResponse()); - } - - @Test - public void invoke_requestThrow() throws Exception { - Throwable t = new Error(); - doAnswer(a -> { - exceptionHandler.handle(t); - return null; - }).when(request).end(); - restClientInvocation.invoke(invocation, asyncResp); - restClientInvocation.invoke(invocation, asyncResp); - - Assert.assertThat(((InvocationException) response.getResult()).getCause(), Matchers.sameInstance(t)); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartClientFiltersRequest()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishClientFiltersResponse()); - } - - @Test - public void testSetCseContext() { - Map contextMap = Collections.singletonMap("k", "v"); - when(invocation.getContext()).thenReturn(contextMap); - - restClientInvocation.setCseContext(); - - Assert.assertEquals("{x-cse-context={\"k\":\"v\"}}", headers.toString()); - } - - @Test - public void testSetCseContext_failed() { - LogCollector logCollector = new LogCollector(); - logCollector.setLogLevel(RestClientInvocation.class.getName(), Level.DEBUG); - Deencapsulation.setField(restClientInvocation, "invocation", null); - - restClientInvocation.setCseContext(); - - Assert.assertEquals("Failed to encode and set cseContext.", logCollector.getEvents().get(0).getMessage()); - logCollector.teardown(); - } - - @SuppressWarnings("unchecked") - @Test - public void handleResponse() { - HttpClientResponse httpClientResponse = mock(HttpClientResponse.class); - doAnswer(a -> { - bodyHandler = (Handler) a.getArguments()[0]; - return httpClientResponse; - }).when(httpClientResponse).bodyHandler(any()); - - Buffer buf = Buffer.buffer(); - new MockUp(restClientInvocation) { - @Mock - void processResponseBody(Buffer responseBuf) { - asyncResp.success(buf); - } - }; - - restClientInvocation.handleResponse(httpClientResponse); - bodyHandler.handle(buf); - - Assert.assertSame(buf, response.getResult()); - } - - public Part returnPart() { - return null; - } - - @Test - public void handleResponse_readStreamPart() { - HttpClientResponse httpClientResponse = mock(HttpClientResponse.class); - when(httpClientResponse.statusCode()).thenReturn(200); - Method method = ReflectUtils.findMethod(this.getClass(), "returnPart"); - when(operationMeta.getMethod()).thenReturn(method); - new MockUp(restClientInvocation) { - @Mock - void processResponseBody(Buffer responseBuf) { - } - }; - - restClientInvocation.handleResponse(httpClientResponse); - - Assert.assertThat(handlerContext.get(RestConst.READ_STREAM_PART), Matchers.instanceOf(ReadStreamPart.class)); - } - - @SuppressWarnings("unchecked") - @Test - public void handleResponse_responseException() { - HttpClientResponse httpClientResponse = mock(HttpClientResponse.class); - - NetSocket netSocket = mock(NetSocket.class); - when(httpClientResponse.netSocket()).thenReturn(netSocket); - when(netSocket.remoteAddress()).thenReturn(mock(SocketAddress.class)); - - doAnswer(a -> { - exceptionHandler = (Handler) a.getArguments()[0]; - return httpClientResponse; - }).when(httpClientResponse).exceptionHandler(any()); - - restClientInvocation.handleResponse(httpClientResponse); - Error error = new Error(); - exceptionHandler.handle(error); - - Assert.assertThat(((InvocationException) response.getResult()).getCause(), Matchers.sameInstance(error)); - } - - @Test - public void processResponseBody() { - Response resp = Response.ok(null); - - HttpClientResponse httpClientResponse = mock(HttpClientResponse.class); - Deencapsulation.setField(restClientInvocation, "clientResponse", httpClientResponse); - - { - HttpClientFilter filter = mock(HttpClientFilter.class); - when(filter.afterReceiveResponse(any(), any())).thenReturn(null); - when(filter.enabled()).thenReturn(true); - httpClientFilters.add(filter); - } - { - HttpClientFilter filter = mock(HttpClientFilter.class); - when(filter.afterReceiveResponse(any(), any())).thenReturn(resp); - when(filter.enabled()).thenReturn(true); - httpClientFilters.add(filter); - } - - when(invocation.getResponseExecutor()).thenReturn(new ReactiveExecutor()); - - restClientInvocation.processResponseBody(null); - - Assert.assertSame(resp, response); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishReceiveResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishGetConnection()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishWriteToBuffer()); - } - - @SuppressWarnings("unchecked") - @Test - public void processResponseBody_throw() { - HttpClientResponse httpClientResponse = mock(HttpClientResponse.class); - Deencapsulation.setField(restClientInvocation, "clientResponse", httpClientResponse); - - { - HttpClientFilter filter = mock(HttpClientFilter.class); - when(filter.afterReceiveResponse(any(), any())).thenThrow(Error.class); - when(filter.enabled()).thenReturn(true); - httpClientFilters.add(filter); - } - - when(invocation.getResponseExecutor()).thenReturn(new ReactiveExecutor()); - - restClientInvocation.processResponseBody(null); - - Assert.assertThat(((InvocationException) response.getResult()).getCause(), Matchers.instanceOf(Error.class)); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getStartClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishClientFiltersResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishReceiveResponse()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishGetConnection()); - Assert.assertEquals(nanoTime, invocation.getInvocationStageTrace().getFinishWriteToBuffer()); - } - - @Test - public void createRequestPath_NoUrlPrefixNoPath() throws Exception { - when(address.getFirst(Const.URL_PREFIX)).thenReturn(null); - - when(urlPathBuilder.createRequestPath(any())).thenReturn("/path"); - - String path = restClientInvocation.createRequestPath(swaggerRestOperation); - Assert.assertEquals("/path", path); - } - - @Test - public void createRequestPath_noUrlPrefixHavePath() throws Exception { - handlerContext.put(RestConst.REST_CLIENT_REQUEST_PATH, "/client/path"); - when(address.getFirst(Const.URL_PREFIX)).thenReturn(null); - - String path = restClientInvocation.createRequestPath(swaggerRestOperation); - Assert.assertEquals("/client/path", path); - } - - @Test - public void createRequestPath_haveUrlPrefixNoPath() throws Exception { - when(address.getFirst(Const.URL_PREFIX)).thenReturn("/prefix"); - - when(urlPathBuilder.createRequestPath(any())).thenReturn("/path"); - - String path = restClientInvocation.createRequestPath(swaggerRestOperation); - Assert.assertEquals("/prefix/path", path); - } - - @Test - public void createRequestPath_haveUrlPrefixHavePath() throws Exception { - when(address.getFirst(Const.URL_PREFIX)).thenReturn("/prefix"); - handlerContext.put(RestConst.REST_CLIENT_REQUEST_PATH, "/client/path"); - - String path = restClientInvocation.createRequestPath(swaggerRestOperation); - Assert.assertEquals("/prefix/client/path", path); - } - - @Test - public void createRequestPath_haveUrlPrefixHavePathAndStartWith() throws Exception { - when(address.getFirst(Const.URL_PREFIX)).thenReturn("/prefix"); - handlerContext.put(RestConst.REST_CLIENT_REQUEST_PATH, "/prefix/client/path"); - - String path = restClientInvocation.createRequestPath(swaggerRestOperation); - Assert.assertEquals("/prefix/client/path", path); - } -} diff --git a/transports/transport-rest/transport-rest-client/src/test/resources/log4j.properties b/transports/transport-rest/transport-rest-client/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/transports/transport-rest/transport-rest-client/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/transports/transport-rest/transport-rest-client/src/test/resources/log4j2.xml b/transports/transport-rest/transport-rest-client/src/test/resources/log4j2.xml new file mode 100644 index 00000000000..8cee07220ec --- /dev/null +++ b/transports/transport-rest/transport-rest-client/src/test/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/transports/transport-rest/transport-rest-servlet/pom.xml b/transports/transport-rest/transport-rest-servlet/pom.xml index a27f58e6762..0bdac6777ef 100644 --- a/transports/transport-rest/transport-rest-servlet/pom.xml +++ b/transports/transport-rest/transport-rest-servlet/pom.xml @@ -22,15 +22,15 @@ org.apache.servicecomb transport-rest - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT transport-rest-servlet Java Chassis::Transports::Rest::Servlet - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api @@ -41,20 +41,29 @@ org.apache.servicecomb transport-rest-client - - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + registry-service-center + test + + + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test org.apache.servicecomb foundation-test-scaffolding + + org.jmockit + jmockit + test + diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseDispatcherServlet.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseDispatcherServlet.java deleted file mode 100644 index 1b2ad700050..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseDispatcherServlet.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.servicecomb.transport.rest.servlet; - -import org.springframework.context.ApplicationContext; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; - -public class CseDispatcherServlet extends DispatcherServlet { - private static final long serialVersionUID = 5755456289644038012L; - - @Override - protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { - setContextClass(CseXmlWebApplicationContext.class); - return super.createWebApplicationContext(parent); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseXmlWebApplicationContext.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseXmlWebApplicationContext.java deleted file mode 100644 index 59918d52485..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/CseXmlWebApplicationContext.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.Set; - -import javax.servlet.ServletContext; - -import org.apache.commons.lang3.StringUtils; -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.web.context.support.XmlWebApplicationContext; - -public class CseXmlWebApplicationContext extends XmlWebApplicationContext { - private static final Logger LOGGER = LoggerFactory.getLogger(CseXmlWebApplicationContext.class); - - static final String KEY_LOCATION = "contextConfigLocation"; - - private String defaultBeanResource = BeanUtils.DEFAULT_BEAN_RESOURCE; - - public CseXmlWebApplicationContext() { - } - - public CseXmlWebApplicationContext(ServletContext servletContext) { - setServletContext(servletContext); - } - - public void setDefaultBeanResource(String defaultBeanResource) { - this.defaultBeanResource = defaultBeanResource; - } - - @Override - protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { - super.invokeBeanFactoryPostProcessors(beanFactory); - - // inject servlet after config installed and before transport init - ServletUtils.init(getServletContext()); - } - - @Override - public String[] getConfigLocations() { - String contextConfigLocation = getServletContext().getInitParameter(KEY_LOCATION); - String[] locationArray = splitLocations(contextConfigLocation); - - LOGGER.info("init spring context: {}.", Arrays.toString(locationArray)); - return locationArray; - } - - private String[] splitLocations(String locations) { - Set locationSet = new LinkedHashSet<>(); - if (!StringUtils.isEmpty(locations)) { - for (String location : locations.split("[,\n]")) { - location = location.trim(); - if (StringUtils.isEmpty(location)) { - continue; - } - - locationSet.add(location); - } - } - - if (!StringUtils.isEmpty(defaultBeanResource)) { - locationSet.add(defaultBeanResource); - } - - return locationSet.toArray(new String[locationSet.size()]); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestAsyncListener.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestAsyncListener.java index 08d87bf1ba3..0ed7ad203b6 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestAsyncListener.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestAsyncListener.java @@ -20,13 +20,13 @@ import java.io.IOException; import java.io.PrintWriter; -import javax.servlet.AsyncEvent; -import javax.servlet.AsyncListener; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; +import jakarta.servlet.AsyncEvent; +import jakarta.servlet.AsyncListener; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.foundation.common.utils.JsonUtils; diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServlet.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServlet.java index 0fb3385813a..d4d26f0117b 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServlet.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServlet.java @@ -17,10 +17,10 @@ package org.apache.servicecomb.transport.rest.servlet; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +33,7 @@ public class RestServlet extends HttpServlet { private static final Logger LOGGER = LoggerFactory.getLogger(RestServlet.class); - private ServletRestDispatcher servletRestServer = new ServletRestDispatcher(); + private final ServletRestDispatcher servletRestServer = new ServletRestDispatcher(); @Override public void init() throws ServletException { diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletContextListener.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletContextListener.java deleted file mode 100644 index df15558d7ac..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletContextListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import static java.lang.Boolean.FALSE; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.servicecomb.foundation.common.utils.Log4jUtils; -import org.springframework.context.support.AbstractApplicationContext; - -public class RestServletContextListener implements ServletContextListener { - private AbstractApplicationContext context; - - @Override - public void contextInitialized(ServletContextEvent sce) { - try { - initLog(sce); - initSpring(sce); - } catch (Exception e) { - throw new Error(e); - } - } - - public void initLog(ServletContextEvent sce) throws Exception { - String logMerged = sce.getServletContext().getInitParameter("servicecomb.logging.merged"); - if (!FALSE.toString().equalsIgnoreCase(logMerged)) { - Log4jUtils.init(); - } - } - - public AbstractApplicationContext initSpring(ServletContextEvent sce) { - context = new CseXmlWebApplicationContext(sce.getServletContext()); - context.refresh(); - return context; - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - if (context == null) { - return; - } - - context.close(); - context = null; - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletInjector.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletInjector.java index 7caa36f5715..24879517664 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletInjector.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletInjector.java @@ -19,33 +19,34 @@ import java.util.Arrays; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration.Dynamic; - +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; +import org.springframework.core.env.Environment; + +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletRegistration.Dynamic; public class RestServletInjector { private static final Logger LOGGER = LoggerFactory.getLogger(RestServletInjector.class); public static final String SERVLET_NAME = "ServicecombRestServlet"; - public static Dynamic defaultInject(ServletContext servletContext) { + public static Dynamic defaultInject(ServletContext servletContext, Environment environment) { RestServletInjector injector = new RestServletInjector(); - String urlPattern = ServletConfig.getServletUrlPattern(); - return injector.inject(servletContext, urlPattern); + String urlPattern = ServletConfig.getServletUrlPattern(environment); + return injector.inject(servletContext, urlPattern, environment); } - public Dynamic inject(ServletContext servletContext, String urlPattern) { + public Dynamic inject(ServletContext servletContext, String urlPattern, Environment environment) { String[] urlPatterns = splitUrlPattern(urlPattern); if (urlPatterns.length == 0) { LOGGER.warn("urlPattern is empty, ignore register {}.", SERVLET_NAME); return null; } - String listenAddress = ServletConfig.getLocalServerAddress(); + String listenAddress = ServletConfig.getLocalServerAddress(environment); if (!ServletUtils.canPublishEndpoint(listenAddress)) { LOGGER.warn("ignore register {}.", SERVLET_NAME); return null; diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocation.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocation.java deleted file mode 100644 index 299c6112c13..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocation.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import org.apache.servicecomb.common.rest.RestProducerInvocation; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletRequestEx; - -public class RestServletProducerInvocation extends RestProducerInvocation { - @Override - protected void findRestOperation() { - super.findRestOperation(); - - boolean cacheRequest = collectCacheRequest(restOperationMeta.getOperationMeta()); - ((StandardHttpServletRequestEx) requestEx).setCacheRequest(cacheRequest); - } - - protected boolean collectCacheRequest(OperationMeta operationMeta) { - for (HttpServerFilter filter : httpServerFilters) { - if (filter.needCacheRequest(operationMeta)) { - return true; - } - } - return false; - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java new file mode 100644 index 00000000000..1b31cf95336 --- /dev/null +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.transport.rest.servlet; + +import org.apache.servicecomb.common.rest.HttpTransportContext; +import org.apache.servicecomb.common.rest.RestProducerInvocationCreator; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; +import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; + +public class RestServletProducerInvocationCreator extends RestProducerInvocationCreator { + public RestServletProducerInvocationCreator(MicroserviceMeta microserviceMeta, Endpoint endpoint, + HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) { + super(microserviceMeta, endpoint, requestEx, responseEx); + } + + @Override + protected void initTransportContext(Invocation invocation) { + HttpTransportContext transportContext = new HttpTransportContext(requestEx, responseEx); + invocation.setTransportContext(transportContext); + } +} diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletConfig.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletConfig.java index 9993a3dfb8f..195e3fe3681 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletConfig.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletConfig.java @@ -17,9 +17,7 @@ package org.apache.servicecomb.transport.rest.servlet; -import com.netflix.config.DynamicLongProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; +import org.springframework.core.env.Environment; public final class ServletConfig { public static final long DEFAULT_ASYN_SERVLET_TIMEOUT = -1; @@ -32,26 +30,19 @@ public final class ServletConfig { public static final String DEFAULT_URL_PATTERN = "/*"; - private static final DynamicLongProperty asyncServletTimeoutProperty = - DynamicPropertyFactory.getInstance().getLongProperty(KEY_SERVICECOMB_ASYC_SERVLET_TIMEOUT, - DEFAULT_ASYN_SERVLET_TIMEOUT); - private ServletConfig() { } - public static long getAsyncServletTimeout() { - return asyncServletTimeoutProperty.get(); + public static long getAsyncServletTimeout(Environment environment) { + return environment.getProperty(KEY_SERVICECOMB_ASYC_SERVLET_TIMEOUT, long.class, + DEFAULT_ASYN_SERVLET_TIMEOUT); } - public static String getLocalServerAddress() { - DynamicStringProperty address = - DynamicPropertyFactory.getInstance().getStringProperty(SERVICECOMB_REST_ADDRESS, null); - return address.get(); + public static String getLocalServerAddress(Environment environment) { + return environment.getProperty(SERVICECOMB_REST_ADDRESS); } - public static String getServletUrlPattern() { - DynamicStringProperty address = - DynamicPropertyFactory.getInstance().getStringProperty(KEY_SERVLET_URL_PATTERN, null); - return address.get(); + public static String getServletUrlPattern(Environment environment) { + return environment.getProperty(KEY_SERVLET_URL_PATTERN, DEFAULT_URL_PATTERN); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestDispatcher.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestDispatcher.java index 01dd4b17f26..b0f465d9c87 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestDispatcher.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestDispatcher.java @@ -17,43 +17,46 @@ package org.apache.servicecomb.transport.rest.servlet; -import java.util.List; - -import javax.servlet.AsyncContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.invocation.InvocationCreator; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletRequestEx; import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletResponseEx; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + public class ServletRestDispatcher { - private RestAsyncListener restAsyncListener = new RestAsyncListener(); + private final RestAsyncListener restAsyncListener = new RestAsyncListener(); private Transport transport; - private List httpServerFilters = SPIServiceUtils.getSortedService(HttpServerFilter.class); + private MicroserviceMeta microserviceMeta; public void service(HttpServletRequest request, HttpServletResponse response) { if (transport == null) { - transport = CseContext.getInstance().getTransportManager().findTransport(Const.RESTFUL); + transport = SCBEngine.getInstance().getTransportManager().findTransport(CoreConst.RESTFUL); + microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); } // 异步场景 - final AsyncContext asyncCtx = request.startAsync(); + AsyncContext asyncCtx = request.startAsync(); asyncCtx.addListener(restAsyncListener); - asyncCtx.setTimeout(ServletConfig.getAsyncServletTimeout()); + asyncCtx.setTimeout(ServletConfig.getAsyncServletTimeout(SCBEngine.getInstance().getEnvironment())); HttpServletRequestEx requestEx = new StandardHttpServletRequestEx(request); HttpServletResponseEx responseEx = new StandardHttpServletResponseEx(response); - RestServletProducerInvocation restProducerInvocation = new RestServletProducerInvocation(); - restProducerInvocation.invoke(transport, requestEx, responseEx, httpServerFilters); + ((StandardHttpServletRequestEx) requestEx).setCacheRequest(true); + InvocationCreator creator = new RestServletProducerInvocationCreator(microserviceMeta, transport.getEndpoint(), + requestEx, responseEx); + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java index a6981887ea2..b06fbfcba04 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletRestTransport.java @@ -20,31 +20,25 @@ import java.util.HashMap; import java.util.Map; -import org.apache.servicecomb.core.Invocation; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.transport.AbstractTransport; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.transport.rest.client.RestTransportClient; -import org.apache.servicecomb.transport.rest.client.RestTransportClientManager; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; -@Component public class ServletRestTransport extends AbstractTransport { private static final Logger LOGGER = LoggerFactory.getLogger(ServletRestTransport.class); - private RestTransportClient restClient; - @Override public String getName() { - return org.apache.servicecomb.core.Const.RESTFUL; + return CoreConst.RESTFUL; } @Override public boolean canInit() { - String listenAddress = ServletConfig.getLocalServerAddress(); + String listenAddress = ServletConfig.getLocalServerAddress(environment); if (listenAddress == null) { // not publish, but can init and be RESTful client return true; @@ -60,21 +54,15 @@ public boolean canInit() { @Override public boolean init() { - String urlPrefix = System.getProperty(Const.URL_PREFIX); + String urlPrefix = ClassLoaderScopeContext.getClassLoaderScopeProperty(DefinitionConst.URL_PREFIX); Map queryMap = new HashMap<>(); if (!StringUtils.isEmpty(urlPrefix)) { - queryMap.put(Const.URL_PREFIX, urlPrefix); + queryMap.put(DefinitionConst.URL_PREFIX, urlPrefix); } - String listenAddress = ServletConfig.getLocalServerAddress(); + String listenAddress = ServletConfig.getLocalServerAddress(environment); setListenAddressWithoutSchema(listenAddress, queryMap); - restClient = RestTransportClientManager.INSTANCE.getRestClient(); return true; } - - @Override - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - restClient.send(invocation, asyncResp); - } } diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java index 94c726f2a24..6bdead6974b 100644 --- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java +++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/ServletUtils.java @@ -23,19 +23,21 @@ import java.util.List; import java.util.stream.Collectors; -import javax.servlet.MultipartConfigElement; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; -import javax.servlet.ServletRegistration.Dynamic; - +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.common.rest.UploadConfig; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.common.net.IpPort; import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.apache.servicecomb.serviceregistry.api.Const; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; +import org.springframework.core.env.Environment; + +import jakarta.servlet.MultipartConfigElement; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletRegistration; +import jakarta.servlet.ServletRegistration.Dynamic; public class ServletUtils { private static final Logger LOGGER = LoggerFactory.getLogger(ServletUtils.class); @@ -68,7 +70,7 @@ static void checkUrlPattern(String urlPattern) { } int idx = urlPattern.indexOf("/*"); - if (idx < 0 || (idx >= 0 && idx != urlPattern.length() - 2)) { + if (idx < 0 || idx != urlPattern.length() - 2) { throw new ServiceCombException("only support rule like /* or /path/* or /path1/path2/* and so on."); } } @@ -106,6 +108,9 @@ static String[] collectUrlPatterns(ServletContext servletContext, Class servl static List findServletRegistrations(ServletContext servletContext, Class servletCls) { + if (servletContext == null) { + return null; + } return servletContext.getServletRegistrations() .values() .stream() @@ -132,7 +137,7 @@ public static void saveUrlPrefix(ServletContext servletContext) { return; } - System.setProperty(Const.URL_PREFIX, urlPrefix); + ClassLoaderScopeContext.setClassLoaderScopeProperty(DefinitionConst.URL_PREFIX, urlPrefix); LOGGER.info("UrlPrefix of this instance is \"{}\".", urlPrefix); } @@ -150,30 +155,29 @@ static File createUploadDir(ServletContext servletContext, String location) { return dir; } - static void setServletParameters(ServletContext servletContext) { - UploadConfig uploadConfig = new UploadConfig(); + static void setServletParameters(ServletContext servletContext, Environment environment) { + UploadConfig uploadConfig = new UploadConfig(environment); MultipartConfigElement multipartConfig = uploadConfig.toMultipartConfigElement(); - if (multipartConfig == null) { - return; - } File dir = createUploadDir(servletContext, multipartConfig.getLocation()); - LOGGER.info("set uploads directory to {}.", dir.getAbsolutePath()); + LOGGER.info("set uploads directory to \"{}\".", dir.getAbsolutePath()); List servlets = findServletRegistrations(servletContext, RestServlet.class); - for (ServletRegistration servletRegistration : servlets) { - if (!Dynamic.class.isInstance(servletRegistration)) { - continue; + if (servlets != null) { + for (ServletRegistration servletRegistration : servlets) { + if (!Dynamic.class.isInstance(servletRegistration)) { + continue; + } + + Dynamic dynamic = (Dynamic) servletRegistration; + dynamic.setMultipartConfig(multipartConfig); } - - Dynamic dynamic = (Dynamic) servletRegistration; - dynamic.setMultipartConfig(multipartConfig); } } - public static void init(ServletContext servletContext) { - RestServletInjector.defaultInject(servletContext); + public static void init(ServletContext servletContext, Environment environment) { + RestServletInjector.defaultInject(servletContext, environment); ServletUtils.saveUrlPrefix(servletContext); - setServletParameters(servletContext); + setServletParameters(servletContext, environment); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport b/transports/transport-rest/transport-rest-servlet/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport new file mode 100644 index 00000000000..f4603761582 --- /dev/null +++ b/transports/transport-rest/transport-rest-servlet/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.transport.rest.servlet.ServletRestTransport diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestCseXmlWebApplicationContext.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestCseXmlWebApplicationContext.java deleted file mode 100644 index 8d1b89605bc..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestCseXmlWebApplicationContext.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration.Dynamic; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.foundation.common.utils.BeanUtils; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; - -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestCseXmlWebApplicationContext { - @Mocked - ServletContext servletContext; - - CseXmlWebApplicationContext context; - - @Before - public void setup() { - context = new CseXmlWebApplicationContext(servletContext); - } - - @Test - public void testGetConfigLocationsEmpty() { - String[] result = context.getConfigLocations(); - Assert.assertThat(result, Matchers.arrayContaining(BeanUtils.DEFAULT_BEAN_RESOURCE)); - } - - @Test - public void testGetConfigLocationsEmptyAndDefaultEmpty() { - context.setDefaultBeanResource(""); - String[] result = context.getConfigLocations(); - Assert.assertThat(result.length, Matchers.is(0)); - } - - @Test - public void testGetConfigLocationsComma() { - new Expectations() { - { - servletContext.getInitParameter(CseXmlWebApplicationContext.KEY_LOCATION); - result = "a,b"; - } - }; - - String[] result = context.getConfigLocations(); - Assert.assertThat(result, Matchers.arrayContaining("a", "b", BeanUtils.DEFAULT_BEAN_RESOURCE)); - } - - @Test - public void testGetConfigLocationsPartEmpty() { - new Expectations() { - { - servletContext.getInitParameter(CseXmlWebApplicationContext.KEY_LOCATION); - result = "a,,b"; - } - }; - String[] result = context.getConfigLocations(); - Assert.assertThat(result, Matchers.arrayContaining("a", "b", BeanUtils.DEFAULT_BEAN_RESOURCE)); - } - - @Test - public void testGetConfigLocationsLine() { - new Expectations() { - { - servletContext.getInitParameter(CseXmlWebApplicationContext.KEY_LOCATION); - result = "a\r\nb"; - } - }; - String[] result = context.getConfigLocations(); - Assert.assertThat(result, Matchers.arrayContaining("a", "b", BeanUtils.DEFAULT_BEAN_RESOURCE)); - } - - @Test - public void testGetConfigLocationsMix() { - new Expectations() { - { - servletContext.getInitParameter(CseXmlWebApplicationContext.KEY_LOCATION); - result = "a\r\nb,,c"; - } - }; - String[] result = context.getConfigLocations(); - Assert.assertThat(result, Matchers.arrayContaining("a", "b", "c", BeanUtils.DEFAULT_BEAN_RESOURCE)); - } - - @Test - public void testInjectServlet(@Mocked ConfigurableListableBeanFactory beanFactory) { - Holder holder = new Holder<>(); - new MockUp() { - @Mock - public Dynamic defaultInject(ServletContext servletContext) { - holder.value = true; - return null; - } - }; - - context.invokeBeanFactoryPostProcessors(beanFactory); - - Assert.assertTrue(holder.value); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestAsyncListener.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestAsyncListener.java index a0c73853d87..2302d6f13b1 100644 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestAsyncListener.java +++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestAsyncListener.java @@ -22,23 +22,23 @@ import java.io.StringWriter; import java.io.Writer; -import javax.servlet.AsyncContext; -import javax.servlet.AsyncEvent; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.MediaType; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.AsyncEvent; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.MediaType; import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.foundation.vertx.http.AbstractHttpServletRequest; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletRequestEx; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; public class TestRestAsyncListener { HttpServletRequest request = new AbstractHttpServletRequest() { @@ -114,8 +114,8 @@ public void onTimeoutCommitted() throws IOException { committed = true; listener.onTimeout(event); - Assert.assertNull(request.getAttribute(RestConst.REST_REQUEST)); - Assert.assertFalse(flushed); + Assertions.assertNull(request.getAttribute(RestConst.REST_REQUEST)); + Assertions.assertFalse(flushed); } @Test @@ -123,10 +123,10 @@ public void onTimeoutNotCommitted() throws IOException { committed = false; listener.onTimeout(event); - Assert.assertNull(request.getAttribute(RestConst.REST_REQUEST)); - Assert.assertEquals(MediaType.APPLICATION_JSON, contentType); - Assert.assertEquals(500, statusCode); - Assert.assertTrue(flushed); - Assert.assertEquals("{\"message\":\"Timeout when processing the request.\"}", writer.toString()); + Assertions.assertNull(request.getAttribute(RestConst.REST_REQUEST)); + Assertions.assertEquals(MediaType.APPLICATION_JSON, contentType); + Assertions.assertEquals(500, statusCode); + Assertions.assertTrue(flushed); + Assertions.assertEquals("{\"message\":\"Timeout when processing the request.\"}", writer.toString()); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServlet.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServlet.java index bd46e4e5ecf..9c94e49d58c 100644 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServlet.java +++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServlet.java @@ -17,21 +17,23 @@ package org.apache.servicecomb.transport.rest.servlet; -import java.io.IOException; +import static org.apache.servicecomb.core.transport.AbstractTransport.PUBLISH_ADDRESS; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; +import org.springframework.core.env.Environment; +import io.vertx.core.impl.SysProps; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import mockit.Deencapsulation; import mockit.Mock; import mockit.MockUp; @@ -39,27 +41,39 @@ public class TestRestServlet { private RestServlet restservlet = null; + Environment environment = Mockito.mock(Environment.class); + @Before - public void setUp() throws Exception { + public void setUp() { + Mockito.when(environment.getProperty(PUBLISH_ADDRESS, String.class, "")) + .thenReturn(""); + Mockito.when(environment.getProperty("servicecomb.rest.publishPort", int.class, 0)) + .thenReturn(0); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); restservlet = new RestServlet(); - CseContext.getInstance().setTransportManager(Mockito.mock(TransportManager.class)); + SCBBootstrap.createSCBEngineForTest(environment); } @After - public void tearDown() throws Exception { + public void tearDown() { restservlet = null; + SCBEngine.getInstance().destroy(); } @Test public void testInit() throws ServletException { restservlet.init(); - Assert.assertTrue(true); + Assertions.assertTrue(true); } // useless, but for coverage @Test - public void testService() throws ServletException, IOException { + public void testService() { Holder holder = new Holder<>(); ServletRestDispatcher servletRestServer = new MockUp() { @Mock @@ -70,6 +84,6 @@ void service(HttpServletRequest request, HttpServletResponse response) { Deencapsulation.setField(restservlet, "servletRestServer", servletRestServer); restservlet.service(null, null); - Assert.assertTrue(holder.value); + Assertions.assertTrue(holder.value); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletContextListener.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletContextListener.java deleted file mode 100644 index 14dbe7d2cac..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletContextListener.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; - -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -public class TestRestServletContextListener { - @Test - public void testcontextInitializedException() { - boolean status = true; - RestServletContextListener listener = new RestServletContextListener(); - ServletContextEvent sce = Mockito.mock(ServletContextEvent.class); - - try { - listener.contextInitialized(sce); - } catch (Exception | Error e) { - status = false; - } - Assert.assertFalse(status); - } - - @Test - public void testInitSpring() { - boolean status = true; - RestServletContextListener listener = new RestServletContextListener(); - ServletContextEvent sce = Mockito.mock(ServletContextEvent.class); - ServletContext context = Mockito.mock(ServletContext.class); - Mockito.when(sce.getServletContext()).thenReturn(context); - Mockito.when(sce.getServletContext().getInitParameter("contextConfigLocation")).thenReturn("locations"); - try { - listener.initSpring(sce); - } catch (Exception e) { - status = false; - } - Assert.assertFalse(status); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletInjector.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletInjector.java index 6134c955d30..57b69000c6d 100644 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletInjector.java +++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletInjector.java @@ -22,26 +22,29 @@ import java.net.ServerSocket; import java.net.UnknownHostException; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration.Dynamic; - -import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletRegistration.Dynamic; import mockit.Expectations; import mockit.Mocked; public class TestRestServletInjector { + Environment environment = Mockito.mock(Environment.class); + @Test public void testDefaultInjectEmptyUrlPattern(@Mocked ServletContext servletContext, @Mocked Dynamic dynamic) { new Expectations(ServletConfig.class) { { - ServletConfig.getServletUrlPattern(); + ServletConfig.getServletUrlPattern(environment); result = null; } }; - Assert.assertEquals(null, RestServletInjector.defaultInject(servletContext)); + Assertions.assertNull(RestServletInjector.defaultInject(servletContext, environment)); } @Test @@ -52,15 +55,15 @@ public void testDefaultInjectNotListen(@Mocked ServletContext servletContext, new Expectations(ServletConfig.class) { { - ServletConfig.getServletUrlPattern(); + ServletConfig.getServletUrlPattern(environment); result = "/*"; - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "127.0.0.1:" + port; } }; } - Assert.assertEquals(null, RestServletInjector.defaultInject(servletContext)); + Assertions.assertNull(RestServletInjector.defaultInject(servletContext, environment)); } @Test @@ -71,14 +74,14 @@ public void testDefaultInjectListen(@Mocked ServletContext servletContext, new Expectations(ServletConfig.class) { { - ServletConfig.getServletUrlPattern(); + ServletConfig.getServletUrlPattern(environment); result = "/rest/*"; - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "127.0.0.1:" + port; } }; - Assert.assertEquals(dynamic, RestServletInjector.defaultInject(servletContext)); + Assertions.assertEquals(dynamic, RestServletInjector.defaultInject(servletContext, environment)); } } } diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletProducerInvocation.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletProducerInvocation.java deleted file mode 100644 index 1705792dc0e..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestRestServletProducerInvocation.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import java.util.Arrays; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.servicecomb.common.rest.RestProducerInvocation; -import org.apache.servicecomb.common.rest.definition.RestOperationMeta; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletRequestEx; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestRestServletProducerInvocation { - @Mocked - OperationMeta operationMeta; - - @Mocked - RestOperationMeta restOperationMeta; - - RestServletProducerInvocation restInvocation = new RestServletProducerInvocation(); - - @Test - public void findRestOperationCacheTrue(@Mocked HttpServletRequest request, @Mocked HttpServerFilter f1) { - HttpServletRequestEx requestEx = new StandardHttpServletRequestEx(request); - Deencapsulation.setField(restInvocation, "requestEx", requestEx); - - new MockUp() { - @Mock - void findRestOperation() { - Deencapsulation.setField(getMockInstance(), "restOperationMeta", restOperationMeta); - } - }; - - List httpServerFilters = Arrays.asList(f1); - new Expectations() { - { - f1.needCacheRequest(operationMeta); - result = true; - } - }; - - restInvocation.setHttpServerFilters(httpServerFilters); - - restInvocation.findRestOperation(); - Assert.assertTrue(Deencapsulation.getField(requestEx, "cacheRequest")); - } - - @Test - public void collectCacheRequestCacheTrue(@Mocked HttpServerFilter f1) { - List httpServerFilters = Arrays.asList(f1); - new Expectations() { - { - f1.needCacheRequest(operationMeta); - result = true; - } - }; - - restInvocation.setHttpServerFilters(httpServerFilters); - Assert.assertTrue(restInvocation.collectCacheRequest(operationMeta)); - } - - @Test - public void collectCacheRequestCacheFalse(@Mocked HttpServerFilter f1) { - List httpServerFilters = Arrays.asList(f1); - new Expectations() { - { - f1.needCacheRequest(operationMeta); - result = false; - } - }; - - restInvocation.setHttpServerFilters(httpServerFilters); - Assert.assertFalse(restInvocation.collectCacheRequest(operationMeta)); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletConfig.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletConfig.java deleted file mode 100644 index 4b0bda906bd..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.netflix.config.DynamicPropertyFactory; - -public class TestServletConfig { - @BeforeClass - public static void classSetup() { - ArchaiusUtils.resetConfig(); - } - - @AfterClass - public static void classTeardown() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testGetLocalServerAddress() { - Assert.assertNull(ServletConfig.getLocalServerAddress()); - } - - @Test - public void testGetServerTimeout() { - Assert.assertEquals(ServletConfig.DEFAULT_ASYN_SERVLET_TIMEOUT, ServletConfig.getAsyncServletTimeout()); - } - - @Test - public void testGetServletUrlPattern() { - DynamicPropertyFactory.getInstance(); - Configuration configuration = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - configuration.setProperty(ServletConfig.KEY_SERVLET_URL_PATTERN, "/*"); - Assert.assertEquals("/*", ServletConfig.getServletUrlPattern()); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestDispatcher.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestDispatcher.java deleted file mode 100644 index 6593a05d44c..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestDispatcher.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.servlet; - -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Transport; -import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; - -public class TestServletRestDispatcher { - ServletRestDispatcher dispatcher = new ServletRestDispatcher(); - - @Mocked - HttpServletRequest request; - - @Mocked - HttpServletResponse response; - - @Mocked - TransportManager transportManager; - - @Before - public void setup() { - CseContext.getInstance().setTransportManager(transportManager); - } - - @After - public void teardown() { - CseContext.getInstance().setTransportManager(null); - } - - @Test - public void service() { - Holder handled = new Holder<>(); - - new MockUp() { - @Mock - void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, - List httpServerFilters) { - handled.value = true; - } - }; - - dispatcher.service(request, response); - - Assert.assertTrue(handled.value); - } -} diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java index 714f81e6b89..6875965a109 100644 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java +++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletRestTransport.java @@ -17,117 +17,105 @@ package org.apache.servicecomb.transport.rest.servlet; +import static org.apache.servicecomb.core.transport.AbstractTransport.PUBLISH_ADDRESS; + import java.io.IOException; import java.net.ServerSocket; -import org.apache.servicecomb.serviceregistry.Features; -import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; -import org.apache.servicecomb.serviceregistry.api.Const; -import org.apache.servicecomb.transport.rest.client.RestTransportClient; -import org.apache.servicecomb.transport.rest.client.RestTransportClientManager; -import org.junit.Assert; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; +import io.vertx.core.impl.SysProps; import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; -import mockit.Mocked; public class TestServletRestTransport { - ServletRestTransport transport = new ServletRestTransport(); + ServletRestTransport transport; + + Environment environment = Mockito.mock(Environment.class); + + @Before + public void setUp() { + Mockito.when(environment.getProperty(PUBLISH_ADDRESS, "")) + .thenReturn(""); + Mockito.when(environment.getProperty("servicecomb.rest.publishPort", int.class, 0)) + .thenReturn(0); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + transport = new ServletRestTransport(); + transport.setEnvironment(environment); + } - @Test - public void testInitNotPublish(@Mocked RestTransportClient restTransportClient) { - new MockUp() { - @Mock - public RestTransportClient getRestTransportClient(boolean sslEnabled) { - return restTransportClient; - } - }; + @After + public void tearDown() { + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); + } + @Test + public void testInitNotPublish() { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = null; } }; - Assert.assertTrue(transport.init()); - Assert.assertNull(transport.getPublishEndpoint()); + Assertions.assertTrue(transport.init()); + Assertions.assertNull(transport.getPublishEndpoint()); } @Test - public void testInitPublishNoUrlPrefix(@Mocked RestTransportClient restTransportClient) { - new MockUp() { - @Mock - public RestTransportClient getRestTransportClient(boolean sslEnabled) { - return restTransportClient; - } - }; - + public void testInitPublishNoUrlPrefix() { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "1.1.1.1:1234"; } }; - System.clearProperty(Const.URL_PREFIX); - - Assert.assertTrue(transport.init()); - Assert.assertEquals("rest://1.1.1.1:1234", transport.getPublishEndpoint().getEndpoint()); + Assertions.assertTrue(transport.init()); + Assertions.assertEquals("rest://1.1.1.1:1234", transport.getPublishEndpoint().getEndpoint()); } @Test - public void testInitPublishWithUrlPrefix(@Mocked RestTransportClient restTransportClient, - @Mocked ServiceRegistry serviceRegistry) { - Features features = new Features(); - new Expectations(RegistryUtils.class) { - { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getFeatures(); - result = features; - } - }; - - new MockUp() { - @Mock - public RestTransportClient getRestTransportClient(boolean sslEnabled) { - return restTransportClient; - } - }; - + public void testInitPublishWithUrlPrefix() { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "1.1.1.1:1234"; } }; - System.setProperty(Const.URL_PREFIX, "/root"); - - Assert.assertTrue(transport.init()); - Assert.assertEquals("rest://1.1.1.1:1234?urlPrefix=/root", transport.getPublishEndpoint().getEndpoint()); + ClassLoaderScopeContext.setClassLoaderScopeProperty(DefinitionConst.URL_PREFIX, "/root"); - System.clearProperty(Const.URL_PREFIX); + Assertions.assertTrue(transport.init()); + Assertions.assertEquals("rest://1.1.1.1:1234?urlPrefix=%2Froot", transport.getPublishEndpoint().getEndpoint()); } @Test public void testGetOrder() { ServletRestTransport transport = new ServletRestTransport(); - Assert.assertEquals(0, transport.getOrder()); + Assertions.assertEquals(0, transport.getOrder()); } @Test public void testCanInitNullAddress() throws IOException { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = null; } }; ServletRestTransport transport = new ServletRestTransport(); - Assert.assertTrue(transport.canInit()); + transport.setEnvironment(environment); + Assertions.assertTrue(transport.canInit()); } @Test @@ -137,13 +125,14 @@ public void testCanInitListened() throws IOException { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "0.0.0.0:" + port; } }; ServletRestTransport transport = new ServletRestTransport(); - Assert.assertTrue(transport.canInit()); + transport.setEnvironment(environment); + Assertions.assertTrue(transport.canInit()); ss.close(); } @@ -156,12 +145,13 @@ public void testCanInitNotListened() throws IOException { new Expectations(ServletConfig.class) { { - ServletConfig.getLocalServerAddress(); + ServletConfig.getLocalServerAddress(environment); result = "0.0.0.0:" + port; } }; ServletRestTransport transport = new ServletRestTransport(); - Assert.assertFalse(transport.canInit()); + transport.setEnvironment(environment); + Assertions.assertFalse(transport.canInit()); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java index 28506948c79..b40eb473aba 100644 --- a/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java +++ b/transports/transport-rest/transport-rest-servlet/src/test/java/org/apache/servicecomb/transport/rest/servlet/TestServletUtils.java @@ -29,36 +29,43 @@ import java.util.List; import java.util.Map; -import javax.servlet.MultipartConfigElement; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; -import javax.servlet.ServletRegistration.Dynamic; -import javax.servlet.http.HttpServlet; - import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.apache.servicecomb.serviceregistry.api.Const; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.registry.definition.DefinitionConst; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; - +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; + +import jakarta.servlet.MultipartConfigElement; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletRegistration; +import jakarta.servlet.ServletRegistration.Dynamic; +import jakarta.servlet.http.HttpServlet; import mockit.Expectations; import mockit.Mock; import mockit.MockUp; import mockit.Mocked; public class TestServletUtils { + Environment environment = Mockito.mock(Environment.class); + @Before public void setUp() { - ArchaiusUtils.resetConfig(); - } - - @After - public void tearDown() { - ArchaiusUtils.resetConfig(); + Mockito.when(environment.getProperty(RestConst.UPLOAD_DIR, RestConst.UPLOAD_DEFAULT_DIR)) + .thenReturn(RestConst.UPLOAD_DEFAULT_DIR); + Mockito.when(environment.getProperty(RestConst.UPLOAD_MAX_FILE_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_MAX_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, int.class, 0)) + .thenReturn(0); + LegacyPropertyFactory.setEnvironment(environment); } @Test @@ -74,9 +81,9 @@ public void testCheckUrlPatternNormal() { public void testCheckUrlPatternMiddleWideChar() { try { ServletUtils.checkUrlPattern("/abc/*def"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); + Assertions.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); } } @@ -84,9 +91,9 @@ public void testCheckUrlPatternMiddleWideChar() { public void testCheckUrlPatternNoWideChar() { try { ServletUtils.checkUrlPattern("/abcdef"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); + Assertions.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); } } @@ -94,9 +101,9 @@ public void testCheckUrlPatternNoWideChar() { public void testCheckUrlPatternNotStartWithSlash() { try { ServletUtils.checkUrlPattern("abcdef/*"); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); + Assertions.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); } } @@ -106,17 +113,17 @@ public void testFilterUrlPatternsNormal() { Collection urlPatterns = Arrays.asList(urlPattern); String[] result = ServletUtils.filterUrlPatterns(urlPatterns); - Assert.assertThat(result, Matchers.arrayContaining("/r1/*")); + MatcherAssert.assertThat(result, Matchers.arrayContaining("/r1/*")); result = ServletUtils.filterUrlPatterns(urlPattern); - Assert.assertThat(result, Matchers.arrayContaining("/r1/*")); + MatcherAssert.assertThat(result, Matchers.arrayContaining("/r1/*")); } @Test public void testFilterUrlPatternsEmpty() { Collection urlPatterns = Arrays.asList(" ", "\t"); String[] result = ServletUtils.filterUrlPatterns(urlPatterns); - Assert.assertThat(result, Matchers.emptyArray()); + MatcherAssert.assertThat(result, Matchers.emptyArray()); } @Test @@ -124,9 +131,9 @@ public void testFilterUrlPatternsInvalid() { Collection urlPatterns = Arrays.asList("/abc"); try { ServletUtils.filterUrlPatterns(urlPatterns); - Assert.fail("must throw exception"); + Assertions.fail("must throw exception"); } catch (ServiceCombException e) { - Assert.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); + Assertions.assertEquals("only support rule like /* or /path/* or /path1/path2/* and so on.", e.getMessage()); } } @@ -143,7 +150,7 @@ public void testcollectUrlPatternsNoRestServlet(@Mocked ServletContext servletCo }; String[] result = ServletUtils.collectUrlPatterns(servletContext, RestServlet.class); - Assert.assertThat(result, Matchers.emptyArray()); + MatcherAssert.assertThat(result, Matchers.emptyArray()); } @Test @@ -169,23 +176,23 @@ public void testcollectUrlPatternsNormalMapping(@Mocked ServletContext servletCo }; String[] result = ServletUtils.collectUrlPatterns(servletContext, RestServlet.class); - Assert.assertThat(result, Matchers.arrayContaining("/r1/*", "/r1/1/*")); + MatcherAssert.assertThat(result, Matchers.arrayContaining("/r1/*", "/r1/1/*")); } @Test public void testSaveUrlPrefixNull(@Mocked ServletContext servletContext) { - System.clearProperty(Const.URL_PREFIX); + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); ServletUtils.saveUrlPrefix(servletContext); - Assert.assertNull(System.getProperty(Const.URL_PREFIX)); - System.clearProperty(Const.URL_PREFIX); + Assertions.assertNull(ClassLoaderScopeContext.getClassLoaderScopeProperty(DefinitionConst.URL_PREFIX)); + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); } @Test public void testSaveUrlPrefixNormal(@Mocked ServletContext servletContext, @Mocked ServletRegistration servletRegistration) { - System.clearProperty(Const.URL_PREFIX); + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); new Expectations() { { servletContext.getContextPath(); @@ -201,8 +208,9 @@ public void testSaveUrlPrefixNormal(@Mocked ServletContext servletContext, ServletUtils.saveUrlPrefix(servletContext); - Assert.assertThat(System.getProperty(Const.URL_PREFIX), Matchers.is("/root/rest")); - System.clearProperty(Const.URL_PREFIX); + MatcherAssert.assertThat(ClassLoaderScopeContext.getClassLoaderScopeProperty(DefinitionConst.URL_PREFIX), + Matchers.is("/root/rest")); + ClassLoaderScopeContext.clearClassLoaderScopeProperty(); } @Test @@ -216,17 +224,17 @@ public void createUploadDir_relative(@Mocked ServletContext servletContext) thro }; File expectDir = new File(tempDir, "upload"); - Assert.assertFalse(expectDir.exists()); + Assertions.assertFalse(expectDir.exists()); File dir = ServletUtils.createUploadDir(servletContext, "upload"); - Assert.assertTrue(expectDir.exists()); - Assert.assertEquals(expectDir.getAbsolutePath(), dir.getAbsolutePath()); + Assertions.assertTrue(expectDir.exists()); + Assertions.assertEquals(expectDir.getAbsolutePath(), dir.getAbsolutePath()); dir.delete(); - Assert.assertFalse(expectDir.exists()); + Assertions.assertFalse(expectDir.exists()); tempDir.delete(); - Assert.assertFalse(tempDir.exists()); + Assertions.assertFalse(tempDir.exists()); } @Test @@ -234,23 +242,23 @@ public void createUploadDir_absolute(@Mocked ServletContext servletContext) thro File tempDir = Files.createTempDirectory("temp").toFile(); File expectDir = new File(tempDir, "upload"); - Assert.assertFalse(expectDir.exists()); + Assertions.assertFalse(expectDir.exists()); File dir = ServletUtils.createUploadDir(servletContext, expectDir.getAbsolutePath()); - Assert.assertTrue(expectDir.exists()); - Assert.assertEquals(expectDir.getAbsolutePath(), dir.getAbsolutePath()); + Assertions.assertTrue(expectDir.exists()); + Assertions.assertEquals(expectDir.getAbsolutePath(), dir.getAbsolutePath()); dir.delete(); - Assert.assertFalse(expectDir.exists()); + Assertions.assertFalse(expectDir.exists()); tempDir.delete(); - Assert.assertFalse(tempDir.exists()); + Assertions.assertFalse(tempDir.exists()); } @Test public void setServletParameters_notSupportUpload() { // not support upload will not set parameters to servlet, so servletContext is null will not throw exception - ServletUtils.setServletParameters(null); + ServletUtils.setServletParameters(null, environment); } @Test @@ -280,20 +288,21 @@ void setMultipartConfig(MultipartConfigElement multipartConfig) { File tempDir = Files.createTempDirectory("temp").toFile(); File uploadDir = new File(tempDir, "upload"); - ArchaiusUtils.setProperty(RestConst.UPLOAD_DIR, uploadDir.getAbsolutePath()); + Mockito.when(environment.getProperty(RestConst.UPLOAD_DIR, RestConst.UPLOAD_DEFAULT_DIR)) + .thenReturn(uploadDir.getAbsolutePath()); - ServletUtils.setServletParameters(servletContext); + ServletUtils.setServletParameters(servletContext, environment); - Assert.assertEquals(1, multipartConfigs.size()); + Assertions.assertEquals(1, multipartConfigs.size()); MultipartConfigElement multipartConfigElement = multipartConfigs.get(0); - Assert.assertEquals(uploadDir.getAbsolutePath(), multipartConfigElement.getLocation()); - Assert.assertEquals(-1, multipartConfigElement.getMaxFileSize()); - Assert.assertEquals(-1, multipartConfigElement.getMaxRequestSize()); - Assert.assertEquals(0, multipartConfigElement.getFileSizeThreshold()); + Assertions.assertEquals(uploadDir.getAbsolutePath(), multipartConfigElement.getLocation()); + Assertions.assertEquals(-1, multipartConfigElement.getMaxFileSize()); + Assertions.assertEquals(-1, multipartConfigElement.getMaxRequestSize()); + Assertions.assertEquals(0, multipartConfigElement.getFileSizeThreshold()); uploadDir.delete(); tempDir.delete(); - Assert.assertFalse(tempDir.exists()); + Assertions.assertFalse(tempDir.exists()); } } diff --git a/transports/transport-rest/transport-rest-servlet/src/test/resources/config/log4j.cse.transport.rest.properties b/transports/transport-rest/transport-rest-servlet/src/test/resources/config/log4j.cse.transport.rest.properties deleted file mode 100644 index e8997f404f8..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/resources/config/log4j.cse.transport.rest.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -paas.logs.dir=target/ -paas.logs.file=cse_rest.log - -log4j.rootLogger=INFO,paas,stdout diff --git a/transports/transport-rest/transport-rest-servlet/src/test/resources/log4j.properties b/transports/transport-rest/transport-rest-servlet/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/transports/transport-rest/transport-rest-servlet/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true diff --git a/transports/transport-rest/transport-rest-vertx/pom.xml b/transports/transport-rest/transport-rest-vertx/pom.xml index 7dd47285a86..7a3475d38dd 100644 --- a/transports/transport-rest/transport-rest-vertx/pom.xml +++ b/transports/transport-rest/transport-rest-vertx/pom.xml @@ -22,7 +22,7 @@ org.apache.servicecomb transport-rest - 1.2.0-SNAPSHOT + 3.4.0-SNAPSHOT transport-rest-vertx Java Chassis::Transports::Rest::Vertx @@ -32,26 +32,38 @@ org.apache.servicecomb transport-rest-client - io.vertx vertx-codegen provided - - org.slf4j - slf4j-log4j12 + org.apache.servicecomb + registry-service-center + test + + + org.apache.logging.log4j + log4j-slf4j-impl test - log4j - log4j + org.apache.logging.log4j + log4j-core test org.apache.servicecomb foundation-test-scaffolding + + org.apache.servicecomb + common-access-log + + + org.jmockit + jmockit + test + diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/AbstractVertxHttpDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/AbstractVertxHttpDispatcher.java index 5d357c1f8f8..8963c6f8d9b 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/AbstractVertxHttpDispatcher.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/AbstractVertxHttpDispatcher.java @@ -17,11 +17,8 @@ package org.apache.servicecomb.transport.rest.vertx; -import java.util.List; - import org.apache.servicecomb.common.rest.UploadConfig; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,22 +27,19 @@ public abstract class AbstractVertxHttpDispatcher implements VertxHttpDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractVertxHttpDispatcher.class); - protected List httpServerFilters = SPIServiceUtils.getSortedService(HttpServerFilter.class); - protected BodyHandler createBodyHandler() { RestBodyHandler bodyHandler = new RestBodyHandler(); - UploadConfig uploadConfig = new UploadConfig(); + UploadConfig uploadConfig = new UploadConfig(LegacyPropertyFactory.getEnvironment()); bodyHandler.setUploadsDirectory(uploadConfig.getLocation()); bodyHandler.setDeleteUploadedFilesOnEnd(true); bodyHandler.setBodyLimit(uploadConfig.getMaxSize()); if (uploadConfig.toMultipartConfigElement() != null) { - LOGGER.info("set uploads directory to {}.", uploadConfig.getLocation()); + LOGGER.info("set uploads directory to \"{}\".", uploadConfig.getLocation()); } return bodyHandler; } } - diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/HttpServerExceptionHandler.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/HttpServerExceptionHandler.java new file mode 100644 index 00000000000..9829f3ca8b1 --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/HttpServerExceptionHandler.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.vertx; + +import io.vertx.core.Handler; +import org.apache.servicecomb.foundation.common.utils.SPIOrder; + +public interface HttpServerExceptionHandler extends Handler, SPIOrder { +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java index 7e8105fadf8..cc74e6d0a8a 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestBodyHandler.java @@ -22,30 +22,30 @@ package org.apache.servicecomb.transport.rest.vertx; import java.io.File; -import java.util.Set; +import java.util.List; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.ws.rs.core.Response.Status; - import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory; -import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import com.google.common.annotations.VisibleForTesting; + +import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.FileSystem; import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.http.HttpVersion; import io.vertx.ext.web.FileUpload; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.BodyHandler; -import io.vertx.ext.web.handler.impl.BodyHandlerImpl; import io.vertx.ext.web.impl.FileUploadImpl; +import io.vertx.ext.web.impl.RoutingContextInternal; /** * copy from io.vertx.ext.web.handler.impl.BodyHandlerImpl @@ -55,41 +55,115 @@ */ public class RestBodyHandler implements BodyHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(BodyHandlerImpl.class); - - private static final String BODY_HANDLED = "__body-handled"; - private long bodyLimit = DEFAULT_BODY_LIMIT; + private boolean handleFileUploads; + private String uploadsDir; private boolean mergeFormAttributes = DEFAULT_MERGE_FORM_ATTRIBUTES; private boolean deleteUploadedFilesOnEnd = DEFAULT_DELETE_UPLOADED_FILES_ON_END; + private boolean isPreallocateBodyBuffer = DEFAULT_PREALLOCATE_BODY_BUFFER; + + private static final int DEFAULT_INITIAL_BODY_BUFFER_SIZE = 1024; //bytes + + public static final String BYPASS_BODY_HANDLER = "__bypass_body_handler"; + public RestBodyHandler() { - setUploadsDirectory(DEFAULT_UPLOADS_DIRECTORY); + this(true, DEFAULT_UPLOADS_DIRECTORY); + } + + public RestBodyHandler(boolean handleFileUploads) { + this(handleFileUploads, DEFAULT_UPLOADS_DIRECTORY); } public RestBodyHandler(String uploadDirectory) { + this(true, uploadDirectory); + } + + private RestBodyHandler(boolean handleFileUploads, String uploadDirectory) { + this.handleFileUploads = handleFileUploads; setUploadsDirectory(uploadDirectory); } + @VisibleForTesting + boolean isDeleteUploadedFilesOnEnd() { + return deleteUploadedFilesOnEnd; + } + @Override public void handle(RoutingContext context) { - HttpServerRequest request = context.request(); + final HttpServerRequest request = context.request(); + final HttpServerResponse response = context.response(); + if (request.headers().contains(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET, true)) { context.next(); return; } + Boolean bypass = context.get(BYPASS_BODY_HANDLER); + if (Boolean.TRUE.equals(bypass)) { + context.next(); + return; + } + // we need to keep state since we can be called again on reroute - Boolean handled = context.get(BODY_HANDLED); - if (handled == null || !handled) { - BHandler handler = new BHandler(context); - request.handler(handler); - request.endHandler(v -> handler.end()); - context.put(BODY_HANDLED, true); + if (!((RoutingContextInternal) context).seenHandler(RoutingContextInternal.BODY_HANDLER)) { + ((RoutingContextInternal) context).visitHandler(RoutingContextInternal.BODY_HANDLER); + + // Check if a request has a request body. + // A request with a body __must__ either have `transfer-encoding` + // or `content-length` headers set. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 + final long parsedContentLength = parseContentLengthHeader(request); + // http2 never transmits a `transfer-encoding` as frames are chunks. + final boolean hasTransferEncoding = + request.version() == HttpVersion.HTTP_2 || request.headers().contains(HttpHeaders.TRANSFER_ENCODING); + + if (!hasTransferEncoding && parsedContentLength == -1) { + // there is no "body", so we can skip this handler + context.next(); + return; + } + + // before parsing the body we can already discard a bad request just by inspecting the content-length against + // the body limit, this will reduce load, on the server by totally skipping parsing the request body + if (bodyLimit != -1 && parsedContentLength != -1) { + if (parsedContentLength > bodyLimit) { + context.fail(413); + return; + } + } + + // handle expectations + // https://httpwg.org/specs/rfc7231.html#header.expect + final String expect = request.getHeader(HttpHeaders.EXPECT); + if (expect != null) { + // requirements validation + if (expect.equalsIgnoreCase("100-continue")) { + // A server that receives a 100-continue expectation in an HTTP/1.0 request MUST ignore that expectation. + if (request.version() != HttpVersion.HTTP_1_0) { + // signal the client to continue + response.writeContinue(); + } + } else { + // the server cannot meet the expectation, we only know about 100-continue + context.fail(417); + return; + } + } + + final BHandler handler = new BHandler(context, isPreallocateBodyBuffer ? parsedContentLength : -1); + boolean ended = request.isEnded(); + if (!ended) { + request + // resume the request (if paused) + .handler(handler) + .endHandler(handler::end) + .resume(); + } } else { // on reroute we need to re-merge the form params if that was desired if (mergeFormAttributes && request.isExpectMultipart()) { @@ -100,6 +174,12 @@ public void handle(RoutingContext context) { } } + @Override + public BodyHandler setHandleFileUploads(boolean handleFileUploads) { + this.handleFileUploads = handleFileUploads; + return this; + } + @Override public BodyHandler setBodyLimit(long bodyLimit) { this.bodyLimit = bodyLimit; @@ -124,29 +204,57 @@ public BodyHandler setDeleteUploadedFilesOnEnd(boolean deleteUploadedFilesOnEnd) return this; } + @Override + public BodyHandler setPreallocateBodyBuffer(boolean isPreallocateBodyBuffer) { + this.isPreallocateBodyBuffer = isPreallocateBodyBuffer; + return this; + } + + private long parseContentLengthHeader(HttpServerRequest request) { + String contentLength = request.getHeader(HttpHeaders.CONTENT_LENGTH); + if (contentLength == null || contentLength.isEmpty()) { + return -1; + } + try { + long parsedContentLength = Long.parseLong(contentLength); + return parsedContentLength < 0 ? -1 : parsedContentLength; + } catch (NumberFormatException ex) { + return -1; + } + } + private class BHandler implements Handler { + private static final int MAX_PREALLOCATED_BODY_BUFFER_BYTES = 65535; - private RoutingContext context; + final RoutingContext context; - private Buffer body = Buffer.buffer(); + final long contentLength; - private boolean failed; + Buffer body; - private AtomicInteger uploadCount = new AtomicInteger(); + volatile boolean failed; - AtomicBoolean cleanup = new AtomicBoolean(false); + final AtomicInteger uploadCount = new AtomicInteger(); - private boolean ended; + volatile boolean ended; - private long uploadSize = 0L; + long uploadSize = 0L; - private final boolean isMultipart; + final boolean isMultipart; - private final boolean isUrlEncoded; + final boolean isUrlEncoded; - BHandler(RoutingContext context) { + public BHandler(RoutingContext context, long contentLength) { this.context = context; - Set fileUploads = context.fileUploads(); + this.contentLength = contentLength; + // the request clearly states that there should + // be a body, so we respect the client and ensure + // that the body will not be null + if (contentLength != -1) { + initBodyBuffer(); + } + + List fileUploads = context.fileUploads(); final String contentType = context.request().getHeader(HttpHeaders.CONTENT_TYPE); if (contentType == null) { @@ -159,8 +267,10 @@ private class BHandler implements Handler { } if (isMultipart || isUrlEncoded) { - makeUploadDir(context.vertx().fileSystem()); context.request().setExpectMultipart(true); + if (handleFileUploads) { + makeUploadDir(context.vertx().fileSystem()); + } context.request().uploadHandler(upload -> { // *** cse begin *** if (uploadsDir == null) { @@ -175,30 +285,61 @@ private class BHandler implements Handler { long size = uploadSize + upload.size(); if (size > bodyLimit) { failed = true; - context.fail(new InvocationException(Status.REQUEST_ENTITY_TOO_LARGE, - Status.REQUEST_ENTITY_TOO_LARGE.getReasonPhrase())); + context.cancelAndCleanupFileUploads(); + context.fail(413); return; } } - // we actually upload to a file with a generated filename - uploadCount.incrementAndGet(); - String uploadedFileName = new File(uploadsDir, UUID.randomUUID().toString()).getPath(); - upload.streamToFileSystem(uploadedFileName); - FileUploadImpl fileUpload = new FileUploadImpl(uploadedFileName, upload); - fileUploads.add(fileUpload); - upload.exceptionHandler(t -> { - deleteFileUploads(); - context.fail(t); - }); - upload.endHandler(v -> uploadEnded()); + if (handleFileUploads) { + // we actually upload to a file with a generated filename + uploadCount.incrementAndGet(); + String uploadedFileName = new File(uploadsDir, UUID.randomUUID().toString()).getPath(); + FileUploadImpl fileUpload = new FileUploadImpl(context.vertx().fileSystem(), uploadedFileName, upload); + fileUploads.add(fileUpload); + Future fut = upload.streamToFileSystem(uploadedFileName); + fut.onComplete(ar -> { + if (fut.succeeded()) { + uploadEnded(); + } else { + context.cancelAndCleanupFileUploads(); + context.fail(ar.cause()); + } + }); + } }); } + context.request().exceptionHandler(t -> { - deleteFileUploads(); - context.fail(t); + context.cancelAndCleanupFileUploads(); + int sc = 200; + if (t instanceof DecoderException) { + // bad request + sc = 400; + if (t.getCause() != null) { + t = t.getCause(); + } + } + context.fail(sc, t); }); } + private void initBodyBuffer() { + int initialBodyBufferSize; + if (contentLength < 0) { + initialBodyBufferSize = DEFAULT_INITIAL_BODY_BUFFER_SIZE; + } else if (contentLength > MAX_PREALLOCATED_BODY_BUFFER_BYTES) { + initialBodyBufferSize = MAX_PREALLOCATED_BODY_BUFFER_BYTES; + } else { + initialBodyBufferSize = (int) contentLength; + } + + if (bodyLimit != -1) { + initialBodyBufferSize = (int) Math.min(initialBodyBufferSize, bodyLimit); + } + + this.body = Buffer.buffer(initialBodyBufferSize); + } + private void makeUploadDir(FileSystem fileSystem) { // *** cse begin *** if (uploadsDir == null) { @@ -219,15 +360,16 @@ public void handle(Buffer buff) { uploadSize += buff.length(); if (bodyLimit != -1 && uploadSize > bodyLimit) { failed = true; - // enqueue a delete for the error uploads - context.fail(new InvocationException(Status.REQUEST_ENTITY_TOO_LARGE, - Status.REQUEST_ENTITY_TOO_LARGE.getReasonPhrase())); - context.vertx().runOnContext(v -> deleteFileUploads()); + context.cancelAndCleanupFileUploads(); + context.fail(413); } else { // multipart requests will not end up in the request body // url encoded should also not, however jQuery by default // post in urlencoded even if the payload is something else if (!isMultipart /* && !isUrlEncoded */) { + if (body == null) { + initBodyBuffer(); + } body.appendBuffer(buff); } } @@ -241,7 +383,7 @@ void uploadEnded() { } } - void end() { + void end(Void v) { // this marks the end of body parsing, calling doEnd should // only be possible from this moment onwards ended = true; @@ -253,42 +395,25 @@ void end() { } void doEnd() { - if (failed) { - deleteFileUploads(); + + if (failed || context.failed()) { + context.cancelAndCleanupFileUploads(); return; } if (deleteUploadedFilesOnEnd) { - context.addBodyEndHandler(x -> deleteFileUploads()); + context.addBodyEndHandler(x -> context.cancelAndCleanupFileUploads()); } HttpServerRequest req = context.request(); if (mergeFormAttributes && req.isExpectMultipart()) { req.params().addAll(req.formAttributes()); } - context.setBody(body); - context.next(); - } + ((RoutingContextInternal) context).setBody(body); + // release body as it may take lots of memory + body = null; - private void deleteFileUploads() { - if (cleanup.compareAndSet(false, true)) { - for (FileUpload fileUpload : context.fileUploads()) { - FileSystem fileSystem = context.vertx().fileSystem(); - String uploadedFileName = fileUpload.uploadedFileName(); - fileSystem.exists(uploadedFileName, existResult -> { - if (existResult.failed()) { - LOGGER.warn("Could not detect if uploaded file exists, not deleting: " + uploadedFileName, - existResult.cause()); - } else if (existResult.result()) { - fileSystem.delete(uploadedFileName, deleteResult -> { - if (deleteResult.failed()) { - LOGGER.warn("Delete of uploaded file failed: " + uploadedFileName, deleteResult.cause()); - } - }); - } - }); - } - } + context.next(); } } } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java index 3ac2ee7a21a..70f8e43c765 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java @@ -21,11 +21,14 @@ import java.util.List; import java.util.Set; -import javax.ws.rs.core.MediaType; - +import org.apache.servicecomb.common.accessLog.AccessLogConfig; +import org.apache.servicecomb.common.accessLog.core.element.impl.LocalHostAccessItem; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.event.ServerAccessLogEvent; import org.apache.servicecomb.core.transport.AbstractTransport; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; import org.apache.servicecomb.foundation.common.utils.ExceptionUtils; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; @@ -37,18 +40,16 @@ import org.apache.servicecomb.foundation.vertx.metrics.metric.DefaultServerEndpointMetric; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogConfiguration; -import org.apache.servicecomb.transport.rest.vertx.accesslog.impl.AccessLogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; -import com.netflix.config.DynamicPropertyFactory; +import com.google.common.annotations.VisibleForTesting; import io.vertx.core.AbstractVerticle; import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.http.Http2Settings; import io.vertx.core.http.HttpMethod; @@ -59,60 +60,76 @@ import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.CorsHandler; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; public class RestServerVerticle extends AbstractVerticle { private static final Logger LOGGER = LoggerFactory.getLogger(RestServerVerticle.class); private static final String SSL_KEY = "rest.provider"; - private Endpoint endpoint; - private URIEndpointObject endpointObject; + private WebSocketDispatcher webSocketDispatcher; + @Override public void init(Vertx vertx, Context context) { super.init(vertx, context); - this.endpoint = (Endpoint) context.config().getValue(AbstractTransport.ENDPOINT_KEY); + Endpoint endpoint = (Endpoint) context.config().getValue(AbstractTransport.ENDPOINT_KEY); this.endpointObject = (URIEndpointObject) endpoint.getAddress(); + this.webSocketDispatcher = new WebSocketDispatcher(endpoint); } @Override - public void start(Future startFuture) throws Exception { + public void start(Promise startPromise) throws Exception { try { super.start(); // 如果本地未配置地址,则表示不必监听,只需要作为客户端使用即可 if (endpointObject == null) { LOGGER.warn("rest listen address is not configured, will not start."); - startFuture.complete(); + startPromise.complete(); return; } Router mainRouter = Router.router(vertx); - mountGlobalRestFailureHandler(mainRouter); mountAccessLogHandler(mainRouter); mountCorsHandler(mainRouter); initDispatcher(mainRouter); + mountGlobalRestFailureHandler(mainRouter); HttpServer httpServer = createHttpServer(); - httpServer.requestHandler(mainRouter::accept); + httpServer.requestHandler(httpServerRequest -> { + if (this.endpointObject.isWebsocketEnabled()) { + String path = LegacyPropertyFactory.getStringProperty("servicecomb.rest.server.websocket-prefix"); + if (httpServerRequest.path().startsWith(path)) { + httpServerRequest.toWebSocket().onComplete(w -> webSocketDispatcher.onRequest(w), + e -> LOGGER.error("WebSocket error.", e)); + return; + } + } + mainRouter.handle(httpServerRequest); + }); httpServer.connectionHandler(connection -> { DefaultHttpServerMetrics serverMetrics = (DefaultHttpServerMetrics) ((ConnectionBase) connection).metrics(); DefaultServerEndpointMetric endpointMetric = serverMetrics.getEndpointMetric(); long connectedCount = endpointMetric.getCurrentConnectionCount(); - int connectionLimit = DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.server.connection-limit", Integer.MAX_VALUE).get(); + int connectionLimit = LegacyPropertyFactory.getIntProperty("servicecomb.rest.server.connection-limit", + Integer.MAX_VALUE); if (connectedCount > connectionLimit) { connection.close(); endpointMetric.onRejectByConnectionLimit(); } }); + List httpServerExceptionHandlers = + SPIServiceUtils.getAllService(HttpServerExceptionHandler.class); httpServer.exceptionHandler(e -> { - if(e instanceof ClosedChannelException) { - // This is quite normal in between browser and ege, so do not print out. + if (e instanceof ClosedChannelException) { + // This is quite normal in between browser and edge, so do not print out. LOGGER.debug("Unexpected error in server.{}", ExceptionUtils.getExceptionMessageWithoutTrace(e)); } else { LOGGER.error("Unexpected error in server.{}", ExceptionUtils.getExceptionMessageWithoutTrace(e)); } + httpServerExceptionHandlers.forEach(httpServerExceptionHandler -> httpServerExceptionHandler.handle(e)); }); - startListen(httpServer, startFuture); + startListen(httpServer, startPromise); } catch (Throwable e) { // vert.x got some states that not print error and execute call back in VertexUtils.blockDeploy, we add a log our self. LOGGER.error("", e); @@ -120,23 +137,23 @@ public void start(Future startFuture) throws Exception { } } - private void mountGlobalRestFailureHandler(Router mainRouter) { + @VisibleForTesting + void mountGlobalRestFailureHandler(Router mainRouter) { GlobalRestFailureHandler globalRestFailureHandler = SPIServiceUtils.getPriorityHighestService(GlobalRestFailureHandler.class); Handler failureHandler = null == globalRestFailureHandler ? ctx -> { - if (ctx.response().closed()) { + if (ctx.response().closed() || ctx.response().ended()) { // response has been sent, do nothing LOGGER.error("get a failure with closed response", ctx.failure()); - ctx.next(); + return; } HttpServerResponse response = ctx.response(); - if (ctx.failure() instanceof InvocationException) { + if (ctx.failure() instanceof InvocationException exception) { // ServiceComb defined exception - InvocationException exception = (InvocationException) ctx.failure(); response.setStatusCode(exception.getStatusCode()); - response.setStatusMessage(exception.getErrorData().toString()); - response.end(); + response.setStatusMessage(exception.getReasonPhrase()); + response.end(exception.getErrorData().toString()); return; } @@ -159,14 +176,19 @@ private void mountGlobalRestFailureHandler(Router mainRouter) { } private void mountAccessLogHandler(Router mainRouter) { - if (AccessLogConfiguration.INSTANCE.getAccessLogEnabled()) { - String pattern = AccessLogConfiguration.INSTANCE.getAccesslogPattern(); - LOGGER.info("access log enabled, pattern = {}", pattern); - mainRouter.route() - .handler(new AccessLogHandler( - pattern - )); + if (!AccessLogConfig.INSTANCE.isServerLogEnabled()) { + return; } + LOGGER.info("access log enabled, pattern = {}", AccessLogConfig.INSTANCE.getServerLogPattern()); + mainRouter.route().handler(context -> { + ServerAccessLogEvent accessLogEvent = new ServerAccessLogEvent() + .setRoutingContext(context) + .setMilliStartTime(System.currentTimeMillis()) + .setLocalAddress(LocalHostAccessItem.getLocalAddress(context)); + context.response().endHandler(event -> + EventManager.post(accessLogEvent.setMilliEndTime(System.currentTimeMillis()))); + context.next(); + }); } /** @@ -177,7 +199,7 @@ void mountCorsHandler(Router mainRouter) { return; } - CorsHandler corsHandler = getCorsHandler(TransportConfig.getCorsAllowedOrigin()); + CorsHandler corsHandler = getCorsHandler(); // Access-Control-Allow-Credentials corsHandler.allowCredentials(TransportConfig.isCorsAllowCredentials()); // Access-Control-Allow-Headers @@ -199,12 +221,22 @@ void mountCorsHandler(Router mainRouter) { mainRouter.route().handler(corsHandler); } - private CorsHandler getCorsHandler(String corsAllowedOrigin) { - return CorsHandler.create(corsAllowedOrigin); + private CorsHandler getCorsHandler() { + CorsHandler handler = CorsHandler.create(); + String[] origin = TransportConfig.getCorsAllowedOrigin(); + if (origin == null) { + handler.addOrigin("*"); + } else { + for (String item : origin) { + handler.addOrigin(item); + } + } + return handler; } private void initDispatcher(Router mainRouter) { - List dispatchers = SPIServiceUtils.getSortedService(VertxHttpDispatcher.class); + List dispatchers = SPIServiceUtils.getOrLoadSortedService(VertxHttpDispatcher.class); + for (VertxHttpDispatcher dispatcher : dispatchers) { if (dispatcher.enabled()) { dispatcher.init(mainRouter); @@ -212,21 +244,22 @@ private void initDispatcher(Router mainRouter) { } } - private void startListen(HttpServer server, Future startFuture) { - server.listen(endpointObject.getPort(), endpointObject.getHostOrIp(), ar -> { - if (ar.succeeded()) { + private void startListen(HttpServer server, Promise startPromise) { + Future result = server.listen(endpointObject.getPort(), endpointObject.getHostOrIp()); + result.onComplete((s, f) -> { + if (f == null) { LOGGER.info("rest listen success. address={}:{}", endpointObject.getHostOrIp(), - ar.result().actualPort()); - startFuture.complete(); + s.actualPort()); + startPromise.complete(); return; } String msg = String.format("rest listen failed, address=%s:%d", endpointObject.getHostOrIp(), endpointObject.getPort()); - LOGGER.error(msg, ar.cause()); - startFuture.fail(ar.cause()); + LOGGER.error(msg, f); + startPromise.fail(f); }); } @@ -237,21 +270,37 @@ private HttpServer createHttpServer() { private HttpServerOptions createDefaultHttpServerOptions() { HttpServerOptions serverOptions = new HttpServerOptions(); - serverOptions.setUsePooledBuffers(true); - serverOptions.setIdleTimeout(TransportConfig.getConnectionIdleTimeoutInSeconds()); serverOptions.setCompressionSupported(TransportConfig.getCompressed()); serverOptions.setMaxHeaderSize(TransportConfig.getMaxHeaderSize()); + serverOptions.setMaxFormAttributeSize(TransportConfig.getMaxFormAttributeSize()); + serverOptions.setMaxFormFields(TransportConfig.getMaxFormFields()); + serverOptions.setMaxFormBufferedBytes(TransportConfig.getMaxFormBufferedBytes()); + serverOptions.setCompressionLevel(TransportConfig.getCompressionLevel()); + serverOptions.setMaxChunkSize(TransportConfig.getMaxChunkSize()); + serverOptions.setDecompressionSupported(TransportConfig.getDecompressionSupported()); + serverOptions.setDecoderInitialBufferSize(TransportConfig.getDecoderInitialBufferSize()); serverOptions.setMaxInitialLineLength(TransportConfig.getMaxInitialLineLength()); if (endpointObject.isHttp2Enabled()) { serverOptions.setUseAlpn(TransportConfig.getUseAlpn()) - .setInitialSettings(new Http2Settings().setMaxConcurrentStreams(TransportConfig.getMaxConcurrentStreams())); + .setHttp2ConnectionWindowSize(TransportConfig.getHttp2ConnectionWindowSize()) + .setIdleTimeout(TransportConfig.getHttp2ConnectionIdleTimeoutInSeconds()) + .setHttp2RstFloodMaxRstFramePerWindow(TransportConfig.getHttp2RstFloodMaxRstFramePerWindow()) + .setInitialSettings(new Http2Settings().setPushEnabled(TransportConfig.getPushEnabled()) + .setMaxConcurrentStreams(TransportConfig.getMaxConcurrentStreams()) + .setHeaderTableSize(TransportConfig.getHttp2HeaderTableSize()) + .setInitialWindowSize(TransportConfig.getInitialWindowSize()) + .setMaxFrameSize(TransportConfig.getMaxFrameSize()) + .setMaxHeaderListSize(TransportConfig.getMaxHeaderListSize()) + ); + } else { + serverOptions.setIdleTimeout(TransportConfig.getConnectionIdleTimeoutInSeconds()); } if (endpointObject.isSslEnabled()) { SSLOptionFactory factory = - SSLOptionFactory.createSSLOptionFactory(SSL_KEY, null); + SSLOptionFactory.createSSLOptionFactory(SSL_KEY, LegacyPropertyFactory.getEnvironment()); SSLOption sslOption; if (factory == null) { - sslOption = SSLOption.buildFromYaml(SSL_KEY); + sslOption = SSLOption.build(SSL_KEY, LegacyPropertyFactory.getEnvironment()); } else { sslOption = factory.createSSLOption(); } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java index d3fd4f1b5cc..5c81d75646b 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java @@ -21,20 +21,16 @@ import java.util.Set; import java.util.stream.Stream; -import org.springframework.util.StringUtils; - -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.transport.common.TransportConfigUtils; import io.vertx.core.Verticle; +import io.vertx.core.http.Http2Settings; import io.vertx.core.http.HttpServerOptions; public final class TransportConfig { - - public static final int DEFAULT_SERVER_THREAD_COUNT = 1; - - public static final int DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND = 60; + public static final int DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND = 180; public static final boolean DEFAULT_SERVER_COMPRESSION_SUPPORT = false; @@ -57,93 +53,164 @@ public static void setRestServerVerticle(Class restServerVer } public static String getAddress() { - DynamicStringProperty address = - DynamicPropertyFactory.getInstance().getStringProperty("servicecomb.rest.address", null); - return address.get(); + return LegacyPropertyFactory.getStringProperty("servicecomb.rest.address", null); + } + + public static int getMaxFormAttributeSize() { + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.server.maxFormAttributeSize", + HttpServerOptions.DEFAULT_MAX_FORM_ATTRIBUTE_SIZE); + } + + public static int getMaxFormFields() { + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.server.maxFormFields", + HttpServerOptions.DEFAULT_MAX_FORM_FIELDS); + } + + public static int getMaxFormBufferedBytes() { + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.server.maxFormBufferedBytes", + HttpServerOptions.DEFAULT_MAX_FORM_BUFFERED_SIZE); + } + + public static int getCompressionLevel() { + return LegacyPropertyFactory.getIntProperty("servicecomb.rest.server.compressionLevel", + HttpServerOptions.DEFAULT_COMPRESSION_LEVEL); + } + + public static int getMaxChunkSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.maxChunkSize", + HttpServerOptions.DEFAULT_MAX_CHUNK_SIZE); + } + + public static int getDecoderInitialBufferSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.decoderInitialBufferSize", + HttpServerOptions.DEFAULT_DECODER_INITIAL_BUFFER_SIZE); + } + + public static int getHttp2ConnectionWindowSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.connectionWindowSize", + HttpServerOptions.DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE); + } + + public static int getHttp2RstFloodMaxRstFramePerWindow() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.rstFloodMaxRstFramePerWindow", + HttpServerOptions.DEFAULT_HTTP2_RST_FLOOD_MAX_RST_FRAME_PER_WINDOW); } public static int getThreadCount() { - DynamicIntProperty address = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.server.thread-count", DEFAULT_SERVER_THREAD_COUNT); - return address.get(); + return TransportConfigUtils.readVerticleCount( + "servicecomb.rest.server.verticle-count", + "servicecomb.rest.server.thread-count"); } public static int getConnectionIdleTimeoutInSeconds() { - return DynamicPropertyFactory.getInstance() + return LegacyPropertyFactory .getIntProperty("servicecomb.rest.server.connection.idleTimeoutInSeconds", - DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND) - .get(); + DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND); + } + + public static int getHttp2ConnectionIdleTimeoutInSeconds() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.connection.idleTimeoutInSeconds", + DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND); } public static boolean getCompressed() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.server.compression", DEFAULT_SERVER_COMPRESSION_SUPPORT) - .get(); + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.server.compression", DEFAULT_SERVER_COMPRESSION_SUPPORT); + } + + public static boolean getDecompressionSupported() { + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.server.decompressionSupported", + HttpServerOptions.DEFAULT_DECOMPRESSION_SUPPORTED); } public static long getMaxConcurrentStreams() { - return DynamicPropertyFactory.getInstance() + return LegacyPropertyFactory .getLongProperty("servicecomb.rest.server.http2.concurrentStreams", - HttpServerOptions.DEFAULT_INITIAL_SETTINGS_MAX_CONCURRENT_STREAMS) - .get(); + HttpServerOptions.DEFAULT_INITIAL_SETTINGS_MAX_CONCURRENT_STREAMS); + } + + public static long getHttp2HeaderTableSize() { + return LegacyPropertyFactory + .getLongProperty("servicecomb.rest.server.http2.HeaderTableSize", + Http2Settings.DEFAULT_HEADER_TABLE_SIZE); + } + + public static boolean getPushEnabled() { + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.server.http2.pushEnabled", + Http2Settings.DEFAULT_ENABLE_PUSH); + } + + public static int getInitialWindowSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.initialWindowSize", + Http2Settings.DEFAULT_INITIAL_WINDOW_SIZE); + } + + public static int getMaxFrameSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.maxFrameSize", + Http2Settings.DEFAULT_MAX_FRAME_SIZE); + } + + public static int getMaxHeaderListSize() { + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.http2.maxHeaderListSize", + Http2Settings.DEFAULT_MAX_HEADER_LIST_SIZE); } public static boolean getUseAlpn() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.rest.server.http2.useAlpnEnabled", true) - .get(); + return LegacyPropertyFactory + .getBooleanProperty("servicecomb.rest.server.http2.useAlpnEnabled", true); } public static int getMaxHeaderSize() { - return DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.rest.server.maxHeaderSize", DEFAULT_SERVER_MAX_HEADER_SIZE) - .get(); + return LegacyPropertyFactory + .getIntProperty("servicecomb.rest.server.maxHeaderSize", DEFAULT_SERVER_MAX_HEADER_SIZE); } public static boolean isCorsEnabled() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".enabled", false) - .get(); + return LegacyPropertyFactory + .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".enabled", false); } - public static String getCorsAllowedOrigin() { - return DynamicPropertyFactory.getInstance() - .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".origin", "*") - .get(); + public static String[] getCorsAllowedOrigin() { + return LegacyPropertyFactory + .getProperty(SERVICECOMB_CORS_CONFIG_BASE + ".origin", String[].class); } public static boolean isCorsAllowCredentials() { - return DynamicPropertyFactory.getInstance() - .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowCredentials", false) - .get(); + return LegacyPropertyFactory + .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowCredentials", false); } public static Set getCorsAllowedHeaders() { - String allowedHeaders = DynamicPropertyFactory.getInstance() - .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedHeader", null) - .get(); + String allowedHeaders = LegacyPropertyFactory + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedHeader"); return convertToSet(allowedHeaders); } public static Set getCorsAllowedMethods() { - String allowedMethods = DynamicPropertyFactory.getInstance() - .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedMethod", null) - .get(); + String allowedMethods = LegacyPropertyFactory + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedMethod"); return convertToSet(allowedMethods); } public static Set getCorsExposedHeaders() { - String exposedHeaders = DynamicPropertyFactory.getInstance() - .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".exposedHeader", null) - .get(); + String exposedHeaders = LegacyPropertyFactory + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".exposedHeader"); return convertToSet(exposedHeaders); } public static int getCorsMaxAge() { - return DynamicPropertyFactory.getInstance() - .getIntProperty(SERVICECOMB_CORS_CONFIG_BASE + ".maxAge", -1) - .get(); + return LegacyPropertyFactory + .getIntProperty(SERVICECOMB_CORS_CONFIG_BASE + ".maxAge", -1); } private static Set convertToSet(String setString) { @@ -157,9 +224,8 @@ private static Set convertToSet(String setString) { } public static int getMaxInitialLineLength() { - return DynamicPropertyFactory.getInstance() + return LegacyPropertyFactory .getIntProperty("servicecomb.rest.server.maxInitialLineLength", - HttpServerOptions.DEFAULT_MAX_INITIAL_LINE_LENGTH) - .get(); + HttpServerOptions.DEFAULT_MAX_INITIAL_LINE_LENGTH); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxHttpDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxHttpDispatcher.java index cc8b6dc23d8..cb96d8c2280 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxHttpDispatcher.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxHttpDispatcher.java @@ -17,11 +17,13 @@ package org.apache.servicecomb.transport.rest.vertx; -import io.vertx.ext.web.Router; +import org.apache.servicecomb.foundation.common.utils.SPIEnabled; +import org.apache.servicecomb.foundation.common.utils.SPIOrder; -public interface VertxHttpDispatcher { - int getOrder(); +import io.vertx.ext.web.Router; +public interface VertxHttpDispatcher extends SPIOrder, SPIEnabled { + @Override default boolean enabled() { return true; } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestDispatcher.java index 20f70bd961c..20f83446e57 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestDispatcher.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestDispatcher.java @@ -17,17 +17,14 @@ package org.apache.servicecomb.transport.rest.vertx; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.Status.Family; - -import org.apache.servicecomb.common.rest.AbstractRestInvocation; -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.VertxRestInvocation; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.common.rest.RestProducerInvocationFlow; +import org.apache.servicecomb.common.rest.RestVertxProducerInvocationCreator; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.invocation.InvocationCreator; import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest; @@ -36,66 +33,71 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.netflix.config.DynamicPropertyFactory; - import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.CookieHandler; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.Response.Status.Family; public class VertxRestDispatcher extends AbstractVertxHttpDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestDispatcher.class); + private static final String KEY_ORDER = "servicecomb.http.dispatcher.rest.order"; + private static final String KEY_ENABLED = "servicecomb.http.dispatcher.rest.enabled"; + public static final String KEY_PATTERN = "servicecomb.http.dispatcher.rest.pattern"; + private Transport transport; + private MicroserviceMeta microserviceMeta; + @Override public int getOrder() { - return Integer.MAX_VALUE; + return LegacyPropertyFactory.getIntProperty(KEY_ORDER, Integer.MAX_VALUE); } @Override public boolean enabled() { - return DynamicPropertyFactory.getInstance().getBooleanProperty(KEY_ENABLED, true).get(); + return LegacyPropertyFactory.getBooleanProperty(KEY_ENABLED, true); } @Override public void init(Router router) { - router.route().handler(CookieHandler.create()); - router.route().handler(createBodyHandler()); - router.route().failureHandler(this::failureHandler).handler(this::onRequest); + // cookies handler are enabled by default start from 3.8.3 + String pattern = LegacyPropertyFactory.getStringProperty(KEY_PATTERN); + if (pattern == null) { + router.route().handler(createBodyHandler()); + router.route().failureHandler(this::failureHandler).handler(this::onRequest); + } else { + router.routeWithRegex(pattern).handler(createBodyHandler()); + router.routeWithRegex(pattern).failureHandler(this::failureHandler).handler(this::onRequest); + } } - private void failureHandler(RoutingContext context) { + protected void failureHandler(RoutingContext context) { LOGGER.error("http server failed.", context.failure()); - AbstractRestInvocation restProducerInvocation = context.get(RestConst.REST_PRODUCER_INVOCATION); Throwable e = context.failure(); - if (ErrorDataDecoderException.class.isInstance(e)) { + if (e instanceof ErrorDataDecoderException) { Throwable cause = e.getCause(); - if (InvocationException.class.isInstance(cause)) { + if (cause instanceof InvocationException) { e = cause; } } // only when unexpected exception happens, it will run into here. // the connection should be closed. - handleFailureAndClose(context, restProducerInvocation, e); + handleFailureAndClose(context, e); } /** * Try to find out the failure information and send it in response. */ - private void handleFailureAndClose(RoutingContext context, AbstractRestInvocation restProducerInvocation, - Throwable e) { - if (null != restProducerInvocation) { - // if there is restProducerInvocation, let it send exception in response. The exception is allowed to be null. - sendFailResponseByInvocation(context, restProducerInvocation, e); - return; - } - + private void handleFailureAndClose(RoutingContext context, Throwable e) { if (null != e) { // if there exists exception, try to send this exception by RoutingContext sendExceptionByRoutingContext(context, e); @@ -122,23 +124,21 @@ private void sendFailureRespDeterminedByStatus(RoutingContext context) { .setStatusMessage(Status.INTERNAL_SERVER_ERROR.getReasonPhrase()) .end(wrapResponseBody(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())); } - context.response().close(); } /** * Use routingContext to send failure information in throwable. */ private void sendExceptionByRoutingContext(RoutingContext context, Throwable e) { - if (InvocationException.class.isInstance(e)) { - InvocationException invocationException = (InvocationException) e; + if (e instanceof InvocationException invocationException) { context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD) .setStatusCode(invocationException.getStatusCode()).setStatusMessage(invocationException.getReasonPhrase()) .end(wrapResponseBody(invocationException.getReasonPhrase())); } else { context.response().putHeader(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD) - .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode()).end(wrapResponseBody(e.getMessage())); + .setStatusCode(Status.INTERNAL_SERVER_ERROR.getStatusCode()) + .end(wrapResponseBody(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())); } - context.response().close(); } /** @@ -173,24 +173,18 @@ private boolean isValidJson(String message) { return true; } - /** - * Use restProducerInvocation to send failure message. The throwable is allowed to be null. - */ - private void sendFailResponseByInvocation(RoutingContext context, AbstractRestInvocation restProducerInvocation, - Throwable e) { - restProducerInvocation.sendFailResponse(e); - context.response().close(); - } - - private void onRequest(RoutingContext context) { + protected void onRequest(RoutingContext context) { if (transport == null) { - transport = CseContext.getInstance().getTransportManager().findTransport(Const.RESTFUL); + transport = SCBEngine.getInstance().getTransportManager().findTransport(CoreConst.RESTFUL); + microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); } HttpServletRequestEx requestEx = new VertxServerRequestToHttpServletRequest(context); HttpServletResponseEx responseEx = new VertxServerResponseToHttpServletResponse(context.response()); - VertxRestInvocation vertxRestInvocation = new VertxRestInvocation(); - context.put(RestConst.REST_PRODUCER_INVOCATION, vertxRestInvocation); - vertxRestInvocation.invoke(transport, requestEx, responseEx, httpServerFilters); + InvocationCreator creator = new RestVertxProducerInvocationCreator(context, + microserviceMeta, transport.getEndpoint(), + requestEx, responseEx); + new RestProducerInvocationFlow(creator, requestEx, responseEx) + .run(); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestTransport.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestTransport.java index 8ec17c1b841..8566a3c3b6b 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestTransport.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/VertxRestTransport.java @@ -17,31 +17,32 @@ package org.apache.servicecomb.transport.rest.vertx; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.core.CoreConst; import org.apache.servicecomb.core.transport.AbstractTransport; import org.apache.servicecomb.foundation.common.net.NetUtils; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.common.utils.BeanUtils; +import org.apache.servicecomb.foundation.common.utils.ClassLoaderScopeContext; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.vertx.SimpleJsonObject; import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.apache.servicecomb.transport.rest.client.RestTransportClient; -import org.apache.servicecomb.transport.rest.client.RestTransportClientManager; +import org.apache.servicecomb.registry.definition.DefinitionConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; import io.vertx.core.DeploymentOptions; +import io.vertx.core.VertxOptions; -@Component public class VertxRestTransport extends AbstractTransport { private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestTransport.class); - private RestTransportClient restClient; - @Override public String getName() { - return Const.RESTFUL; + return CoreConst.RESTFUL; } @Override @@ -51,7 +52,16 @@ public int getOrder() { @Override public boolean canInit() { - setListenAddressWithoutSchema(TransportConfig.getAddress()); + String pattern = environment.getProperty(VertxRestDispatcher.KEY_PATTERN, String.class); + String urlPrefix = null; + if (pattern == null || pattern.length() <= 5) { + setListenAddressWithoutSchema(TransportConfig.getAddress()); + } else { + // e.g. "/api/(.*)" -> "/api" + urlPrefix = pattern.substring(0, pattern.length() - 5); + setListenAddressWithoutSchema(TransportConfig.getAddress(), + Collections.singletonMap(DefinitionConst.URL_PREFIX, urlPrefix)); + } URIEndpointObject ep = (URIEndpointObject) getEndpoint().getAddress(); if (ep == null) { @@ -60,29 +70,42 @@ public boolean canInit() { if (!NetUtils.canTcpListen(ep.getSocketAddress().getAddress(), ep.getPort())) { LOGGER.warn( - "Can not start VertxRestTransport, the port:{} may have been occupied. You can ignore this message if you are using a web container like tomcat.", + "Can not start VertxRestTransport, the port:{} may have been occupied. " + + "You can ignore this message if you are using a web container like tomcat.", ep.getPort()); return false; } + if (urlPrefix != null) { + ClassLoaderScopeContext.setClassLoaderScopeProperty(DefinitionConst.URL_PREFIX, urlPrefix); + } + return true; } @Override public boolean init() throws Exception { - restClient = RestTransportClientManager.INSTANCE.getRestClient(); - // 部署transport server DeploymentOptions options = new DeploymentOptions().setInstances(TransportConfig.getThreadCount()); SimpleJsonObject json = new SimpleJsonObject(); json.put(ENDPOINT_KEY, getEndpoint()); - json.put(RestTransportClient.class.getName(), restClient); options.setConfig(json); - return VertxUtils.blockDeploy(transportVertx, TransportConfig.getRestServerVerticle(), options); + options.setWorkerPoolName("pool-worker-transport-rest"); + options.setWorkerPoolSize(VertxOptions.DEFAULT_WORKER_POOL_SIZE); + + prepareBlockResource(); + Map result = VertxUtils.blockDeploy(transportVertx, TransportConfig.getRestServerVerticle(), + options); + if ((boolean) result.get("code")) { + return true; + } else { + throw new IllegalStateException((String) result.get("message")); + } } - @Override - public void send(Invocation invocation, AsyncResponse asyncResp) throws Exception { - restClient.send(invocation, asyncResp); + private void prepareBlockResource() { + // block deploy will load resources in event loop, but beans auto wire can only be done in main thread + List dispatchers = SPIServiceUtils.getOrLoadSortedService(VertxHttpDispatcher.class); + BeanUtils.addBeans(VertxHttpDispatcher.class, dispatchers); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketDispatcher.java new file mode 100644 index 00000000000..5f8e2cd329d --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketDispatcher.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.vertx; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.servicecomb.common.rest.EdgeServerWebSocketInvocationCreator; +import org.apache.servicecomb.common.rest.ProviderServerWebSocketInvocationCreator; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationItem; +import org.apache.servicecomb.common.rest.route.URLMappedConfigurationLoader; +import org.apache.servicecomb.common.rest.route.Utils; +import org.apache.servicecomb.config.ConfigurationChangedEvent; +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.definition.MicroserviceMeta; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.apache.servicecomb.foundation.common.event.EventManager; +import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; + +import com.google.common.eventbus.Subscribe; + +import io.vertx.core.http.ServerWebSocket; +import jakarta.ws.rs.core.Response.Status; + +public class WebSocketDispatcher { + private static final String KEY_MAPPING_PREFIX = "servicecomb.http.dispatcher.edge.websocket.mappings"; + + private final Object LOCK = new Object(); + + private volatile boolean initialized = false; + + private Endpoint endpoint; + + private MicroserviceMeta microserviceMeta; + + private boolean isEdge; + + private Map configurations = new HashMap<>(); + + public WebSocketDispatcher(Endpoint endpoint) { + this.endpoint = endpoint; + EventManager.register(this); + } + + private void loadConfigurations() { + configurations = URLMappedConfigurationLoader.loadConfigurations( + LegacyPropertyFactory.getEnvironment(), KEY_MAPPING_PREFIX); + } + + @Subscribe + public void onConfigurationChangedEvent(ConfigurationChangedEvent event) { + for (String changed : event.getChanged()) { + if (changed.startsWith(KEY_MAPPING_PREFIX)) { + loadConfigurations(); + break; + } + } + } + + protected void onRequest(ServerWebSocket webSocket) { + if (!initialized) { + synchronized (LOCK) { + if (!initialized) { + Transport transport = SCBEngine.getInstance().getTransportManager().findTransport(CoreConst.WEBSOCKET); + this.microserviceMeta = SCBEngine.getInstance().getProducerMicroserviceMeta(); + this.endpoint = new Endpoint(transport, this.endpoint.getEndpoint()); + this.isEdge = TransportConfig.getRestServerVerticle() + .getName().equals("org.apache.servicecomb.edge.core.EdgeRestServerVerticle"); + if (this.isEdge) { + loadConfigurations(); + } + } + initialized = true; + } + } + + InvocationCreator creator; + if (isEdge) { + URLMappedConfigurationItem configurationItem = findConfigurationItem(webSocket.path()); + if (configurationItem == null) { + throw new InvocationException(Status.NOT_FOUND, new CommonExceptionData( + String.format("path %s not found", webSocket.path()))); + } + String path = Utils.findActualPath(webSocket.path(), configurationItem.getPrefixSegmentCount()); + creator = new EdgeServerWebSocketInvocationCreator( + configurationItem.getMicroserviceName(), path, endpoint, webSocket); + } else { + creator = new ProviderServerWebSocketInvocationCreator(microserviceMeta, + endpoint, webSocket); + } + new WebSocketProducerInvocationFlow(creator, webSocket).run(); + } + + private URLMappedConfigurationItem findConfigurationItem(String path) { + for (URLMappedConfigurationItem item : configurations.values()) { + if (item.getPattern().matcher(path).matches()) { + return item; + } + } + return null; + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketProducerInvocationFlow.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketProducerInvocationFlow.java new file mode 100644 index 00000000000..1297da53a51 --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketProducerInvocationFlow.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.vertx; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.invocation.InvocationCreator; +import org.apache.servicecomb.core.invocation.ProducerInvocationFlow; +import org.apache.servicecomb.swagger.invocation.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.http.ServerWebSocket; + +public class WebSocketProducerInvocationFlow extends ProducerInvocationFlow { + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProducerInvocationFlow.class); + + private final ServerWebSocket websocket; + + public WebSocketProducerInvocationFlow(InvocationCreator invocationCreator, ServerWebSocket webSocket) { + super(invocationCreator); + this.websocket = webSocket; + } + + @Override + protected Invocation sendCreateInvocationException(Throwable throwable) { + LOGGER.error("Web socket create invocation error.", throwable); + websocket.writeTextMessage("Web socket create invocation error " + throwable.getMessage()); + websocket.close(); + return null; + } + + @Override + protected void endResponse(Invocation invocation, Response response) { + + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketTransport.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketTransport.java new file mode 100644 index 00000000000..9bcd614a374 --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/WebSocketTransport.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.vertx; + +import org.apache.servicecomb.core.CoreConst; +import org.apache.servicecomb.core.transport.AbstractTransport; + +public class WebSocketTransport extends AbstractTransport { + @Override + public String getName() { + return CoreConst.WEBSOCKET; + } + + @Override + public int getOrder() { + return -500; + } + + @Override + public boolean init() throws Exception { + return true; + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java deleted file mode 100644 index eee43079fcd..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog; - -import com.netflix.config.DynamicPropertyFactory; - -public final class AccessLogConfiguration { - - private static final String BASE = "servicecomb.accesslog."; - - private static final String ACCESSLOG_ENABLED = BASE + "enabled"; - - private static final String ACCESSLOG_PATTERN = BASE + "pattern"; - - public static final AccessLogConfiguration INSTANCE = new AccessLogConfiguration(); - - public static final String DEFAULT_PATTERN = "%h - - %t %r %s %B %D"; - - private AccessLogConfiguration() { - - } - - public boolean getAccessLogEnabled() { - return getBooleanProperty(false, ACCESSLOG_ENABLED); - } - - public String getAccesslogPattern() { - return getProperty(DEFAULT_PATTERN, ACCESSLOG_PATTERN); - } - - private String getProperty(String defaultValue, String key) { - return DynamicPropertyFactory.getInstance().getStringProperty(key, defaultValue).get(); - } - - private boolean getBooleanProperty(boolean defaultValue, String key) { - return DynamicPropertyFactory.getInstance().getBooleanProperty(key, defaultValue).get(); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGenerator.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGenerator.java deleted file mode 100644 index 27d8e0ca456..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGenerator.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog; - -import java.util.List; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.AccessLogPatternParser; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.VertxRestAccessLogPatternParser; - -import com.google.common.collect.Iterables; - -import io.vertx.ext.web.RoutingContext; - -/* - * Accept {@link AccessLogParam} and generate access log. - *
- * Each AccessLogParam for a line of access log. - */ -public class AccessLogGenerator { - /* - * traversal this array to generate access log segment. - */ - private AccessLogItem[] accessLogItems; - - private AccessLogPatternParser accessLogPatternParser = new VertxRestAccessLogPatternParser(); - - @SuppressWarnings("unchecked") - public AccessLogGenerator(String rawPattern) { - List> accessLogItemList = accessLogPatternParser.parsePattern(rawPattern); - accessLogItems = Iterables.toArray(accessLogItemList, AccessLogItem.class); - } - - public String generateLog(AccessLogParam accessLogParam) { - StringBuilder log = new StringBuilder(128); - accessLogParam.setEndMillisecond(System.currentTimeMillis()); - - AccessLogItem[] accessLogItems = getAccessLogItems(); - for (int i = 0; i < accessLogItems.length; ++i) { - log.append(accessLogItems[i].getFormattedItem(accessLogParam)); - } - - return log.toString(); - } - - private AccessLogItem[] getAccessLogItems() { - return accessLogItems; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java deleted file mode 100644 index 809030f2f56..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogParam.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog; - -/** - * carry the data used in access log. - */ -public class AccessLogParam { - /** - * data object that contains request and response information. - * For example, in vertx rest transport it's {@link io.vertx.ext.web.RoutingContext} - */ - private T contextData; - - private long startMillisecond; - - private long endMillisecond; - - /** - * If client send request via a short-lived connection, the connection may be closed before the corresponding - * access log is generated, and then the - * {@linkplain org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem LocalHostItem} - * may get "0.0.0.0" as result. So we need to get local address before the connection is closed. - */ - private String localAddress; - - public T getContextData() { - return contextData; - } - - public AccessLogParam setContextData(T contextData) { - this.contextData = contextData; - return this; - } - - public long getStartMillisecond() { - return startMillisecond; - } - - public AccessLogParam setStartMillisecond(long startMillisecond) { - this.startMillisecond = startMillisecond; - return this; - } - - public long getEndMillisecond() { - return endMillisecond; - } - - public AccessLogParam setEndMillisecond(long endMillisecond) { - this.endMillisecond = endMillisecond; - return this; - } - - public String getLocalAddress() { - return localAddress; - } - - public AccessLogParam setLocalAddress(String localAddress) { - this.localAddress = localAddress; - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("AccessLogParam{"); - sb.append("contextData=").append(contextData); - sb.append(", startMillisecond=").append(startMillisecond); - sb.append(", endMillisecond=").append(endMillisecond); - sb.append(", localAddress='").append(localAddress).append('\''); - sb.append('}'); - return sb.toString(); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/README.md b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/README.md deleted file mode 100644 index 0826dbe1efe..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# transport-rest-vertx Access Log - -## Enable access log printing - -To enable access log printing, you can config access log in microservice.yaml like below: -```yaml -servicecomb: - accesslog: - enabled: true - pattern: "%h - - %t %r %s %B" -``` - -***Access Log Configurations in microservice.yaml*** - -| Config Item | Range of Value | Default Value | Meaning | -| :---------- | :------------- | :------------ | :------ | -| servicecomb.accesslog.enabled | true/false | false | print access log if true | -| servicecomb.accesslog.pattern | a string field representing log pattern | "%h - - %t %r %s %B" | see details of ***Currently Supported Elements*** below | - -> ***Caution:*** -> - all of the configuration items above can be omitted, in this case, default value will take effect. - -## Supported log elements - -***Currently Supported Elements (Apache & W3C)*** - -| Element | Apache | W3C | Comment | -| :---- | :----- | :-- | :------ | -| HTTP method | %m | cs-method | | -| HTTP status | %s | sc-status | | -| Duration in second | %T | - | The time taken to serve the request, in seconds | -| Duration in millisecond | %D | - | The time taken to serve the request, in millisecond | -| Remote hostname | %h | - | | -| Local hostname | %v | - | | -| Local port | %p | - | | -| Size of response | %B | - | | -| Size of response | %b | - | In CLF format, i.e. "-" is written if response size is 0 | -| First line of request | %r | - | | -| URI path | %U | cs-uri-stem | | -| Query string | %q | cs-uri-query | | -| URI path and query string | - | cs-uri | | -| Request protocol | %H | - | | -| Datetime the request was received | %t | - | Write in default format, i.e. pattern is "EEE, dd MMM yyyy HH:mm:ss zzz", Locale is US and Timezone is GMT | -| Configurable datetime the request was received | %{PATTERN|TIMEZONE|LOCALE}t | - | Write datetime in specified format pattern, timezone and locale. TIMEZONE and LOCALE can be omitted | -| Request Header | %{VARNAME}i | - | '-' is written if not found | -| Response header | %{VARNAME}o | - | '-' is written if not found | -| Cookie | %{VARNAME}C | - | '-' is written if not found | - -***Currently Supported Elements (ServiceComb)*** - -| Element | Placeholder | Comment | -| :---- | :---------- | :------ | -| TraceId | %SCB-traceId | TraceId provided by ServiceComb | -| Invocation Context | %{VARNAME}SCB-ctx | Variable carried in invocation context, '-' is written if not found | - -## Access log file settings - -Access log will be written in a separate log file named `access.log` located in the same directory with common logs. - -Default access log printer is based on Log4j, users can override access log file configuration in their `log4j.properties` file. - -***Common access log file configuration items*** - -| Configuration Item | Default Value | Meaning | -| :----------------- | :------------ | :------ | -| paas.logs.accesslog.dir | ${paas.logs.dir} | access log output directory | -| paas.logs.accesslog.file | access.log | access log file name | - -## Access log item reference - -- [mod_log_config - Apache HTTP Server Version 2.4](http://httpd.apache.org/docs/2.4/en/mod/mod_log_config.html) -- [Extended Log File Format](https://www.w3.org/TR/WD-logfile.html) diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/AccessLogItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/AccessLogItem.java deleted file mode 100644 index 078066f6830..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/AccessLogItem.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; - -/* - * Access log item represents the items supported in access log printing. - * It generate the segment of access log according to {@link AccessLogParam} - */ -public interface AccessLogItem { - /* - * find out specified content from {@link AccessLogParam}, format the content and return it. - */ - String getFormattedItem(AccessLogParam accessLogParam); -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItem.java deleted file mode 100644 index aa20a02abaa..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItem.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import java.util.Set; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.Cookie; -import io.vertx.ext.web.RoutingContext; - -public class CookieItem implements AccessLogItem { - - public static final String RESULT_NOT_FOUND = "-"; - - private final String varName; - - public CookieItem(String varName) { - this.varName = varName; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - Set cookieSet = accessLogParam.getContextData().cookies(); - if (null == cookieSet) { - return RESULT_NOT_FOUND; - } - - String result = null; - for (Cookie cookie : cookieSet) { - if (varName.equals(cookie.getName())) { - result = cookie.getValue(); - } - } - - if (null == result) { - return RESULT_NOT_FOUND; - } - - return result; - } - - public String getVarName() { - return varName; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItem.java deleted file mode 100644 index 740c474deca..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItem.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.ext.web.RoutingContext; - -/** - * Configurable dateTime element. - */ -public class DatetimeConfigurableItem implements AccessLogItem { - - public static final String DEFAULT_DATETIME_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz"; - - public static final Locale DEFAULT_LOCALE = Locale.US; - - private final ThreadLocal datetimeFormatHolder = new ThreadLocal<>(); - - private String pattern; - - private TimeZone timezone; - - private Locale locale; - - /** - * all configuration is set to default value. - */ - public DatetimeConfigurableItem() { - this(DEFAULT_DATETIME_PATTERN); - } - - /** - * the configurations not specified will get a default value. - * @param config the format of configuration is "PATTERN|TIMEZONE|LOCALE" or "PATTERN". It depends on whether the config contains the separator "|" - */ - public DatetimeConfigurableItem(String config) { - String[] configArr = null; - if (config.contains("|")) { - configArr = splitConfig(config); - } else { - // if there is no separator "|", regard configuration as pattern. - configArr = new String[3]; - configArr[0] = config; - } - if (3 != configArr.length) { - throw new IllegalArgumentException( - "wrong format of configuration, \"PATTERN|TIMEZONE|LOCALE\" is expected, but actually is \"" + config + "\""); - } - - setConfigruations(configArr); - } - - private String[] splitConfig(String config) { - return config.split("\\|{1}?", -1); - } - - private void setConfigruations(String[] configArr) { - this.pattern = StringUtils.isEmpty(configArr[0]) ? DEFAULT_DATETIME_PATTERN : configArr[0]; - this.timezone = StringUtils.isEmpty(configArr[1]) ? TimeZone.getDefault() : TimeZone.getTimeZone(configArr[1]); - this.locale = StringUtils.isEmpty(configArr[2]) ? DEFAULT_LOCALE : Locale.forLanguageTag(configArr[2]); - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - SimpleDateFormat dateFormat = getDatetimeFormat(); - return dateFormat.format(new Date(accessLogParam.getStartMillisecond())); - } - - private SimpleDateFormat getDatetimeFormat() { - SimpleDateFormat dateFormat = datetimeFormatHolder.get(); - if (null == dateFormat) { - dateFormat = new SimpleDateFormat(pattern, locale); - dateFormat.setTimeZone(timezone); - - datetimeFormatHolder.set(dateFormat); - } - - return dateFormat; - } - - public String getPattern() { - return pattern; - } - - public TimeZone getTimezone() { - return timezone; - } - - public Locale getLocale() { - return locale; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItem.java deleted file mode 100644 index 88980a32ad5..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItem.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -public class DurationMillisecondItem implements AccessLogItem { - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return String.valueOf(accessLogParam.getEndMillisecond() - accessLogParam.getStartMillisecond()); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItem.java deleted file mode 100644 index b8ec486b34c..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItem.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -public class DurationSecondItem implements AccessLogItem { - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return String.valueOf((accessLogParam.getEndMillisecond() - accessLogParam.getStartMillisecond()) / 1000); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItem.java deleted file mode 100644 index c3b37bb3392..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItem.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -public class FirstLineOfRequestItem implements AccessLogItem { - private static final HttpMethodItem METHOD_ELEMENT = new HttpMethodItem(); - - private static final UrlPathItem URI_PATH_ONLY_ELEMENT = new UrlPathItem(); - - private static final RequestProtocolItem VERSION_OR_PROTOCOL_ELEMENT = new RequestProtocolItem(); - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - StringBuilder result = new StringBuilder(64) - .append("\"") - .append(METHOD_ELEMENT.getFormattedItem(accessLogParam)) - .append(" ") - .append(URI_PATH_ONLY_ELEMENT.getFormattedItem(accessLogParam)) - .append(" ") - .append(VERSION_OR_PROTOCOL_ELEMENT.getFormattedItem(accessLogParam)) - .append("\""); - - return result.toString(); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItem.java deleted file mode 100644 index 866e5b731c7..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItem.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -/** - * HTTP method - */ -public class HttpMethodItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - HttpMethod method = request.method(); - if (null == method) { - return EMPTY_RESULT; - } - return method.toString(); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpStatusItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpStatusItem.java deleted file mode 100644 index 17f589b6cea..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpStatusItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -public class HttpStatusItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerResponse response = accessLogParam.getContextData().response(); - if (null == response) { - return EMPTY_RESULT; - } - - return String.valueOf(response.getStatusCode()); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItem.java deleted file mode 100644 index f479d1bf024..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItem.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import java.util.Map; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.ext.web.RoutingContext; - -public class InvocationContextItem implements AccessLogItem { - - public static final String NOT_FOUND = "-"; - - String varName; - - public InvocationContextItem(String varName) { - this.varName = varName; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - String invocationContextValue = getValueFromInvocationContext(accessLogParam); - - if (StringUtils.isEmpty(invocationContextValue)) { - return NOT_FOUND; - } - - return invocationContextValue; - } - - protected String getValueFromInvocationContext(AccessLogParam accessLogParam) { - Map data = accessLogParam.getContextData().data(); - if (null == data) { - return null; - } - - Invocation invocation = (Invocation) data.get(RestConst.REST_INVOCATION_CONTEXT); - if (null == invocation) { - return null; - } - - return invocation.getContext(varName); - } - - public String getVarName() { - return varName; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItem.java deleted file mode 100644 index cbb1e87b3d9..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItem.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class LocalHostItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return accessLogParam.getLocalAddress(); - } - - public static String getLocalAddress(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - SocketAddress localAddress = request.localAddress(); - if (null == localAddress) { - return EMPTY_RESULT; - } - - String localHost = localAddress.host(); - if (StringUtils.isEmpty(localHost)) { - return EMPTY_RESULT; - } - return localHost; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItem.java deleted file mode 100644 index 3209d961bb1..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItem.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class LocalPortItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - SocketAddress localAddress = request.localAddress(); - if (null == localAddress) { - return EMPTY_RESULT; - } - - return String.valueOf(localAddress.port()); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItem.java deleted file mode 100644 index fb7683f19ab..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -/** - * Print content as it is. - */ -public class PlainTextItem implements AccessLogItem { - private final String content; - - public PlainTextItem(String content) { - this.content = content; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return content; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItem.java deleted file mode 100644 index 6439b990c9a..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItem.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class QueryStringItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - String query = request.query(); - if (StringUtils.isEmpty(query)) { - return EMPTY_RESULT; - } - return query; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItem.java deleted file mode 100644 index 82ace24320a..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItem.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class RemoteHostItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - SocketAddress remoteAddress = request.remoteAddress(); - if (null == remoteAddress) { - return EMPTY_RESULT; - } - - String remoteHost = remoteAddress.host(); - if (StringUtils.isEmpty(remoteHost)) { - return EMPTY_RESULT; - } - return remoteHost; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItem.java deleted file mode 100644 index 94a463da231..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItem.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.MultiMap; -import io.vertx.ext.web.RoutingContext; - -public class RequestHeaderItem implements AccessLogItem { - - public static final String RESULT_NOT_FOUND = "-"; - - private final String varName; - - public RequestHeaderItem(String varName) { - this.varName = varName; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - MultiMap headers = accessLogParam.getContextData().request().headers(); - if (null == headers) { - return "-"; - } - - String result = headers.get(varName); - - if (null == result) { - return RESULT_NOT_FOUND; - } - - return result; - } - - public String getVarName() { - return varName; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItem.java deleted file mode 100644 index b2a994870ea..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItem.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpVersion; -import io.vertx.ext.web.RoutingContext; - -public class RequestProtocolItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - if (null == request.version()) { - return EMPTY_RESULT; - } - return getStringVersion(request.version()); - } - - private String getStringVersion(HttpVersion version) { - switch (version) { - case HTTP_2: - return "HTTP/2.0"; - case HTTP_1_0: - return "HTTP/1.0"; - case HTTP_1_1: - return "HTTP/1.1"; - default: - return EMPTY_RESULT; - } - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItem.java deleted file mode 100644 index af8cfbb6084..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItem.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -public class ResponseHeaderItem implements AccessLogItem { - - public static final String RESULT_NOT_FOUND = "-"; - - private final String varName; - - public ResponseHeaderItem(String varName) { - this.varName = varName; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerResponse response = accessLogParam.getContextData().response(); - if (null == response) { - return RESULT_NOT_FOUND; - } - - MultiMap headers = response.headers(); - if (null == headers) { - return RESULT_NOT_FOUND; - } - - String result = headers.get(varName); - if (null == result) { - return RESULT_NOT_FOUND; - } - - return result; - } - - public String getVarName() { - return varName; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItem.java deleted file mode 100644 index cb43bd5e221..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItem.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -public class ResponseSizeItem implements AccessLogItem { - // print zeroBytes when bytes is zero - private final String zeroBytes; - - public ResponseSizeItem(String zeroBytesPlaceholder) { - zeroBytes = zeroBytesPlaceholder; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerResponse response = accessLogParam.getContextData().response(); - if (null == response) { - return zeroBytes; - } - - long bytesWritten = response.bytesWritten(); - return 0 == bytesWritten ? zeroBytes : String.valueOf(bytesWritten); - } - - public String getZeroBytes() { - return zeroBytes; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItem.java deleted file mode 100644 index 5499033a7aa..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItem.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.springframework.util.StringUtils; - -import io.vertx.ext.web.RoutingContext; - -public class TraceIdItem extends InvocationContextItem { - - public static final String TRACE_ID = Const.TRACE_ID_NAME; - - public TraceIdItem() { - super(TRACE_ID); - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - String traceId = getValueFromInvocationContext(accessLogParam); - if (StringUtils.isEmpty(traceId)) { - traceId = accessLogParam.getContextData().request().getHeader(TRACE_ID); - } - - if (StringUtils.isEmpty(traceId)) { - return InvocationContextItem.NOT_FOUND; - } - - return traceId; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItem.java deleted file mode 100644 index 309ecc0bd1b..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItem.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class UrlPathItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - - if (null == request) { - return EMPTY_RESULT; - } - - String uri = request.path(); - if (null == uri) { - return EMPTY_RESULT; - } - - return uri; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItem.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItem.java deleted file mode 100644 index 2d65985de67..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItem.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.springframework.util.StringUtils; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class UrlPathWithQueryItem implements AccessLogItem { - - public static final String EMPTY_RESULT = "-"; - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - HttpServerRequest request = accessLogParam.getContextData().request(); - if (null == request) { - return EMPTY_RESULT; - } - - String uri = request.uri(); - if (StringUtils.isEmpty(uri)) { - return EMPTY_RESULT; - } - - return uri; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java deleted file mode 100644 index 0edc7c05ba4..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogGenerator; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; - -public class AccessLogHandler implements Handler { - private static Logger LOGGER = LoggerFactory.getLogger("accesslog"); - - private AccessLogGenerator accessLogGenerator; - - public AccessLogHandler(String rawPattern) { - accessLogGenerator = new AccessLogGenerator(rawPattern); - } - - @Override - public void handle(RoutingContext context) { - AccessLogParam accessLogParam = getRoutingContextAccessLogParam(context); - - context.response().endHandler(event -> LOGGER.info(accessLogGenerator.generateLog(accessLogParam))); - - context.next(); - } - - private AccessLogParam getRoutingContextAccessLogParam(RoutingContext context) { - AccessLogParam accessLogParam = new AccessLogParam<>(); - accessLogParam.setStartMillisecond(System.currentTimeMillis()).setContextData(context); - accessLogParam.setLocalAddress(LocalHostItem.getLocalAddress(accessLogParam)); - return accessLogParam; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java deleted file mode 100644 index bc38768d4cf..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/AccessLogPatternParser.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser; - -import java.util.List; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -/** - * This parser will parse the rawPattern of access log and generate a list of {@link AccessLogItem}, - * which will be used in {@link org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogGenerator} to generate - * access log content. - * @param the type of {@linkplain org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam#contextData - * AccessLogParam.contextData}, which usually depends on the transport way. - */ -public interface AccessLogPatternParser { - List> parsePattern(String rawPattern); -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java deleted file mode 100644 index aaaf9f0f0aa..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/DefaultCompositeVertxRestAccessLogItemMeta.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpMethodItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpStatusItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.InvocationContextItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryStringItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestProtocolItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseSizeItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.TraceIdItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathWithQueryItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta; - -import io.vertx.ext.web.RoutingContext; - -public class DefaultCompositeVertxRestAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta { - private static final List SUPPORTED_META = new ArrayList<>(); - - static { - final AccessLogItem httpMethodItem = new HttpMethodItem(); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%m", config -> httpMethodItem)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-method", config -> httpMethodItem)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%s", config -> new HttpStatusItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("sc-status", config -> new HttpStatusItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%T", config -> new DurationSecondItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%D", config -> new DurationMillisecondItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%h", config -> new RemoteHostItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%v", config -> new LocalHostItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%p", config -> new LocalPortItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%B", config -> new ResponseSizeItem("0"))); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%b", config -> new ResponseSizeItem("-"))); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%r", config -> new FirstLineOfRequestItem())); - final AccessLogItem urlPathItem = new UrlPathItem(); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%U", config -> urlPathItem)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-stem", config -> urlPathItem)); - final AccessLogItem queryStringItem = new QueryStringItem(); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%q", config -> queryStringItem)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri-query", config -> queryStringItem)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("cs-uri", config -> new UrlPathWithQueryItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%H", config -> new RequestProtocolItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%t", config -> new DatetimeConfigurableItem())); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%SCB-traceId", config -> new TraceIdItem())); - - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}t", DatetimeConfigurableItem::new)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}i", RequestHeaderItem::new)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}o", ResponseHeaderItem::new)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}C", CookieItem::new)); - SUPPORTED_META.add(new VertxRestAccessLogItemMeta("%{", "}SCB-ctx", InvocationContextItem::new)); - } - - @Override - public List getAccessLogItemMetas() { - return SUPPORTED_META; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport b/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport new file mode 100644 index 00000000000..74ae694b980 --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.core.Transport @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +org.apache.servicecomb.transport.rest.vertx.VertxRestTransport +org.apache.servicecomb.transport.rest.vertx.WebSocketTransport diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta b/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta deleted file mode 100644 index 7a9f86cc49c..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta +++ /dev/null @@ -1,18 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.DefaultCompositeVertxRestAccessLogItemMeta \ No newline at end of file diff --git a/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties b/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties deleted file mode 100644 index d19fd976a9b..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/main/resources/config/base/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# access log default configuration -paas.logs.accesslog.dir=${paas.logs.dir} -paas.logs.accesslog.file=access.log -# access log File appender -log4j.logger.accesslog=INFO,access -log4j.appender.access=org.apache.servicecomb.foundation.common.utils.RollingFileAppenderExt -log4j.appender.access.MaxBackupIndex=10 -log4j.appender.access.MaxFileSize=20MB -log4j.appender.access.file=${paas.logs.accesslog.dir}${paas.logs.accesslog.file} -log4j.appender.access.layout=org.apache.log4j.PatternLayout -log4j.appender.access.layout.ConversionPattern=%m%n -log4j.appender.access.logPermission=rw------- -log4j.additivity.accesslog=false diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockForRestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockForRestServerVerticle.java index debfe1470db..965f14ed894 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockForRestServerVerticle.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockForRestServerVerticle.java @@ -27,7 +27,7 @@ public class MockForRestServerVerticle { - private static MockForRestServerVerticle instance = new MockForRestServerVerticle(); + private static final MockForRestServerVerticle instance = new MockForRestServerVerticle(); private MockForRestServerVerticle() { // private constructor for Singleton diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockHttpServerResponse.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockHttpServerResponse.java new file mode 100644 index 00000000000..74a8307262b --- /dev/null +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/MockHttpServerResponse.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.transport.rest.vertx; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import io.vertx.codegen.annotations.Nullable; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.Cookie; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.net.HostAndPort; + +class MockHttpServerResponse implements HttpServerResponse { + boolean responseEnded; + + Map responseHeader = new HashMap<>(1); + + int responseStatusCode; + + String responseStatusMessage; + + String responseChunk; + + @Override + public HttpServerResponse putHeader(String name, String value) { + responseHeader.put(name, value); + return this; + } + + @Override + public HttpServerResponse setStatusCode(int statusCode) { + responseStatusCode = statusCode; + return this; + } + + @Override + public HttpServerResponse setStatusMessage(String statusMessage) { + responseStatusMessage = statusMessage; + return this; + } + + @Override + public Future end() { + responseEnded = true; + return Future.succeededFuture(); + } + + @Override + public Future end(String chunk) { + responseEnded = true; + responseChunk = chunk; + return Future.succeededFuture(); + } + + @Override + public HttpServerResponse exceptionHandler(Handler handler) { + return null; + } + + @Override + public Future write(Buffer data) { + return Future.succeededFuture(); + } + + @Override + public HttpServerResponse setWriteQueueMaxSize(int maxSize) { + return null; + } + + @Override + public boolean writeQueueFull() { + return false; + } + + @Override + public HttpServerResponse drainHandler(Handler handler) { + return null; + } + + @Override + public int getStatusCode() { + return 0; + } + + @Override + public String getStatusMessage() { + return null; + } + + @Override + public HttpServerResponse setChunked(boolean chunked) { + return null; + } + + @Override + public boolean isChunked() { + return false; + } + + @Override + public MultiMap headers() { + return null; + } + + @Override + public HttpServerResponse putHeader(CharSequence name, CharSequence value) { + return null; + } + + @Override + public HttpServerResponse putHeader(String name, Iterable values) { + return null; + } + + @Override + public HttpServerResponse putHeader(CharSequence name, Iterable values) { + return null; + } + + @Override + public MultiMap trailers() { + return null; + } + + @Override + public HttpServerResponse putTrailer(String name, String value) { + return null; + } + + @Override + public HttpServerResponse putTrailer(CharSequence name, CharSequence value) { + return null; + } + + @Override + public HttpServerResponse putTrailer(String name, Iterable values) { + return null; + } + + @Override + public HttpServerResponse putTrailer(CharSequence name, Iterable value) { + return null; + } + + @Override + public HttpServerResponse closeHandler(Handler handler) { + return null; + } + + @Override + public HttpServerResponse endHandler(Handler handler) { + return null; + } + + @Override + public Future writeHead() { + return null; + } + + @Override + public Future write(String chunk, String enc) { + return Future.succeededFuture(); + } + + + @Override + public Future write(String chunk) { + return Future.succeededFuture(); + } + + @Override + public Future writeContinue() { + return null; + } + + @Override + public Future writeEarlyHints(MultiMap headers) { + return Future.succeededFuture(); + } + + @Override + public Future end(String chunk, String enc) { + return Future.succeededFuture(); + } + + + @Override + public Future end(Buffer chunk) { + return Future.succeededFuture(); + } + + + @Override + public Future sendFile(String filename, long offset, long length) { + return Future.succeededFuture(); + } + + @Override + public Future sendFile(FileChannel channel, long offset, long length) { + return null; + } + + @Override + public Future sendFile(RandomAccessFile file, long offset, long length) { + return null; + } + + @Override + public boolean ended() { + return false; + } + + @Override + public boolean closed() { + return false; + } + + @Override + public boolean headWritten() { + return false; + } + + @Override + public HttpServerResponse headersEndHandler(Handler handler) { + return null; + } + + @Override + public HttpServerResponse bodyEndHandler(Handler handler) { + return null; + } + + @Override + public long bytesWritten() { + return 0; + } + + @Override + public int streamId() { + return 0; + } + + @Override + public Future push(HttpMethod httpMethod, HostAndPort hostAndPort, String s, MultiMap multiMap) { + return null; + } + + @Override + public Future reset(long code) { + return null; + } + + @Override + public Future writeCustomFrame(int type, int flags, Buffer payload) { + return null; + } + + @Override + public HttpServerResponse addCookie(Cookie cookie) { + return null; + } + + @Override + public @Nullable Cookie removeCookie(String name, boolean invalidate) { + return null; + } + + @Override + public Set removeCookies(String name, boolean invalidate) { + return null; + } + + @Override + public @Nullable Cookie removeCookie(String name, String domain, String path, boolean invalidate) { + return null; + } +} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestAbstractVertxHttpDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestAbstractVertxHttpDispatcher.java index 8b336b91b1b..6636b87c468 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestAbstractVertxHttpDispatcher.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestAbstractVertxHttpDispatcher.java @@ -17,27 +17,22 @@ package org.apache.servicecomb.transport.rest.vertx; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; +import org.apache.servicecomb.common.rest.RestConst; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; +import org.junit.Before; +import org.junit.FixMethodOrder; import org.junit.Test; - -import com.netflix.config.DynamicPropertyFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.vertx.ext.web.Router; import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mocked; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestAbstractVertxHttpDispatcher { - class AbstractVertxHttpDispatcherForTest extends AbstractVertxHttpDispatcher { + static class AbstractVertxHttpDispatcherForTest extends AbstractVertxHttpDispatcher { @Override public int getOrder() { return 0; @@ -48,50 +43,43 @@ public void init(Router router) { } } - Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - - @BeforeClass - public static void setup() { - ArchaiusUtils.resetConfig(); - } - - - @AfterClass - public static void teardown() { - ArchaiusUtils.resetConfig(); + Environment environment = Mockito.mock(Environment.class); + + @Before + public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty( + RestConst.UPLOAD_MAX_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_MAX_FILE_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, int.class, 0)) + .thenReturn(0); } @Test - public void construct(@Mocked HttpServerFilter filter) { - List filters = Arrays.asList(filter); - new Expectations(SPIServiceUtils.class) { - { - SPIServiceUtils.getSortedService(HttpServerFilter.class); - result = filters; - } - }; + public void createBodyHandlerUploadDefault() { + Mockito.when(environment.getProperty( + "servicecomb.uploads.directory", RestConst.UPLOAD_DEFAULT_DIR)) + .thenReturn(RestConst.UPLOAD_DEFAULT_DIR); - AbstractVertxHttpDispatcher dispatcher = new AbstractVertxHttpDispatcherForTest(); - Assert.assertSame(filters, dispatcher.httpServerFilters); - } - - @Test - public void createBodyHandlerUploadNull() { AbstractVertxHttpDispatcher dispatcher = new AbstractVertxHttpDispatcherForTest(); RestBodyHandler bodyHandler = (RestBodyHandler) dispatcher.createBodyHandler(); - Assert.assertTrue(Deencapsulation.getField(bodyHandler, "deleteUploadedFilesOnEnd")); - Assert.assertNull(Deencapsulation.getField(bodyHandler, "uploadsDir")); + Assertions.assertTrue(bodyHandler.isDeleteUploadedFilesOnEnd()); + Assertions.assertEquals(RestConst.UPLOAD_DEFAULT_DIR, Deencapsulation.getField(bodyHandler, "uploadsDir")); } @Test public void createBodyHandlerUploadNormal() { - config.setProperty("servicecomb.uploads.directory", "/path"); + Mockito.when(environment.getProperty( + "servicecomb.uploads.directory", RestConst.UPLOAD_DEFAULT_DIR)) + .thenReturn("/path"); AbstractVertxHttpDispatcher dispatcher = new AbstractVertxHttpDispatcherForTest(); RestBodyHandler bodyHandler = (RestBodyHandler) dispatcher.createBodyHandler(); - Assert.assertTrue(Deencapsulation.getField(bodyHandler, "deleteUploadedFilesOnEnd")); - Assert.assertEquals("/path", Deencapsulation.getField(bodyHandler, "uploadsDir")); + Assertions.assertTrue(bodyHandler.isDeleteUploadedFilesOnEnd()); + Assertions.assertEquals("/path", Deencapsulation.getField(bodyHandler, "uploadsDir")); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java index c9846cf351a..4154cc635c5 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java @@ -17,38 +17,63 @@ package org.apache.servicecomb.transport.rest.vertx; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_COMPRESSION_LEVEL; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_DECODER_INITIAL_BUFFER_SIZE; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_DECOMPRESSION_SUPPORTED; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_MAX_CHUNK_SIZE; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_MAX_FORM_ATTRIBUTE_SIZE; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_MAX_FORM_BUFFERED_SIZE; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_MAX_FORM_FIELDS; +import static io.vertx.core.http.HttpServerOptions.DEFAULT_MAX_INITIAL_LINE_LENGTH; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.CLIENT_LOG_ENABLED; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.CLIENT_LOG_PATTERN; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.DEFAULT_CLIENT_PATTERN; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.DEFAULT_SERVER_PATTERN; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.SERVER_LOG_ENABLED; +import static org.apache.servicecomb.common.accessLog.AccessLogConfig.SERVER_LOG_PATTERN; +import static org.apache.servicecomb.core.transport.AbstractTransport.PUBLISH_ADDRESS; +import static org.apache.servicecomb.transport.rest.vertx.TransportConfig.DEFAULT_SERVER_COMPRESSION_SUPPORT; +import static org.apache.servicecomb.transport.rest.vertx.TransportConfig.DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND; +import static org.apache.servicecomb.transport.rest.vertx.TransportConfig.DEFAULT_SERVER_MAX_HEADER_SIZE; +import static org.apache.servicecomb.transport.rest.vertx.TransportConfig.SERVICECOMB_CORS_CONFIG_BASE; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import javax.xml.ws.Holder; - -import org.apache.servicecomb.core.CseContext; +import org.apache.servicecomb.common.rest.RestConst; import org.apache.servicecomb.core.Endpoint; +import org.apache.servicecomb.core.SCBEngine; import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.core.transport.AbstractTransport; -import org.apache.servicecomb.core.transport.TransportManager; +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConfig; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.vertx.core.Context; -import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.Vertx; +import io.vertx.core.http.Http2Settings; import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.impl.SysProps; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Route; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.CorsHandler; -import mockit.Deencapsulation; import mockit.Expectations; import mockit.Mock; import mockit.MockUp; @@ -58,26 +83,117 @@ public class TestRestServerVerticle { private RestServerVerticle instance = null; - Future startFuture = null; + Promise startPromise = null; + + Environment environment = Mockito.mock(Environment.class); @Before public void setUp() { + Mockito.when(environment.getProperty( + "servicecomb.request.timeout", long.class, (long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT)) + .thenReturn((long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT); + Mockito.when(environment.getProperty("servicecomb.rest.client.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.client.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.server.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.server.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.rest.order", int.class, Integer.MAX_VALUE)) + .thenReturn(Integer.MAX_VALUE); + Mockito.when(environment.getProperty("servicecomb.rest.publishPort", int.class, 0)) + .thenReturn(0); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.rest.enabled", boolean.class, true)) + .thenReturn(true); + Mockito.when(environment.getProperty(SERVICECOMB_CORS_CONFIG_BASE + ".enabled", boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(PUBLISH_ADDRESS, "")) + .thenReturn(""); + Mockito.when(environment.getProperty( + RestConst.UPLOAD_MAX_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_MAX_FILE_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, int.class, 0)) + .thenReturn(0); + Mockito.when(environment.getProperty("servicecomb.rest.server.compression", boolean.class, + DEFAULT_SERVER_COMPRESSION_SUPPORT)) + .thenReturn(false); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxHeaderSize", int.class, + DEFAULT_SERVER_MAX_HEADER_SIZE)) + .thenReturn(DEFAULT_SERVER_MAX_HEADER_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxFormAttributeSize", int.class, + DEFAULT_MAX_FORM_ATTRIBUTE_SIZE)) + .thenReturn(DEFAULT_MAX_FORM_ATTRIBUTE_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.compressionLevel", int.class, + DEFAULT_COMPRESSION_LEVEL)) + .thenReturn(DEFAULT_COMPRESSION_LEVEL); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxFormFields", int.class, + DEFAULT_MAX_FORM_FIELDS)) + .thenReturn(DEFAULT_MAX_FORM_FIELDS); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxFormBufferedBytes", int.class, + DEFAULT_MAX_FORM_BUFFERED_SIZE)) + .thenReturn(DEFAULT_MAX_FORM_BUFFERED_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxChunkSize", int.class, + DEFAULT_MAX_CHUNK_SIZE)) + .thenReturn(DEFAULT_MAX_CHUNK_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.decompressionSupported", boolean.class, + DEFAULT_DECOMPRESSION_SUPPORTED)) + .thenReturn(DEFAULT_DECOMPRESSION_SUPPORTED); + Mockito.when(environment.getProperty("servicecomb.rest.server.decoderInitialBufferSize", int.class, + DEFAULT_DECODER_INITIAL_BUFFER_SIZE)) + .thenReturn(DEFAULT_DECODER_INITIAL_BUFFER_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.maxInitialLineLength", int.class, + DEFAULT_MAX_INITIAL_LINE_LENGTH)) + .thenReturn(DEFAULT_MAX_INITIAL_LINE_LENGTH); + Mockito.when(environment.getProperty("servicecomb.rest.server.connection.idleTimeoutInSeconds", int.class, + DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND)) + .thenReturn(DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND); + Mockito.when(environment.getProperty("servicecomb.rest.server.http2.useAlpnEnabled", boolean.class, + true)) + .thenReturn(true); + Mockito.when(environment.getProperty("servicecomb.rest.server.http2ConnectionWindowSize", int.class, + DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE)) + .thenReturn(DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE); + Mockito.when(environment.getProperty("servicecomb.rest.server.http2.connection.idleTimeoutInSeconds", int.class, + DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND)) + .thenReturn(DEFAULT_SERVER_CONNECTION_IDLE_TIMEOUT_SECOND); + Mockito.when(environment.getProperty("servicecomb.rest.server.http2.pushEnabled", boolean.class, + Http2Settings.DEFAULT_ENABLE_PUSH)) + .thenReturn(Http2Settings.DEFAULT_ENABLE_PUSH); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + Mockito.when(environment.getProperty(CLIENT_LOG_ENABLED, boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(SERVER_LOG_ENABLED, boolean.class, false)) + .thenReturn(false); + Mockito.when(environment.getProperty(CLIENT_LOG_PATTERN, String.class, DEFAULT_CLIENT_PATTERN)) + .thenReturn(DEFAULT_CLIENT_PATTERN); + Mockito.when(environment.getProperty(SERVER_LOG_PATTERN, String.class, DEFAULT_SERVER_PATTERN)) + .thenReturn(DEFAULT_CLIENT_PATTERN); + LegacyPropertyFactory.setEnvironment(environment); + instance = new RestServerVerticle(); - startFuture = Future.future(); + startPromise = Promise.promise(); - CseContext.getInstance().setTransportManager(new TransportManager()); + SCBBootstrap.createSCBEngineForTest(environment); } @After public void tearDown() { instance = null; - startFuture = null; + startPromise = null; + SCBEngine.getInstance().destroy(); } @Test public void testRestServerVerticleWithRouter(@Mocked Transport transport, @Mocked Vertx vertx, @Mocked Context context, - @Mocked JsonObject jsonObject, @Mocked Future startFuture) throws Exception { + @Mocked JsonObject jsonObject, @Mocked Promise startPromise) throws Exception { + URIEndpointObject endpointObject = new URIEndpointObject("http://127.0.0.1:8080"); new Expectations() { { @@ -85,26 +201,26 @@ public void testRestServerVerticleWithRouter(@Mocked Transport transport, @Mocke result = endpointObject; } }; - Endpoint endpiont = new Endpoint(transport, "http://127.0.0.1:8080"); + Endpoint endpoint = new Endpoint(transport, "http://127.0.0.1:8080"); new Expectations() { { context.config(); result = jsonObject; jsonObject.getValue(AbstractTransport.ENDPOINT_KEY); - result = endpiont; + result = endpoint; } }; RestServerVerticle server = new RestServerVerticle(); // process stuff done by Expectations server.init(vertx, context); - server.start(startFuture); + server.start(startPromise); } @Test public void testRestServerVerticleWithRouterSSL(@Mocked Transport transport, @Mocked Vertx vertx, @Mocked Context context, - @Mocked JsonObject jsonObject, @Mocked Future startFuture) throws Exception { + @Mocked JsonObject jsonObject, @Mocked Promise startPromise) throws Exception { URIEndpointObject endpointObject = new URIEndpointObject("http://127.0.0.1:8080?sslEnabled=true"); new Expectations() { { @@ -112,63 +228,32 @@ public void testRestServerVerticleWithRouterSSL(@Mocked Transport transport, @Mo result = endpointObject; } }; - Endpoint endpiont = new Endpoint(transport, "http://127.0.0.1:8080?sslEnabled=true"); + Endpoint endpoint = new Endpoint(transport, "http://127.0.0.1:8080?sslEnabled=true"); new Expectations() { { context.config(); result = jsonObject; jsonObject.getValue(AbstractTransport.ENDPOINT_KEY); - result = endpiont; + result = endpoint; } }; RestServerVerticle server = new RestServerVerticle(); // process stuff done by Expectations server.init(vertx, context); - server.start(startFuture); + server.start(startPromise); } - @Test - public void testRestServerVerticleWithHttp2(@Mocked Transport transport, @Mocked Vertx vertx, - @Mocked Context context, - @Mocked JsonObject jsonObject, @Mocked Future startFuture) { - URIEndpointObject endpointObject = new URIEndpointObject("http://127.0.0.1:8080?protocol=http2"); - new Expectations() { - { - transport.parseAddress("http://127.0.0.1:8080?protocol=http2"); - result = endpointObject; - } - }; - Endpoint endpiont = new Endpoint(transport, "http://127.0.0.1:8080?protocol=http2"); - - new Expectations() { - { - context.config(); - result = jsonObject; - jsonObject.getValue(AbstractTransport.ENDPOINT_KEY); - result = endpiont; - } - }; - RestServerVerticle server = new RestServerVerticle(); - boolean status = false; - try { - server.init(vertx, context); - server.start(startFuture); - } catch (Exception e) { - status = true; - } - Assert.assertFalse(status); - } @Test public void testStartFutureAddressEmpty() { boolean status = false; try { - instance.start(startFuture); + instance.start(startPromise); } catch (Exception ex) { status = true; } - Assert.assertFalse(status); + Assertions.assertFalse(status); } @Test @@ -177,20 +262,32 @@ public void testStartFutureAddressNotEmpty() { MockForRestServerVerticle.getInstance().mockTransportConfig(); MockForRestServerVerticle.getInstance().mockRestServerVerticle(); try { - instance.start(startFuture); + instance.start(startPromise); } catch (Exception ex) { status = true; } - Assert.assertFalse(status); + Assertions.assertFalse(status); } @Test public void testMountCorsHandler() { - ArchaiusUtils.setProperty("servicecomb.cors.enabled", true); - ArchaiusUtils.setProperty("servicecomb.cors.allowedMethod", "GET,PUT,POST"); - ArchaiusUtils.setProperty("servicecomb.cors.allowedHeader", "abc,def"); - ArchaiusUtils.setProperty("servicecomb.cors.exposedHeader", "abc2,def2"); - ArchaiusUtils.setProperty("servicecomb.cors.maxAge", 1); + Mockito.when(environment.getProperty("servicecomb.cors.enabled", boolean.class, + false)) + .thenReturn(true); + Mockito.when(environment.getProperty("servicecomb.cors.origin", + String[].class)) + .thenReturn(null); + Mockito.when(environment.getProperty("servicecomb.cors.allowedMethod")) + .thenReturn("GET,PUT,POST"); + Mockito.when(environment.getProperty("servicecomb.cors.allowedHeader")) + .thenReturn("abc,def"); + Mockito.when(environment.getProperty("servicecomb.cors.exposedHeader")) + .thenReturn("abc2,def2"); + Mockito.when(environment.getProperty("servicecomb.cors.maxAge", int.class, -1)) + .thenReturn(1); + Mockito.when(environment.getProperty("servicecomb.cors.allowCredentials", boolean.class, false)) + .thenReturn(false); + Set methodSet = new HashSet<>(3); methodSet.add(HttpMethod.GET); methodSet.add(HttpMethod.PUT); @@ -200,28 +297,28 @@ public void testMountCorsHandler() { CorsHandler corsHandler = new MockUp() { @Mock CorsHandler allowCredentials(boolean allow) { - Assert.assertFalse(allow); + Assertions.assertFalse(allow); counter.incrementAndGet(); return null; } @Mock CorsHandler allowedHeaders(Set headerNames) { - Assert.assertThat(headerNames, Matchers.containsInAnyOrder("abc", "def")); + MatcherAssert.assertThat(headerNames, Matchers.containsInAnyOrder("abc", "def")); counter.incrementAndGet(); return null; } @Mock CorsHandler exposedHeaders(Set headerNames) { - Assert.assertThat(headerNames, Matchers.containsInAnyOrder("abc2", "def2")); + MatcherAssert.assertThat(headerNames, Matchers.containsInAnyOrder("abc2", "def2")); counter.incrementAndGet(); return null; } @Mock CorsHandler allowedMethod(HttpMethod method) { - Assert.assertTrue(methodSet.contains(method)); + Assertions.assertTrue(methodSet.contains(method)); counter.incrementAndGet(); methodSet.remove(method); return null; @@ -229,7 +326,7 @@ CorsHandler allowedMethod(HttpMethod method) { @Mock CorsHandler maxAgeSeconds(int maxAgeSeconds) { - Assert.assertEquals(1, maxAgeSeconds); + Assertions.assertEquals(1, maxAgeSeconds); counter.incrementAndGet(); return null; } @@ -237,8 +334,7 @@ CorsHandler maxAgeSeconds(int maxAgeSeconds) { new MockUp() { @Mock - CorsHandler getCorsHandler(String corsAllowedOrigin) { - Assert.assertEquals("*", corsAllowedOrigin); + CorsHandler getCorsHandler() { return corsHandler; } }; @@ -247,8 +343,8 @@ CorsHandler getCorsHandler(String corsAllowedOrigin) { RestServerVerticle server = new RestServerVerticle(); - Deencapsulation.invoke(server, "mountCorsHandler", router); - Assert.assertEquals(7, counter.get()); + server.mountCorsHandler(router); + Assertions.assertEquals(7, counter.get()); } @Test @@ -274,8 +370,8 @@ Route handler(io.vertx.core.Handler requestHand RestServerVerticle restServerVerticle = new RestServerVerticle(); - Deencapsulation.invoke(restServerVerticle, "mountGlobalRestFailureHandler", mainRouter); - Assert.assertNotNull(handlerHolder.value); + restServerVerticle.mountGlobalRestFailureHandler(mainRouter); + Assertions.assertNotNull(handlerHolder.value); RoutingContext routingContext = Mockito.mock(RoutingContext.class); HttpServerResponse response = Mockito.mock(HttpServerResponse.class); diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java deleted file mode 100644 index a3970f49b33..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx; - -import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TestTransportConfig { - - @Before - public void before() { - ArchaiusUtils.resetConfig(); - } - - @After - public void after() { - ArchaiusUtils.resetConfig(); - } - - @Test - public void testGetAddressNull() { - Assert.assertNull(TransportConfig.getAddress()); - } - - @Test - public void testGetAddressNormal() { - ArchaiusUtils.setProperty("servicecomb.rest.address", "1.1.1.1"); - Assert.assertEquals("1.1.1.1", TransportConfig.getAddress()); - } - - @Test - public void testGetThreadCountNull() { - Assert.assertEquals(1, TransportConfig.getThreadCount()); - } - - @Test - public void testGetThreadCountNormal() { - ArchaiusUtils.setProperty("servicecomb.rest.server.thread-count", 10); - Assert.assertEquals(10, TransportConfig.getThreadCount()); - } - - @Test - public void testGetCompressedAndHeaderSize() { - ArchaiusUtils.setProperty("servicecomb.rest.server.compression", true); - Assert.assertEquals(true, TransportConfig.getCompressed()); - ArchaiusUtils.setProperty("servicecomb.rest.server.maxHeaderSize", 2048); - Assert.assertEquals(2048, TransportConfig.getMaxHeaderSize()); - } - - @Test - public void testIsCorsEnabled() { - Assert.assertFalse(TransportConfig.isCorsEnabled()); - ArchaiusUtils.setProperty("servicecomb.cors.enabled", true); - Assert.assertTrue(TransportConfig.isCorsEnabled()); - ArchaiusUtils.setProperty("servicecomb.cors.enabled", false); - Assert.assertFalse(TransportConfig.isCorsEnabled()); - } - - @Test - public void testGetCorsAllowedOrigin() { - Assert.assertEquals("*", TransportConfig.getCorsAllowedOrigin()); - String origin = "http://localhost:8080"; - ArchaiusUtils.setProperty("servicecomb.cors.origin", origin); - Assert.assertEquals(origin, TransportConfig.getCorsAllowedOrigin()); - } - - @Test - public void testIsCorsAllowCredentials() { - Assert.assertFalse(TransportConfig.isCorsAllowCredentials()); - ArchaiusUtils.setProperty("servicecomb.cors.allowCredentials", true); - Assert.assertTrue(TransportConfig.isCorsAllowCredentials()); - ArchaiusUtils.setProperty("servicecomb.cors.allowCredentials", false); - Assert.assertFalse(TransportConfig.isCorsAllowCredentials()); - } - - @Test - public void testGetCorsAllowedHeaders() { - String configKey = "servicecomb.cors.allowedHeader"; - Assert.assertTrue(TransportConfig.getCorsAllowedHeaders().isEmpty()); - ArchaiusUtils.setProperty(configKey, "abc"); - Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc")); - ArchaiusUtils.setProperty(configKey, "abc, def"); - Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc", "def")); - ArchaiusUtils.setProperty(configKey, "abc ,, def"); - Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc", "def")); - ArchaiusUtils.setProperty(configKey, ""); - Assert.assertTrue(TransportConfig.getCorsAllowedHeaders().isEmpty()); - } - - @Test - public void testGetCorsAllowedMethods() { - String configKey = "servicecomb.cors.allowedMethod"; - Assert.assertTrue(TransportConfig.getCorsAllowedMethods().isEmpty()); - ArchaiusUtils.setProperty(configKey, "GET"); - Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET")); - ArchaiusUtils.setProperty(configKey, "GET, POST"); - Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET", "POST")); - ArchaiusUtils.setProperty(configKey, "GET,,POST"); - Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET", "POST")); - ArchaiusUtils.setProperty(configKey, ""); - Assert.assertTrue(TransportConfig.getCorsAllowedMethods().isEmpty()); - } - - @Test - public void testGetCorsExposedHeaders() { - String configKey = "servicecomb.cors.exposedHeader"; - Assert.assertTrue(TransportConfig.getCorsExposedHeaders().isEmpty()); - ArchaiusUtils.setProperty(configKey, "abc"); - Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc")); - ArchaiusUtils.setProperty(configKey, "abc, def"); - Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc", "def")); - ArchaiusUtils.setProperty(configKey, "abc ,, def"); - Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc", "def")); - ArchaiusUtils.setProperty(configKey, ""); - Assert.assertTrue(TransportConfig.getCorsExposedHeaders().isEmpty()); - } - - @Test - public void testGetCorsMaxAge() { - Assert.assertEquals(-1, TransportConfig.getCorsMaxAge()); - ArchaiusUtils.setProperty("servicecomb.cors.maxAge", 3600); - Assert.assertEquals(3600, TransportConfig.getCorsMaxAge()); - } - - @Test - public void testMaxConcurrentStreams() { - Assert.assertEquals(100L, TransportConfig.getMaxConcurrentStreams()); - ArchaiusUtils.setProperty("servicecomb.rest.server.http2.concurrentStreams", 200L); - Assert.assertEquals(200L, TransportConfig.getMaxConcurrentStreams()); - } - - @Test - public void testUseAlpn() { - Assert.assertTrue(TransportConfig.getUseAlpn()); - ArchaiusUtils.setProperty("servicecomb.rest.server.http2.useAlpnEnabled", false); - Assert.assertFalse(TransportConfig.getUseAlpn()); - } - - - @Test - public void testGetMaxInitialLineLength() { - Assert.assertEquals(4096, TransportConfig.getMaxInitialLineLength()); - ArchaiusUtils.setProperty("servicecomb.rest.server.maxInitialLineLength", 8000); - Assert.assertEquals(8000, TransportConfig.getMaxInitialLineLength()); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestDispatcher.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestDispatcher.java index f02ee0ebb29..db5edd19f8a 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestDispatcher.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestDispatcher.java @@ -17,48 +17,28 @@ package org.apache.servicecomb.transport.rest.vertx; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; - import org.apache.http.HttpHeaders; import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.common.rest.RestProducerInvocation; -import org.apache.servicecomb.common.rest.VertxRestInvocation; -import org.apache.servicecomb.common.rest.filter.HttpServerFilter; -import org.apache.servicecomb.core.CseContext; -import org.apache.servicecomb.core.Transport; +import org.apache.servicecomb.core.SCBEngine; +import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.core.transport.TransportManager; -import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx; -import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; -import io.vertx.core.AsyncResult; -import io.vertx.core.Context; -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.impl.VertxImpl; import io.vertx.core.json.JsonObject; -import io.vertx.core.net.SocketAddress; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Mock; -import mockit.MockUp; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response.Status; import mockit.Mocked; public class TestVertxRestDispatcher { @@ -72,236 +52,112 @@ public class TestVertxRestDispatcher { Throwable throwable; - boolean invoked; + Environment environment = Mockito.mock(Environment.class); @Before public void setUp() { + LegacyPropertyFactory.setEnvironment(environment); + Mockito.when(environment.getProperty( + RestConst.UPLOAD_MAX_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_MAX_FILE_SIZE, long.class, -1L)) + .thenReturn(-1L); + Mockito.when(environment.getProperty(RestConst.UPLOAD_FILE_SIZE_THRESHOLD, int.class, 0)) + .thenReturn(0); + dispatcher = new VertxRestDispatcher(); dispatcher.init(mainRouter); - new MockUp() { - @Mock - void sendFailResponse(Throwable throwable) { - TestVertxRestDispatcher.this.throwable = throwable; - } - - @Mock - void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServletResponseEx responseEx, - List httpServerFilters) { - invoked = true; - } - }; - - CseContext.getInstance().setTransportManager(transportManager); + SCBBootstrap.createSCBEngineForTest(environment).setTransportManager(transportManager); } @After public void teardown() { - CseContext.getInstance().setTransportManager(null); + SCBEngine.getInstance().destroy(); } @Test public void getOrder() { - Assert.assertEquals(Integer.MAX_VALUE, dispatcher.getOrder()); - } - - @Test - public void failureHandlerNormal(@Mocked RoutingContext context) { - RestProducerInvocation restProducerInvocation = new RestProducerInvocation(); - - Exception e = new Exception(); - MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = restProducerInvocation; - context.failure(); - returns(e, e); - context.response(); - result = response; - } - }; - - Deencapsulation.invoke(dispatcher, "failureHandler", context); - - Assert.assertSame(e, this.throwable); - Assert.assertTrue(response.responseClosed); - } - - @Test - public void failureHandlerErrorDataWithInvocation(@Mocked RoutingContext context, @Mocked InvocationException e) { - RestProducerInvocation restProducerInvocation = new RestProducerInvocation(); - - ErrorDataDecoderException edde = new ErrorDataDecoderException(e); - MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = restProducerInvocation; - context.failure(); - returns(edde, edde); - context.response(); - result = response; - } - }; - - Deencapsulation.invoke(dispatcher, "failureHandler", context); - - Assert.assertSame(e, this.throwable); - Assert.assertTrue(response.responseClosed); + Mockito.when(environment.getProperty( + "servicecomb.http.dispatcher.rest.order", int.class, Integer.MAX_VALUE)) + .thenReturn(Integer.MAX_VALUE); + Assertions.assertEquals(Integer.MAX_VALUE, dispatcher.getOrder()); } @Test - public void failureHandlerErrorDataWithNormal(@Mocked RoutingContext context) { - RestProducerInvocation restProducerInvocation = new RestProducerInvocation(); - - Exception e = new Exception(); - ErrorDataDecoderException edde = new ErrorDataDecoderException(e); - MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = restProducerInvocation; - context.failure(); - returns(edde, edde); - context.response(); - result = response; - } - }; - - Deencapsulation.invoke(dispatcher, "failureHandler", context); - - Assert.assertSame(edde, this.throwable); - Assert.assertTrue(response.responseClosed); - } - - @Test - public void failureHandlerWithNoRestProducerInvocationAndInvocationException(@Mocked RoutingContext context) { + public void failureHandlerWithNoRestProducerInvocationAndInvocationException() { + RoutingContext context = Mockito.mock(RoutingContext.class); + Mockito.when(context.get(RestConst.REST_PRODUCER_INVOCATION)).thenReturn(null); InvocationException e = new InvocationException(Status.REQUEST_ENTITY_TOO_LARGE, "testMsg"); ErrorDataDecoderException edde = new ErrorDataDecoderException(e); + Mockito.when(context.failure()).thenReturn(edde); MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = null; - context.failure(); - returns(edde, edde); - context.response(); - result = response; - } - }; + Mockito.when(context.response()).thenReturn(response); - Deencapsulation.invoke(dispatcher, "failureHandler", context); + dispatcher.failureHandler(context); - Assert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); - Assert.assertThat(response.responseStatusCode, Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode())); - Assert.assertThat(response.responseStatusMessage, Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getReasonPhrase())); - Assert.assertThat(response.responseChunk, + MatcherAssert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); + MatcherAssert.assertThat(response.responseStatusCode, Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode())); + MatcherAssert.assertThat(response.responseStatusMessage, + Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getReasonPhrase())); + MatcherAssert.assertThat(response.responseChunk, Matchers.is("{\"message\":\"" + Status.REQUEST_ENTITY_TOO_LARGE.getReasonPhrase() + "\"}")); - Assert.assertTrue(response.responseEnded); + Assertions.assertTrue(response.responseEnded); } @Test - public void failureHandlerWithNoRestProducerInvocationAndOtherException(@Mocked RoutingContext context) { - String exceptionMessage = "test exception message"; + public void failureHandlerWithNoRestProducerInvocationAndOtherException() { + RoutingContext context = Mockito.mock(RoutingContext.class); + Mockito.when(context.get(RestConst.REST_PRODUCER_INVOCATION)).thenReturn(null); + String exceptionMessage = "Internal Server Error"; Exception exception = new Exception(exceptionMessage); + Mockito.when(context.failure()).thenReturn(exception); MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = null; - context.failure(); - returns(exception, exception); - context.response(); - result = response; - } - }; + Mockito.when(context.response()).thenReturn(response); - Deencapsulation.invoke(dispatcher, "failureHandler", context); + dispatcher.failureHandler(context); - Assert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); - Assert.assertThat(response.responseStatusCode, Matchers.is(Status.INTERNAL_SERVER_ERROR.getStatusCode())); - Assert.assertThat(response.responseChunk, + MatcherAssert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); + MatcherAssert.assertThat(response.responseStatusCode, Matchers.is(Status.INTERNAL_SERVER_ERROR.getStatusCode())); + MatcherAssert.assertThat(response.responseChunk, Matchers.is("{\"message\":\"" + exceptionMessage + "\"}")); - Assert.assertTrue(response.responseEnded); + Assertions.assertTrue(response.responseEnded); } @Test - public void failureHandlerWithNoExceptionAndStatusCodeIsSet(@Mocked RoutingContext context) { + public void failureHandlerWithNoExceptionAndStatusCodeIsSet() { + RoutingContext context = Mockito.mock(RoutingContext.class); + Mockito.when(context.get(RestConst.REST_PRODUCER_INVOCATION)).thenReturn(null); + Mockito.when(context.failure()).thenReturn(null); MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = null; - context.failure(); - returns(null, null); - context.response(); - result = response; - context.statusCode(); - result = Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode(); - } - }; + Mockito.when(context.response()).thenReturn(response); + Mockito.when(context.statusCode()).thenReturn(Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode()); - Deencapsulation.invoke(dispatcher, "failureHandler", context); + dispatcher.failureHandler(context); - Assert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); - Assert.assertThat(response.responseStatusCode, Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode())); - Assert.assertTrue(response.responseEnded); + MatcherAssert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); + MatcherAssert.assertThat(response.responseStatusCode, Matchers.is(Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode())); + Assertions.assertTrue(response.responseEnded); } @Test - public void failureHandlerWithNoExceptionAndStatusCodeIsNotSet(@Mocked RoutingContext context) { + public void failureHandlerWithNoExceptionAndStatusCodeIsNotSet() { + RoutingContext context = Mockito.mock(RoutingContext.class); + Mockito.when(context.get(RestConst.REST_PRODUCER_INVOCATION)).thenReturn(null); + Mockito.when(context.failure()).thenReturn(null); MockHttpServerResponse response = new MockHttpServerResponse(); - new Expectations() { - { - context.get(RestConst.REST_PRODUCER_INVOCATION); - result = null; - context.failure(); - returns(null, null); - context.response(); - result = response; - context.statusCode(); - result = Status.OK.getStatusCode(); - } - }; + Mockito.when(context.response()).thenReturn(response); + Mockito.when(context.statusCode()).thenReturn(Status.OK.getStatusCode()); - Deencapsulation.invoke(dispatcher, "failureHandler", context); + dispatcher.failureHandler(context); - Assert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); - Assert.assertThat(response.responseStatusCode, Matchers.is(Status.INTERNAL_SERVER_ERROR.getStatusCode())); - Assert.assertThat(response.responseStatusMessage, Matchers.is(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())); - Assert.assertThat(response.responseChunk, + MatcherAssert.assertThat(response.responseHeader, Matchers.hasEntry(HttpHeaders.CONTENT_TYPE, MediaType.WILDCARD)); + MatcherAssert.assertThat(response.responseStatusCode, Matchers.is(Status.INTERNAL_SERVER_ERROR.getStatusCode())); + MatcherAssert.assertThat(response.responseStatusMessage, + Matchers.is(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())); + MatcherAssert.assertThat(response.responseChunk, Matchers.is("{\"message\":\"" + Status.INTERNAL_SERVER_ERROR.getReasonPhrase() + "\"}")); - Assert.assertTrue(response.responseEnded); - } - - @Test - public void onRequest(@Mocked Context context, @Mocked HttpServerRequest request, - @Mocked SocketAddress socketAdrress) { - Map map = new HashMap<>(); - RoutingContext routingContext = new MockUp() { - @Mock - RoutingContext put(String key, Object obj) { - map.put(key, obj); - return null; - } - - @Mock - HttpServerRequest request() { - return request; - } - }.getMockInstance(); - - new Expectations(VertxImpl.class) { - { - VertxImpl.context(); - result = context; - } - }; - Deencapsulation.invoke(dispatcher, "onRequest", routingContext); - - Assert.assertEquals(VertxRestInvocation.class, map.get(RestConst.REST_PRODUCER_INVOCATION).getClass()); - Assert.assertTrue(invoked); + Assertions.assertTrue(response.responseEnded); } @Test @@ -309,284 +165,32 @@ public void testWrapResponseBody() { VertxRestDispatcher vertxRestDispatcher = new VertxRestDispatcher(); String message = "abcd"; String bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"message\":\"abcd\"}", bodyString); + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"message\":\"abcd\"}", bodyString); message = "\"abcd\""; bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"message\":\"\\\"abcd\\\"\"}", bodyString); + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"message\":\"\\\"abcd\\\"\"}", bodyString); message = ".01ab\"!@#$%^&*()'\\cd"; bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"message\":\".01ab\\\"!@#$%^&*()'\\\\cd\"}", bodyString); + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"message\":\".01ab\\\"!@#$%^&*()'\\\\cd\"}", bodyString); message = new JsonObject().put("key", new JsonObject().put("k2", "value")).toString(); bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"key\":{\"k2\":\"value\"}}", bodyString); + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"key\":{\"k2\":\"value\"}}", bodyString); message = "ab\"23\n@!#cd"; bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"message\":\"ab\\\"23\\n@!#cd\"}", bodyString); + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"message\":\"ab\\\"23\\n@!#cd\"}", bodyString); message = "ab\"23\r\n@!#cd"; bodyString = vertxRestDispatcher.wrapResponseBody(message); - Assert.assertNotNull(bodyString); - Assert.assertEquals("{\"message\":\"ab\\\"23\\r\\n@!#cd\"}", bodyString); - } -} - -class MockHttpServerResponse implements HttpServerResponse { - boolean responseClosed; - - boolean responseEnded; - - Map responseHeader = new HashMap<>(1); - - int responseStatusCode; - - String responseStatusMessage; - - String responseChunk; - - @Override - public void close() { - responseClosed = true; - } - - @Override - public HttpServerResponse putHeader(String name, String value) { - responseHeader.put(name, value); - return this; - } - - @Override - public HttpServerResponse setStatusCode(int statusCode) { - responseStatusCode = statusCode; - return this; - } - - @Override - public HttpServerResponse setStatusMessage(String statusMessage) { - responseStatusMessage = statusMessage; - return this; - } - - @Override - public void end() { - responseEnded = true; - } - - @Override - public void end(String chunk) { - responseEnded = true; - responseChunk = chunk; - } - - @Override - public HttpServerResponse exceptionHandler(Handler handler) { - return null; - } - - @Override - public HttpServerResponse write(Buffer data) { - return null; - } - - @Override - public HttpServerResponse setWriteQueueMaxSize(int maxSize) { - return null; - } - - @Override - public boolean writeQueueFull() { - return false; - } - - @Override - public HttpServerResponse drainHandler(Handler handler) { - return null; - } - - @Override - public int getStatusCode() { - return 0; - } - - @Override - public String getStatusMessage() { - return null; - } - - @Override - public HttpServerResponse setChunked(boolean chunked) { - return null; - } - - @Override - public boolean isChunked() { - return false; - } - - @Override - public MultiMap headers() { - return null; - } - - @Override - public HttpServerResponse putHeader(CharSequence name, CharSequence value) { - return null; - } - - @Override - public HttpServerResponse putHeader(String name, Iterable values) { - return null; - } - - @Override - public HttpServerResponse putHeader(CharSequence name, Iterable values) { - return null; - } - - @Override - public MultiMap trailers() { - return null; - } - - @Override - public HttpServerResponse putTrailer(String name, String value) { - return null; - } - - @Override - public HttpServerResponse putTrailer(CharSequence name, CharSequence value) { - return null; - } - - @Override - public HttpServerResponse putTrailer(String name, Iterable values) { - return null; - } - - @Override - public HttpServerResponse putTrailer(CharSequence name, Iterable value) { - return null; - } - - @Override - public HttpServerResponse closeHandler(Handler handler) { - return null; - } - - @Override - public HttpServerResponse endHandler(Handler handler) { - return null; - } - - @Override - public HttpServerResponse write(String chunk, String enc) { - return null; - } - - @Override - public HttpServerResponse write(String chunk) { - return null; - } - - @Override - public HttpServerResponse writeContinue() { - return null; - } - - @Override - public void end(String chunk, String enc) { - - } - - @Override - public void end(Buffer chunk) { - - } - - @Override - public HttpServerResponse sendFile(String filename, long offset, long length) { - return null; - } - - @Override - public HttpServerResponse sendFile(String filename, long offset, long length, - Handler> resultHandler) { - return null; - } - - @Override - public boolean ended() { - return false; - } - - @Override - public boolean closed() { - return false; - } - - @Override - public boolean headWritten() { - return false; - } - - @Override - public HttpServerResponse headersEndHandler(Handler handler) { - return null; - } - - @Override - public HttpServerResponse bodyEndHandler(Handler handler) { - return null; - } - - @Override - public long bytesWritten() { - return 0; - } - - @Override - public int streamId() { - return 0; - } - - @Override - public HttpServerResponse push(HttpMethod method, String host, String path, - Handler> handler) { - return null; - } - - @Override - public HttpServerResponse push(HttpMethod method, String path, MultiMap headers, - Handler> handler) { - return null; - } - - @Override - public HttpServerResponse push(HttpMethod method, String path, Handler> handler) { - return null; - } - - @Override - public HttpServerResponse push(HttpMethod method, String host, String path, MultiMap headers, - Handler> handler) { - return null; - } - - @Override - public void reset(long code) { - - } - - @Override - public HttpServerResponse writeCustomFrame(int type, int flags, Buffer payload) { - return null; + Assertions.assertNotNull(bodyString); + Assertions.assertEquals("{\"message\":\"ab\\\"23\\r\\n@!#cd\"}", bodyString); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestTransport.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestTransport.java index d43b69fada5..fb14f5115de 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestTransport.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestVertxRestTransport.java @@ -17,38 +17,73 @@ package org.apache.servicecomb.transport.rest.vertx; +import static org.apache.servicecomb.core.transport.AbstractTransport.PUBLISH_ADDRESS; + import java.io.IOException; import java.net.ServerSocket; +import java.util.HashMap; +import java.util.Map; -import org.apache.servicecomb.core.Endpoint; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.common.LegacyPropertyFactory; import org.apache.servicecomb.foundation.vertx.VertxUtils; -import org.apache.servicecomb.swagger.invocation.AsyncResponse; -import org.junit.Assert; +import org.apache.servicecomb.foundation.vertx.client.tcp.TcpClientConfig; +import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.mockito.Mockito; +import org.springframework.core.env.Environment; import io.vertx.core.AbstractVerticle; import io.vertx.core.DeploymentOptions; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.impl.SysProps; import mockit.Expectations; import mockit.Mock; import mockit.MockUp; public class TestVertxRestTransport { - private VertxRestTransport instance = new VertxRestTransport(); + private VertxRestTransport instance; + + Environment environment = Mockito.mock(Environment.class); + + @Before + public void setUp() { + Mockito.when(environment.getProperty( + "servicecomb.request.timeout", long.class, (long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT)) + .thenReturn((long) TcpClientConfig.DEFAULT_LOGIN_TIMEOUT); + Mockito.when(environment.getProperty("servicecomb.rest.client.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.client.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.server.verticle-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.rest.server.thread-count", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty("servicecomb.http.dispatcher.rest.order", int.class, Integer.MAX_VALUE)) + .thenReturn(Integer.MAX_VALUE); + Mockito.when(environment.getProperty("servicecomb.rest.publishPort", int.class, 0)) + .thenReturn(0); + Mockito.when(environment.getProperty(PUBLISH_ADDRESS, "")) + .thenReturn(""); + Mockito.when(environment.getProperty("servicecomb.transport.eventloop.size", int.class, -1)) + .thenReturn(-1); + Mockito.when(environment.getProperty(SysProps.DISABLE_FILE_CP_RESOLVING.name, boolean.class, true)) + .thenReturn(true); + LegacyPropertyFactory.setEnvironment(environment); + instance = new VertxRestTransport(); + instance.setEnvironment(environment); + } @Test public void testGetInstance() { - Assert.assertNotNull(instance); + Assertions.assertNotNull(instance); } @Test public void testGetName() { - Assert.assertEquals("rest", instance.getName()); + Assertions.assertEquals("rest", instance.getName()); } @Test @@ -62,41 +97,25 @@ public Vertx init(VertxOptions vertxOptions) { } @Mock - public boolean blockDeploy(Vertx vertx, Class cls, + public Map blockDeploy(Vertx vertx, Class cls, DeploymentOptions options) throws InterruptedException { - return true; + Map result = new HashMap<>(); + result.put("code", true); + return result; } }; instance.init(); } catch (Exception e) { + e.printStackTrace(); status = true; } - Assert.assertFalse(status); - } - - @Test - public void testSendException() { - boolean validAssert; - Invocation invocation = Mockito.mock(Invocation.class); - AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); - URIEndpointObject endpoint = Mockito.mock(URIEndpointObject.class); - Endpoint end = Mockito.mock(Endpoint.class); - Mockito.when(invocation.getEndpoint()).thenReturn(end); - Mockito.when(invocation.getEndpoint().getAddress()).thenReturn(endpoint); - try { - validAssert = true; - instance.send(invocation, asyncResp); - } catch (Exception e) { - - validAssert = false; - } - Assert.assertFalse(validAssert); + Assertions.assertFalse(status); } @Test public void testGetOrder() { VertxRestTransport transport = new VertxRestTransport(); - Assert.assertEquals(-1000, transport.getOrder()); + Assertions.assertEquals(-1000, transport.getOrder()); } @Test @@ -109,7 +128,9 @@ public void testCanInitNullAddress() throws IOException { }; VertxRestTransport transport = new VertxRestTransport(); - Assert.assertTrue(transport.canInit()); + Environment environment = Mockito.mock(Environment.class); + transport.setEnvironment(environment); + Assertions.assertTrue(transport.canInit()); } @Test @@ -125,7 +146,8 @@ public void testCanInitListened() throws IOException { }; VertxRestTransport transport = new VertxRestTransport(); - Assert.assertFalse(transport.canInit()); + transport.setEnvironment(environment); + Assertions.assertFalse(transport.canInit()); ss.close(); } @@ -144,6 +166,7 @@ public void testCanInitNotListened() throws IOException { }; VertxRestTransport transport = new VertxRestTransport(); - Assert.assertTrue(transport.canInit()); + transport.setEnvironment(environment); + Assertions.assertTrue(transport.canInit()); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java deleted file mode 100644 index 0dd1af6f366..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import org.junit.Test; - -public class AccessLogConfigurationTest { - - @Test - public void getAccessLogEnabled() { - boolean result = AccessLogConfiguration.INSTANCE.getAccessLogEnabled(); - assertFalse(result); - } - - @Test - public void getAccesslogPattern() { - String result = AccessLogConfiguration.INSTANCE.getAccesslogPattern(); - assertEquals("%h - - %t %r %s %B %D", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGeneratorTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGeneratorTest.java deleted file mode 100644 index 1df6609d4fa..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogGeneratorTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog; - -import static org.junit.Assert.assertEquals; - -import java.text.SimpleDateFormat; -import java.util.TimeZone; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpMethodItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.PlainTextItem; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; - -public class AccessLogGeneratorTest { - - private static final AccessLogGenerator ACCESS_LOG_GENERATOR = new AccessLogGenerator("%m - %t"); - - @Test - public void testConstructor() { - AccessLogItem[] elements = Deencapsulation.getField(ACCESS_LOG_GENERATOR, "accessLogItems"); - assertEquals(3, elements.length); - assertEquals(HttpMethodItem.class, elements[0].getClass()); - assertEquals(PlainTextItem.class, elements[1].getClass()); - assertEquals(DatetimeConfigurableItem.class, elements[2].getClass()); - } - - @Test - public void testLog() { - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - long startMillisecond = 1416863450581L; - AccessLogParam accessLogParam = new AccessLogParam<>(); - accessLogParam.setStartMillisecond(startMillisecond).setContextData(context); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatetimeConfigurableItem.DEFAULT_DATETIME_PATTERN, - DatetimeConfigurableItem.DEFAULT_LOCALE); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.method()).thenReturn(HttpMethod.DELETE); - - String log = ACCESS_LOG_GENERATOR.generateLog(accessLogParam); - - Assert.assertEquals("DELETE" + " - " + simpleDateFormat.format(startMillisecond), log); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItemTest.java deleted file mode 100644 index d8977aabebe..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/CookieItemTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import java.util.HashSet; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.ext.web.Cookie; -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.impl.CookieImpl; - -public class CookieItemTest { - - public static final String COOKIE_NAME = "cookieName"; - - private static final CookieItem ELEMENT = new CookieItem(COOKIE_NAME); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HashSet cookieSet = new HashSet<>(); - String cookieValue = "cookieValue"; - CookieImpl cookie = new CookieImpl(COOKIE_NAME, cookieValue); - - cookieSet.add(cookie); - Mockito.when(mockContext.cookieCount()).thenReturn(1); - Mockito.when(mockContext.cookies()).thenReturn(cookieSet); - param.setContextData(mockContext); - - String result = ELEMENT.getFormattedItem(param); - - Assert.assertEquals(cookieValue, result); - } - - @Test - public void getFormattedElementOnCookieCountIsZero() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HashSet cookieSet = new HashSet<>(); - - Mockito.when(mockContext.cookieCount()).thenReturn(0); - Mockito.when(mockContext.cookies()).thenReturn(cookieSet); - param.setContextData(mockContext); - - String result = ELEMENT.getFormattedItem(param); - - Assert.assertEquals("-", result); - } - - @Test - public void getFormattedElementOnCookieSetIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - - Mockito.when(mockContext.cookieCount()).thenReturn(1); - Mockito.when(mockContext.cookies()).thenReturn(null); - param.setContextData(mockContext); - - String result = ELEMENT.getFormattedItem(param); - - Assert.assertEquals("-", result); - } - - @Test - public void getFormattedElementOnNotFound() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HashSet cookieSet = new HashSet<>(); - String cookieValue = "cookieValue"; - CookieImpl cookie = new CookieImpl("anotherCookieName", cookieValue); - - cookieSet.add(cookie); - Mockito.when(mockContext.cookieCount()).thenReturn(1); - Mockito.when(mockContext.cookies()).thenReturn(cookieSet); - param.setContextData(mockContext); - - String result = ELEMENT.getFormattedItem(param); - - Assert.assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItemTest.java deleted file mode 100644 index 17876efc644..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DatetimeConfigurableItemTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import java.text.SimpleDateFormat; -import java.util.Locale; -import java.util.TimeZone; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; - -import io.vertx.ext.web.RoutingContext; - -public class DatetimeConfigurableItemTest { - - private static final long START_MILLISECOND = 1416863450581L; - - @Test - public void getFormattedElement() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem( - "EEE, yyyy MMM dd HH:mm:ss zzz|GMT-08|zh-CN"); - - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals("星期一, 2014 十一月 24 13:10:50 GMT-08:00", result); - } - - @Test - public void getFormattedElementOnNoPattern() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem( - "|GMT+08|zh-CN"); - - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals("星期二, 25 十一月 2014 05:10:50 GMT+08:00", result); - } - - @Test - public void getFormattedElementOnNoTimezone() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem( - "yyyy/MM/dd zzz||zh-CN"); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd zzz", Locale.forLanguageTag("zh-CN")); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals(simpleDateFormat.format(START_MILLISECOND), result); - } - - @Test - public void getFormattedElementOnNoLocale() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem( - "EEE, dd MMM yyyy HH:mm:ss zzz|GMT+08|"); - - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals("Tue, 25 Nov 2014 05:10:50 GMT+08:00", result); - } - - @Test - public void getFormattedElementOnNoConfig() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem( - "||"); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatetimeConfigurableItem.DEFAULT_DATETIME_PATTERN, - Locale.US); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals(simpleDateFormat.format(START_MILLISECOND), result); - } - - @Test - public void testConstructorWithNoArg() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem(); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals("EEE, dd MMM yyyy HH:mm:ss zzz", element.getPattern()); - assertEquals(Locale.US, element.getLocale()); - assertEquals(TimeZone.getDefault(), element.getTimezone()); - assertEquals(simpleDateFormat.format(START_MILLISECOND), result); - } - - @Test - public void testConstructorWithNoSeparator() { - DatetimeConfigurableItem element = new DatetimeConfigurableItem("yyyy/MM/dd HH:mm:ss zzz"); - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zzz", Locale.US); - simpleDateFormat.setTimeZone(TimeZone.getDefault()); - AccessLogParam accessLogParam = - new AccessLogParam().setStartMillisecond(START_MILLISECOND); - - String result = element.getFormattedItem(accessLogParam); - - assertEquals("yyyy/MM/dd HH:mm:ss zzz", element.getPattern()); - assertEquals(Locale.US, element.getLocale()); - assertEquals(TimeZone.getDefault(), element.getTimezone()); - assertEquals(simpleDateFormat.format(START_MILLISECOND), result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItemTest.java deleted file mode 100644 index 88e18f0188e..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationMillisecondItemTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; - -import io.vertx.ext.web.RoutingContext; - -public class DurationMillisecondItemTest { - - public static final DurationMillisecondItem ELEMENT = new DurationMillisecondItem(); - - @Test - public void getFormattedElement() { - AccessLogParam param = - new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(2L); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("1", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItemTest.java deleted file mode 100644 index 6f99e475292..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/DurationSecondItemTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; - -import io.vertx.ext.web.RoutingContext; - -public class DurationSecondItemTest { - - public static final DurationSecondItem ELEMENT = new DurationSecondItem(); - - @Test - public void getFormattedElementOn999ms() { - AccessLogParam param = - new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1000L); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("0", result); - } - - @Test - public void getFormattedElementOn1000ms() { - AccessLogParam param = - new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1001L); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("1", result); - } - - @Test - public void getFormattedElementOn1001ms() { - AccessLogParam param = - new AccessLogParam().setStartMillisecond(1L).setEndMillisecond(1002L); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("1", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItemTest.java deleted file mode 100644 index db30ecf7f5f..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/FirstLineOfRequestItemTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpVersion; -import io.vertx.ext.web.RoutingContext; - -public class FirstLineOfRequestItemTest { - - public static final FirstLineOfRequestItem ELEMENT = new FirstLineOfRequestItem(); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String uri = "/test/uri"; - - param.setContextData(mockContext); - Mockito.when(mockContext.request()).thenReturn(request); - Mockito.when(request.method()).thenReturn(HttpMethod.DELETE); - Mockito.when(request.path()).thenReturn(uri); - Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_1); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("\"DELETE " + uri + " HTTP/1.1\"", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItemTest.java deleted file mode 100644 index 82bb42fdf99..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/HttpMethodItemTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class HttpMethodItemTest { - - @Test - public void getFormattedElement() { - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - Mockito.when(routingContext.request()).thenReturn(request); - Mockito.when(request.method()).thenReturn(HttpMethod.DELETE); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(routingContext); - - Assert.assertEquals("DELETE", new HttpMethodItem().getFormattedItem(param)); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(routingContext); - - Mockito.when(routingContext.request()).thenReturn(null); - - Assert.assertEquals("-", new HttpMethodItem().getFormattedItem(param)); - } - - @Test - public void getFormattedElementOnMethodIsNull() { - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(routingContext); - - Mockito.when(routingContext.request()).thenReturn(request); - Mockito.when(request.method()).thenReturn(null); - - Assert.assertEquals("-", new HttpMethodItem().getFormattedItem(param)); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItemTest.java deleted file mode 100644 index a3c39d435c8..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/InvocationContextItemTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.ext.web.RoutingContext; - -public class InvocationContextItemTest { - - public static final String INVOCATION_CONTEXT_KEY = "testKey"; - - private static InvocationContextItem ITEM = new InvocationContextItem(INVOCATION_CONTEXT_KEY); - - @Test - public void testGetFormattedItem() { - AccessLogParam accessLogParam = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map routingContextData = new HashMap<>(); - Invocation invocation = Mockito.mock(Invocation.class); - String testValue = "testValue"; - - accessLogParam.setContextData(routingContext); - Mockito.when(routingContext.data()).thenReturn(routingContextData); - routingContextData.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - Mockito.when(invocation.getContext(INVOCATION_CONTEXT_KEY)).thenReturn(testValue); - - String result = ITEM.getFormattedItem(accessLogParam); - - Assert.assertThat(result, Matchers.is(testValue)); - } - - @Test - public void testGetFormattedItemOnInvocationContextValueNotFound() { - AccessLogParam accessLogParam = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map routingContextData = new HashMap<>(); - Invocation invocation = Mockito.mock(Invocation.class); - - accessLogParam.setContextData(routingContext); - Mockito.when(routingContext.data()).thenReturn(routingContextData); - routingContextData.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - Mockito.when(invocation.getContext(INVOCATION_CONTEXT_KEY)).thenReturn(null); - - String result = ITEM.getFormattedItem(accessLogParam); - - Assert.assertThat(result, Matchers.is(InvocationContextItem.NOT_FOUND)); - } - - @Test - public void testGetFormattedItemOnInvocationNotFound() { - AccessLogParam accessLogParam = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map routingContextData = new HashMap<>(); - - accessLogParam.setContextData(routingContext); - Mockito.when(routingContext.data()).thenReturn(routingContextData); - - String result = ITEM.getFormattedItem(accessLogParam); - - Assert.assertThat(result, Matchers.is(InvocationContextItem.NOT_FOUND)); - } - - @Test - public void testGetFormattedItemOnRoutingContextDataNotFound() { - AccessLogParam accessLogParam = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - - accessLogParam.setContextData(routingContext); - Mockito.when(routingContext.data()).thenReturn(null); - - String result = ITEM.getFormattedItem(accessLogParam); - - Assert.assertThat(result, Matchers.is(InvocationContextItem.NOT_FOUND)); - } -} \ No newline at end of file diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItemTest.java deleted file mode 100644 index 285529d729f..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalHostItemTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class LocalHostItemTest { - - public static final LocalHostItem ELEMENT = new LocalHostItem(); - - @Test - public void getFormattedItem() { - String localAddress = "192.168.0.1"; - AccessLogParam accessLogParam = new AccessLogParam<>(); - accessLogParam.setLocalAddress(localAddress); - - Assert.assertEquals(localAddress, ELEMENT.getFormattedItem(accessLogParam)); - } - - @Test - public void getLocalAddress() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress localAddress = Mockito.mock(SocketAddress.class); - String localHost = "testHost"; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(localAddress); - Mockito.when(localAddress.host()).thenReturn(localHost); - - String result = LocalHostItem.getLocalAddress(param); - - assertEquals(localHost, result); - } - - @Test - public void getLocalAddressOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = LocalHostItem.getLocalAddress(param); - - assertEquals("-", result); - } - - @Test - public void getLocalAddressOnLocalAddressIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(null); - - String result = LocalHostItem.getLocalAddress(param); - - assertEquals("-", result); - } - - @Test - public void getLocalAddressOnHostIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress localAddress = Mockito.mock(SocketAddress.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(localAddress); - Mockito.when(localAddress.host()).thenReturn(null); - - String result = LocalHostItem.getLocalAddress(param); - - assertEquals("-", result); - } - - @Test - public void getLocalAddressIsEmpty() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress localAddress = Mockito.mock(SocketAddress.class); - String localHost = ""; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(localAddress); - Mockito.when(localAddress.host()).thenReturn(localHost); - - String result = LocalHostItem.getLocalAddress(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItemTest.java deleted file mode 100644 index e1ad26a6e00..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/LocalPortItemTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class LocalPortItemTest { - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress localAddress = Mockito.mock(SocketAddress.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(localAddress); - Mockito.when(localAddress.port()).thenReturn(8080); - - String result = new LocalPortItem().getFormattedItem(param); - - assertEquals("8080", result); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = new LocalPortItem().getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnLocalAddressIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.localAddress()).thenReturn(null); - - String result = new LocalPortItem().getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItemTest.java deleted file mode 100644 index e4f812f9256..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/PlainTextItemTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class PlainTextItemTest { - - @Test - public void getFormattedElement() { - PlainTextItem element = new PlainTextItem("contentTest"); - assertEquals("contentTest", element.getFormattedItem(null)); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItemTest.java deleted file mode 100644 index a653982776e..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/QueryStringItemTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class QueryStringItemTest { - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String query = "?status=up"; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.query()).thenReturn(query); - - String result = new QueryStringItem().getFormattedItem(param); - - assertEquals(query, result); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = new QueryStringItem().getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnQueryIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.query()).thenReturn(null); - - String result = new QueryStringItem().getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnQueryIsEmpty() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String query = ""; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.query()).thenReturn(query); - - String result = new QueryStringItem().getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItemTest.java deleted file mode 100644 index 78f8ee3272f..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RemoteHostItemTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.RoutingContext; - -public class RemoteHostItemTest { - - public static final RemoteHostItem ELEMENT = new RemoteHostItem(); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress address = Mockito.mock(SocketAddress.class); - String remoteHost = "remoteHost"; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.remoteAddress()).thenReturn(address); - Mockito.when(address.host()).thenReturn(remoteHost); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals(remoteHost, result); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - - @Test - public void getFormattedElementOnRemoteAddressIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.remoteAddress()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - - @Test - public void getFormattedElementOnHostIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress address = Mockito.mock(SocketAddress.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.remoteAddress()).thenReturn(address); - Mockito.when(address.host()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - - @Test - public void getFormattedElementOnHostIsEmpty() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - SocketAddress address = Mockito.mock(SocketAddress.class); - String remoteHost = ""; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.remoteAddress()).thenReturn(address); - Mockito.when(address.host()).thenReturn(remoteHost); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItemTest.java deleted file mode 100644 index f8a41966f8c..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestHeaderItemTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.impl.headers.VertxHttpHeaders; -import io.vertx.ext.web.RoutingContext; - -public class RequestHeaderItemTest { - - private static final String VAR_NAME = "varName"; - - private static final RequestHeaderItem ELEMENT = new RequestHeaderItem(VAR_NAME); - - @Test - public void getFormattedElement() { - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(mockContext); - HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class); - VertxHttpHeaders headers = new VertxHttpHeaders(); - String testValue = "testValue"; - headers.add(VAR_NAME, testValue); - - Mockito.when(mockContext.request()).thenReturn(mockRequest); - Mockito.when(mockRequest.headers()).thenReturn(headers); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals(testValue, result); - assertEquals(ELEMENT.getVarName(), VAR_NAME); - } - - @Test - public void getFormattedElementIfHeaderIsNull() { - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(mockContext); - HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class); - - Mockito.when(mockContext.request()).thenReturn(mockRequest); - Mockito.when(mockRequest.headers()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementIfNotFound() { - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - AccessLogParam param = new AccessLogParam<>(); - param.setContextData(mockContext); - HttpServerRequest mockRequest = Mockito.mock(HttpServerRequest.class); - VertxHttpHeaders headers = new VertxHttpHeaders(); - String testValue = "testValue"; - headers.add("anotherHeader", testValue); - - Mockito.when(mockContext.request()).thenReturn(mockRequest); - Mockito.when(mockRequest.headers()).thenReturn(headers); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItemTest.java deleted file mode 100644 index f5c90c7add9..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/RequestProtocolItemTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpVersion; -import io.vertx.ext.web.RoutingContext; - -public class RequestProtocolItemTest { - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_1); - - String result = new RequestProtocolItem().getFormattedItem(param); - assertEquals("HTTP/1.1", result); - - Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_1_0); - result = new RequestProtocolItem().getFormattedItem(param); - assertEquals("HTTP/1.0", result); - - Mockito.when(request.version()).thenReturn(HttpVersion.HTTP_2); - result = new RequestProtocolItem().getFormattedItem(param); - assertEquals("HTTP/2.0", result); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = new RequestProtocolItem().getFormattedItem(param); - - assertEquals("-", result); - } - - - @Test - public void getFormattedElementOnVersionIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.version()).thenReturn(null); - - String result = new RequestProtocolItem().getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItemTest.java deleted file mode 100644 index 47593d62f5f..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseHeaderItemTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.http.impl.headers.VertxHttpHeaders; -import io.vertx.ext.web.RoutingContext; - -public class ResponseHeaderItemTest { - - private static final String VAR_NAME = "varName"; - - private static final ResponseHeaderItem ELEMENT = new ResponseHeaderItem(VAR_NAME); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class); - VertxHttpHeaders headers = new VertxHttpHeaders(); - String headerValue = "headerValue"; - - param.setContextData(mockContext); - headers.add(VAR_NAME, headerValue); - - Mockito.when(mockContext.response()).thenReturn(mockResponse); - Mockito.when(mockResponse.headers()).thenReturn(headers); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals(headerValue, result); - assertEquals(ELEMENT.getVarName(), VAR_NAME); - } - - @Test - public void getFormattedElementOnHeadersIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class); - - param.setContextData(mockContext); - - Mockito.when(mockContext.response()).thenReturn(mockResponse); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnResponseIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - - param.setContextData(mockContext); - - Mockito.when(mockContext.response()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnNotFound() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class); - VertxHttpHeaders headers = new VertxHttpHeaders(); - String headerValue = "headerValue"; - - param.setContextData(mockContext); - headers.add("anotherHeader", headerValue); - - Mockito.when(mockContext.response()).thenReturn(mockResponse); - Mockito.when(mockResponse.headers()).thenReturn(headers); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItemTest.java deleted file mode 100644 index dd7576fe43c..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/ResponseSizeItemTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -public class ResponseSizeItemTest { - - private static final ResponseSizeItem ELEMENT = new ResponseSizeItem("0"); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class); - long bytesWritten = 16L; - - param.setContextData(mockContext); - Mockito.when(mockContext.response()).thenReturn(mockResponse); - Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals(String.valueOf(bytesWritten), result); - } - - @Test - public void getFormattedElementOnResponseIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - - param.setContextData(mockContext); - Mockito.when(mockContext.response()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("0", result); - } - - - @Test - public void getFormattedElementOnBytesWrittenIsZero() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext mockContext = Mockito.mock(RoutingContext.class); - HttpServerResponse mockResponse = Mockito.mock(HttpServerResponse.class); - long bytesWritten = 0L; - - param.setContextData(mockContext); - Mockito.when(mockContext.response()).thenReturn(mockResponse); - Mockito.when(mockResponse.bytesWritten()).thenReturn(bytesWritten); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("0", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusItemTest.java deleted file mode 100644 index 19197a3f6f2..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/StatusItemTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.RoutingContext; - -public class StatusItemTest { - - private static final HttpStatusItem STATUS_ELEMENT = new HttpStatusItem(); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerResponse response = Mockito.mock(HttpServerResponse.class); - int statusCode = 200; - - param.setContextData(context); - Mockito.when(context.response()).thenReturn(response); - Mockito.when(response.getStatusCode()).thenReturn(statusCode); - - String result = STATUS_ELEMENT.getFormattedItem(param); - - assertEquals("200", result); - } - - - @Test - public void getFormattedElementOnResponseIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.response()).thenReturn(null); - - String result = STATUS_ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItemTest.java deleted file mode 100644 index fce9e96ccba..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/TraceIdItemTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.hamcrest.core.Is.is; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.servicecomb.common.rest.RestConst; -import org.apache.servicecomb.core.Const; -import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class TraceIdItemTest { - private static final TraceIdItem ELEMENT = new TraceIdItem(); - - @Test - public void testGetFormattedElementFromInvocationContext() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map data = new HashMap<>(); - Invocation invocation = Mockito.mock(Invocation.class); - String traceIdTest = "traceIdTest"; - - Mockito.when(invocation.getContext(Const.TRACE_ID_NAME)).thenReturn(traceIdTest); - Mockito.when(routingContext.data()).thenReturn(data); - data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - - param.setContextData(routingContext); - - String result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is(traceIdTest)); - } - - @Test - public void testGetFormattedElementFromRequestHeader() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map data = new HashMap<>(); - Invocation invocation = Mockito.mock(Invocation.class); - String traceIdTest = "traceIdTest"; - - Mockito.when(invocation.getContext(Const.TRACE_ID_NAME)).thenReturn(null); - Mockito.when(routingContext.data()).thenReturn(data); - data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - Mockito.when(request.getHeader(Const.TRACE_ID_NAME)).thenReturn(traceIdTest); - Mockito.when(routingContext.request()).thenReturn(request); - - param.setContextData(routingContext); - - String result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is(traceIdTest)); - } - - @Test - public void testGetFormattedElementOnTraceIdNotFound() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map data = new HashMap<>(); - Invocation invocation = Mockito.mock(Invocation.class); - - Mockito.when(invocation.getContext(Const.TRACE_ID_NAME)).thenReturn(""); - Mockito.when(routingContext.data()).thenReturn(data); - data.put(RestConst.REST_INVOCATION_CONTEXT, invocation); - - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - Mockito.when(request.getHeader(Const.TRACE_ID_NAME)).thenReturn(null); - Mockito.when(routingContext.request()).thenReturn(request); - - param.setContextData(routingContext); - - String result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is("-")); - - Mockito.when(invocation.getContext(Const.TRACE_ID_NAME)).thenReturn(null); - result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is("-")); - } - - @Test - public void testGetFormattedElementOnInvocationContextIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - Map data = new HashMap<>(); - - Mockito.when(routingContext.data()).thenReturn(data); - - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - Mockito.when(request.getHeader(Const.TRACE_ID_NAME)).thenReturn(null); - Mockito.when(routingContext.request()).thenReturn(request); - - param.setContextData(routingContext); - - String result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is("-")); - } - - @Test - public void testGetFormattedElementOnDataIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - Mockito.when(request.getHeader(Const.TRACE_ID_NAME)).thenReturn(null); - Mockito.when(routingContext.request()).thenReturn(request); - - param.setContextData(routingContext); - Mockito.when(routingContext.data()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - Assert.assertThat(result, is("-")); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItemTest.java deleted file mode 100644 index ee200bc0c1b..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathItemTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class UrlPathItemTest { - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String uri = "/uri/test"; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.path()).thenReturn(uri); - - String result = new UrlPathItem().getFormattedItem(param); - - Assert.assertEquals(uri, result); - } - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = new UrlPathItem().getFormattedItem(param); - - Assert.assertEquals("-", result); - } - - @Test - public void getFormattedElementOnMethodIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.path()).thenReturn(null); - - String result = new UrlPathItem().getFormattedItem(param); - - Assert.assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItemTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItemTest.java deleted file mode 100644 index 11710e451af..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UrlPathWithQueryItemTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import static org.junit.Assert.assertEquals; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; - -public class UrlPathWithQueryItemTest { - - public static final UrlPathWithQueryItem ELEMENT = new UrlPathWithQueryItem(); - - @Test - public void getFormattedElement() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String uri = "uriTest"; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.uri()).thenReturn(uri); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals(uri, result); - } - - - @Test - public void getFormattedElementOnRequestIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - @Test - public void getFormattedElementOnUriIsNull() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.uri()).thenReturn(null); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } - - - @Test - public void getFormattedElementOnUriIsEmpty() { - AccessLogParam param = new AccessLogParam<>(); - RoutingContext context = Mockito.mock(RoutingContext.class); - HttpServerRequest request = Mockito.mock(HttpServerRequest.class); - String uri = ""; - - param.setContextData(context); - Mockito.when(context.request()).thenReturn(request); - Mockito.when(request.uri()).thenReturn(uri); - - String result = ELEMENT.getFormattedItem(param); - - assertEquals("-", result); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java deleted file mode 100644 index a2559c6737a..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -/** - * For access log extension test - */ -public class UserDefinedAccessLogItem implements AccessLogItem { - private String config; - - public UserDefinedAccessLogItem(String config) { - this.config = config; - } - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return "user-defined-" + config; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java deleted file mode 100644 index eec7b29fc19..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/element/impl/UserDefinedAccessLogItemLowPriority.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.AccessLogParam; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; - -import io.vertx.ext.web.RoutingContext; - -/** - * For access log extension test, will be overridden by {@link RemoteHostItem}("%h"), - * and takes no effect. - */ -public class UserDefinedAccessLogItemLowPriority implements AccessLogItem { - - @Override - public String getFormattedItem(AccessLogParam accessLogParam) { - return "OverriddenItem"; - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java deleted file mode 100644 index 0ef62e50872..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/impl/AccessLogHandlerTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.impl; - -import java.util.HashSet; -import java.util.concurrent.TimeUnit; - -import javax.xml.ws.Holder; - -import org.apache.log4j.Level; -import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vertx.core.Handler; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.net.SocketAddress; -import io.vertx.ext.web.Cookie; -import io.vertx.ext.web.RoutingContext; -import mockit.Mock; -import mockit.MockUp; - -public class AccessLogHandlerTest { - private static final AccessLogHandler ACCESS_LOG_HANDLER = new AccessLogHandler( - "%h - - %s durationMillisecond=[%D] %{test-config}user-defined %{cookie-name}C %v"); - - private LogCollector logCollector; - - @Before - public void setUp() { - logCollector = new LogCollector(); - logCollector.setLogLevel("accesslog", Level.INFO); - } - - @After - public void tearDown() { - logCollector.teardown(); - } - - @Test - public void testHandle() { - RoutingContext routingContext = Mockito.mock(RoutingContext.class); - HashSet cookies = new HashSet<>(); - Cookie cookie = Mockito.mock(Cookie.class); - HttpServerResponse httpServerResponse = new MockUp() { - @Mock - public HttpServerResponse endHandler(Handler handler) { - handler.handle(null); - return null; - } - - @Mock - public int getStatusCode() { - return 200; - } - }.getMockInstance(); - HttpServerRequest httpServerRequest = Mockito.mock(HttpServerRequest.class); - SocketAddress remoteSocketAddress = Mockito.mock(SocketAddress.class); - SocketAddress localSocketAddress = Mockito.mock(SocketAddress.class); - - Holder counter = new Holder<>(); - counter.value = 0; - String testThreadName = Thread.currentThread().getName(); - new MockUp() { - @Mock - long currentTimeMillis() { - if (!testThreadName.equals(Thread.currentThread().getName())) { - return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - } - if (counter.value < 1) { - ++counter.value; - return 1L; - } - return 123L; - } - }; - cookies.add(cookie); - Mockito.when(cookie.getName()).thenReturn("cookie-name"); - Mockito.when(cookie.getValue()).thenReturn("cookie-value"); - Mockito.when(routingContext.cookies()).thenReturn(cookies); - Mockito.when(routingContext.response()).thenReturn(httpServerResponse); - Mockito.when(routingContext.request()).thenReturn(httpServerRequest); - Mockito.when(httpServerRequest.remoteAddress()).thenReturn(remoteSocketAddress); - Mockito.when(remoteSocketAddress.host()).thenReturn("192.168.0.22"); - Mockito.when(httpServerRequest.localAddress()).thenReturn(localSocketAddress); - Mockito.when(localSocketAddress.host()).thenReturn("192.168.0.33"); - ACCESS_LOG_HANDLER.handle(routingContext); - - Assert.assertEquals( - "192.168.0.22 - - 200 durationMillisecond=[122] user-defined-test-config cookie-value 192.168.0.33", - logCollector.getEvents().get(0).getMessage()); - } -} \ No newline at end of file diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java deleted file mode 100644 index cf31d15835b..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/parser/impl/VertxRestAccessLogPatternParserTest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; - -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.AccessLogItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.CookieItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DatetimeConfigurableItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationMillisecondItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.DurationSecondItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.FirstLineOfRequestItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpMethodItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.HttpStatusItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.InvocationContextItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalHostItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.LocalPortItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.QueryStringItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RemoteHostItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestHeaderItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.RequestProtocolItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseHeaderItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.ResponseSizeItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.TraceIdItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.element.impl.UrlPathWithQueryItem; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.CompositeVertxRestAccessLogItemMeta; -import org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta; -import org.junit.Assert; -import org.junit.Test; - -import io.vertx.ext.web.RoutingContext; -import mockit.Deencapsulation; -import mockit.Mock; -import mockit.MockUp; - -public class VertxRestAccessLogPatternParserTest { - private static final String ROW_PATTERN = "[cs-method] %m %s%T%D%h%v%p%B%b%r%U%q" - + "cs-uri-stemcs-uri-querycs-uri%H%t%{yyyy MM dd HH:mm:ss zzz}t" - + "%{yyyy MM dd HH:mm:ss|GMT+0|en-US}t" - + "%{incoming-header}i" - + "%{outgoing-header}o" - + "%{cookie}C" - + "%SCB-traceId" - + "%{ctx}SCB-ctx"; - - private static VertxRestAccessLogPatternParser accessLogPatternParser = new VertxRestAccessLogPatternParser(); - - @Test - public void testParsePatternFullTest() { - List> result = accessLogPatternParser.parsePattern(ROW_PATTERN); - assertEquals(28, result.size()); - - assertEquals("[", result.get(0).getFormattedItem(null)); - assertEquals(HttpMethodItem.class, result.get(1).getClass()); - assertEquals("] ", result.get(2).getFormattedItem(null)); - assertEquals(HttpMethodItem.class, result.get(3).getClass()); - assertEquals(" ", result.get(4).getFormattedItem(null)); - assertEquals(HttpStatusItem.class, result.get(5).getClass()); - assertEquals(DurationSecondItem.class, result.get(6).getClass()); - assertEquals(DurationMillisecondItem.class, result.get(7).getClass()); - assertEquals(RemoteHostItem.class, result.get(8).getClass()); - assertEquals(LocalHostItem.class, result.get(9).getClass()); - assertEquals(LocalPortItem.class, result.get(10).getClass()); - assertEquals(ResponseSizeItem.class, result.get(11).getClass()); - assertEquals("0", ((ResponseSizeItem) result.get(11)).getZeroBytes()); - assertEquals(ResponseSizeItem.class, result.get(12).getClass()); - assertEquals("-", ((ResponseSizeItem) result.get(12)).getZeroBytes()); - assertEquals(FirstLineOfRequestItem.class, result.get(13).getClass()); - assertEquals(UrlPathItem.class, result.get(14).getClass()); - assertEquals(QueryStringItem.class, result.get(15).getClass()); - assertEquals(UrlPathItem.class, result.get(16).getClass()); - assertEquals(QueryStringItem.class, result.get(17).getClass()); - assertEquals(UrlPathWithQueryItem.class, result.get(18).getClass()); - assertEquals(RequestProtocolItem.class, result.get(19).getClass()); - assertEquals(DatetimeConfigurableItem.class, result.get(20).getClass()); - assertEquals(DatetimeConfigurableItem.DEFAULT_DATETIME_PATTERN, - ((DatetimeConfigurableItem) result.get(20)).getPattern()); - assertEquals(DatetimeConfigurableItem.DEFAULT_LOCALE, ((DatetimeConfigurableItem) result.get(20)).getLocale()); - assertEquals(TimeZone.getDefault(), ((DatetimeConfigurableItem) result.get(20)).getTimezone()); - assertEquals("yyyy MM dd HH:mm:ss zzz", ((DatetimeConfigurableItem) result.get(21)).getPattern()); - assertEquals(DatetimeConfigurableItem.DEFAULT_LOCALE, ((DatetimeConfigurableItem) result.get(21)).getLocale()); - assertEquals(TimeZone.getDefault(), ((DatetimeConfigurableItem) result.get(21)).getTimezone()); - assertEquals("yyyy MM dd HH:mm:ss", ((DatetimeConfigurableItem) result.get(22)).getPattern()); - assertEquals(Locale.forLanguageTag("en-US"), ((DatetimeConfigurableItem) result.get(22)).getLocale()); - assertEquals(TimeZone.getTimeZone("GMT+0"), ((DatetimeConfigurableItem) result.get(22)).getTimezone()); - assertEquals(RequestHeaderItem.class, result.get(23).getClass()); - assertEquals("incoming-header", ((RequestHeaderItem) result.get(23)).getVarName()); - assertEquals(ResponseHeaderItem.class, result.get(24).getClass()); - assertEquals("outgoing-header", ((ResponseHeaderItem) result.get(24)).getVarName()); - assertEquals(CookieItem.class, result.get(25).getClass()); - assertEquals("cookie", ((CookieItem) result.get(25)).getVarName()); - assertEquals(TraceIdItem.class, result.get(26).getClass()); - assertEquals(InvocationContextItem.class, result.get(27).getClass()); - assertEquals("ctx", ((InvocationContextItem) result.get(27)).getVarName()); - } - - @Test - public void testParsePattern() { - String pattern = " %m cs-uri-stem %{response-header}o "; - List> result = accessLogPatternParser.parsePattern(pattern); - assertEquals(7, result.size()); - - assertEquals(" ", result.get(0).getFormattedItem(null)); - assertEquals(HttpMethodItem.class, result.get(1).getClass()); - assertEquals(" ", result.get(2).getFormattedItem(null)); - assertEquals(UrlPathItem.class, result.get(3).getClass()); - assertEquals(" ", result.get(4).getFormattedItem(null)); - assertEquals(ResponseHeaderItem.class, result.get(5).getClass()); - assertEquals("response-header", ((ResponseHeaderItem) result.get(5)).getVarName()); - assertEquals(" ", result.get(6).getFormattedItem(null)); - } - - @Test - public void testParsePatternWithNoBlank() { - String pattern = "%mcs-uri-stem%{response-header}o"; - List> result = accessLogPatternParser.parsePattern(pattern); - assertEquals(3, result.size()); - - assertEquals(HttpMethodItem.class, result.get(0).getClass()); - assertEquals(UrlPathItem.class, result.get(1).getClass()); - assertEquals(ResponseHeaderItem.class, result.get(2).getClass()); - assertEquals("response-header", ((ResponseHeaderItem) result.get(2)).getVarName()); - } - - @Test - public void testParsePatternComplex() { - String pattern = "%m cs-uri-stem %{response-header}o abc cs-uri-query %s%{request} header}i plain cs-uri"; - List> result = accessLogPatternParser.parsePattern(pattern); - assertEquals(12, result.size()); - - assertEquals(HttpMethodItem.class, result.get(0).getClass()); - assertEquals(" ", result.get(1).getFormattedItem(null)); - assertEquals(UrlPathItem.class, result.get(2).getClass()); - assertEquals(" ", result.get(3).getFormattedItem(null)); - assertEquals(ResponseHeaderItem.class, result.get(4).getClass()); - assertEquals("response-header", ((ResponseHeaderItem) result.get(4)).getVarName()); - assertEquals(" abc ", result.get(5).getFormattedItem(null)); - assertEquals(QueryStringItem.class, result.get(6).getClass()); - assertEquals(" ", result.get(7).getFormattedItem(null)); - assertEquals(HttpStatusItem.class, result.get(8).getClass()); - assertEquals(RequestHeaderItem.class, result.get(9).getClass()); - assertEquals("request} header", ((RequestHeaderItem) result.get(9)).getVarName()); - assertEquals(" plain ", result.get(10).getFormattedItem(null)); - assertEquals(UrlPathWithQueryItem.class, result.get(11).getClass()); - } - - Comparator comparator = VertxRestAccessLogPatternParser.accessLogItemMetaComparator; - - /** - * one factor test - */ - @Test - public void testCompareMetaSimple() { - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta(null, null, null, 0), - new VertxRestAccessLogItemMeta(null, null, null, 1) - ) < 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta(null, "}abc", null, 0), - new VertxRestAccessLogItemMeta(null, null, null, 0) - ) < 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta(null, "}abc", null, 0), - new VertxRestAccessLogItemMeta(null, "}de", null, 0) - ) < 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta(null, "}abc", null, 0), - new VertxRestAccessLogItemMeta(null, "}ab", null, 0) - ) < 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%abc", null, null, 0), - new VertxRestAccessLogItemMeta("%de", null, null, 0) - ) < 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%abc", null, null, 0), - new VertxRestAccessLogItemMeta("%ab", null, null, 0) - ) < 0 - ); - Assert.assertEquals(0, comparator.compare( - new VertxRestAccessLogItemMeta("%abc", null, null, 0), - new VertxRestAccessLogItemMeta("%abc", null, null, 0) - )); - } - - /** - * multiple factors test - */ - @Test - public void testCompareMetaComplex() { - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0), - new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0) - ) > 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%abc", null, null, 0), - new VertxRestAccessLogItemMeta("%bcd", "}ab", null, 0) - ) > 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%bcd", "}abc", null, 0), - new VertxRestAccessLogItemMeta("%abc", "}abc", null, 0) - ) > 0 - ); - Assert.assertTrue( - comparator.compare( - new VertxRestAccessLogItemMeta("%abc", "}abc", null, 1), - new VertxRestAccessLogItemMeta("%ab", "}ab", null, 0) - ) > 0 - ); - } - - @Test - public void testComparePlaceholderString() { - Assert.assertTrue( - VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "bbc") < 0 - ); - Assert.assertTrue( - VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "ab") < 0 - ); - Assert.assertEquals(0, VertxRestAccessLogPatternParser.comparePlaceholderString("abc", "abc")); - Assert.assertTrue( - VertxRestAccessLogPatternParser.comparePlaceholderString("bbc", "abc") > 0 - ); - Assert.assertTrue( - VertxRestAccessLogPatternParser.comparePlaceholderString("ab", "abc") > 0 - ); - } - - @Test - public void testExtendedVertxRestAccessLogItemCreator() { - final List metaList0 = new ArrayList<>(); - metaList0.add(new VertxRestAccessLogItemMeta("%{", "}abc", null)); - metaList0.add(new VertxRestAccessLogItemMeta("%{", "}a", null)); - metaList0.add(new VertxRestAccessLogItemMeta("%_", null, null, -1)); - - final List metaList1 = new ArrayList<>(); - metaList0.add(new VertxRestAccessLogItemMeta("%a", "}abc", null)); - metaList0.add(new VertxRestAccessLogItemMeta("%0", "}abc", null, 1)); - metaList0.add(new VertxRestAccessLogItemMeta("%m", null, null)); - - new MockUp() { - @Mock - List loadVertxRestAccessLogItemMeta() { - List metaList = new ArrayList<>(1); - CompositeVertxRestAccessLogItemMeta compositeMeta0 = new CompositeVertxRestAccessLogItemMeta() { - @Override - public List getAccessLogItemMetas() { - return metaList0; - } - }; - CompositeVertxRestAccessLogItemMeta compositeMeta1 = new CompositeVertxRestAccessLogItemMeta() { - @Override - public List getAccessLogItemMetas() { - return metaList1; - } - }; - metaList.add(compositeMeta0); - metaList.add(compositeMeta1); - metaList.add(new VertxRestAccessLogItemMeta("%{", null, null)); - return metaList; - } - }; - - VertxRestAccessLogPatternParser parser = new VertxRestAccessLogPatternParser(); - - List accessLogItemMetaList = - Deencapsulation.getField(parser, "metaList"); - - assertEquals(7, accessLogItemMetaList.size()); - assertEquals("%_", accessLogItemMetaList.get(0).getPrefix()); - assertEquals("%a", accessLogItemMetaList.get(1).getPrefix()); - assertEquals("}abc", accessLogItemMetaList.get(1).getSuffix()); - assertEquals("%{", accessLogItemMetaList.get(2).getPrefix()); - assertEquals("}abc", accessLogItemMetaList.get(2).getSuffix()); - assertEquals("%{", accessLogItemMetaList.get(3).getPrefix()); - assertEquals("}a", accessLogItemMetaList.get(3).getSuffix()); - assertEquals("%m", accessLogItemMetaList.get(4).getPrefix()); - assertNull(accessLogItemMetaList.get(4).getSuffix()); - assertEquals("%{", accessLogItemMetaList.get(5).getPrefix()); - assertNull(accessLogItemMetaList.get(5).getSuffix()); - assertEquals("%0", accessLogItemMetaList.get(6).getPrefix()); - assertEquals("}abc", accessLogItemMetaList.get(6).getSuffix()); - } -} diff --git a/transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta b/transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta deleted file mode 100644 index b539f7c7d3e..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.TestSingleExtendedAccessLogItemMeta -org.apache.servicecomb.transport.rest.vertx.accesslog.parser.impl.TestCompositeExtendedAccessLogItemMeta \ No newline at end of file diff --git a/transports/transport-rest/transport-rest-vertx/src/test/resources/log4j.properties b/transports/transport-rest/transport-rest-vertx/src/test/resources/log4j.properties deleted file mode 100644 index fbea91e7afd..00000000000 --- a/transports/transport-rest/transport-rest-vertx/src/test/resources/log4j.properties +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -log4j.rootLogger=INFO, out, stdout - -# CONSOLE appender not used by default -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n - -# File appender -log4j.appender.out=org.apache.log4j.FileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n -log4j.appender.out.file=target/test.log -log4j.appender.out.append=true